feat(nut12): deterministic DLEQ nonce derivation #368
No reviewers
Labels
No labels
breaking change
bug
documentation
enhancement
needs discussion
needs implementation
new nut
ready
wallet-only
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo-admin/nuts!368
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "robwoodgate/nut12-deterministic-nonce"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
In a DLEQ proof, the mint publishes challenge and response values
eands, related by:a- the mint’s long-lived private key (from its keyset).r- a temporary, per-proof nonce used in the DLEQ signature.If the same
ris ever reused with two different challengese₁ande₂, the private key can be recovered immediately:It’s the same class of failure that affected Bitcoin Android wallets in 2013, where repeated ECDSA nonces (
k) allowed attackers to derive private keys and drain funds.However, the current spec does not "fail safe". A poorly written RNG wrapper, re-used seed, or language-level entropy issue could silently break key safety while remaining spec-compliant.
Solution - The spec should "Fail Safe"
To remove the RNG "weak link", RFC 6979 and BIP-340 both moved from "random nonce" to deterministic nonce derivation: the nonce is derived from the private key and the signing context rather than sampled fresh each time.
This PR brings the same approach to NUT-12's DLEQ proof.
The nonce
ris now derived via HMAC-SHA256, keyed on the mint's private key and bound to the proof context:Mints SHOULD use this derivation. Mints using random nonces MUST use a CSPRNG.
This is not a breaking change, as verifiers reconstruct R1 and R2 from (e, s) and never see r.
All existing proofs continue to verify.
Also adds a test vector section to
tests/12-tests.mdwith fixed inputs and exact expected (e, s) output, so implementations can verify byte-for-byte conformance.Proof
Here is a simplified TS proof showing how nonce reuse allows private key recoverability:
Why are we hashing the key
abefore inputting into the HMAC?Mostly for defense in depth - it keeps the raw scalar out of direct HMAC-key use, and ensures the HMAC key is always fixed-width 32-byte, regardless of keygen.
So just key-derivation hygiene (it doesn't add entropy or protect weak mint keys etc)
@robwoodgate I think it's an unnecessary measure and also
ais always 32 bytesAgree it's a bit belt and braces - am happy we just use the scalar without hashing if you think it adds nothing.
Addressed in e57b141
LGTM.
ACK
e57b141241View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.