The HD wallet seed is now BIP-39-compatible. Pipeline:
entropy = HKDF-SHA256(nsec, info="agora/v1", length=32)
mnemonic = BIP-39 encoding of (entropy || checksum) // 24 words
seed = PBKDF2-HMAC-SHA512(mnemonic, salt="mnemonic", iters=2048)
The 24 words import cleanly into Sparrow, Electrum, Trezor, Ledger,
BlueWallet, Phoenix, etc., at the BIP-86 / BIP-352 paths. HKDF domain
separation means a leaked mnemonic compromises only the wallet, not
the Nostr identity (unlike the raw nsec).
v1 derivation (nsec used directly as BIP-32 master seed) is retained
as migration-only code. A new /wallet/migrate-v1 page detects funds
at the legacy addresses and builds a single sweep PSBT to consolidate
them into the v2 wallet. A persistent banner on /wallet surfaces the
flow when v1 funds exist.
The mnemonic shows up in two places: a "Back up wallet" dialog on
/wallet, and a section in Profile -> Advanced next to the nsec
backup. nsec backup copy updated to explain the relationship.
Locked test vectors pin the entire derivation pipeline (nsec -> 24
words -> first BIP-86 address -> sp1q...) so any future drift fails
loudly. Regenerate via scripts/derive_vectors.mjs.
Other changes:
- Re-key SP storage NIP-78 d-tag to /v2 so v1 and v2 UTXOs do not mix
- Re-key the persisted receive-address cursor to :v2: namespace
- Relax SP spend-key helper to 16-64 byte seeds (BIP-32 range) so the
migration sweep can sign with the legacy 32-byte v1 seed too
- Remove stale NIP-SP references from derivation comments (the draft
was not relevant to our use case)
- Document the wallet derivation scheme in NIP.md
- Translate every new string to all 10 non-English locales