This document specifies the reproducible path for running the iOS demo client with UniFFI Swift bindings, Keychain-backed secret storage, file-protected local metadata, guided secondary-device onboarding, and APNs token capture.
flowchart LR
UI[SwiftUI Setup, Chat, Call, and Security UI] --> NET[URLSession JSON transport]
UI --> STORE[Keychain and file-protected app state]
UI --> SWIFT[UniFFI Swift bindings]
SWIFT --> XC[pqmsg_iosFFI.xcframework]
XC --> RUST[pqmsg-ios crate]
RUST --> CORE[pqmsg-core]
NET --> SRV[pqmsg-server]
UI --> APNS[APNs registration]
- private keys, session snapshots, and APNs token are persisted in iOS Keychain,
- setup, progress, cursor, bundle, identity-pin, and conversation metadata are persisted under Application Support with
completeUntilFirstUserAuthenticationfile protection, - protocol operations are executed in Rust (
pqmsg-ios->pqmsg-core), - first-seen identity keys are pinned and key changes are blocked by default,
- relay and inbox requests use Ed25519 request-auth headers from Rust,
- iOS client automatically checks prekey inventory via
/v1/users/{user_id}/prekeys/statusafter each inbox poll and replenishes one-time prekeys when the server signals low inventory, - the Security tab can list linked devices, link a new device id, and revoke non-current linked devices through authenticated server requests,
- the Security tab can rotate the current device identity to fresh keys and a new device id via
/rotate/init+/rotate/confirm, automatically republish prekeys for the new identity, and inspect/identity-logrotation history, - the Security tab can prepare a portable linked-device onboarding package by first linking the target device id on the server and then sealing regenerated device prekeys with the existing identity keys using a versioned internal payload format (
SecondaryDeviceOnboardingPayloadwith version, server URL, keys, and export timestamp) wrapped viaSecretStringpassphrase protection andWrappedSecretArgon2id + AES-256-GCM storage format, - the Setup tab can import that sealed onboarding package on the secondary device, automatically apply the embedded server URL, persist the adopted keys, publish fresh prekeys automatically, and leave the final local step as
Verify server, - APNs token registration is integrated and exposed through setup/security screens,
- the Security tab exposes a destructive reset action that first retires the authenticated current device on the server when keys are still present, then removes per-user keys, sessions, pins, cursors, conversation metadata, and the stored APNs token,
- HTTP transport is accepted only for local debug hosts; production builds require HTTPS.
The iOS client includes PQ-encrypted 1:1 voice and video calling:
- CallView: SwiftUI sheet with dark gradient background, peer avatar, call status, timer, and PQ-Protected badge,
- Call buttons: phone and video icons in the Chat toolbar trigger
startOutgoingCall(peerUserId:callType:), - Incoming calls: accept/decline buttons with polling-based signal detection,
- PQ key exchange: UniFFI
buildFormatStringAuthHeaders()signs call signaling requests with the user's Ed25519 identity key, - Signaling: REST-based call signaling via
callOffer(),callAnswer(),callIceCandidate(),callHangup(), andpollCallSignals()onApiClient, - State management:
AppStatemanages call lifecycle with@Publishedproperties (activeCallId,callStatus,callElapsedSeconds,showCallView).
- macOS with Xcode 15+,
- Rust toolchain,
xcodegen(brew install xcodegen),- iOS simulator or physical device,
- optional Apple Developer account for APNs entitlement signing.
From repository root:
cd mobile/ios
chmod +x scripts/build_rust_ios.sh scripts/generate_project.sh
./scripts/build_rust_ios.shThis script performs:
- target installation (
aarch64-apple-ios,aarch64-apple-ios-sim,x86_64-apple-ios), - release builds for
pqmsg-iosusing its manifest-pinnedpq-oqsbackend, - UniFFI Swift binding generation into
mobile/ios/PQMsgDemo/Generated, - XCFramework assembly at
mobile/ios/Frameworks/pqmsg_iosFFI.xcframework.
When crates/pqmsg-ios/src/lib.rs changes, rerun this script before opening Xcode so the Swift bindings and XCFramework include the latest bridge exports.
cd mobile/ios
./scripts/generate_project.sh
open PQMsgDemo.xcodeproj- Start server:
PQMSG_DATABASE_URL='sqlite://./pqmsg-server.db?mode=rwc' \
PQMSG_BIND='127.0.0.1:3000' \
PQMSG_SECURITY_PROFILE='research' \
cargo run -p pqmsg-server- In the iOS app:
- Setup tab:
- set server URL to
http://127.0.0.1:3000for simulator-local demo, - generate keys, register user, publish prekeys, verify server,
- for a secondary device, paste the sealed package from the primary device into
Import Linked Device, provide the passphrase, then runVerify Server, - request APNs token if push entitlements are configured.
- set server URL to
- Chats tab:
- open peer conversation,
- fetch bundle, send encrypted message, poll inbox,
- tap phone or video icon in the chat toolbar to initiate a PQ-encrypted call.
- Security tab:
- inspect active crypto profile, transport validity, pinned identities, and local state counts.
- use
Secondary Device Onboardingto enter a target device id, seal a passphrase-protected onboarding package, and copy the resulting package text to the secondary device. - use the Devices section to list linked devices, manually link a new device id, or revoke a non-current device.
- use
Rotate Identitywith a fresh managed device id to generate new identity keys for the current device, complete the server challenge-confirm rotation, republish prekeys, and return the setup flow toVerify Server. - use
Load Identity Logto inspect server-recorded initial and rotation identity events. - use
Reset Local Stateto retire the current device on the server when possible and then purge the current user's local device material when rotating or revoking the account.
- The app requests notification permission and registers for APNs via
UIApplicationDelegate. - APNs token is surfaced in Setup/Security and optionally submitted to
/v1/users/{user_id}/push-token. - For APNs registration payloads, use
provider: "apns"andtoken: <apns-device-token-hex>on/v1/users/{user_id}/push-token. - Server-side APNs wake dispatch requires
PQMSG_APNS_BEARER_TOKENandPQMSG_APNS_TOPIC.
- Replace debug HTTP endpoint with production HTTPS endpoint.
- Configure certificate pinning policy in client transport.
- Switch entitlement from development to production APS environment.
- Verify push behavior on physical devices.
- Produce release archive, validate in Organizer, and submit through App Store Connect.