]> git.codecow.com Git - nano25519.git/commitdiff
Clear output buffer and locals prior to execution.
authorChris Duncan <chris@codecow.com>
Thu, 27 Aug 2026 13:47:47 +0000 (06:47 -0700)
committerChris Duncan <chris@codecow.com>
Thu, 27 Aug 2026 13:47:47 +0000 (06:47 -0700)
src/assembly/index.ts

index cf1e680e09c66ea994d06958a3381e60292bbc0b..cdf6cf5266016961589fb52d181a15f5e59b9e04 100644 (file)
@@ -59,6 +59,9 @@ const derive_pub = new StaticArray<u8>(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<usize>(OUTPUT_BUFFER), changetype<usize>(derive_pub), KEY_BYTELENGTH)
 
        // Clear local result
@@ -94,18 +96,22 @@ const sign_sig = new StaticArray<u8>(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<usize>(sign_prv), changetype<usize>(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<usize>(OUTPUT_BUFFER), changetype<usize>(sign_sig), SIGNATURE_BYTELENGTH)
 
        // Clear local result
@@ -135,32 +140,33 @@ const verify_sig = new StaticArray<u8>(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<usize>(verify_pub), changetype<usize>(PUB_BUFFER), KEY_BYTELENGTH)
        PUB_BUFFER.fill(0)
        memory.copy(changetype<usize>(verify_sig), changetype<usize>(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<u8>(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<usize>(verify_blocks_pub), changetype<usize>(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<usize>(MESSAGE_BUFFER); i < count; i++, j += 96) {
                        // Copy message buffer to local block hash/signature buffers
-                       memory.copy(changetype<usize>(verify_blocks_msg), changetype<usize>(MESSAGE_BUFFER) + (96 * i), BLOCKHASH_BYTELENGTH)
-                       memory.copy(changetype<usize>(verify_blocks_sig), changetype<usize>(MESSAGE_BUFFER) + BLOCKHASH_BYTELENGTH + (96 * i), SIGNATURE_BYTELENGTH)
+                       memory.copy(changetype<usize>(verify_blocks_msg), j, BLOCKHASH_BYTELENGTH)
+                       memory.copy(changetype<usize>(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)
 }