From bbbe7f86027ecdd5404b15f11625d000fedc45a1 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Wed, 19 Aug 2026 16:40:04 -0700 Subject: [PATCH] Adjust variable names now that primitives are module-scoped. Copy parameters locally in derive to free buffer. Fill output buffer in verify for consistency between calls. --- src/assembly/crypto_derive.ts | 12 ++++++---- src/assembly/crypto_sign.ts | 22 +++++++----------- src/assembly/crypto_verify.ts | 23 +++++++----------- src/assembly/index.ts | 44 +++++++++++++++++++++-------------- 4 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/assembly/crypto_derive.ts b/src/assembly/crypto_derive.ts index f1bb450..64cda1a 100644 --- a/src/assembly/crypto_derive.ts +++ b/src/assembly/crypto_derive.ts @@ -12,8 +12,10 @@ const SECRETKEY_BYTES: i32 = PRIVATEKEY_BYTES + PUBLICKEY_BYTES // crypto_hash function const blake2b = new Blake2b() -const crypto_derive_h: StaticArray = new StaticArray(SECRETKEY_BYTES) -const crypto_derive_s: StaticArray = new StaticArray(PRIVATEKEY_BYTES) +// algorithm variables +const h: StaticArray = new StaticArray(SECRETKEY_BYTES) +const s: StaticArray = new StaticArray(PRIVATEKEY_BYTES) + /** * Hash seed to 32-byte scalar `a`, clamp it, then point-multiply it by the * Ed25519 base point. The Nano specification uses BLAKE2b as the hash function @@ -25,15 +27,17 @@ const crypto_derive_s: StaticArray = new StaticArray(PRIVATEKEY_BYTES) * @param key 32-byte private key "seed" of cryptographically secure random data */ export function crypto_derive (A: StaticArray, key: StaticArray): void { - const h = crypto_derive_h - const s = crypto_derive_s + // Hash private key to 64-byte buffer `h` blake2b.init().update(key, 32).digest(h) + // Keep only the lower 32 bytes as secret scalar `s` for deriving public key memory.copy(changetype(s), changetype(h), 32) h.fill(0) + // Clear lowest three bits and highest bit, then set second highest bit clamp(s) + // Perform fixed-base scalar multiplication `[s]B`, output to public key `A` ge_scalarmult_base_tobytes(A, s) s.fill(0) diff --git a/src/assembly/crypto_sign.ts b/src/assembly/crypto_sign.ts index df81ade..66e9664 100644 --- a/src/assembly/crypto_sign.ts +++ b/src/assembly/crypto_sign.ts @@ -11,13 +11,14 @@ const PRIVATEKEY_BYTES: i32 = 32 // crypto_hash function const blake2b = new Blake2b() -const crypto_sign_h = new StaticArray(64) -const crypto_sign_s = new StaticArray(32) -const crypto_sign_prefix = new StaticArray(32) -const crypto_sign_r = new StaticArray(64) -const crypto_sign_R = new StaticArray(64) -const crypto_sign_k = new StaticArray(64) -const crypto_sign_S = new StaticArray(64) +// algorithm variables +const h = new StaticArray(64) +const s = new StaticArray(32) +const prefix = new StaticArray(32) +const r = new StaticArray(64) +const R = new StaticArray(64) +const k = new StaticArray(64) +const S = new StaticArray(64) /** * Sign a message with a secret key. The Nano specification uses BLAKE2b as the * hash function instead of SHA-512 specified by RFC 8032. @@ -38,13 +39,6 @@ const crypto_sign_S = new StaticArray(64) * @param {StaticArray} A 32-byte public key from input buffer */ export function crypto_sign (RS: StaticArray, M: StaticArray, mlen: i32, key: StaticArray, A: StaticArray): void { - const h = crypto_sign_h - const s = crypto_sign_s - const prefix = crypto_sign_prefix - const r = crypto_sign_r - const R = crypto_sign_R - const k = crypto_sign_k - const S = crypto_sign_S // Hash private key to `h` blake2b.init().update(key, PRIVATEKEY_BYTES).digest(h) diff --git a/src/assembly/crypto_verify.ts b/src/assembly/crypto_verify.ts index 9dda4a6..f558b2d 100644 --- a/src/assembly/crypto_verify.ts +++ b/src/assembly/crypto_verify.ts @@ -9,24 +9,19 @@ import { sc_is_canonical, sc_reduce } from './sc' // crypto_hash function const blake2b = new Blake2b() -const crypto_verify_h = new StaticArray(64) -const crypto_verify_check = new ge_p3() -const crypto_verify_expected_r = new ge_p3() -const crypto_verify_A = new ge_p3() -const crypto_verify_sb_ah = new ge_p3() -const crypto_verify_S = new StaticArray(32) +// algorithm variables +const h = new StaticArray(64) +const check = new ge_p3() +const expected_r = new ge_p3() +const A = new ge_p3() +const sb_ah = new ge_p3() +const S = new StaticArray(32) + /** * Verify signature `s` was made by signing message `m` using public key `pk`. * @returns -1 if signature fails to verify, else return 0 if signature is good */ -export function crypto_verify (s: StaticArray, m: usize, mlen: i32, pub: StaticArray): i32 { - const M = changetype>(m) - const h = crypto_verify_h - const check = crypto_verify_check - const expected_r = crypto_verify_expected_r - const A = crypto_verify_A - const sb_ah = crypto_verify_sb_ah - const S = crypto_verify_S +export function crypto_verify (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 diff --git a/src/assembly/index.ts b/src/assembly/index.ts index eb18a1d..72e781a 100644 --- a/src/assembly/index.ts +++ b/src/assembly/index.ts @@ -33,24 +33,29 @@ export function getMessagePointer (): usize { return MESSAGE_BUFFER } +const derive_pub = new StaticArray(PUBLICKEY_BYTES) +const derive_prv = new StaticArray(PRIVATEKEY_BYTES) /** * Derive a 32-byte Nano public key from a 32-byte private key. Parameters are * read as bytes from the input buffer in the following order: * * - `[0,31]: private key` - * - `[32,63]: public key` * * The public key is written to the output buffer. */ export function derive (): void { - const pub = changetype>(OUTPUT_BUFFER) - const prv = changetype>(INPUT_BUFFER) - memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES) - crypto_derive(pub, prv) + const pub = derive_pub + const prv = derive_prv + + memory.copy(changetype(prv), INPUT_BUFFER, PRIVATEKEY_BYTES) memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES) + + crypto_derive(pub, prv) + memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES) + memory.copy(OUTPUT_BUFFER, changetype(pub), PUBLICKEY_BYTES) } -const sign_s = new StaticArray(SIGNATURE_BYTES) +const sign_sig = new StaticArray(SIGNATURE_BYTES) const sign_prv = new StaticArray(PRIVATEKEY_BYTES) const sign_pub = new StaticArray(PUBLICKEY_BYTES) /** @@ -66,7 +71,7 @@ const sign_pub = new StaticArray(PUBLICKEY_BYTES) */ export function sign (mlen: i32): void { if (mlen < 0 || mlen > 32768) throw new Error() - const s = sign_s + const sig = sign_sig const prv = sign_prv const pub = sign_pub @@ -74,15 +79,15 @@ export function sign (mlen: i32): void { memory.copy(changetype(pub), INPUT_BUFFER + PRIVATEKEY_BYTES, PUBLICKEY_BYTES) memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES) - const m = changetype>(MESSAGE_BUFFER) + const msg = changetype>(MESSAGE_BUFFER) + crypto_sign(sig, msg, mlen, prv, pub) memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES) - crypto_sign(s, m, mlen, prv, pub) - memory.copy(OUTPUT_BUFFER, changetype(s), SIGNATURE_BYTES) + memory.copy(OUTPUT_BUFFER, changetype(sig), SIGNATURE_BYTES) } -const verify_s = new StaticArray(SIGNATURE_BYTES) -const verify_k = new StaticArray(PUBLICKEY_BYTES) +const verify_sig = new StaticArray(SIGNATURE_BYTES) +const verify_pub = new StaticArray(PUBLICKEY_BYTES) /** * Verify a 64-byte detached signature for a variable-length message against a * 32-byte public key. Parameters are read as bytes from the input buffer in the @@ -97,12 +102,15 @@ const verify_k = new StaticArray(PUBLICKEY_BYTES) */ export function verify (mlen: i32): i32 { if (mlen < 0 || mlen > 32768) throw new Error('invalid message length') - const s = verify_s - const m = MESSAGE_BUFFER - const k = verify_k + const sig = verify_sig + const pub = verify_pub - memory.copy(changetype(s), INPUT_BUFFER, SIGNATURE_BYTES) - memory.copy(changetype(k), INPUT_BUFFER + SIGNATURE_BYTES, PUBLICKEY_BYTES) + memory.copy(changetype(sig), INPUT_BUFFER, SIGNATURE_BYTES) + memory.copy(changetype(pub), INPUT_BUFFER + SIGNATURE_BYTES, PUBLICKEY_BYTES) memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES) - return crypto_verify(s, m, mlen, k) + + const msg = changetype>(MESSAGE_BUFFER) + + memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES) + return crypto_verify(sig, msg, mlen, pub) } -- 2.52.0