mirror of
https://github.com/bitcoin/bips.git
synced 2026-03-23 16:05:41 +00:00
Review comments and assistance by: Armin Sabouri <armins88@gmail.com> D++ <82842780+dplusplus1024@users.noreply.github.com> Jameson Lopp <jameson.lopp@gmail.com> jbride <jbride2001@yahoo.com> Joey Yandle <xoloki@gmail.com> Jon Atack <jon@atack.com> Jonas Nick <jonasd.nick@gmail.com> Kyle Crews <kylecrews@Kyles-Mac-Studio.local> Mark "Murch" Erhardt <murch@murch.one> notmike-5 <notmike-5@users.noreply.github.com> Vojtěch Strnad <43024885+vostrnad@users.noreply.github.com> Co-authored-by: Ethan Heilman <ethan.r.heilman@gmail.com> Co-authored-by: Isabel Foxen Duke <110147802+Isabelfoxenduke@users.noreply.github.com>
198 lines
7.1 KiB
JavaScript
198 lines
7.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Node.js test script for Bitcoin PQC WASM module (High-Level API)
|
|
*
|
|
* Usage: node test-npm-package.js
|
|
*
|
|
* This script tests the high-level TypeScript wrapper API (index.js) from the
|
|
* command line, which provides a cleaner interface than the low-level API.
|
|
*/
|
|
|
|
import { randomBytes } from 'node:crypto';
|
|
|
|
// Load the high-level WASM module
|
|
let bitcoinpqc;
|
|
let Algorithm;
|
|
|
|
try {
|
|
const module = await import('@jbride/bitcoinpqc-wasm');
|
|
bitcoinpqc = module.bitcoinpqc || module.default;
|
|
Algorithm = module.Algorithm;
|
|
|
|
if (!bitcoinpqc || !Algorithm) {
|
|
throw new Error('Failed to import bitcoinpqc or Algorithm from @jbride/bitcoinpqc-wasm');
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load WASM module:', error);
|
|
console.error('Make sure you have installed the @jbride/bitcoinpqc-wasm package before running this test.');
|
|
process.exit(1);
|
|
}
|
|
|
|
// Helper function to generate random bytes
|
|
function generateRandomBytes(length) {
|
|
const array = new Uint8Array(length);
|
|
const bytes = randomBytes(length);
|
|
array.set(bytes);
|
|
return array;
|
|
}
|
|
|
|
// Test function
|
|
async function testAlgorithm(algorithm, name) {
|
|
console.log(`\nTesting ${name} algorithm:`);
|
|
console.log('------------------------');
|
|
|
|
try {
|
|
// Get key and signature sizes
|
|
const pkSize = bitcoinpqc.publicKeySize(algorithm);
|
|
const skSize = bitcoinpqc.secretKeySize(algorithm);
|
|
const sigSize = bitcoinpqc.signatureSize(algorithm);
|
|
|
|
console.log(`Public key size: ${pkSize} bytes`);
|
|
console.log(`Secret key size: ${skSize} bytes`);
|
|
console.log(`Signature size: ${sigSize} bytes`);
|
|
|
|
// Generate random data for key generation
|
|
const randomData = generateRandomBytes(128);
|
|
|
|
// Generate a key pair
|
|
const keygenStart = Date.now();
|
|
const keypair = bitcoinpqc.generateKeypair(algorithm, randomData);
|
|
const keygenDuration = Date.now() - keygenStart;
|
|
console.log(`Key generation time: ${keygenDuration} ms`);
|
|
|
|
// Create a message to sign
|
|
const messageText = 'This is a test message for PQC signature verification';
|
|
const message = Buffer.from(messageText, 'utf8');
|
|
const messageUint8 = new Uint8Array(message);
|
|
console.log(`Message to sign: "${messageText}"`);
|
|
console.log(`Message length: ${message.length} bytes`);
|
|
|
|
// Sign the message
|
|
const signStart = Date.now();
|
|
let signature;
|
|
try {
|
|
signature = bitcoinpqc.sign(keypair.secretKey, messageUint8, algorithm);
|
|
const signDuration = Date.now() - signStart;
|
|
console.log(`Signing time: ${signDuration} ms`);
|
|
console.log(`Actual signature size: ${signature.size} bytes`);
|
|
} catch (error) {
|
|
const signDuration = Date.now() - signStart;
|
|
console.log(`Signing failed after ${signDuration} ms`);
|
|
console.log(`Error: ${error.message}`);
|
|
if (algorithm === Algorithm.SLH_DSA_SHAKE_128S) {
|
|
console.log('');
|
|
console.log('⚠️ NOTE: SLH-DSA-SHAKE-128s signing is currently experiencing');
|
|
console.log(' issues when compiled to WebAssembly. This appears to be a');
|
|
console.log(' bug in the SPHINCS+ reference implementation when compiled');
|
|
console.log(' to WASM. ML-DSA-44 (Dilithium) works correctly.');
|
|
console.log('');
|
|
console.log(' Key generation succeeded, but signing failed.');
|
|
console.log(' This is a known limitation of the browser/WASM build.');
|
|
}
|
|
throw error;
|
|
}
|
|
|
|
// Verify the signature
|
|
const verifyStart = Date.now();
|
|
const verifyResult = bitcoinpqc.verify(
|
|
keypair.publicKey,
|
|
messageUint8,
|
|
signature,
|
|
algorithm
|
|
);
|
|
const verifyDuration = Date.now() - verifyStart;
|
|
|
|
if (verifyResult) {
|
|
console.log('Signature verified successfully!');
|
|
} else {
|
|
console.log('ERROR: Signature verification failed!');
|
|
}
|
|
console.log(`Verification time: ${verifyDuration} ms`);
|
|
|
|
// Try to verify with a modified message
|
|
const modifiedMessageText = 'This is a MODIFIED message for PQC signature verification';
|
|
const modifiedMessage = Buffer.from(modifiedMessageText, 'utf8');
|
|
const modifiedMessageUint8 = new Uint8Array(modifiedMessage);
|
|
console.log(`Modified message: "${modifiedMessageText}"`);
|
|
const modifiedVerifyResult = bitcoinpqc.verify(
|
|
keypair.publicKey,
|
|
modifiedMessageUint8,
|
|
signature,
|
|
algorithm
|
|
);
|
|
|
|
if (modifiedVerifyResult) {
|
|
console.log('ERROR: Signature verified for modified message!');
|
|
} else {
|
|
console.log('Correctly rejected signature for modified message');
|
|
}
|
|
|
|
console.log('✓ Test passed!\n');
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`❌ Error: ${error.message}`);
|
|
if (error.stack) {
|
|
console.error(error.stack);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function runTests() {
|
|
console.log('Bitcoin PQC Library Example (Node.js - High-Level API)');
|
|
console.log('======================================================\n');
|
|
console.log('This example tests the post-quantum signature algorithms designed for BIP-360 and the Bitcoin QuBit soft fork.');
|
|
console.log('Using the high-level TypeScript wrapper API (index.js).\n');
|
|
|
|
// Initialize the module
|
|
try {
|
|
console.log('Initializing WASM module...');
|
|
await bitcoinpqc.init({
|
|
onRuntimeInitialized: () => {
|
|
console.log('✓ WASM module initialized successfully!\n');
|
|
},
|
|
print: (text) => {
|
|
// Enable WASM print output for debugging
|
|
console.log('WASM:', text);
|
|
},
|
|
printErr: (text) => {
|
|
console.error('WASM Error:', text);
|
|
},
|
|
// Node.js-specific: provide crypto.getRandomValues
|
|
getRandomValues: (arr) => {
|
|
const bytes = randomBytes(arr.length);
|
|
arr.set(bytes);
|
|
return arr;
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to initialize module:', error);
|
|
if (error.stack) {
|
|
console.error(error.stack);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
const results = [];
|
|
|
|
// Test ML-DSA-44
|
|
results.push(await testAlgorithm(Algorithm.ML_DSA_44, 'ML-DSA-44'));
|
|
|
|
// Test SLH-DSA-Shake-128s
|
|
results.push(await testAlgorithm(Algorithm.SLH_DSA_SHAKE_128S, 'SLH-DSA-Shake-128s'));
|
|
|
|
// Summary
|
|
console.log('\n======================================================');
|
|
console.log('Test Summary:');
|
|
console.log(` ML-DSA-44: ${results[0] ? '✓ PASSED' : '✗ FAILED'}`);
|
|
console.log(` SLH-DSA-Shake-128s: ${results[1] ? '✓ PASSED' : '✗ FAILED'}`);
|
|
console.log('======================================================\n');
|
|
|
|
const exitCode = results.every(r => r) ? 0 : 1;
|
|
process.exit(exitCode);
|
|
}
|
|
|
|
// Start
|
|
runTests();
|