Skip to content

Swift SDK: move identity-key derivation & enableNetwork mnemonic handling behind platform-wallet FFI #3808

@QuantumExplorer

Description

@QuantumExplorer

Summary

Two Swift sites still orchestrate the mnemonic → seed → DIP-9 path → key derivation pipeline (and pull cleartext mnemonics across the FFI boundary) instead of persisting only Rust-returned key material. This violates the architectural rules in packages/swift-sdk/CLAUDE.md:

  • "Do not build derivation paths in Swift."
  • "Do not orchestrate multi-step derivation pipelines in Swift (mnemonic → seed → path → key → store)."
  • "No pulling mnemonics or seeds across the FFI boundary so Swift can 'finish' an operation Rust already knows how to complete."
  • "Identity key derivation + any action that uses a derived key belongs in platform-wallet."

Surfaced as Major / Heavy-lift review findings on #3772; deferred from that PR because it is a cross-language refactor independent of that PR's network-scoping scope.

Site 1 — identity-key derivation in the persister callback

packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletPersistenceHandler.swiftderiveAndStoreIdentityKey(...) (~L1803). The method resolves the wallet's network, fetches the mnemonic from Keychain, builds the DIP-9 identity-authentication path via KeyDerivation.getIdentityAuthenticationPath, and derives the private key in Swift, then writes it to Keychain.

Target shape: a platform-wallet FFI entry point that takes (wallet handle / wallet_id, identity_index, key_index, network) and returns (serialized_path, 32 private-key bytes) — derivation entirely Rust-side. Swift keeps only the sanctioned final step: writing the returned bytes to Keychain under PersistentPublicKey.privateKeyKeychainIdentifier.

Site 2 — enableNetwork re-feeds the mnemonic across FFI

packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swiftenableNetwork(_:) (~L744-759) calls WalletStorage().retrieveMnemonic(for: wallet.walletId) in a SwiftUI view and hands the cleartext mnemonic back to mgr.createWallet(mnemonic:network:name:). This is the exact anti-precedent named in CLAUDE.md and also widens the window where the cleartext phrase lives in a Swift String.

Target shape: a single FFI entry point, e.g. platform_wallet_enable_on_network(wallet_id, target_network), that resolves seed material entirely inside platform-wallet and registers the per-network sibling wallet. Swift only persists the resulting per-network Keychain entries (mnemonic + metadata blob) under the new scoped walletId.

Acceptance criteria

  • New platform-wallet (Rust) entry point(s) performing the full derivation/registration internally, exposed through rs-platform-wallet-ffi.
  • deriveAndStoreIdentityKey reduced to: call FFI → write returned key bytes to Keychain. No Mnemonic.toSeed / KeyDerivation.* / path-building in Swift.
  • enableNetwork no longer calls retrieveMnemonic; it calls the new enable-on-network FFI and persists the Rust-returned per-network entries.
  • No remaining WalletStorage().retrieveMnemonic(...) calls in views/handlers that re-feed an FFI re-derivation.
  • iOS app builds; identity-key and add-to-network flows verified on simulator.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions