diff --git a/12.md b/12.md index ced19d48..6b2910f0 100644 --- a/12.md +++ b/12.md @@ -18,11 +18,11 @@ The complete DLEQ proof reads (These steps occur when Bob returns C') Bob: -r = random nonce +r = HMAC-SHA256(key=a, data="Cashu_DLEQ_R_v1" || A || B' || C' || 0x00) mod n R1 = r*G R2 = r*B' e = hash(R1,R2,A,C') -s = r + e*a +s = (r + e*a) mod n return e, s Alice: @@ -51,6 +51,20 @@ def hash_e(*publickeys: PublicKey) -> bytes: > [!NOTE] > For examples of valid DLEQ proofs, see the [test vectors][tests]. +### Nonce derivation + +`r` **SHOULD** be derived deterministically from the private key and proof context: + +``` +r = HMAC-SHA256(key=a, data="Cashu_DLEQ_R_v1" || A || B' || C' || ctr) mod n +``` + +`a` is the 32-byte secp256k1 private key scalar, encoded as big-endian bytes. `A`, `B'`, and `C'` are uncompressed SEC1 (65 bytes each). `ctr` is a single byte starting at `0x00` and incremented if `r == 0` (max 256 attempts). + +This removes a 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`. + +Mints that use random nonces instead **MUST** source them from a cryptographically secure RNG. + ### Mint to user: DLEQ in `BlindSignature` The mint produces these DLEQ proofs when returning `BlindSignature`'s in the responses for minting ([NUT-04][04]) and swapping ([NUT-03][03]) tokens. The `BlindSignature` object is extended in the following way to include the DLEQ proof: diff --git a/tests/12-tests.md b/tests/12-tests.md index f38d2027..af22cb64 100644 --- a/tests/12-tests.md +++ b/tests/12-tests.md @@ -13,6 +13,24 @@ C_: "02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2" hash(R1, R2, K, C_): "a4dc034b74338c28c6bc3ea49731f2a24440fc7c4affc08b31a93fc9fbe6401e" ``` +## Deterministic nonce derivation + +The following vectors verify the deterministic `r` derivation. All values are fixed; an implementation **MUST** reproduce `e` and `s` exactly. + +```shell +a: 0000000000000000000000000000000000000000000000000000000000000002 +A: 02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5 +B_: 02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2 +C_: 0244eccfc7a348274458bb38044c7f3c389b3c2086c7ec18b5812d2877ab937787 +``` + +```shell +e: 2a16ffee280aff3c429045607f9b8e0bf8b35910c44c1b20b9dfaf01b263d7b3 +s: 9df27731238334718d120d4f74611a7c668233f988e687ac3fb188f0a34a2dab +``` + +Verification (`e == hash(R1, R2, A, C_)`) **MUST** pass. + ## DLEQ verification on `BlindSignature` The following is a `BlindSignature` with a **valid** DLEQ proof.