]> git.codecow.com Git - nano25519.git/commitdiff
Refactor I/O buffers to separate per primitive. Reduce bulk block verification size...
authorChris Duncan <chris@codecow.com>
Thu, 27 Aug 2026 16:04:41 +0000 (09:04 -0700)
committerChris Duncan <chris@codecow.com>
Thu, 27 Aug 2026 16:04:41 +0000 (09:04 -0700)
src/assembly/index.ts
src/index.ts
src/lib/derive.ts
src/lib/sign.ts
src/lib/verify.ts
src/lib/wasm.ts
test/index.html
test/node.mjs

index 12e0dae601234fa067162d080026f4a41597ccef..6be7f023063c8c1af18458cf908ab7e4ca1be321 100644 (file)
@@ -7,45 +7,54 @@ import { crypto_verify_pubkey, crypto_verify_relaxed, crypto_verify_strict } fro
 
 export const BLOCKHASH_BYTELENGTH: i32 = 32
 export const KEY_BYTELENGTH: i32 = 32
+export const MAX_VERIFY_BLOCKS: i32 = 32
+export const MAX_MESSAGE_BYTELENGTH: i32 = MAX_VERIFY_BLOCKS << 10
 export const SIGNATURE_BYTELENGTH: i32 = 64
 export const SIGNEDBLOCK_BYTELENGTH: i32 = BLOCKHASH_BYTELENGTH + SIGNATURE_BYTELENGTH
 
-export const MESSAGE_BUFFER_BYTELENGTH: i32 = BLOCKHASH_BYTELENGTH << 10
-export const PRV_BUFFER_BYTELENGTH: i32 = KEY_BYTELENGTH
-export const PUB_BUFFER_BYTELENGTH: i32 = KEY_BYTELENGTH
-export const OUTPUT_BUFFER_BYTELENGTH: i32 = MESSAGE_BUFFER_BYTELENGTH / SIGNEDBLOCK_BYTELENGTH
-export const SIGNATURE_BUFFER_BYTELENGTH: i32 = SIGNATURE_BYTELENGTH
-
 // Static I/O buffers
-const MESSAGE_BUFFER = new StaticArray<u8>(MESSAGE_BUFFER_BYTELENGTH)
-const OUTPUT_BUFFER = new StaticArray<u8>(OUTPUT_BUFFER_BYTELENGTH)
-const PRV_BUFFER = new StaticArray<u8>(PRV_BUFFER_BYTELENGTH)
-const PUB_BUFFER = new StaticArray<u8>(PUB_BUFFER_BYTELENGTH)
-const SIGNATURE_BUFFER = new StaticArray<u8>(SIGNATURE_BUFFER_BYTELENGTH)
+const INPUT_MSG = new StaticArray<u8>(MAX_MESSAGE_BYTELENGTH)
+const INPUT_PRV = new StaticArray<u8>(KEY_BYTELENGTH)
+const INPUT_PUB = new StaticArray<u8>(KEY_BYTELENGTH)
+const INPUT_SIG = new StaticArray<u8>(SIGNATURE_BYTELENGTH)
 
-/** Returns the pointer to the static message input buffer (32 KiB). */
-export function getMessagePointer (): usize {
-       return changetype<usize>(MESSAGE_BUFFER)
-}
+const OUTPUT_DERIVE = new StaticArray<u8>(KEY_BYTELENGTH)
+const OUTPUT_SIGN = new StaticArray<u8>(SIGNATURE_BYTELENGTH)
+const OUTPUT_VERIFY = new StaticArray<u8>(MAX_VERIFY_BLOCKS)
 
-/** Returns the pointer to the static output buffer (341 bytes). */
-export function getOutputPointer (): usize {
-       return changetype<usize>(OUTPUT_BUFFER)
+/** Returns the pointer to the static message input buffer (32 KiB). */
+export function ptrInputMsg (): usize {
+       return changetype<usize>(INPUT_MSG)
 }
 
 /** Returns the pointer to the static private key input buffer (32 bytes). */
-export function getPrivateKeyPointer (): usize {
-       return changetype<usize>(PRV_BUFFER)
+export function ptrInputPrv (): usize {
+       return changetype<usize>(INPUT_PRV)
 }
 
 /** Returns the pointer to the static public key input buffer (32 bytes). */
-export function getPublicKeyPointer (): usize {
-       return changetype<usize>(PUB_BUFFER)
+export function ptrInputPub (): usize {
+       return changetype<usize>(INPUT_PUB)
 }
 
 /** Returns the pointer to the static signature input buffer (64 bytes). */
-export function getSignaturePointer (): usize {
-       return changetype<usize>(SIGNATURE_BUFFER)
+export function ptrInputSig (): usize {
+       return changetype<usize>(INPUT_SIG)
+}
+
+/** Returns the pointer to the derive() static output buffer (64 bytes). */
+export function ptrOutputDerive (): usize {
+       return changetype<usize>(OUTPUT_DERIVE)
+}
+
+/** Returns the pointer to the sign() static output buffer (64 bytes). */
+export function ptrOutputSign (): usize {
+       return changetype<usize>(OUTPUT_SIGN)
+}
+
+/** Returns the pointer to the verify() static output buffer (64 bytes). */
+export function ptrOutputVerify (): usize {
+       return changetype<usize>(OUTPUT_VERIFY)
 }
 
 const h = new StaticArray<u8>(BLOCKHASH_BYTELENGTH)
@@ -63,22 +72,22 @@ const sig = new StaticArray<u8>(SIGNATURE_BYTELENGTH)
  */
 export function derive (): void {
        // Clear output buffer so errors do not retain stale prior data
-       OUTPUT_BUFFER.fill(0)
+       OUTPUT_DERIVE.fill(0)
 
        // Clear local buffers
        prv.fill(0)
        pub.fill(0)
 
        // Copy input buffer to local parameterss, then clear input buffer
-       memory.copy(changetype<usize>(prv), changetype<usize>(PRV_BUFFER), KEY_BYTELENGTH)
-       PRV_BUFFER.fill(0)
+       memory.copy(changetype<usize>(prv), changetype<usize>(INPUT_PRV), KEY_BYTELENGTH)
+       INPUT_PRV.fill(0)
 
        // Derive, then clear local input
        crypto_derive(pub, prv)
        prv.fill(0)
 
        // Copy local result to output buffer
-       memory.copy(changetype<usize>(OUTPUT_BUFFER), changetype<usize>(pub), KEY_BYTELENGTH)
+       memory.copy(changetype<usize>(OUTPUT_DERIVE), changetype<usize>(pub), KEY_BYTELENGTH)
 
        // Clear local result
        pub.fill(0)
@@ -97,7 +106,7 @@ export function derive (): void {
  */
 export function sign (mlen: i32): void {
        // Clear output buffer so errors do not retain stale prior data
-       OUTPUT_BUFFER.fill(0)
+       OUTPUT_SIGN.fill(0)
 
        // Clear local buffers
        prv.fill(0)
@@ -105,27 +114,27 @@ export function sign (mlen: i32): void {
        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)
+       if (mlen < 0 || mlen > MAX_MESSAGE_BYTELENGTH) {
+               INPUT_PRV.fill(0)
+               INPUT_PUB.fill(0)
+               INPUT_MSG.fill(0)
                throw new Error('Invalid message length')
        }
 
        // Copy input buffers to local parameters, then clear input buffer
-       memory.copy(changetype<usize>(prv), changetype<usize>(PRV_BUFFER), KEY_BYTELENGTH)
-       PRV_BUFFER.fill(0)
-       memory.copy(changetype<usize>(pub), changetype<usize>(PUB_BUFFER), KEY_BYTELENGTH)
-       PUB_BUFFER.fill(0)
+       memory.copy(changetype<usize>(prv), changetype<usize>(INPUT_PRV), KEY_BYTELENGTH)
+       INPUT_PRV.fill(0)
+       memory.copy(changetype<usize>(pub), changetype<usize>(INPUT_PUB), KEY_BYTELENGTH)
+       INPUT_PUB.fill(0)
 
        // Sign message from buffer, then clear local input
-       crypto_sign(sig, MESSAGE_BUFFER, mlen, prv, pub)
+       crypto_sign(sig, INPUT_MSG, mlen, prv, pub)
        prv.fill(0)
        pub.fill(0)
-       MESSAGE_BUFFER.fill(0)
+       INPUT_MSG.fill(0)
 
        // Copy local result to output buffer
-       memory.copy(changetype<usize>(OUTPUT_BUFFER), changetype<usize>(sig), SIGNATURE_BYTELENGTH)
+       memory.copy(changetype<usize>(OUTPUT_SIGN), changetype<usize>(sig), SIGNATURE_BYTELENGTH)
 
        // Clear local result
        sig.fill(0)
@@ -139,30 +148,30 @@ export function sign (mlen: i32): void {
  */
 export function verify (mlen: i32): void {
        // Set all output to false so errors fail closed
-       OUTPUT_BUFFER.fill(255)
+       OUTPUT_VERIFY.fill(255)
 
        // Clear local buffers
        pub.fill(0)
        sig.fill(0)
 
        // Check message length
-       if (mlen < 0 || mlen > MESSAGE_BUFFER_BYTELENGTH) {
-               MESSAGE_BUFFER.fill(0)
-               PUB_BUFFER.fill(0)
+       if (mlen < 0 || mlen > MAX_MESSAGE_BYTELENGTH) {
+               INPUT_MSG.fill(0)
+               INPUT_PUB.fill(0)
                throw new Error('Invalid message length')
        }
 
        // Copy input buffer to local parameters, then clear input buffer
-       memory.copy(changetype<usize>(pub), changetype<usize>(PUB_BUFFER), KEY_BYTELENGTH)
-       PUB_BUFFER.fill(0)
-       memory.copy(changetype<usize>(sig), changetype<usize>(SIGNATURE_BUFFER), SIGNATURE_BYTELENGTH)
-       SIGNATURE_BUFFER.fill(0)
+       memory.copy(changetype<usize>(pub), changetype<usize>(INPUT_PUB), KEY_BYTELENGTH)
+       INPUT_PUB.fill(0)
+       memory.copy(changetype<usize>(sig), changetype<usize>(INPUT_SIG), SIGNATURE_BYTELENGTH)
+       INPUT_SIG.fill(0)
 
        // Verify message from buffer, then write result to output buffer
-       OUTPUT_BUFFER[0] = u8(crypto_verify_strict(sig, MESSAGE_BUFFER, mlen, pub))
+       OUTPUT_VERIFY[0] = u8(crypto_verify_strict(sig, INPUT_MSG, mlen, pub))
 
        // Clear message buffer and input locals
-       MESSAGE_BUFFER.fill(0)
+       INPUT_MSG.fill(0)
        pub.fill(0)
        sig.fill(0)
 }
@@ -172,17 +181,21 @@ export function verify (mlen: i32): void {
  * 32-byte public key. Input parameters are read as bytes from separate buffers.
  *
  * The message buffer holds both the signature and the block hash as a 96-byte
- * concatenated value. The 32 KiB message buffer cannot be divided evenly by 96,
- * so up to 341 block signature/hash pairs are supported with an extra 32 bytes
- * left at the end.
+ * concatenated value. The performance gain of verifying in bulk scales as
+ * `(1-(1/n)) x (k/(k+r))` where `n` is block count, `k` is the time required to
+ * verify the public key, and `r` is the time required to compute all the
+ * remaining verification steps. Testing shows `k` to be ~8.5% the total
+ * verification time, so batching up to 32 block signature/hash pairs reaches
+ * ~96% of that gain; any more blocks would simply add latency returning the
+ * final results.
  *
  * All pairs are verified against a single public key. The results are written
  * to the output buffer in the same order they were received.
- * @param {i32} count Number of signatures to verify, up to 341
+ * @param {i32} count Number of signatures to verify, up to 32
  */
 export function verify_blocks (count: i32): void {
        // Set all output to false so errors fail closed
-       OUTPUT_BUFFER.fill(255)
+       OUTPUT_VERIFY.fill(255)
 
        // Clear local buffers
        h.fill(0)
@@ -190,32 +203,32 @@ export function verify_blocks (count: i32): void {
        sig.fill(0)
 
        // Check number of blocks is valid
-       if (count < 1 || OUTPUT_BUFFER_BYTELENGTH < count) {
-               MESSAGE_BUFFER.fill(0)
-               PUB_BUFFER.fill(0)
+       if (count < 1 || MAX_VERIFY_BLOCKS < count) {
+               INPUT_MSG.fill(0)
+               INPUT_PUB.fill(0)
                throw new Error('Invalid block count')
        }
 
        // Copy public key input buffer to local parameter, then clear input buffer
-       memory.copy(changetype<usize>(pub), changetype<usize>(PUB_BUFFER), KEY_BYTELENGTH)
-       PUB_BUFFER.fill(0)
+       memory.copy(changetype<usize>(pub), changetype<usize>(INPUT_PUB), KEY_BYTELENGTH)
+       INPUT_PUB.fill(0)
 
        // Verify public key before proceeding with signature verification
        if (crypto_verify_pubkey(pub) == 0) {
 
                // Iterate over block signature/hash pairs
-               for (let i = 0, ptr = changetype<usize>(MESSAGE_BUFFER); i < count; i++, ptr += 96) {
+               for (let i = 0, ptr = changetype<usize>(INPUT_MSG); i < count; i++, ptr += 96) {
                        // Copy block signature/hash from message buffer to locals
                        memory.copy(changetype<usize>(sig), ptr, SIGNATURE_BYTELENGTH)
                        memory.copy(changetype<usize>(h), ptr + SIGNATURE_BYTELENGTH, BLOCKHASH_BYTELENGTH)
 
                        // Verify hash and signature, then write result to output buffer
-                       OUTPUT_BUFFER[i] = u8(crypto_verify_relaxed(sig, h, pub))
+                       OUTPUT_VERIFY[i] = u8(crypto_verify_relaxed(sig, h, pub))
                }
        }
 
        // Clear message buffer and input locals
-       MESSAGE_BUFFER.fill(0)
+       INPUT_MSG.fill(0)
        h.fill(0)
        pub.fill(0)
        sig.fill(0)
index e843a5c43ccf8e90bfd3971dc5549aed977dc3fe..4c539186405c1bab05208c3c5ab1bdafc3af9419 100644 (file)
@@ -85,7 +85,7 @@ export function verify (sig: string | Uint8Array<ArrayBuffer>, msg: string | Uin
 /**
  * Nano block signature bulk verification using WebAssembly.
  * @param {Uint8Array<ArrayBuffer>} publicKey - 32-byte public key
- * @param {object[]} blocks - Array of up to 341 block signature/hash pairs
+ * @param {object[]} blocks - Array of up to 32 block signature/hash pairs
  * @param {Uint8Array<ArrayBuffer>} blocks.signature - 64-byte block signature
  * @param {Uint8Array<ArrayBuffer>} blocks.hash - 32-byte block hash
  * @returns Array of results with, for each case, true if signature matches block hash and public key, else false
@@ -94,7 +94,7 @@ export function verify_blocks (publicKey: Uint8Array<ArrayBuffer>, blocks: { has
 /**
  * Nano block signature bulk verification using WebAssembly.
  * @param {string} publicKey - 64-character hexadecimal public key
- * @param {object[]} blocks - Array of up to 341 block signature/hash pairs
+ * @param {object[]} blocks - Array of up to 32 block signature/hash pairs
  * @param {string} blocks.signature - 128-character hexadecimal block signature
  * @param {string} blocks.hash - 64-character hexadecimal block hash
  * @returns Array of results with, for each case, true if signature matches block hash and public key, else false
index 28e28f6b4c140ead84daf7636a65c3019e00ff70..6eed51e7f73823f990a09eb457ee57222c18fa64 100644 (file)
@@ -1,23 +1,23 @@
 //! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { clear, exports, isBytes, KEY_LEN, normalize, OUT_PTR, PRV_PTR } from './wasm'
+import { clear, exports, INPUT_PRV, isBytes, KEY_BYTELENGTH, normalize, OUTPUT_DERIVE } from './wasm'
 
 export function derive (prv: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> | void {
-       if (typeof out !== 'undefined' && !(isBytes(out) && out.byteLength === KEY_LEN)) {
+       if (typeof out !== 'undefined' && !(isBytes(out) && out.byteLength === KEY_BYTELENGTH)) {
                throw new TypeError('Derive output buffer must be 32-byte Uint8Array<ArrayBuffer>')
        }
-       const privateKey = normalize('private key', KEY_LEN, KEY_LEN, prv)
-       const publicKey = new Uint8Array(KEY_LEN)
+       const privateKey = normalize('private key', KEY_BYTELENGTH, KEY_BYTELENGTH, prv)
+       const publicKey = new Uint8Array(KEY_BYTELENGTH)
        let buffer = new Uint8Array(exports.memory.buffer)
        try {
-               for (let i = 0; i < KEY_LEN; i++) {
-                       buffer[PRV_PTR + i] = privateKey[i]
+               for (let i = 0; i < KEY_BYTELENGTH; i++) {
+                       buffer[INPUT_PRV + i] = privateKey[i]
                }
                exports.derive()
                buffer = new Uint8Array(exports.memory.buffer)
-               for (let i = 0; i < KEY_LEN; i++) {
-                       publicKey[i] = buffer[OUT_PTR + i]
+               for (let i = 0; i < KEY_BYTELENGTH; i++) {
+                       publicKey[i] = buffer[OUTPUT_DERIVE + i]
                }
                if (typeof prv === 'string') {
                        let hex = ''
index c3c3361c3362770582b436dbbb71081a2144773d..402dea9c46f16ca10651ed4a98750b7801878a17 100644 (file)
@@ -1,31 +1,31 @@
 //! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { clear, exports, isBytes, KEY_LEN, MSG_BUF_LEN, MSG_PTR, normalize, OUT_PTR, PRV_PTR, PUB_PTR, SIG_LEN } from './wasm'
+import { clear, exports, INPUT_MSG, INPUT_PRV, INPUT_PUB, isBytes, KEY_BYTELENGTH, MAX_MESSAGE_BYTELENGTH, normalize, OUTPUT_SIGN, SIGNATURE_BYTELENGTH } from './wasm'
 
 export function sign (msg: unknown, prv: unknown, pub: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> | void {
        if (typeof out !== 'undefined' && !(isBytes(out) && out.byteLength === 64)) {
                throw new TypeError('Sign output buffer must be 64-byte Uint8Array<ArrayBuffer>')
        }
-       const message = normalize('message', 0, MSG_BUF_LEN, msg)
-       const privateKey = normalize('private key', KEY_LEN, KEY_LEN, prv)
-       const publicKey = normalize('public key', KEY_LEN, KEY_LEN, pub)
-       const signature = new Uint8Array(SIG_LEN)
+       const message = normalize('message', 0, MAX_MESSAGE_BYTELENGTH, msg)
+       const privateKey = normalize('private key', KEY_BYTELENGTH, KEY_BYTELENGTH, prv)
+       const publicKey = normalize('public key', KEY_BYTELENGTH, KEY_BYTELENGTH, pub)
+       const signature = new Uint8Array(SIGNATURE_BYTELENGTH)
        let buffer = new Uint8Array(exports.memory.buffer)
        try {
                for (let i = 0; i < message.byteLength; i++) {
-                       buffer[MSG_PTR + i] = message[i]
+                       buffer[INPUT_MSG + i] = message[i]
                }
-               for (let i = 0; i < KEY_LEN; i++) {
-                       buffer[PRV_PTR + i] = privateKey[i]
+               for (let i = 0; i < KEY_BYTELENGTH; i++) {
+                       buffer[INPUT_PRV + i] = privateKey[i]
                }
-               for (let i = 0; i < KEY_LEN; i++) {
-                       buffer[PUB_PTR + i] = publicKey[i]
+               for (let i = 0; i < KEY_BYTELENGTH; i++) {
+                       buffer[INPUT_PUB + i] = publicKey[i]
                }
                exports.sign(message.byteLength)
                buffer = new Uint8Array(exports.memory.buffer)
-               for (let i = 0; i < SIG_LEN; i++) {
-                       signature[i] = buffer[OUT_PTR + i]
+               for (let i = 0; i < SIGNATURE_BYTELENGTH; i++) {
+                       signature[i] = buffer[OUTPUT_SIGN + i]
                }
                if (typeof prv === 'string') {
                        let hex = ''
index e61efd79a759f747efdd7faee2f8273743827032..f2e433c2a8025c36b6e982754931563093b01ef9 100644 (file)
@@ -1,26 +1,26 @@
 //! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { BLK_LEN, KEY_LEN, MSG_BUF_LEN, MSG_PTR, OUT_BUF_LEN, OUT_PTR, PUB_PTR, SIG_LEN, SIG_PTR, clear, exports, normalize } from './wasm'
+import { BLOCKHASH_BYTELENGTH, INPUT_MSG, INPUT_PUB, INPUT_SIG, KEY_BYTELENGTH, MAX_MESSAGE_BYTELENGTH, MAX_VERIFY_BLOCKS, OUTPUT_VERIFY, SIGNATURE_BYTELENGTH, clear, exports, normalize } from './wasm'
 
 export function verify (sig: unknown, msg: unknown, pub: unknown): boolean {
        let buffer = new Uint8Array(exports.memory.buffer)
        try {
-               const message = normalize('message', 0, MSG_BUF_LEN, msg)
-               const publicKey = normalize('public key', KEY_LEN, KEY_LEN, pub)
-               const signature = normalize('signature', SIG_LEN, SIG_LEN, sig)
+               const message = normalize('message', 0, MAX_MESSAGE_BYTELENGTH, msg)
+               const publicKey = normalize('public key', KEY_BYTELENGTH, KEY_BYTELENGTH, pub)
+               const signature = normalize('signature', SIGNATURE_BYTELENGTH, SIGNATURE_BYTELENGTH, sig)
                for (let i = 0; i < message.byteLength; i++) {
-                       buffer[MSG_PTR + i] = message[i]
+                       buffer[INPUT_MSG + i] = message[i]
                }
-               for (let i = 0; i < KEY_LEN; i++) {
-                       buffer[PUB_PTR + i] = publicKey[i]
+               for (let i = 0; i < KEY_BYTELENGTH; i++) {
+                       buffer[INPUT_PUB + i] = publicKey[i]
                }
-               for (let i = 0; i < SIG_LEN; i++) {
-                       buffer[SIG_PTR + i] = signature[i]
+               for (let i = 0; i < SIGNATURE_BYTELENGTH; i++) {
+                       buffer[INPUT_SIG + i] = signature[i]
                }
                exports.verify(message.byteLength)
                buffer = new Uint8Array(exports.memory.buffer)
-               const verified = buffer[OUT_PTR]
+               const verified = buffer[OUTPUT_VERIFY]
                return verified === 0
        } finally {
                clear(buffer)
@@ -33,17 +33,17 @@ export function verify_blocks (pub: unknown, data: unknown): boolean[] {
        if (count < 1) {
                throw new RangeError('Must pass at least one block', { cause: data })
        }
-       if (OUT_BUF_LEN < count) {
-               throw new RangeError(`Bulk Nano block verification must be no more than ${OUT_BUF_LEN} blocks`, { cause: count })
+       if (MAX_VERIFY_BLOCKS < count) {
+               throw new RangeError(`Bulk Nano block verification must be no more than ${MAX_VERIFY_BLOCKS} blocks`, { cause: count })
        }
        const verified = new Uint8Array(count)
        let buffer = new Uint8Array(exports.memory.buffer)
        try {
-               const publicKey = normalize('public key', KEY_LEN, KEY_LEN, pub)
-               for (let i = 0; i < KEY_LEN; i++) {
-                       buffer[PUB_PTR + i] = publicKey[i]
+               const publicKey = normalize('public key', KEY_BYTELENGTH, KEY_BYTELENGTH, pub)
+               for (let i = 0; i < KEY_BYTELENGTH; i++) {
+                       buffer[INPUT_PUB + i] = publicKey[i]
                }
-               for (let b = 0, p = MSG_PTR; b < count; b++) {
+               for (let b = 0, p = INPUT_MSG; b < count; b++) {
                        const block = blocks[b]
                        if (block == null || typeof block !== 'object') {
                                throw new TypeError('Invalid block', { cause: block })
@@ -54,20 +54,20 @@ export function verify_blocks (pub: unknown, data: unknown): boolean[] {
                        if (!('hash' in block)) {
                                throw new TypeError('Block hash is required to verify', { cause: block })
                        }
-                       const signature = normalize('signature', SIG_LEN, SIG_LEN, block.signature)
-                       const hash = normalize('hash', BLK_LEN, BLK_LEN, block.hash)
-                       for (let i = 0; i < SIG_LEN; i++) {
+                       const signature = normalize('signature', SIGNATURE_BYTELENGTH, SIGNATURE_BYTELENGTH, block.signature)
+                       const hash = normalize('hash', BLOCKHASH_BYTELENGTH, BLOCKHASH_BYTELENGTH, block.hash)
+                       for (let i = 0; i < SIGNATURE_BYTELENGTH; i++) {
                                buffer[p + i] = signature[i]
                        }
-                       p += SIG_LEN
-                       for (let i = 0; i < BLK_LEN; i++) {
+                       p += SIGNATURE_BYTELENGTH
+                       for (let i = 0; i < BLOCKHASH_BYTELENGTH; i++) {
                                buffer[p + i] = hash[i]
                        }
-                       p += BLK_LEN
+                       p += BLOCKHASH_BYTELENGTH
                }
                exports.verify_blocks(blocks.length)
                for (let i = 0; i < count; i++) {
-                       verified[i] = buffer[OUT_PTR + i]
+                       verified[i] = buffer[OUTPUT_VERIFY + i]
                }
                return [...verified].map(v => v === 0)
        } finally {
index 138a555228f12d31ad836651a1037f8b7402b4a7..1bd81d3b068ce5b327911b4b702f8e1190739a1a 100644 (file)
@@ -10,19 +10,19 @@ type Exports = {
                sign: (mlen: number) => void
                verify: (mlen: number) => void
                verify_blocks: (count: number) => void
-               getMessagePointer: () => number
-               getOutputPointer: () => number
-               getPrivateKeyPointer: () => number
-               getPublicKeyPointer: () => number
-               getSignaturePointer: () => number
+               ptrInputMsg: () => number
+               ptrInputPrv: () => number
+               ptrInputPub: () => number
+               ptrInputSig: () => number
+               ptrOutputDerive: () => number
+               ptrOutputSign: () => number
+               ptrOutputVerify: () => number
                BLOCKHASH_BYTELENGTH: WebAssembly.Global
                KEY_BYTELENGTH: WebAssembly.Global
+               MAX_VERIFY_BLOCKS: WebAssembly.Global
+               MAX_MESSAGE_BYTELENGTH: WebAssembly.Global
                SIGNATURE_BYTELENGTH: WebAssembly.Global
-               MESSAGE_BUFFER_BYTELENGTH: WebAssembly.Global
-               OUTPUT_BUFFER_BYTELENGTH: WebAssembly.Global
-               PRV_BUFFER_BYTELENGTH: WebAssembly.Global
-               PUB_BUFFER_BYTELENGTH: WebAssembly.Global
-               SIGNATURE_BUFFER_BYTELENGTH: WebAssembly.Global
+               SIGNEDBLOCK_BYTELENGTH: WebAssembly.Global
                memory: WebAssembly.Memory
        }
 }
@@ -54,28 +54,29 @@ export const { exports } = new WebAssembly.Instance(module, {
        }
 }) as Exports
 
-export const BLK_LEN = exports.BLOCKHASH_BYTELENGTH.value
-export const KEY_LEN = exports.KEY_BYTELENGTH.value
-export const SIG_LEN = exports.SIGNATURE_BYTELENGTH.value
+export const BLOCKHASH_BYTELENGTH = exports.BLOCKHASH_BYTELENGTH.value
+export const KEY_BYTELENGTH = exports.KEY_BYTELENGTH.value
+export const MAX_MESSAGE_BYTELENGTH = exports.MAX_MESSAGE_BYTELENGTH.value
+export const MAX_VERIFY_BLOCKS = exports.MAX_VERIFY_BLOCKS.value
+export const SIGNATURE_BYTELENGTH = exports.SIGNATURE_BYTELENGTH.value
+export const SIGNEDBLOCK_BYTELENGTH = exports.SIGNEDBLOCK_BYTELENGTH.value
 
-export const MSG_BUF_LEN = exports.MESSAGE_BUFFER_BYTELENGTH.value
-export const OUT_BUF_LEN = exports.OUTPUT_BUFFER_BYTELENGTH.value
-export const PRV_BUF_LEN = exports.PRV_BUFFER_BYTELENGTH.value
-export const PUB_BUF_LEN = exports.PUB_BUFFER_BYTELENGTH.value
-export const SIG_BUF_LEN = exports.SIGNATURE_BUFFER_BYTELENGTH.value
-
-export const MSG_PTR = exports.getMessagePointer()
-export const OUT_PTR = exports.getOutputPointer()
-export const PRV_PTR = exports.getPrivateKeyPointer()
-export const PUB_PTR = exports.getPublicKeyPointer()
-export const SIG_PTR = exports.getSignaturePointer()
+export const INPUT_MSG = exports.ptrInputMsg()
+export const INPUT_PRV = exports.ptrInputPrv()
+export const INPUT_PUB = exports.ptrInputPub()
+export const INPUT_SIG = exports.ptrInputSig()
+export const OUTPUT_DERIVE = exports.ptrOutputDerive()
+export const OUTPUT_SIGN = exports.ptrOutputSign()
+export const OUTPUT_VERIFY = exports.ptrOutputVerify()
 
 export function clear (memory: Uint8Array): void {
-       memory.fill(0, MSG_PTR, MSG_PTR + MSG_BUF_LEN)
-       memory.fill(0, OUT_PTR, OUT_PTR + OUT_BUF_LEN)
-       memory.fill(0, PRV_PTR, PRV_PTR + KEY_LEN)
-       memory.fill(0, PUB_PTR, PUB_PTR + KEY_LEN)
-       memory.fill(0, SIG_PTR, SIG_PTR + SIG_LEN)
+       memory.fill(0, INPUT_MSG, INPUT_MSG + MAX_MESSAGE_BYTELENGTH)
+       memory.fill(0, INPUT_PRV, INPUT_PRV + KEY_BYTELENGTH)
+       memory.fill(0, INPUT_PUB, INPUT_PUB + KEY_BYTELENGTH)
+       memory.fill(0, INPUT_SIG, INPUT_SIG + SIGNATURE_BYTELENGTH)
+       memory.fill(0, OUTPUT_DERIVE, OUTPUT_DERIVE + KEY_BYTELENGTH)
+       memory.fill(0, OUTPUT_SIGN, OUTPUT_SIGN + SIGNATURE_BYTELENGTH)
+       memory.fill(0, OUTPUT_VERIFY, OUTPUT_VERIFY + MAX_VERIFY_BLOCKS)
 }
 
 export function isBytes (a: unknown): a is Uint8Array<ArrayBuffer> {
index 87542cd85e3376d741b2c28a29416f3e6316b67b..c74d0911c81ab6fdc1c0da6bb3e05bcdcdf350cf 100644 (file)
@@ -380,7 +380,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
                                                if (api === 'nano25519 with bulk block verification') {
                                                        publicKey = derive(privateKey, 'nano25519')
                                                        const blocks = []
-                                                       for (let i = 0; i < 341; i++) {
+                                                       for (let i = 0; i < 32; i++) {
                                                                blockHash = random()
                                                                signature = sign(blockHash, privateKey, publicKey, 'nano25519')
                                                                blocks[i] = { hash: blockHash, signature }
@@ -391,7 +391,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
                                                        if (verified.some(v => v !== true)) {
                                                                throw new Error(`invalid result\nsignature: ${signature}\nblock hash: ${blockHash}\npublic key: ${publicKey}`)
                                                        }
-                                                       duration = (end - start) / 341
+                                                       duration = (end - start) / 32
                                                        deriveTimes[i].push(0)
                                                        signTimes[i].push(0)
                                                        verifyTimes[i].push(duration)
index 3f646bc5bce957de0bc6e6e3df3b167c13940a93..467c3790ced50ad861f944aaadea18c4eddac568 100644 (file)
@@ -385,7 +385,7 @@ failures += +!test
 
 try {
        const blocks = []
-       for (let i = 0; i < 341; i++) {
+       for (let i = 0; i < 32; i++) {
                blocks[i] = { hash: NANO_ORG_VECTOR.blockHashBytes, signature: NANO_ORG_VECTOR.signatureBytes }
        }
        const verified = verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, blocks)
@@ -395,7 +395,7 @@ try {
        result = false
 }
 test = result === true
-check(`verify_blocks 341 max`, test)
+check(`verify_blocks 32 max`, test)
 passes += +test
 failures += +!test
 
@@ -420,14 +420,14 @@ failures += +!test
 
 try {
        const blocks = []
-       for (let i = 0; i < 342; i++) {
+       for (let i = 0; i < 33; i++) {
                blocks[i] = { hash: NANO_ORG_VECTOR.blockHashBytes, signature: NANO_ORG_VECTOR.signatureBytes }
        }
        verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, blocks)
        result = false
 } catch (err) {
        if (err != null && typeof err === 'object' && 'message' in err) {
-               result = err.message === 'Bulk Nano block verification must be no more than 341 blocks'
+               result = err.message === 'Bulk Nano block verification must be no more than 32 blocks'
        } else {
                result = false
        }