From: Chris Duncan Date: Thu, 27 Aug 2026 04:13:31 +0000 (-0700) Subject: Split up error messaging for bulk block verification and add unit tests. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=e713a4ebbe9b116b0924fc0cdf05636197372c97;p=nano25519.git Split up error messaging for bulk block verification and add unit tests. --- diff --git a/src/lib/verify.ts b/src/lib/verify.ts index cc1984e..356fee5 100644 --- a/src/lib/verify.ts +++ b/src/lib/verify.ts @@ -34,7 +34,7 @@ export function verify_blocks (pub: unknown, data: unknown): boolean[] { 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 256 blocks', { cause: data }) + throw new RangeError('Bulk Nano block verification must be no more than 256 blocks', { cause: count }) } const verified = new Uint8Array(count) let buffer = new Uint8Array(exports.memory.buffer) @@ -45,8 +45,14 @@ export function verify_blocks (pub: unknown, data: unknown): boolean[] { } for (let b = 0, p = MSG_PTR; b < count; b++) { const block = blocks[b] - if (!(block != null && typeof block === 'object' && 'hash' in block && 'signature' in block)) { - throw new TypeError('invalid block', { cause: block }) + if (block == null || typeof block !== 'object') { + throw new TypeError('Invalid block', { cause: block }) + } + if (!('hash' in block)) { + throw new TypeError('Block hash is required to verify', { cause: block }) + } + if (!('signature' in block)) { + throw new TypeError('Block signature is required to verify', { cause: block }) } const hash = normalize('hash', BLK_LEN, BLK_LEN, block.hash) const signature = normalize('signature', SIG_LEN, SIG_LEN, block.signature) diff --git a/test/node.mjs b/test/node.mjs index 0c9b951..d3ea7aa 100644 --- a/test/node.mjs +++ b/test/node.mjs @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2026 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { derive, sign, verify } from 'nano25519' +import { derive, sign, verify, verify_blocks } from 'nano25519' import { NANO_ORG_VECTOR, PROBLEM_VECTOR, PYTHON_ED25519_BLAKE2B_VECTORS } from './vectors.mjs' /** @@ -179,7 +179,6 @@ try { result = false } catch (err) { if (err != null && typeof err === 'object' && 'message' in err && typeof err.message === 'string') { - console.log(err.message.substring(0, 38)) result = err.message.includes('Nano25519WasmError') && err.message.includes('Invalid public key') } else { result = false @@ -372,6 +371,121 @@ for (const { privateKey, publicKey, message, signature } of PYTHON_ED25519_BLAKE failures += +!test } +// Check bulk verification of Nano blocks +try { + result = verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, [{ hash: NANO_ORG_VECTOR.blockHashBytes, signature: NANO_ORG_VECTOR.signatureBytes }])[0] +} catch (err) { + console.log(err) + result = false +} +test = result === true +check(`verify_blocks single hash bytes ${NANO_ORG_VECTOR.blockHash} with signature bytes ${NANO_ORG_VECTOR.signature}`, test) +passes += +test +failures += +!test + +try { + const blocks = [] + for (let i = 0; i < 256; i++) { + blocks[i] = { hash: NANO_ORG_VECTOR.blockHashBytes, signature: NANO_ORG_VECTOR.signatureBytes } + } + const verified = verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, blocks) + result = verified.every(v => v === true) +} catch (err) { + console.log(err) + result = false +} +test = result === true +check(`verify_blocks 256 max`, test) +passes += +test +failures += +!test + +// Check min and max ranges of bulk verification +try { + //@ts-expect-error + const blocks = [] + //@ts-expect-error + verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, blocks) + result = false +} catch (err) { + if (err != null && typeof err === 'object' && 'message' in err) { + result = err.message === 'Must pass at least one block' + } else { + result = false + } +} +test = result === true +check(`verify_blocks empty blocks`, test) +passes += +test +failures += +!test + +try { + const blocks = [] + for (let i = 0; i < 257; 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 256 blocks' + } else { + result = false + } +} +test = result === true +check(`verify_blocks too many blocks`, test) +passes += +test +failures += +!test + +// Check proper format of bulk block verification +try { + //@ts-expect-error + verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, [null]) + result = false +} catch (err) { + if (err != null && typeof err === 'object' && 'message' in err) { + result = err.message === 'Invalid block' + } else { + result = false + } +} +test = result === true +check(`verify_blocks null block`, test) +passes += +test +failures += +!test + +try { + //@ts-expect-error + verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, [{ signature: NANO_ORG_VECTOR.signatureBytes }]) + result = false +} catch (err) { + if (err != null && typeof err === 'object' && 'message' in err) { + result = err.message === 'Block hash is required to verify' + } else { + result = false + } +} +test = result === true +check(`verify_blocks missing hash`, test) +passes += +test +failures += +!test + +try { + //@ts-expect-error + verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, [{ hash: NANO_ORG_VECTOR.blockHashBytes }]) + result = false +} catch (err) { + if (err != null && typeof err === 'object' && 'message' in err) { + result = err.message === 'Block signature is required to verify' + } else { + result = false + } +} +test = result === true +check(`verify_blocks missing signature`, test) +passes += +test +failures += +!test + console.log(`${passes} \x1b[32mPASSED\x1b[0m`) console.log(`${failures} \x1b[31mFAILED\x1b[0m`)