Swift Performance
Finding
The optimized Swift facade is neutral or faster for the shared crypto workloads. Identity import is 7.38% faster after removing the generic combined record path; the cached public-key getter is 91.90% faster. Parse-and-verify is 6.96% slower at the median and 12.49% slower at p95, within the descriptive 10%/15% latency budgets and not reproduced as a native Rust regression.
The audit used three paired optimized processes on a GitHub-hosted arm64
macos-15 runner with Swift 6.1.2. Values are nanoseconds per authored
SoftchatKit call. Negative deltas mean the current SDK is faster.
| Operation | Bytes | Old median ns | Current median ns | Delta | Current p95 ns | p95 delta |
|---|---|---|---|---|---|---|
| Import identity | 32 | 17,871 | 16,552 | -7.38% | 17,979 | -1.18% |
| Read cached public key | 0 | 247 | 20 | -91.90% | 20 | -92.22% |
| NIP-44 encrypt | 32 | 45,979 | 44,054 | -4.19% | 44,490 | -5.50% |
| NIP-44 decrypt | 32 | 43,587 | 43,153 | -1.00% | 43,286 | -6.57% |
| NIP-44 encrypt | 1,024 | 53,399 | 48,900 | -8.43% | 49,421 | -13.90% |
| NIP-44 decrypt | 1,024 | 52,602 | 48,059 | -8.64% | 48,727 | -13.77% |
| NIP-44 encrypt | 64,000 | 376,964 | 366,781 | -2.70% | 379,782 | -8.74% |
| NIP-44 decrypt | 64,000 | 386,037 | 366,391 | -5.09% | 406,401 | +4.27% |
| Sign NIP-01 event | 32 | 95,549 | 92,454 | -3.24% | 97,601 | +0.01% |
| Parse and verify event | 374 | 39,696 | 42,460 | +6.96% | 45,655 | +12.49% |
The 20-ns getter is an API-shape check, not a useful absolute latency claim.
Current-only baseline
| Operation | Bytes | Median ns | p95 ns |
|---|---|---|---|
| Create NIP-59 rumor | 15 | 4,897 | 4,947 |
| Create NIP-17 text message | 15 | 15,485 | 15,689 |
| Create durable gift wrap | 15 | 292,357 | 295,934 |
| Authenticate and unwrap | 15 | 173,322 | 173,632 |
| Stream-encrypt attachment | 64,000 | 681,080 | 687,838 |
Optimizations retained
SoftchatIdentityimports through the lightweight native constructor, caches its validated public key, and avoids the Android-only registry state.- Encrypt and decrypt return or accept direct payload fields instead of round-tripping an aggregate generated record.
- Immutable Swift values own received events, messages, and metadata; native records do not leak into application layers.
- The identity lock protects handle lifetime and early erasure without making every public getter an FFI call.
- Streaming media uses bounded chunks and delays exposing decrypted output until authentication succeeds.
Footprint
The performance harness links three unstripped dynamic libraries:
| Harness library set | Old bytes | Current bytes | Delta |
|---|---|---|---|
Rust + generated FFI + SoftchatKit | 2,425,336 | 4,895,304 | +101.84% |
This is a link-input measurement, not a shipped iOS application size. The Swift package carries a static XCFramework so the final application linker can dead-strip unused code. A release archive and dSYM measurement on physical iOS is still required before setting an Apple footprint gate.
Developer guidance
- Create one
SoftchatIdentityfor the authenticated session and retain its cachedpublicKey; do not recreate it per message. - Call synchronous crypto and parsing from a bounded task or executor rather
than the main actor. Do not add an
asyncwrapper that hides unbounded work. - Keep the identity as an ordinary ARC-owned reference. Call
erase()only when authority must end early. - Pass complete events, envelopes, relay frames, and attachment chunks through
SoftchatKit. The generated FFI module is internal. - Keep Keychain/Secure Enclave policy,
URLSession, GRDB, background transfer, and application lifecycle in Swift. - For extensions, create an independent session owner and close it explicitly; do not share callbacks or secret-derived state across process boundaries.
Run the shared and current-only audit with
scripts/run-swift-performance.sh, or dispatch the manual performance
workflow. Any facade, FFI, package, or native-profile change requires the
macOS package consumer and affected performance audit.
Open work
The macOS source, DocC, XCFramework/SwiftPM build, and package consumer are green. Remaining Apple evidence is an external application/archive/extension integration, physical-iOS latency, startup and memory, and final archive/dSYM footprint.