12 KiB
Amber Integration Analysis for PQ Nostr Web App
⚠️ Design-only research document. This is an analysis of a possible integration, not an implemented feature. The current system is a research prototype and does not make Nostr identities post-quantum secure by itself.
Amber Capabilities (from source code analysis)
Amber is an Android Nostr event signer that keeps the nsec segregated in a dedicated app. Based on source code inspection:
Seed Phrase Support ✅
- NIP-06 key derivation: Uses
com.vitorpamplona.quartz.nip06KeyDerivation.Bip39MnemonicsandNip06for deriving secp256k1 keys from mnemonics - Stores seed words:
DataStoreAccess.SEED_WORDSpersists the mnemonic in Android encrypted storage (DataStoreAccess.kt) - Generates new seeds: Login screen generates random entropy →
Bip39Mnemonics.toMnemonics(entropy)(LoginScreen.kt) - Mnemonic login: UI supports 12 or 24 word entry with account index selection (
MnemonicLoginInput.kt) - Seed backup: Account export includes encrypted seed words (
AccountExportService.kt)
Signing Operations ✅
Amber supports these signer types (SignerType.kt):
SIGN_EVENT— sign any Nostr eventGET_PUBLIC_KEY— return npubNIP04_ENCRYPT/NIP04_DECRYPTNIP44_ENCRYPT/NIP44_DECRYPTNIP44_V3_ENCRYPT/NIP44_V3_DECRYPT(new v3 cipher with kind+scope context)DECRYPT_ZAP_EVENT
NIP-46 Remote Signing ✅
- Amber acts as a NIP-46 signing device — "your smartphone act as a NIP-46 signing device without any need for servers or additional hardware"
- Web apps can connect to Amber via NIP-46 (nostrconnect:// URI)
- Supports permission management per-app
Multiple Accounts ✅
- Supports multiple accounts, each with its own nsec/seed words
How Amber Fits the PQ Web App Vision
The Key Insight
Amber already stores the seed phrase (BIP39 mnemonic) and uses it to derive secp256k1 keys via NIP-06. The seed phrase is algorithm-agnostic — it's just 128/256 bits of entropy. Our plan's Component 1 (seed phrase as root of trust) means PQ keys can be derived from the same seed using different derivation paths.
Three Architecture Options
Option A: Web App + Amber Signing (Minimal Amber Changes)
┌─────────────────┐ NIP-46 ┌──────────────────┐
│ Web App │ ◄──────────────► │ Amber │
│ (browser) │ │ (Android) │
│ │ │ │
│ 1. User enters │ getPublicKey │ Returns npub │
│ seed phrase │ ──────────────► │ │
│ (client-side │ │ │
│ only, WASM) │ signEvent │ Signs key-link │
│ │ (key-link) │ event with │
│ 2. Derives PQ │ ──────────────► │ secp256k1 │
│ keys from │ │ │
│ seed (WASM) │ │ │
│ │ │ │
│ 3. PQ-signs │ │ │
│ key-link │ │ │
│ client-side │ │ │
│ │ │ │
│ 4. Assembles & │ │ │
│ publishes │ │ │
│ key-link │ │ │
│ event │ │ │
└─────────────────┘ └──────────────────┘
Flow:
- User connects to Amber via NIP-46 for secp256k1 signing
- User enters their seed phrase in the web app (client-side only, WASM, never sent to server)
- Web app derives PQ keys (ML-DSA, ML-KEM, SLH-DSA) from seed using liboqs-WASM
- Web app requests Amber to sign the key-link event content with secp256k1
- Web app PQ-signs the key-link event content client-side
- Web app assembles the complete key-link event (secp256k1 sig + PQ sigs) and publishes to relays
- Web app requests OpenTimestamps attestation via NIP-03
Pros: No Amber modifications needed. Full PQ key derivation in browser. Cons: User must enter seed phrase in browser (even though client-side only). Trust model requires user to verify the web app isn't exfiltrating the seed.
Option B: Extend Amber for PQ Key Derivation (Best Security)
┌─────────────────┐ NIP-46 ┌──────────────────┐
│ Web App │ ◄──────────────► │ Amber │
│ (browser) │ │ (Android) │
│ │ │ │
│ 1. Connect to │ new method: │ Derives PQ keys │
│ Amber via │ pq_derive_keys │ from stored seed │
│ NIP-46 │ ──────────────► │ (liboqs native) │
│ │ │ │
│ 2. Requests PQ │ Returns PQ │ Returns PQ │
│ pubkey list │ ◄────────────── │ pubkeys only │
│ │ │ (privkeys stay │
│ 3. Requests │ new method: │ in Amber) │
│ key-link │ pq_sign │ │
│ signing │ ──────────────► │ PQ-signs event │
│ │ │ with PQ privkeys │
│ 4. Requests │ signEvent │ │
│ secp256k1 │ (existing) │ secp256k1 signs │
│ signing │ ──────────────► │ │
│ │ │ │
│ 5. Assembles & │ │ │
│ publishes │ │ │
└─────────────────┘ └──────────────────┘
Flow:
- User connects to Amber via NIP-46
- Web app calls new NIP-46 method
pq_derive_keys— Amber derives PQ keys from its stored seed phrase using liboqs (native Android) - Amber returns only the PQ public keys (private keys never leave Amber)
- Web app constructs the key-link event content with all pubkeys
- Web app calls
pq_sign— Amber PQ-signs the event content with each PQ private key - Web app calls
signEvent— Amber secp256k1-signs the event - Web app assembles and publishes the complete key-link event
Pros: Seed phrase never leaves Amber. PQ private keys never leave Amber. Best security model — consistent with Amber's philosophy of "private keys should be exposed to as few systems as possible." Cons: Requires Amber modifications (new NIP-46 methods, liboqs integration for Android).
Option C: Hybrid (Pragmatic)
┌─────────────────┐ NIP-46 ┌──────────────────┐
│ Web App │ ◄──────────────► │ Amber │
│ (browser) │ │ (Android) │
│ │ │ │
│ User chooses: │ │ │
│ │ │ │
│ Path 1 (Amber │ signEvent │ Signs with │
│ has seed): │ ──────────────► │ secp256k1 │
│ Request secp │ │ │
│ sig from Amber │ │ │
│ Enter seed in │ │ │
│ web app for PQ │ │ │
│ key derivation │ │ │
│ (client-side) │ │ │
│ │ │ │
│ Path 2 (raw │ signEvent │ Signs with │
│ nsec, no seed │ ──────────────► │ secp256k1 │
│ in Amber): │ │ │
│ Generate new │ │ │
│ seed in web app │ │ │
│ (client-side), │ │ │
│ derive PQ keys, │ │ │
│ request secp │ │ │
│ sig from Amber │ │ │
└─────────────────┘ └──────────────────┘
Pros: Works for both existing seed-phrase users and raw-nsec users. No Amber changes required for initial launch. Can upgrade to Option B later. Cons: Seed phrase still enters browser for PQ derivation. Two code paths.
Recommendation: Option B (Extend Amber)
This aligns with:
- Amber's security philosophy: "Private keys should be exposed to as few systems as possible"
- Our plan's Component 1: Seed phrase as algorithm-agnostic root of trust — Amber already stores it
- Our plan's Component 2: Cross-signed key-link events — Amber can sign with both secp256k1 and PQ keys
- Community discussion (Issue #1971): trbouma and mikedilger both advocate for HSM/enclave-based PQ key storage
Required Amber Changes
- Add liboqs dependency: Native library for PQ algorithms (ML-DSA, ML-KEM, SLH-DSA)
- PQ key derivation from seed: New function that takes the stored BIP39 seed and derives PQ keys using a deterministic scheme (e.g.,
HKDF(seed, "nostr-pq-ml-dsa-44")→ PQ private key) - New NIP-46 methods:
pq_get_public_keys— return array of PQ public keys with algorithm identifierspq_sign— sign a message with a specified PQ algorithm's private key
- Permission management: New permission types for PQ signing operations
- UI updates: Show PQ key information, approval screens for PQ signing requests
Required Web App Components
- NIP-46 client: Connect to Amber, send signing requests
- Key-link event builder: Construct the event content with all pubkeys, request signatures, assemble final event
- OpenTimestamps client: Request OTS attestation for the key-link event (NIP-03)
- Relay publisher: Publish the key-link event to relays
- Verification UI: Show the user what was created, verify the key-link event is valid
- No server-side secrets: The web app is a static site — no backend that could intercept keys
For Users Without Amber (or Without Seed Phrase in Amber)
The web app should also support:
- NIP-07 browser extension signing (nos2x, etc.) for secp256k1 signatures
- Client-side seed phrase entry (WASM, never transmitted) for users who want to derive PQ keys in-browser
- New seed generation for users who don't have a seed phrase yet (Component 4: migrating existing users with raw nsec)