'use strict'; const common = require('../common.js'); const crypto = require('node:crypto'); const fs = require('node:fs'); const path = require('node:path'); const fixtureDir = path.resolve(__dirname, '../../test/fixtures/keys'); const certificate = fs.readFileSync(path.join(fixtureDir, 'agent1-cert.pem')); const key = Buffer.alloc(32, 0x01); const hmacAlgorithm = { name: 'HMAC', hash: 'SHA-256' }; const keyUsages = ['sign']; const iv = Buffer.alloc(16, 0x02); const input = Buffer.alloc(16, 0x03); const iterations = { 'Cipheriv-update': 1e6, 'Decipheriv-update': 1e6, 'DiffieHellman-getGenerator': 2e5, 'DiffieHellmanGroup-getGenerator': 2e6, 'ECDH-getPrivateKey': 2e6, 'Hash-update': 5e6, 'Hmac-update': 5e6, 'KeyObject-equals': 2e6, 'KeyObject-symmetricKeySize-first': 1e5, 'KeyObject-type-first': 1e5, 'KeyObject-type': 1e8, 'Sign-update': 5e6, 'Verify-update': 5e6, 'CryptoKey-toKeyObject': 2e5, 'CryptoKey-algorithm-first': 1e5, 'CryptoKey-extractable-first': 1e5, 'CryptoKey-type-first': 1e5, 'CryptoKey-usages-first': 1e5, 'CryptoKey-type': 1e8, 'X509Certificate-checkHost': 1e6, 'X509Certificate-publicKey-first': 5e3, 'X509Certificate-publicKey': 1e8, 'X509Certificate-subject-first': 5e3, 'X509Certificate-subject': 1e8, }; const bench = common.createBenchmark(main, { operation: Object.keys(iterations), n: [...new Set(Object.values(iterations))], }, { combinationFilter({ operation, n }) { // Benchmark test mode reduces numeric options to 1. return n === 1 || iterations[operation] === n; }, }); function setup(operation) { switch (operation) { case 'Cipheriv-update': { const cipher = crypto.createCipheriv('aes-256-ctr', key, iv); return { run: () => cipher.update(input), finish: () => cipher.final(), }; } case 'Decipheriv-update': { const decipher = crypto.createDecipheriv('aes-256-ctr', key, iv); return { run: () => decipher.update(input), finish: () => decipher.final(), }; } case 'DiffieHellman-getGenerator': { const dh = crypto.createDiffieHellman( crypto.getDiffieHellman('modp14').getPrime()); return { run: () => dh.getGenerator() }; } case 'DiffieHellmanGroup-getGenerator': { const dh = crypto.getDiffieHellman('modp14'); return { run: () => dh.getGenerator() }; } case 'ECDH-getPrivateKey': { const ecdh = crypto.createECDH('prime256v1'); ecdh.generateKeys(); return { run: () => ecdh.getPrivateKey() }; } case 'Hash-update': { const hash = crypto.createHash('sha256'); return { run: () => hash.update(input), finish: () => hash.digest(), }; } case 'Hmac-update': { const hmac = crypto.createHmac('sha256', key); return { run: () => hmac.update(input), finish: () => hmac.digest(), }; } case 'KeyObject-equals': { const keyObject = crypto.createSecretKey(key); return { run: () => keyObject.equals(keyObject) }; } case 'KeyObject-symmetricKeySize-first': { return { run: () => crypto.createSecretKey(key).symmetricKeySize }; } case 'KeyObject-type-first': { return { run: () => crypto.createSecretKey(key).type }; } case 'KeyObject-type': { const keyObjects = Array.from( { length: 64 }, () => crypto.createSecretKey(key)); for (const keyObject of keyObjects) { if (keyObject.type !== 'secret') throw new Error('Unexpected KeyObject type'); } let index = 0; return { run: () => keyObjects[index++ & 63].type }; } case 'Sign-update': { const sign = crypto.createSign('sha256'); return { run: () => sign.update(input) }; } case 'Verify-update': { const verify = crypto.createVerify('sha256'); return { run: () => verify.update(input) }; } case 'CryptoKey-toKeyObject': { const keyObject = crypto.createSecretKey(key); const cryptoKey = keyObject.toCryptoKey( hmacAlgorithm, true, keyUsages); return { run: () => crypto.KeyObject.from(cryptoKey) }; } case 'CryptoKey-algorithm-first': case 'CryptoKey-extractable-first': case 'CryptoKey-type-first': case 'CryptoKey-usages-first': { const keyObject = crypto.createSecretKey(key); const property = operation.slice('CryptoKey-'.length, -'-first'.length); return { run: () => keyObject.toCryptoKey( hmacAlgorithm, true, keyUsages)[property], }; } case 'CryptoKey-type': { const keyObject = crypto.createSecretKey(key); const cryptoKeys = Array.from( { length: 64 }, () => keyObject.toCryptoKey(hmacAlgorithm, true, keyUsages)); for (const cryptoKey of cryptoKeys) { if (cryptoKey.type !== 'secret') throw new Error('Unexpected CryptoKey type'); } let index = 0; return { run: () => cryptoKeys[index++ & 63].type }; } case 'X509Certificate-checkHost': { const x509 = new crypto.X509Certificate(certificate); return { run: () => x509.checkHost('agent1') }; } case 'X509Certificate-publicKey-first': { return { run: () => new crypto.X509Certificate(certificate).publicKey, }; } case 'X509Certificate-publicKey': { const certificates = Array.from( { length: 64 }, () => new crypto.X509Certificate(certificate)); for (const x509 of certificates) { if (x509.publicKey === undefined) throw new Error('Missing certificate public key'); } let index = 0; return { run: () => certificates[index++ & 63].publicKey }; } case 'X509Certificate-subject-first': { return { run: () => new crypto.X509Certificate(certificate).subject, }; } case 'X509Certificate-subject': { const certificates = Array.from( { length: 64 }, () => new crypto.X509Certificate(certificate)); for (const x509 of certificates) { if (x509.subject === undefined) throw new Error('Missing certificate subject'); } let index = 0; return { run: () => certificates[index++ & 63].subject }; } default: throw new Error(`Unsupported operation: ${operation}`); } } function main({ operation, n }) { const state = setup(operation); let result; bench.start(); for (let i = 0; i < n; ++i) result = state.run(); bench.end(n); if (state.finish) state.finish(); if (result === state) throw new Error('Unexpected benchmark result'); }