From: Chris Duncan Date: Thu, 27 Aug 2026 13:47:47 +0000 (-0700) Subject: Clear output buffer and locals prior to execution. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=e2b87001c744f283680109c88a59a7514ea73cfe;p=nano25519.git Clear output buffer and locals prior to execution. --- diff --git a/src/assembly/index.ts b/src/assembly/index.ts index cf1e680..cdf6cf5 100644 --- a/src/assembly/index.ts +++ b/src/assembly/index.ts @@ -59,6 +59,9 @@ const derive_pub = new StaticArray(KEY_BYTELENGTH) * The public key is written to the output buffer. */ export function derive (): void { + // Clear output buffer so errors do not retain stale prior data + OUTPUT_BUFFER.fill(0) + // Clear local buffers derive_prv.fill(0) derive_pub.fill(0) @@ -71,8 +74,7 @@ export function derive (): void { crypto_derive(derive_pub, derive_prv) derive_prv.fill(0) - // Clear output buffer of prior data, then copy local result to output buffer - OUTPUT_BUFFER.fill(0) + // Copy local result to output buffer memory.copy(changetype(OUTPUT_BUFFER), changetype(derive_pub), KEY_BYTELENGTH) // Clear local result @@ -94,18 +96,22 @@ const sign_sig = new StaticArray(SIGNATURE_BYTELENGTH) * @param {i32} mlen Byte length of message to be signed, up to 32768 */ export function sign (mlen: i32): void { - if (mlen < 0 || mlen > MESSAGE_BUFFER_BYTELENGTH) { - PRV_BUFFER.fill(0) - PUB_BUFFER.fill(0) - MESSAGE_BUFFER.fill(0) - throw new Error('invalid message length') - } + // Clear output buffer so errors do not retain stale prior data + OUTPUT_BUFFER.fill(0) // Clear local buffers sign_prv.fill(0) sign_pub.fill(0) sign_sig.fill(0) + // Check message length + if (mlen < 0 || mlen > MESSAGE_BUFFER_BYTELENGTH) { + PRV_BUFFER.fill(0) + PUB_BUFFER.fill(0) + MESSAGE_BUFFER.fill(0) + throw new Error('Invalid message length') + } + // Copy input buffers to local parameters, then clear input buffer memory.copy(changetype(sign_prv), changetype(PRV_BUFFER), KEY_BYTELENGTH) PRV_BUFFER.fill(0) @@ -114,12 +120,11 @@ export function sign (mlen: i32): void { // Sign message from buffer, then clear local input crypto_sign(sign_sig, MESSAGE_BUFFER, mlen, sign_prv, sign_pub) - MESSAGE_BUFFER.fill(0) sign_prv.fill(0) sign_pub.fill(0) + MESSAGE_BUFFER.fill(0) - // Clear output buffer of prior data, then copy local result to output buffer - OUTPUT_BUFFER.fill(0) + // Copy local result to output buffer memory.copy(changetype(OUTPUT_BUFFER), changetype(sign_sig), SIGNATURE_BYTELENGTH) // Clear local result @@ -135,32 +140,33 @@ const verify_sig = new StaticArray(SIGNATURE_BYTELENGTH) * @returns {boolean} True if message was signed by public key's private key */ export function verify (mlen: i32): void { - if (mlen < 0 || mlen > MESSAGE_BUFFER_BYTELENGTH) { - PRV_BUFFER.fill(0) - PUB_BUFFER.fill(0) - MESSAGE_BUFFER.fill(0) - throw new Error('invalid message length') - } + // Set all output to false so errors fail closed + OUTPUT_BUFFER.fill(255) // Clear local buffers verify_pub.fill(0) verify_sig.fill(0) + // Check message length + if (mlen < 0 || mlen > MESSAGE_BUFFER_BYTELENGTH) { + MESSAGE_BUFFER.fill(0) + PUB_BUFFER.fill(0) + throw new Error('Invalid message length') + } + // Copy input buffer to local parameters, then clear input buffer memory.copy(changetype(verify_pub), changetype(PUB_BUFFER), KEY_BYTELENGTH) PUB_BUFFER.fill(0) memory.copy(changetype(verify_sig), changetype(SIGNATURE_BUFFER), SIGNATURE_BYTELENGTH) SIGNATURE_BUFFER.fill(0) - // Verify message from buffer, then clear local input - const verified = crypto_verify_strict(verify_sig, MESSAGE_BUFFER, mlen, verify_pub) + // Verify message from buffer, then write result to output buffer + OUTPUT_BUFFER[0] = u8(crypto_verify_strict(verify_sig, MESSAGE_BUFFER, mlen, verify_pub)) + + // Clear message buffer and input locals MESSAGE_BUFFER.fill(0) verify_pub.fill(0) verify_sig.fill(0) - - // Clear output buffer of prior data, then copy local result to output buffer - OUTPUT_BUFFER.fill(0) - OUTPUT_BUFFER[0] = u8(verified) } @@ -181,39 +187,42 @@ const verify_blocks_sig = new StaticArray(SIGNATURE_BYTELENGTH) * @param {i32} count Number of signatures to verify, up to 341 */ export function verify_blocks (count: i32): void { - if (count < 1 || OUTPUT_BUFFER_BYTELENGTH < count) { - PRV_BUFFER.fill(0) - PUB_BUFFER.fill(0) - MESSAGE_BUFFER.fill(0) - throw new Error('invalid block count') - } + // Set all output to false so errors fail closed + OUTPUT_BUFFER.fill(255) // Clear local buffers + verify_blocks_msg.fill(0) verify_blocks_pub.fill(0) + verify_blocks_sig.fill(0) + + // Check number of blocks is valid + if (count < 1 || OUTPUT_BUFFER_BYTELENGTH < count) { + MESSAGE_BUFFER.fill(0) + PUB_BUFFER.fill(0) + throw new Error('Invalid block count') + } // Copy public key input buffer to local parameter, then clear input buffer memory.copy(changetype(verify_blocks_pub), changetype(PUB_BUFFER), KEY_BYTELENGTH) PUB_BUFFER.fill(0) - // Set all output to false so errors fail closed - OUTPUT_BUFFER.fill(255) - // Verify public key before proceeding with signature verification if (crypto_verify_pubkey(verify_blocks_pub) == 0) { - + // Iterate over block hash/signature pairs - for (let i = 0; i < count; i++) { + for (let i = 0, j = changetype(MESSAGE_BUFFER); i < count; i++, j += 96) { // Copy message buffer to local block hash/signature buffers - memory.copy(changetype(verify_blocks_msg), changetype(MESSAGE_BUFFER) + (96 * i), BLOCKHASH_BYTELENGTH) - memory.copy(changetype(verify_blocks_sig), changetype(MESSAGE_BUFFER) + BLOCKHASH_BYTELENGTH + (96 * i), SIGNATURE_BYTELENGTH) + memory.copy(changetype(verify_blocks_msg), j, BLOCKHASH_BYTELENGTH) + memory.copy(changetype(verify_blocks_sig), j + BLOCKHASH_BYTELENGTH, SIGNATURE_BYTELENGTH) - // Verify hash and signature + // Verify hash and signature, then write result to output buffer OUTPUT_BUFFER[i] = u8(crypto_verify_relaxed(verify_blocks_sig, verify_blocks_msg, BLOCKHASH_BYTELENGTH, verify_blocks_pub)) - } + } } - // Clear local input + // Clear message buffer and input locals MESSAGE_BUFFER.fill(0) + verify_blocks_msg.fill(0) verify_blocks_pub.fill(0) verify_blocks_sig.fill(0) }