From: Chris Duncan Date: Sat, 3 Oct 2026 07:16:49 +0000 (-0700) Subject: Check signature R canonicity in strict verification. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=fc46ae516edc8dadd145a791ca4050840a368e76;p=nano25519.git Check signature R canonicity in strict verification. --- diff --git a/src/assembly/crypto_verify.ts b/src/assembly/crypto_verify.ts index 752981d..46741d5 100644 --- a/src/assembly/crypto_verify.ts +++ b/src/assembly/crypto_verify.ts @@ -130,7 +130,7 @@ export function crypto_verify_strict (sig: StaticArray, M: StaticArray, function verify_pubkey (pub: StaticArray): boolean { // fail if public key `k` is non-canonical (`p = 2²⁵⁵-19 ≤ k`) - if (!ge_is_canonical(pub)) return false + if (ge_is_canonical(pub) != 0) return false // fail if public key cannot be decoded if (ge_frombytes_negate_vartime(A, pub) != 0) return false @@ -142,7 +142,7 @@ function verify_pubkey (pub: StaticArray): boolean { } /** - * Verify signature `s` is canonical, decodeable, and not small order. Used by + * Verify signature `sig` is canonical, decodeable, and not small order. Used by * `crypto_verify_sodium` and `crypto_verify_strict`. * @returns 0 if signature fails checks, else return 1 if signature is good */ @@ -151,8 +151,13 @@ function verify_signature (sig: StaticArray): boolean { memory.copy(changetype(S), changetype(sig) + 32, 32) if (!sc_is_canonical(S)) return false - // fail if nonce `R` is not a valid point on the curve + // fail if nonce `R` is non-canonical (`p ≤ R`) + if (ge_is_canonical(sig) != 0) return false + + // fail if nonce `R` does not decode to a valid curve point if (ge_frombytes(expected_r, sig) != 0) return false + + // fail if nonce `R` is small order if (ge_has_small_order(expected_r) != 0) return false return true diff --git a/src/assembly/ed25519/ge.ts b/src/assembly/ed25519/ge.ts index 6143eca..55a31e1 100644 --- a/src/assembly/ed25519/ge.ts +++ b/src/assembly/ed25519/ge.ts @@ -265,16 +265,16 @@ export function ge_has_small_order (p: ge_p3): i32 { } /** - * true if `s < p` + * @returns 0 if `s < p`, else -1 */ -export function ge_is_canonical (s: StaticArray): u8 { +export function ge_is_canonical (s: StaticArray): i32 { let c: i32 = (s[31] & 0x7f) ^ 0x7f for (let i = 30; i > 0; i--) { - c |= s[i] ^ 0xff + c |= s[i] } c = (c - 1) >> 8 const d: i32 = (0xec - s[0]) >> 8 - return u8(1 - (c & d & 1)) + return 0 - (c & d & 1) } const ge_scalarmult_base_tobytes_h: ge_p3 = new ge_p3()