feat: NIP-PB — Password-Bound Key Backup#385
Open
tlongwell-block wants to merge 2 commits intomainfrom
Open
Conversation
Add NIP-PB, a minimal protocol for backing up a Nostr private key to any relay using just a password. One blob, one scrypt call, no sharding. The core security property: each password guess is bound to one pubkey, eliminating the accumulation attack that makes relay-published encrypted keys dangerous. Confidentiality chain is entirely symmetric/hash-based (scrypt → HKDF-SHA256 → XChaCha20-Poly1305), providing post-quantum confidentiality with sufficient password entropy. Includes full KDF-chain interop test vector with normative hex values. Spec only — implementation, Tamarin proof, and demo are follow-ups.
Six wording fixes from adversarial crossfire review (Codex, Opus, Gemini). Zero construction changes — crypto, parameters, and event format untouched. - Fix NIP-49 accumulation attack description (Motivation + Security Analysis) - Clarify AAD convention rationale - State three-factor recovery requirement, recommend storing relay URLs - Add verify-before-delete safety for password rotation - Clarify tag validation: extra tags ignored
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
NIP-PB: Password-Bound Key Backup
Minimal protocol for backing up a Nostr private key to any relay using just a password. One blob, one scrypt call, no sharding.
The problem
NIP-49
ncryptsec1is safe for local storage but dangerous on relays. An attacker who dumps a relay can identify every encrypted backup by itsncryptsec1prefix, giving them a list of targets. For each password guess, the attacker gets N chances — the probability of cracking at least one user grows with N, and the cost per successful crack drops to|passwords| × scrypt_cost / N. NIP-49 itself warns against relay publishing for exactly this reason.The solution
Mix the user's public key into the scrypt input. Now each password guess is bound to one target pubkey. To test a password, the attacker must already know which user they're targeting. One guess, one user. To attack all users:
|users| × |passwords| × scrypt.The backup blob is published as a
kind:30078event signed by a throwaway key derived from the password. No field references the user's real pubkey. Recovery requires the password, the public key, and a relay URL.What's in this PR
crates/sprout-core/src/backup/NIP-PB.md— complete protocol spec (~450 lines)Spec only. Implementation and demo script are follow-ups.
Key properties
Design decisions
pubkey ∈ scrypt_input, not from sharding. NIP-PB keeps the core security property and drops the complexity.authors + #d). Eliminates d-tag squatting without pagination complexity.kind:30078(NIP-78 application-specific data). Sharing the kind with other app data provides ambient cover.Adversarial review
Developed through iterative crossfire review across 4 model families:
All three confirm: cryptographic construction is sound, accumulation resistance is mathematically valid, novel in the NIP ecosystem. Remaining reviewer requests are scope/product decisions (version indicator, entropy estimation precision, URL conformance suite) that were consciously declined.
Relationship to NIP-SB (#373)
NIP-PB is an independent, simpler alternative to NIP-SB. Both provide accumulation resistance via the same mechanism (pubkey-bound KDF). NIP-SB additionally provides fault tolerance (RS P=2) and steganographic cover at the cost of significantly more complexity (900+ lines). NIP-PB is the distillation: same crypto, honest threat model, ~200 lines instead of 906.
Test vector
Full KDF-chain interop test vector with normative hex values at
log_n=20: password → base → H → enc_key → d_tag → sign_key → sign_pk → nonce → ciphertext → base64 content.