NUT-XX: Deterministic Keypairs#384
Closed
robwoodgate wants to merge 1 commit into
Closed
Conversation
This was referenced May 29, 2026
a1denvalu3
approved these changes
May 31, 2026
Collaborator
Author
|
Closing as: a) there are live implementations using BIP-32 derivations for both use cases right now |
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.
Supersedes
Summary
Adds a new NUT specifying HMAC-SHA256 derivation of secp256k1 keypairs from the wallet seed, for use as locking keys in spending conditions (NUT-11 P2PK) and as quote locking keys (NUT-20). Each application gets a distinct DST and an independent counter:
Cashu_KDF_HMAC_SHA256_NUT11for NUT-11 P2PK keysCashu_KDF_HMAC_SHA256_NUT20for NUT-20 quote locking keysTest vectors use the canonical NUT-13 mnemonic and publish the first five compressed pubkeys per domain.
This PR supersedes #331 and #373. Both PRs bolt BIP-32 derivation guidance into existing NUTs; this consolidates them into one optional NUT using the HMAC-SHA256 KDF style that NUT-13 v2 already established for the secrets / blinding-factor case.
Why HMAC-SHA256 over BIP-32
Alignment with NUT-13 v2. The spec already chose HMAC-SHA256 with modular reduction for keyset-bound derivation. Using the same primitive for non-keyset-bound P2PK and quote keys keeps one KDF across the spec rather than mixing two (BIP-32 here, HMAC there) and lines up with the direction NUT-13 v2 was already moving.
No BIP-32 features actually apply. P2PK and quote keys are derived wallet-side from a hot seed. BIP-32's design targets hardware-wallet path traversal, chain-code propagation, and non-hardened xpub export. None of these apply: there is no hardware wallet in the loop, no derivation tree to walk, no xpub-export workflow shipping anywhere in the ecosystem. The HD-tree structure pays complexity for benefits Cashu never collects.
The BIP-32 xpub watch-only argument is inconsistent with Cashu's privacy model. BIP-32's non-hardened terminal step allows xpub-based enumeration in theory, but using it for P2PK / NUT-20 keys requires (a) a NUT-shaped query-by-pubkey API that does not exist, (b) wallet xpub-export workflows that no one ships, and (c) a lookup API that does not gain mint-side correlation info by linking a user's many candidate pubkeys into one query. Bitcoin tolerates the equivalent because the chain is already public; Cashu mints actively gain correlation info from each lookup, which the protocol's privacy guarantees specifically try to prevent.
Smaller dependency surface. Wallets need BIP-39 (mnemonic → seed bytes) regardless of derivation choice. BIP-32 derivation adds a second library (
@scure/bip32,python-bip32, similar) carrying path parsing, hardened vs non-hardened logic, and chain-code handling that the wallet never uses. HMAC-SHA256 derivation drops the need for that second dep once legacy keysets are removed.Why separate Domains?
Simply because quotes can be churned and disposed of more often, so a restore based on P2PK locking keys would potentially face larger gaps in a mixed domain scenario. It also helps prevent key collisions (privacy leak) between quotes and locked proofs in cases where counter management goes askew (eg multiple wallets using same seed).
Implementations