From a2e3506a618aa9d1cde3e2772b754eb331d33abf Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Fri, 28 Aug 2026 12:19:05 -0700 Subject: [PATCH] Update speed test page to use byte arguments by default. --- test/index.html | 106 ++++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/test/index.html b/test/index.html index bb30ca9..89413a6 100644 --- a/test/index.html +++ b/test/index.html @@ -113,28 +113,41 @@ SPDX-License-Identifier: GPL-3.0-or-later } } - function random(length = 32) { - const bytes = crypto.getRandomValues(new Uint8Array(length)) + /** @type { { bytes: Uint8Array, hex: string } } */ + const rand32 = { + get bytes() { return crypto.getRandomValues(new Uint8Array(32)) }, + get hex() { return b2a(this.bytes) } + } + + /** @type { (hex: string) => Uint8Array } */ + const a2b = (hex) => { + return new Uint8Array(hex.match(/.{2}/g).map(b => parseInt(b, 16))) + } + + /** @type { (bytes: Uint8Array) => string } */ + const b2a = (bytes) => { return [...bytes].map(b => b.toString(16).padStart(2, '0')).join('') } + /** + * @param {Uint8Array} prv + * @param {string} api + * @returns {Uint8Array} + */ const derive = (prv, api) => { - const prv8 = new Uint8Array(prv.match(/.{2}/g).map(b => parseInt(b, 16))) switch (api) { - case 'nano25519': - case 'nano25519 with bulk block verification': { - const pub8 = nano25519.derive(prv8) - return [...pub8].map(b => b.toString(16).padStart(2, '0')).join('') + case 'nano25519': { + return nano25519.derive(prv) } case 'NanocurrencyWeb': { - return NanocurrencyWeb.wallet.legacyAccounts(prv)[0].publicKey + const { publicKey } = NanocurrencyWeb.wallet.legacyAccounts(b2a(prv))[0] + return a2b(publicKey) } case 'Sodium': { - return sodium.crypto_sign_seed_keypair(prv8, 'hex').publicKey + return sodium.crypto_sign_seed_keypair(prv).publicKey } case 'TweetNaCl.js': { - const pub8 = nacl.sign.keyPair.fromSeed(prv8).publicKey - return [...pub8].map(b => b.toString(16).padStart(2, '0')).join('') + return nacl.sign.keyPair.fromSeed(prv).publicKey } default: { return null @@ -142,27 +155,30 @@ SPDX-License-Identifier: GPL-3.0-or-later } } + /** + * @param {Uint8Array} msg + * @param {Uint8Array} prv + * @param {Uint8Array} pub + * @param {string} api + * @returns {Uint8Array} + */ const sign = (msg, prv, pub, api) => { - const msg8 = new Uint8Array(msg.match(/.{2}/g).map(b => parseInt(b, 16))) - const prv8 = new Uint8Array(prv.match(/.{2}/g).map(b => parseInt(b, 16))) - const pub8 = new Uint8Array(pub.match(/.{2}/g).map(b => parseInt(b, 16))) - const sk8 = new Uint8Array((prv + pub).match(/.{2}/g).map(b => parseInt(b, 16))) + const sk = new Uint8Array([...prv, ...pub]) switch (api) { case 'nano25519': case 'nano25519 with bulk block verification': { - const sig8 = nano25519.sign(msg8, prv8, pub8) - return [...sig8].map(b => b.toString(16).padStart(2, '0')).join('') + return nano25519.sign(msg, prv, pub) } case 'NanocurrencyWeb': { - const { privateKey } = NanocurrencyWeb.wallet.legacyAccounts(prv)[0] - return NanocurrencyWeb.tools.sign(privateKey, msg) + const { privateKey } = NanocurrencyWeb.wallet.legacyAccounts(b2a(prv))[0] + const sig = NanocurrencyWeb.tools.sign(privateKey, b2a(msg)) + return a2b(sig) } case 'Sodium': { - return sodium.crypto_sign_detached(new Uint8Array(msg8), new Uint8Array(sk8), 'hex') + return sodium.crypto_sign_detached(msg, sk) } case 'TweetNaCl.js': { - const sig8 = nacl.sign.detached(new Uint8Array(msg8), new Uint8Array(sk8)) - return [...sig8].map(b => b.toString(16).padStart(2, '0')).join('') + return nacl.sign.detached(msg, sk) } default: { return null @@ -170,22 +186,26 @@ SPDX-License-Identifier: GPL-3.0-or-later } } + /** + * @param {Uint8Array} sig + * @param {Uint8Array} msg + * @param {Uint8Array} pub + * @param {string} api + * @returns {boolean} + */ const verify = (sig, msg, pub, api) => { - const msg8 = new Uint8Array(msg.match(/.{2}/g).map(b => parseInt(b, 16))) - const sig8 = new Uint8Array(sig.match(/.{2}/g).map(b => parseInt(b, 16))) - const pub8 = new Uint8Array(pub.match(/.{2}/g).map(b => parseInt(b, 16))) switch (api) { case 'nano25519': { - return nano25519.verify(sig8, msg8, pub8) + return nano25519.verify(sig, msg, pub) } case 'NanocurrencyWeb': { - return NanocurrencyWeb.tools.verify(pub, sig, msg) + return NanocurrencyWeb.tools.verify(b2a(pub), b2a(sig), b2a(msg)) } case 'Sodium': { - return sodium.crypto_sign_verify_detached(sig8, msg8, pub8) + return sodium.crypto_sign_verify_detached(sig, msg, pub) } case 'TweetNaCl.js': { - return nacl.sign.detached.verify(msg8, sig8, pub8) + return nacl.sign.detached.verify(msg, sig, pub) } default: { return null @@ -193,6 +213,12 @@ SPDX-License-Identifier: GPL-3.0-or-later } } + /** + * @param {string} api + * @param {number} size + * @param {number} runs + * @returns {void} + */ export async function test(api, size, runs) { if (typeof size !== 'number' || size < 1) { size = 1 @@ -204,6 +230,7 @@ SPDX-License-Identifier: GPL-3.0-or-later /** * @param {string} name * @param {boolean} test + * @returns {void} */ function check(name, test) { if (typeof test !== 'boolean') { @@ -320,7 +347,7 @@ SPDX-License-Identifier: GPL-3.0-or-later passes += +test failures += +!test - result = nano25519.verify(NANO_ORG_VECTOR.signature, random(), NANO_ORG_VECTOR.publicKey) + result = nano25519.verify(NANO_ORG_VECTOR.signature, rand32.hex, NANO_ORG_VECTOR.publicKey) console.log(result) test = result === false check(`verify() output for random block hash`, test) @@ -372,18 +399,18 @@ SPDX-License-Identifier: GPL-3.0-or-later for (let j = 0; j < size; j++) { document.getElementById('status').innerHTML = `TESTING IN PROGRESS. THIS MAY TAKE A LONG TIME. ${i}/${runs} ${j}/${size}
` - let start, end, duration, blockhash, privateKey, publicKey, signature + let start, end, duration, message, privateKey, publicKey, signature start = end = duration = 0 - privateKey = random() try { if (api === 'nano25519 with bulk block verification') { + privateKey = rand32.bytes publicKey = derive(privateKey, 'nano25519') const blocks = [] for (let b = 0; b < nano25519.constants.MAX_VERIFY_BLOCKS; b++) { - blockHash = random() - signature = sign(blockHash, privateKey, publicKey, 'nano25519') - blocks[b] = { hash: blockHash, signature } + message = rand32.bytes + signature = sign(message, privateKey, publicKey, 'nano25519') + blocks[b] = { hash: message, signature } } start = performance.now() const verified = nano25519.verify_blocks(publicKey, blocks) @@ -396,7 +423,8 @@ SPDX-License-Identifier: GPL-3.0-or-later signTimes[i].push(0) verifyTimes[i].push(duration) } else { - blockHash = random() + privateKey = rand32.bytes + message = rand32.bytes start = performance.now() publicKey = derive(privateKey, api) @@ -405,14 +433,14 @@ SPDX-License-Identifier: GPL-3.0-or-later deriveTimes[i].push(duration) start = performance.now() - signature = sign(blockHash, privateKey, publicKey, api) + signature = sign(message, privateKey, publicKey, api) end = performance.now() duration = end - start signTimes[i].push(duration) start = performance.now() - if (!verify(signature, blockHash, publicKey, api)) { - throw new Error(`invalid result\nsignature: ${signature}\nblock hash: ${blockHash}\npublic key: ${publicKey}`) + if (!verify(signature, message, publicKey, api)) { + throw new Error(`invalid result\nsignature: ${signature}\nblock hash: ${message}\npublic key: ${publicKey}`) } end = performance.now() duration = end - start -- 2.52.0