1'use strict'; 2 3const common = require('../common.js'); 4const crypto = require('crypto'); 5const fs = require('fs'); 6const path = require('path'); 7const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/'); 8 9function readKey(name) { 10 return fs.readFileSync(`${fixtures_keydir}/${name}.pem`, 'utf8'); 11} 12 13function readKeyPair(publicKeyName, privateKeyName) { 14 return { 15 publicKey: readKey(publicKeyName), 16 privateKey: readKey(privateKeyName), 17 }; 18} 19 20const keyFixtures = { 21 ec: readKeyPair('ec_p256_public', 'ec_p256_private'), 22 rsa: readKeyPair('rsa_public_2048', 'rsa_private_2048'), 23 ed25519: readKeyPair('ed25519_public', 'ed25519_private'), 24}; 25 26const data = crypto.randomBytes(256); 27 28let pems; 29let keyObjects; 30 31const bench = common.createBenchmark(main, { 32 keyType: ['rsa', 'ec', 'ed25519'], 33 mode: ['sync', 'async', 'async-parallel'], 34 keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'], 35 n: [1e3], 36}, { 37 combinationFilter(p) { 38 // "keyObject.unique" allows to compare the result with "keyObject" to 39 // assess whether mutexes over the key material impact the operation 40 return p.keyFormat !== 'keyObject.unique' || 41 (p.keyFormat === 'keyObject.unique' && p.mode === 'async-parallel'); 42 }, 43}); 44 45function measureSync(n, digest, signature, publicKey, keys) { 46 bench.start(); 47 for (let i = 0; i < n; ++i) { 48 crypto.verify( 49 digest, 50 data, 51 publicKey || keys[i], 52 signature); 53 } 54 bench.end(n); 55} 56 57function measureAsync(n, digest, signature, publicKey, keys) { 58 let remaining = n; 59 function done() { 60 if (--remaining === 0) 61 bench.end(n); 62 else 63 one(); 64 } 65 66 function one() { 67 crypto.verify( 68 digest, 69 data, 70 publicKey || keys[n - remaining], 71 signature, 72 done); 73 } 74 bench.start(); 75 one(); 76} 77 78function measureAsyncParallel(n, digest, signature, publicKey, keys) { 79 let remaining = n; 80 function done() { 81 if (--remaining === 0) 82 bench.end(n); 83 } 84 bench.start(); 85 for (let i = 0; i < n; ++i) { 86 crypto.verify( 87 digest, 88 data, 89 publicKey || keys[i], 90 signature, 91 done); 92 } 93} 94 95function main({ n, mode, keyFormat, keyType }) { 96 pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType].publicKey); 97 keyObjects ||= pems.map(crypto.createPublicKey); 98 99 let publicKey, keys, digest; 100 101 switch (keyType) { 102 case 'rsa': 103 case 'ec': 104 digest = 'sha256'; 105 break; 106 case 'ed25519': 107 break; 108 default: 109 throw new Error('not implemented'); 110 } 111 112 switch (keyFormat) { 113 case 'keyObject': 114 publicKey = keyObjects[0]; 115 break; 116 case 'pem': 117 publicKey = pems[0]; 118 break; 119 case 'jwk': { 120 publicKey = { key: keyObjects[0].export({ format: 'jwk' }), format: 'jwk' }; 121 break; 122 } 123 case 'der': { 124 publicKey = { key: keyObjects[0].export({ format: 'der', type: 'spki' }), format: 'der', type: 'spki' }; 125 break; 126 } 127 case 'keyObject.unique': 128 keys = keyObjects; 129 break; 130 default: 131 throw new Error('not implemented'); 132 } 133 134 135 const { privateKey } = keyFixtures[keyType]; 136 const signature = crypto.sign(digest, data, privateKey); 137 138 switch (mode) { 139 case 'sync': 140 measureSync(n, digest, signature, publicKey, keys); 141 break; 142 case 'async': 143 measureAsync(n, digest, signature, publicKey, keys); 144 break; 145 case 'async-parallel': 146 measureAsyncParallel(n, digest, signature, publicKey, keys); 147 break; 148 default: 149 throw new Error('not implemented'); 150 } 151} 152