Skip to content

feat(crypto): deterministic DLEQ nonce derivation (NUT-12)#1010

Open
robwoodgate wants to merge 2 commits into
cashubtc:mainfrom
robwoodgate:feat/deterministic-dleq
Open

feat(crypto): deterministic DLEQ nonce derivation (NUT-12)#1010
robwoodgate wants to merge 2 commits into
cashubtc:mainfrom
robwoodgate:feat/deterministic-dleq

Conversation

@robwoodgate
Copy link
Copy Markdown
Contributor

@robwoodgate robwoodgate commented May 19, 2026

Implements the deterministic nonce derivation from cashubtc/nuts#368.

Summary

Derives the DLEQ nonce r deterministically from the mint's private key and the proof context, instead of sourcing it from the RNG:

r = HMAC-SHA256(key=a, "Cashu_DLEQ_R_v1" || A || B' || C' || ctr) mod n

a is the 32-byte secp256k1 private key scalar (big-endian); A, B', C' are uncompressed SEC1 points (65 bytes each); ctr is a single byte starting at 0x00, incremented if the reduced value is 0 (max 256 attempts).

This removes the dependency on RNG quality. Reusing r across two proofs with different challenges leaks the private key immediately via a = (s₁ - s₂)·(e₁ - e₂)⁻¹ mod n.

Changes

  • cashu/core/crypto/b_dhke.py — new derive_dleq_nonce(a, A, B_, C_). step2_bob_dleq computes C_/A first, then derives p deterministically. The p_bytes override is retained for existing test vectors.
  • tests/test_crypto.py — adds the NUT-12 deterministic-nonce test vector (asserts every fixed value plus e == hash(R1, R2, A, C_) verification), reproducibility, and context-sensitivity tests.

Notes

  • step2_bob (used by the mint in ledger.py) now emits deterministic nonces for every signature. DLEQ verification is unaffected — (e, s) remain valid proofs. No on-disk format or API change.
  • Cross-checked against the canonical cashu-ts NUT12 implementation; the Python output reproduces e, s, A, and C_ from the spec vector exactly.

Test plan

  • tests/test_crypto.py — 19 passed, including the new NUT-12 vector and the two new determinism tests.
  • make check (ruff + mypy) passes.

Derive the DLEQ nonce `r` deterministically from the private key and
proof context instead of from the RNG:

  r = HMAC-SHA256(key=a, "Cashu_DLEQ_R_v1" || A || B' || C' || ctr) mod n

This removes the dependency on RNG quality. Reusing `r` across two
proofs with different challenges would leak the private key.

`step2_bob` now emits deterministic nonces for every signature; DLEQ
verification is unaffected since (e, s) remain valid proofs. The
`p_bytes` override is retained for the existing test vectors.

Adds the NUT-12 deterministic-nonce test vector (cashubtc/nuts#368)
plus reproducibility and context-sensitivity tests.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.96%. Comparing base (8418533) to head (2ca548e).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1010      +/-   ##
==========================================
- Coverage   74.99%   74.96%   -0.03%     
==========================================
  Files         111      111              
  Lines       12065    12076      +11     
==========================================
+ Hits         9048     9053       +5     
- Misses       3017     3023       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant