UNPKG

pqc

Version:

JS Implementation of NIST PQC FIPS Standards

194 lines (163 loc) 7.73 kB
import { ml_kem, ml_dsa, slh_dsa, utils } from "./index.js"; // Helper function to run benchmarks function benchmark(testFn, iterations = 100) { // Warmup for (let i = 0; i < 5; i++) { testFn(); } const times = []; const start = performance.now(); // Run the benchmark for (let i = 0; i < iterations; i++) { const startIter = performance.now(); testFn(); times.push(performance.now() - startIter); } const totalTime = performance.now() - start; const opsPerSec = Math.floor((iterations / totalTime) * 1000); const microSecsPerOp = Math.floor((totalTime / iterations) * 1000); return { opsPerSec, microSecsPerOp, totalTime }; } // Format results nicely function formatResults(category, operation, results) { console.log(`${operation}`); const items = Object.entries(results); for (let i = 0; i < items.length; i++) { const [name, result] = items[i]; const prefix = i === items.length - 1 ? '└─' : '├─'; console.log(`${prefix}${name} x ${result.opsPerSec.toLocaleString()} ops/sec @ ${result.microSecsPerOp}μs/op`); } } // Run all benchmarks async function runBenchmarks() { console.log("Running benchmarks...\n"); // ----------------- ML-KEM Benchmarks ----------------- console.log("ML-KEM"); // Keygen const kemKeygenResults = { "ML-KEM-512": benchmark(() => ml_kem.ml_kem512.keygen()), "ML-KEM-768": benchmark(() => ml_kem.ml_kem768.keygen()), "ML-KEM-1024": benchmark(() => ml_kem.ml_kem1024.keygen()) }; formatResults("ML-KEM", "keygen", kemKeygenResults); // Pre-generate keys for encrypt/decrypt benchmarks const kem512Keys = ml_kem.ml_kem512.keygen(); const kem768Keys = ml_kem.ml_kem768.keygen(); const kem1024Keys = ml_kem.ml_kem1024.keygen(); // Encrypt const kemEncryptResults = { "ML-KEM-512": benchmark(() => ml_kem.ml_kem512.encapsulate(kem512Keys.publicKey)), "ML-KEM-768": benchmark(() => ml_kem.ml_kem768.encapsulate(kem768Keys.publicKey)), "ML-KEM-1024": benchmark(() => ml_kem.ml_kem1024.encapsulate(kem1024Keys.publicKey)) }; formatResults("ML-KEM", "encrypt", kemEncryptResults); // Generate ciphertexts for decrypt benchmarks const { cipherText: kem512CipherText } = ml_kem.ml_kem512.encapsulate(kem512Keys.publicKey); const { cipherText: kem768CipherText } = ml_kem.ml_kem768.encapsulate(kem768Keys.publicKey); const { cipherText: kem1024CipherText } = ml_kem.ml_kem1024.encapsulate(kem1024Keys.publicKey); // Decrypt const kemDecryptResults = { "ML-KEM-512": benchmark(() => ml_kem.ml_kem512.decapsulate(kem512CipherText, kem512Keys.secretKey)), "ML-KEM-768": benchmark(() => ml_kem.ml_kem768.decapsulate(kem768CipherText, kem768Keys.secretKey)), "ML-KEM-1024": benchmark(() => ml_kem.ml_kem1024.decapsulate(kem1024CipherText, kem1024Keys.secretKey)) }; formatResults("ML-KEM", "decrypt", kemDecryptResults); // ----------------- ML-DSA Benchmarks ----------------- console.log("\nML-DSA"); // Keygen const dsaKeygenResults = { "ML-DSA44": benchmark(() => ml_dsa.ml_dsa44.keygen(), 20), "ML-DSA65": benchmark(() => ml_dsa.ml_dsa65.keygen(), 20), "ML-DSA87": benchmark(() => ml_dsa.ml_dsa87.keygen(), 20) }; formatResults("ML-DSA", "keygen", dsaKeygenResults); // Pre-generate keys and messages for sign/verify benchmarks const dsa44Keys = ml_dsa.ml_dsa44.keygen(); const dsa65Keys = ml_dsa.ml_dsa65.keygen(); const dsa87Keys = ml_dsa.ml_dsa87.keygen(); const testMessage = utils.utf8ToBytes('Benchmark test message for ML-DSA signatures'); // Sign const dsaSignResults = { "ML-DSA44": benchmark(() => ml_dsa.ml_dsa44.sign(dsa44Keys.secretKey, testMessage), 10), "ML-DSA65": benchmark(() => ml_dsa.ml_dsa65.sign(dsa65Keys.secretKey, testMessage), 10), "ML-DSA87": benchmark(() => ml_dsa.ml_dsa87.sign(dsa87Keys.secretKey, testMessage), 10) }; formatResults("ML-DSA", "sign", dsaSignResults); // Generate signatures for verify benchmarks const dsa44Signature = ml_dsa.ml_dsa44.sign(dsa44Keys.secretKey, testMessage); const dsa65Signature = ml_dsa.ml_dsa65.sign(dsa65Keys.secretKey, testMessage); const dsa87Signature = ml_dsa.ml_dsa87.sign(dsa87Keys.secretKey, testMessage); // Verify const dsaVerifyResults = { "ML-DSA44": benchmark(() => ml_dsa.ml_dsa44.verify(dsa44Keys.publicKey, testMessage, dsa44Signature), 20), "ML-DSA65": benchmark(() => ml_dsa.ml_dsa65.verify(dsa65Keys.publicKey, testMessage, dsa65Signature), 20), "ML-DSA87": benchmark(() => ml_dsa.ml_dsa87.verify(dsa87Keys.publicKey, testMessage, dsa87Signature), 20) }; formatResults("ML-DSA", "verify", dsaVerifyResults); // ----------------- SLH-DSA Benchmarks ----------------- console.log("\nSLH-DSA"); // Define all SLH-DSA variants const slhDSAVariants = { // SHA2 variants "SLH-DSA-SHA2-128F": slh_dsa.slh_dsa_sha2_128f, "SLH-DSA-SHA2-128S": slh_dsa.slh_dsa_sha2_128s, "SLH-DSA-SHA2-192F": slh_dsa.slh_dsa_sha2_192f, "SLH-DSA-SHA2-192S": slh_dsa.slh_dsa_sha2_192s, "SLH-DSA-SHA2-256F": slh_dsa.slh_dsa_sha2_256f, "SLH-DSA-SHA2-256S": slh_dsa.slh_dsa_sha2_256s, // SHAKE variants "SLH-DSA-SHAKE-128F": slh_dsa.slh_dsa_shake_128f, "SLH-DSA-SHAKE-128S": slh_dsa.slh_dsa_shake_128s, "SLH-DSA-SHAKE-192F": slh_dsa.slh_dsa_shake_192f, "SLH-DSA-SHAKE-192S": slh_dsa.slh_dsa_shake_192s, "SLH-DSA-SHAKE-256F": slh_dsa.slh_dsa_shake_256f, "SLH-DSA-SHAKE-256S": slh_dsa.slh_dsa_shake_256s }; // Keygen console.log("\nRunning SLH-DSA Key Generation benchmarks..."); const slhDSAKeygenResults = {}; const slhDSAKeys = {}; // Generate keys for all variants (with lower iterations due to likely higher complexity) for (const [name, variant] of Object.entries(slhDSAVariants)) { process.stdout.write(` Testing ${name} keygen... `); slhDSAKeygenResults[name] = benchmark(() => variant.keygen(), 5); slhDSAKeys[name] = variant.keygen(); console.log(`✓ (${slhDSAKeygenResults[name].opsPerSec} ops/sec)`); } console.log("\nKey Generation Results:"); formatResults("SLH-DSA", "keygen", slhDSAKeygenResults); // Create test message const slhDSATestMessage = utils.utf8ToBytes('Benchmark test message for SLH-DSA signatures'); // Sign console.log("\nRunning SLH-DSA Signing benchmarks..."); const slhDSASignResults = {}; const slhDSASignatures = {}; // Sign with all variants (with lower iterations due to likely higher complexity) for (const [name, variant] of Object.entries(slhDSAVariants)) { process.stdout.write(` Testing ${name} signing... `); slhDSASignResults[name] = benchmark(() => variant.sign(slhDSAKeys[name].secretKey, slhDSATestMessage), 3); slhDSASignatures[name] = variant.sign(slhDSAKeys[name].secretKey, slhDSATestMessage); console.log(`✓ (${slhDSASignResults[name].opsPerSec} ops/sec)`); } console.log("\nSigning Results:"); formatResults("SLH-DSA", "sign", slhDSASignResults); // Verify console.log("\nRunning SLH-DSA Verification benchmarks..."); const slhDSAVerifyResults = {}; // Verify with all variants for (const [name, variant] of Object.entries(slhDSAVariants)) { process.stdout.write(` Testing ${name} verification... `); slhDSAVerifyResults[name] = benchmark(() => variant.verify(slhDSAKeys[name].publicKey, slhDSATestMessage, slhDSASignatures[name]), 5); console.log(`✓ (${slhDSAVerifyResults[name].opsPerSec} ops/sec)`); } console.log("\nVerification Results:"); formatResults("SLH-DSA", "verify", slhDSAVerifyResults); } // Run the benchmarks runBenchmarks().catch(err => { console.error("Benchmark error:", err); });