From: Chris Duncan Date: Thu, 27 Aug 2026 01:55:29 +0000 (-0700) Subject: Extract public key validation in verify to enable bulk ops. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=97cbcdd64fb96441d4f3cc75c0f597923bfccd94;p=nano25519.git Extract public key validation in verify to enable bulk ops. --- diff --git a/src/assembly/crypto_verify.ts b/src/assembly/crypto_verify.ts index bab9018..9a6a3ae 100644 --- a/src/assembly/crypto_verify.ts +++ b/src/assembly/crypto_verify.ts @@ -18,21 +18,33 @@ const sb_ah = new ge_p3() const S = new StaticArray(32) /** - * Verify signature `s` was made by signing message `M` using public key `pub`. - * @returns -1 if signature fails to verify, else return 0 if signature is good + * Verify public key `pub` is canonical, non-malleable, and correct. + * @returns -1 if public key fails to verify, else return 0 if public key is good */ -export function crypto_verify_strict (s: StaticArray, M: StaticArray, mlen: i32, pub: StaticArray): i32 { +export function crypto_verify_pubkey (pub: StaticArray): i32 { // fail if public key `k` is non-canonical (`p = 2²⁵⁵-19 ≤ k`) if (!ge_is_canonical(pub)) return -1 + if (ge_frombytes_negate_vartime(A, pub) != 0) return -1 + if (ge_has_small_order(A) != 0) return -1 + + return 0 +} + +/** + * Verify signature `s` was made by signing message `M` using public key `pub`. + * + * IMPORTANT: Callers MUST call `crypto_verify_pubkey` first in order to set `A` + * for the scalar multiplication step before checking `sB = R + hA`. + * @returns -1 if signature fails to verify, else return 0 if signature is good + */ +export function crypto_verify_relaxed (s: StaticArray, M: StaticArray, mlen: i32, pub: StaticArray): i32 { + // fail if private scalar `S` is non-canonical (`L ≤ S`) memory.copy(changetype(S), changetype(s) + 32, 32) if (!sc_is_canonical(S)) return -1 - if (ge_frombytes_negate_vartime(A, pub) != 0) return -1 - if (ge_has_small_order(A) != 0) return -1 - if (ge_frombytes(expected_r, s) != 0) return -1 if (ge_has_small_order(expected_r) != 0) return -1 @@ -51,20 +63,19 @@ export function crypto_verify_strict (s: StaticArray, M: StaticArray, ml /** * Verify signature `s` was made by signing message `M` using public key `pub`. + * + * Unlike `crypto_verify_relaxed`, this function is intended for single-use + * verifications and thus can compute and set `A` by calling + * `crypto_verify_pubkey` itself. * @returns -1 if signature fails to verify, else return 0 if signature is good */ -export function crypto_verify_relaxed (s: StaticArray, M: StaticArray, mlen: i32, pub: StaticArray): i32 { - - // fail if public key `k` is non-canonical (`p = 2²⁵⁵-19 ≤ k`) - if (!ge_is_canonical(pub)) return -1 +export function crypto_verify_strict (s: StaticArray, M: StaticArray, mlen: i32, pub: StaticArray): i32 { + if (crypto_verify_pubkey(pub) != 0) return -1 // fail if private scalar `S` is non-canonical (`L ≤ S`) memory.copy(changetype(S), changetype(s) + 32, 32) if (!sc_is_canonical(S)) return -1 - if (ge_frombytes_negate_vartime(A, pub) != 0) return -1 - if (ge_has_small_order(A) != 0) return -1 - if (ge_frombytes(expected_r, s) != 0) return -1 if (ge_has_small_order(expected_r) != 0) return -1 diff --git a/src/assembly/index.ts b/src/assembly/index.ts index 89cfc55..07552cd 100644 --- a/src/assembly/index.ts +++ b/src/assembly/index.ts @@ -3,7 +3,7 @@ import { crypto_derive } from './crypto_derive' import { crypto_sign } from './crypto_sign' -import { crypto_verify_relaxed, crypto_verify_strict } from './crypto_verify' +import { crypto_verify_pubkey, crypto_verify_relaxed, crypto_verify_strict } from './crypto_verify' export const BLOCKHASH_BYTELENGTH: i32 = 32 export const KEY_BYTELENGTH: i32 = 32 @@ -195,6 +195,10 @@ export function verify_blocks (count: i32): void { memory.copy(changetype(verify_blocks_pub), changetype(PUB_BUFFER), KEY_BYTELENGTH) PUB_BUFFER.fill(0) + // Verify public key, then clear local input + const validPubkey = crypto_verify_pubkey(verify_blocks_pub) + verify_blocks_pub.fill(0) + // Iterate over block hash/signature pairs for (let i = 0; i < count; i++) { // Copy message buffer to local block hash/signature buffers @@ -202,8 +206,7 @@ export function verify_blocks (count: i32): void { memory.copy(changetype(verify_blocks_sig), changetype(MESSAGE_BUFFER) + BLOCKHASH_BYTELENGTH + (96 * i), SIGNATURE_BYTELENGTH) // Verify hash and signature, then copy local result to output buffer - const verified = crypto_verify_relaxed(verify_blocks_sig, verify_blocks_msg, BLOCKHASH_BYTELENGTH, verify_blocks_pub) - verify_blocks_out[i] = u8(verified) + verify_blocks_out[i] = u8(validPubkey | crypto_verify_relaxed(verify_blocks_sig, verify_blocks_msg, BLOCKHASH_BYTELENGTH, verify_blocks_pub)) } // Clear local input