Skip to content

feat: add Secure Enclave key type and Swift shim#363

Draft
decofe wants to merge 4 commits intomainfrom
alexey/secure-enclave-keys
Draft

feat: add Secure Enclave key type and Swift shim#363
decofe wants to merge 4 commits intomainfrom
alexey/secure-enclave-keys

Conversation

@decofe
Copy link
Member

@decofe decofe commented Mar 20, 2026

Summary

Add Secure Enclave P-256 key support to the wallet CLI — Swift shim, Rust integration, keystore model, and tempo wallet se subcommand.

Motivation

Secure Enclave provides hardware-bound, non-exportable P-256 keys — ideal for CLI/programmatic signing without browser WebAuthn ceremonies. Tempo supports P-256 on-chain verification via the RIP-7212 precompile, so SE keys work as a new signer type alongside passkeys.

Changes

Swift shim (tools/tempo-se/)

  • ~190 LOC Swift Package using Security.framework
  • generate --tag <tag> — create SE-backed P-256 key, print uncompressed pubkey hex
  • sign --tag <tag> --hash <hex> — sign prehashed digest (.ecdsaSignatureDigestX962SHA256)
  • pubkey --tag <tag> — retrieve existing key's public key
  • delete --tag <tag> — remove key from Keychain
  • Keychain queries scoped to kSecAttrTokenIDSecureEnclave + kSecAttrKeyClassPrivate

Rust integration (tempo-common)

  • KeyType::SecureEnclave variant (P-256 on-chain, SE-backed storage)
  • KeyError::SecureEnclave error variant
  • secure_enclave module — Rust shim that locates + shells out to tempo-se
  • se_label field on KeyEntry for SE key identification
  • has_signing_capability() / is_secure_enclave() methods
  • Key selection updated: passkey > SE > inline key > first entry
  • Readiness checks (has_wallet, whoami) recognize SE keys
  • Keystore::delete_se_label() for key removal

CLI (tempo wallet se)

  • generate [--label] — create SE key, derive EVM address, save to keystore
  • list — show all SE keys with label/address/wallet
  • pubkey [--label] — print uncompressed P-256 public key hex
  • delete [--label] [--yes] — delete from both SE and keystore

Not in this PR

End-to-end signing (SE → mpp::TempoProvider pipeline) requires mpp crate changes and will follow separately.

Testing

make check  # clippy + fmt + tests pass

Co-Authored-By: Alexey Shekhirin 5773434+shekhirin@users.noreply.github.com

Prompted by: alexey

Add initial plumbing for Apple Secure Enclave P-256 key support:

- Add KeyType::SecureEnclave variant (P-256 backed by SE hardware)
- Add KeyError::SecureEnclave error variant
- Add secure_enclave module (shells out to tempo-se Swift binary)
- Add tools/tempo-se Swift Package (generate, sign, pubkey, delete)

The Swift shim uses Security.framework to create non-exportable P-256
keys in the Secure Enclave and sign prehashed digests. Keychain queries
are scoped to kSecAttrTokenIDSecureEnclave + kSecAttrKeyClassPrivate
to prevent cross-key confusion.

This is foundational plumbing — end-to-end signer integration (wiring
SE keys into the Signer/Keystore selection path) and a `tempo wallet`
subcommand for SE key management will follow in subsequent PRs.

Co-Authored-By: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 20, 2026

⚠️ Changelog not found.

A changelog entry is required before merging.

Add changelog

@github-actions
Copy link
Contributor

github-actions bot commented Mar 20, 2026

Tempo Lint Results

Summary

Found 338 issue(s) across 32 file(s)

Severity Count
Errors 0
Warnings 338
Hints 0

Issues by Rule Type

no-unwrap-in-lib (315 occurrences)
  • /home/runner/work/wallet/wallet/crates/tempo-test/src/fixture.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs:1 - Avoid .unwrap() in library code. Use proper error handling with ? or .expect() with context.

... and 305 more

no-leading-whitespace-strings (23 occurrences)
  • /home/runner/work/wallet/wallet/crates/tempo-test/src/fixture.rs:1 - String literals should not start with leading whitespace. Found: ' = '
  • /home/runner/work/wallet/wallet/crates/tempo-test/src/fixture.rs:1 - String literals should not start with leading whitespace. Found: ' = '
  • /home/runner/work/wallet/wallet/crates/tempo-test/src/fixture.rs:1 - String literals should not start with leading whitespace. Found: ' = '
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/args.rs:1 - String literals should not start with leading whitespace. Found: ' ('
  • /home/runner/work/wallet/wallet/crates/tempo-request/src/payment/session/streaming.rs:1 - String literals should not start with leading whitespace. Found: ' 42 '
  • /home/runner/work/wallet/wallet/crates/tempo-common/src/config.rs:1 - String literals should not start with leading whitespace. Found: ' = '
  • /home/runner/work/wallet/wallet/crates/tempo-wallet/src/args.rs:1 - String literals should not start with leading whitespace. Found: ' ('
  • /home/runner/work/wallet/wallet/crates/tempo-request/tests/query/payment.rs:1 - String literals should not start with leading whitespace. Found: ' = '
  • /home/runner/work/wallet/wallet/crates/tempo-wallet/src/commands/debug.rs:1 - String literals should not start with leading whitespace. Found: ' ('
  • /home/runner/work/wallet/wallet/crates/tempo-wallet/tests/session/list.rs:1 - String literals should not start with leading whitespace. Found: ' = '

... and 13 more

Issues by File

View grouped by file

/home/runner/work/wallet/wallet/crates/tempo-request/src/payment/session/streaming.rs (58 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 53 more

/home/runner/work/wallet/wallet/crates/tempo-test/src/mock.rs (46 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 41 more

/home/runner/work/wallet/wallet/crates/tempo-common/src/payment/session/store/storage.rs (38 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 33 more

/home/runner/work/wallet/wallet/crates/tempo-common/src/keys/keystore.rs (32 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 27 more

/home/runner/work/wallet/wallet/crates/tempo-request/src/query/payload.rs (24 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 19 more

/home/runner/work/wallet/wallet/crates/tempo-request/src/http/client.rs (19 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 14 more

/home/runner/work/wallet/wallet/crates/tempo-common/src/payment/session/close/cooperative.rs (18 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 13 more

/home/runner/work/wallet/wallet/crates/tempo-common/src/keys/signer.rs (13 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 8 more

/home/runner/work/wallet/wallet/crates/tempo-request/src/query/challenge.rs (11 issues)

  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • Line 1: [warning] no-unwrap-in-lib
  • ... and 6 more

/home/runner/work/wallet/wallet/crates/tempo-wallet/tests/session/close.rs (10 issues)

  • Line 1: [warning] no-leading-whitespace-strings
  • Line 1: [warning] no-leading-whitespace-strings
  • Line 1: [warning] no-leading-whitespace-strings
  • Line 1: [warning] no-leading-whitespace-strings
  • Line 1: [warning] no-leading-whitespace-strings
  • ... and 5 more

Showing 10 of 32 files


Posted by https://github.com/tempoxyz/lints

@shekhirin shekhirin marked this pull request as draft March 20, 2026 23:15
decofe and others added 3 commits March 20, 2026 23:21
Wire Secure Enclave keys into the keystore model and add CLI commands:

- Add `se_label` field to KeyEntry for SE-backed key identification
- Add `has_signing_capability()` / `is_secure_enclave()` to KeyEntry
- Update key selection: passkey > SE > inline key > first entry
- Update readiness checks to recognize SE keys (has_wallet, whoami)
- Add `Keystore::delete_se_label()` for SE key removal
- Export `KeyType` from tempo_common::keys

CLI commands (`tempo wallet se`):
- `generate [--label]` — create SE key, derive address, save to keystore
- `list` — show all SE keys with label/address/wallet
- `pubkey [--label]` — print uncompressed P-256 public key hex
- `delete [--label] [--yes]` — delete from both SE and keystore

Note: end-to-end signing (SE → mpp::TempoProvider) requires mpp crate
changes and will follow in a separate PR.

Co-Authored-By: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Build the Swift shim alongside tempo-wallet on macOS targets:

- Build tempo-se with `swift build` on darwin-amd64 and darwin-arm64
- Upload tempo-se binaries as separate artifacts
- Ship to GitHub Release and R2 alongside tempo-wallet binaries

Co-Authored-By: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-Authored-By: Georgios Konstantopoulos <17802178+gakonst@users.noreply.github.com>
- Add WalletSigner enum supporting both PrivateKey and SecureEnclave variants
- P-256 transaction signing with SHA-256 prehash, DER parsing, low-s normalization
- P-256 voucher signing for sessions and cooperative channel close
- Pass keyType=p256 hint to Tempo node for correct gas estimation
- SE key generate creates a direct wallet (no browser login required)
- Refuse to overwrite existing SE keys to prevent fund loss
- Xcode project for tempo-se with provisioning profile and entitlements
- Add biometry flag to SE key access control
- Add duplicate key guard in Swift shim
- Add sign_for_key() to authorization for P-256 key type support
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants