const crypto = require('crypto');
const { performance } = require('perf_hooks');
console.log('ECDH Performance Benchmark');
console.log('='.repeat(50));
// Test parameters
const iterations = 100;
const curves = [
'prime256v1', // NIST P-256
'secp384r1', // NIST P-384
'secp521r1', // NIST P-521
'secp256k1', // Bitcoin's curve
'x25519' // Curve25519 (if available)
].filter(curve => crypto.getCurves().includes(curve));
// Helper function to measure time
function measureTime(fn) {
const start = performance.now();
fn();
return performance.now() - start;
}
// Function to generate a single key pair
function generateKeyPair(curve) {
const ecdh = crypto.createECDH(curve);
ecdh.generateKeys();
return ecdh;
}
// Function to perform key exchange
function performKeyExchange(curve) {
const alice = crypto.createECDH(curve);
alice.generateKeys();
const bob = crypto.createECDH(curve);
bob.generateKeys();
// Perform key exchange in both directions
const secret1 = alice.computeSecret(bob.getPublicKey());
const secret2 = bob.computeSecret(alice.getPublicKey());
if (!secret1.equals(secret2)) {
throw new Error('Key exchange failed');
}
return secret1.length; // Return secret length for reference
}
// Run benchmarks
console.log(`Running ${iterations} iterations for each curve...\n`);
const results = [];
for (const curve of curves) {
console.log(`Testing curve: ${curve}`);
// 1. Key Generation Benchmark
const keyGenTime = measureTime(() => {
for (let i = 0; i < iterations; i++) {
generateKeyPair(curve);
}
});
// 2. Key Exchange Benchmark
let keyExchTime = 0;
let secretLength = 0;
// Warm-up
performKeyExchange(curve);
keyExchTime = measureTime(() => {
for (let i = 0; i < iterations; i++) {
secretLength = performKeyExchange(curve);
}
});
// Calculate operations per second
const keyGenOps = Math.round((iterations / keyGenTime) * 1000);
const keyExchOps = Math.round((iterations / keyExchTime) * 1000);
results.push({
curve,
keyGenTime: (keyGenTime / iterations).toFixed(3) + ' ms/op',
keyGenOps: keyGenOps + ' ops/s',
keyExchTime: (keyExchTime / iterations).toFixed(3) + ' ms/op',
keyExchOps: keyExchOps + ' ops/s',
secretLength: secretLength + ' bytes'
});
console.log(` ✓ Completed in ${((keyGenTime + keyExchTime) / 1000).toFixed(2)}s\n`);
}
// Print results table
console.log('\nBenchmark Results:');
console.log('='.repeat(100));
console.log(
'Curve'.padEnd(12),
'Key Gen'.padEnd(20),
'Key Gen/s'.padEnd(15),
'Key Exch'.padEnd(20),
'Key Exch/s'.padEnd(15),
'Secret Length'.padEnd(15)
);
console.log('-'.repeat(100));
for (const result of results) {
console.log(
result.curve.padEnd(12),
result.keyGenTime.padEnd(20),
result.keyGenOps.padEnd(15),
result.keyExchTime.padEnd(20),
result.keyExchOps.padEnd(15),
result.secretLength.padEnd(15)
);
}
// Additional system information
console.log('\nSystem Information:');
console.log('='.repeat(50));
console.log(`- Node.js Version: ${process.version}`);
console.log(`- Platform: ${process.platform} ${process.arch}`);
console.log(`- CPU: ${require('os').cpus()[0].model}`);
console.log(`- Iterations per test: ${iterations}`);
// Memory usage
const used = process.memoryUsage();
console.log('\nMemory Usage:');
for (let [key, value] of Object.entries(used)) {
console.log(`- ${key}: ${Math.round(value / 1024 / 1024 * 100) / 100} MB`);
}