Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"version": "0.2",
"language": "en, en-US, en-GB",
"words": [
"Buildables",
"fileprivate",
"iphonesimulator",
"linuxmain",
"LLDB",
"Ruhe",
"Testables",
"xcodeproj",
"xcpretty",
"xctest"
],
"ignorePaths": [
"**/.cspell.json",
".gitignore"
],
"languageSettings": [
{
"languageId": "swift",
"locale": "en, en-US, en-GB",
"caseSensitive": true
}
]
}
6 changes: 6 additions & 0 deletions .github/.cspell.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"import": "../.cspell.json",
"words": [
"pipefail"
]
}
71 changes: 71 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: CI

on:
push:
pull_request:

jobs:
version:
uses: Myotest/shared-workflows/.github/workflows/version.yml@v1.8.0
with:
tag_prefix: ""
secrets:
FF_MERGE_PAT: ${{ secrets.FF_MERGE_PAT }}

swift-macos:
name: Swift (macOS)
needs: version
runs-on: macos-26
steps:
- uses: actions/checkout@v6
- name: swift test
run: swift test

xcode-ios:
name: Xcode (iOS ${{ matrix.ios }})
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'}}
needs: version
runs-on: macos-26
strategy:
matrix:
ios: ["26.2"]
steps:
- uses: actions/checkout@v6
- name: xcodebuild
run: |
set -o pipefail
xcodebuild clean test \
-destination "platform=iOS Simulator,OS=${{ matrix.ios }},name=iPhone 17" \
-scheme SwiftDigest-CI \
-disableAutomaticPackageResolution \
| xcpretty -c

xcode-macos:
name: Xcode (macOS)
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'}}
needs: version
runs-on: macos-26
steps:
- uses: actions/checkout@v6
- name: xcodebuild
run: |
set -o pipefail
xcodebuild clean test \
-destination "platform=macOS" \
-scheme SwiftDigest-CI-macOS \
-disableAutomaticPackageResolution \
| xcpretty -c

swift-linux:
name: Swift ${{ matrix.swift }} (Linux)
needs: version
runs-on: ubuntu-24.04
strategy:
matrix:
swift: ["5.10.1", "6.0.3", "6.1.3", "6.2.4"]
container:
image: swift:${{ matrix.swift }}
steps:
- uses: actions/checkout@v6
- name: swift test
run: swift test
52 changes: 52 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Build & Test Commands

```bash
# Build
swift build

# Clean build artifacts
swift package clean

# Run all tests
swift test

# Run a single test
swift test --filter MD5DigestTests/testEmptyData

# Regenerate Linux test manifest (after adding/removing tests)
swift test --generate-linuxmain

# Xcode — iOS simulator
xcodebuild clean test \
-destination "platform=iOS Simulator,OS=13.3,name=iPhone 11" \
-scheme SwiftDigest-Travis | xcpretty -c

# Xcode — macOS
xcodebuild clean test \
-destination "platform=macOS" \
-scheme SwiftDigest-Travis-macOS | xcpretty -c
```

## Architecture

Single-file library (`Sources/SwiftDigest/MD5Digest.swift`) with three layers:

1. **Public API** — `Sequence<UInt8>` extension exposing `.md5` computed property on any byte sequence (e.g. `Data`, `String.UTF8View`).

2. **`MD5Digest`** — Immutable 16-byte value type representing the result. Conforms to `Hashable`, `RawRepresentable` (hex string), `LosslessStringConvertible`, and `Codable`.

3. **`MD5State`** (fileprivate) — Core MD5 implementation. Processes 64-byte chunks through four rounds using the standard MD5 functions (`f0`–`f3`). Assumes little-endian and asserts this on init.

Not optimized for large data; the README recommends CommonCrypto for inputs beyond a few KB.

## Constraints

- **Never edit `*.xcodeproj` or `project.pbxproj` files.** Use Xcode directly for any project configuration changes.

## Linux Support

After modifying test files, run `swift test --generate-linuxmain` to update `Tests/SwiftDigestTests/XCTestManifests.swift` and `Tests/LinuxMain.swift`, otherwise Linux CI will miss new tests.
21 changes: 21 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// swift-tools-version:5.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "SwiftDigest",
products: [
.library(
name: "SwiftDigest",
targets: ["SwiftDigest"]),
],
targets: [
.target(
name: "SwiftDigest",
dependencies: []),
.testTarget(
name: "SwiftDigestTests",
dependencies: ["SwiftDigest"]),
]
)
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ Copyright (c) 2017 Nikolai Ruhe.

SwiftDigest is released under the MIT License.

The original repository seems to no longer be maintained.
We will maintain this fork for the foreseeable future, but we are not actively developing it.

## Contents

This is a pure Swift implementation of the MD5 algorithm. I might add more algorithms in the future. Or not.

The main purpose is to provide hashing through a pure Swift framework without dependencies other than
Swift Foundation. Currently no effort has been taken to optimze the performance. When hashing more than a
Swift Foundation. Currently no effort has been taken to optimize the performance. When hashing more than a
couple of kilo bytes it might be better to use Apple's CommonCrypto implementation.

## Examples
Expand Down
2 changes: 0 additions & 2 deletions SwiftDigest/Info.plist → Sources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,5 @@
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ public struct MD5Digest : Hashable, RawRepresentable, LosslessStringConvertible,
/// Pure Swift implementation of the MD5 algorithm.
fileprivate struct MD5State {

var a = UInt32(0x67452301)
var b = UInt32(0xefcdab89)
var c = UInt32(0x98badcfe)
var d = UInt32(0x10325476)
var a: UInt32 = 0x67452301
var b: UInt32 = 0xefcdab89
var c: UInt32 = 0x98badcfe
var d: UInt32 = 0x10325476

static let chunkSize = 64
static let endOfMessageMarker: UInt8 = 0x80
Expand Down Expand Up @@ -147,7 +147,8 @@ fileprivate struct MD5State {
@inline(__always) @discardableResult
private mutating func feedFullChunks(in message: Data) -> Int {
let chunkCount = message.count / MD5State.chunkSize
message.withUnsafeBytes { (pointer: UnsafePointer<UInt32>) -> Void in
message.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in
let pointer = buffer.baseAddress!.assumingMemoryBound(to: UInt32.self)
var cursor = pointer
for _ in 0 ..< chunkCount {
feed(chunkPointer: &cursor)
Expand Down
File renamed without changes.
Loading