From ac260a8246aecaedf8f31ccced681f7ee57a38c4 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Wed, 31 May 2023 21:12:58 +0200 Subject: [PATCH 1/2] benchmark: refactor crypto oneshot --- benchmark/crypto/oneshot-sign-verify.js | 141 ---------------------- benchmark/crypto/oneshot-sign.js | 130 ++++++++++++++++++++ benchmark/crypto/oneshot-verify.js | 150 ++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 141 deletions(-) delete mode 100644 benchmark/crypto/oneshot-sign-verify.js create mode 100644 benchmark/crypto/oneshot-sign.js create mode 100644 benchmark/crypto/oneshot-verify.js diff --git a/benchmark/crypto/oneshot-sign-verify.js b/benchmark/crypto/oneshot-sign-verify.js deleted file mode 100644 index d3c70eb042469e..00000000000000 --- a/benchmark/crypto/oneshot-sign-verify.js +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -const common = require('../common.js'); -const crypto = require('crypto'); -const fs = require('fs'); -const path = require('path'); -const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/'); -const keyFixtures = { - publicKey: fs.readFileSync(`${fixtures_keydir}/ec_p256_public.pem`) - .toString(), - privateKey: fs.readFileSync(`${fixtures_keydir}/ec_p256_private.pem`) - .toString(), -}; - -const data = crypto.randomBytes(256); - -let pems; -let keyObjects; - -function getKeyObject({ privateKey, publicKey }) { - return { - privateKey: crypto.createPrivateKey(privateKey), - publicKey: crypto.createPublicKey(publicKey), - }; -} - -const bench = common.createBenchmark(main, { - mode: ['sync', 'async-serial', 'async-parallel'], - keyFormat: ['pem', 'keyObject', 'pem.unique', 'keyObject.unique'], - n: [1e3], -}); - -function measureSync(n, privateKey, publicKey, keys) { - bench.start(); - for (let i = 0; i < n; ++i) { - crypto.verify( - 'sha256', - data, - { key: publicKey || keys[i].publicKey, dsaEncoding: 'ieee-p1363' }, - crypto.sign( - 'sha256', - data, - { key: privateKey || keys[i].privateKey, dsaEncoding: 'ieee-p1363' })); - } - bench.end(n); -} - -function measureAsyncSerial(n, privateKey, publicKey, keys) { - let remaining = n; - function done() { - if (--remaining === 0) - bench.end(n); - else - one(); - } - - function one() { - crypto.sign( - 'sha256', - data, - { - key: privateKey || keys[n - remaining].privateKey, - dsaEncoding: 'ieee-p1363', - }, - (err, signature) => { - crypto.verify( - 'sha256', - data, - { - key: publicKey || keys[n - remaining].publicKey, - dsaEncoding: 'ieee-p1363', - }, - signature, - done); - }); - } - bench.start(); - one(); -} - -function measureAsyncParallel(n, privateKey, publicKey, keys) { - let remaining = n; - function done() { - if (--remaining === 0) - bench.end(n); - } - bench.start(); - for (let i = 0; i < n; ++i) { - crypto.sign( - 'sha256', - data, - { key: privateKey || keys[i].privateKey, dsaEncoding: 'ieee-p1363' }, - (err, signature) => { - crypto.verify( - 'sha256', - data, - { key: publicKey || keys[i].publicKey, dsaEncoding: 'ieee-p1363' }, - signature, - done); - }); - } -} - -function main({ n, mode, keyFormat }) { - pems ||= [...Buffer.alloc(n)].map(() => ({ - privateKey: keyFixtures.privateKey, - publicKey: keyFixtures.publicKey, - })); - keyObjects ||= pems.map(getKeyObject); - - let privateKey, publicKey, keys; - - switch (keyFormat) { - case 'keyObject': - ({ publicKey, privateKey } = keyObjects[0]); - break; - case 'pem': - ({ publicKey, privateKey } = pems[0]); - break; - case 'pem.unique': - keys = pems; - break; - case 'keyObject.unique': - keys = keyObjects; - break; - default: - throw new Error('not implemented'); - } - - switch (mode) { - case 'sync': - measureSync(n, privateKey, publicKey, keys); - break; - case 'async-serial': - measureAsyncSerial(n, privateKey, publicKey, keys); - break; - case 'async-parallel': - measureAsyncParallel(n, privateKey, publicKey, keys); - break; - } -} diff --git a/benchmark/crypto/oneshot-sign.js b/benchmark/crypto/oneshot-sign.js new file mode 100644 index 00000000000000..19fc75f5055aac --- /dev/null +++ b/benchmark/crypto/oneshot-sign.js @@ -0,0 +1,130 @@ +'use strict'; + +const common = require('../common.js'); +const crypto = require('crypto'); +const fs = require('fs'); +const path = require('path'); +const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/'); + +const keyFixtures = { + ec: fs.readFileSync(`${fixtures_keydir}/ec_p256_private.pem`).toString(), + rsa: fs.readFileSync(`${fixtures_keydir}/rsa_private_2048.pem`).toString(), + ed25519: fs.readFileSync(`${fixtures_keydir}/ed25519_private.pem`).toString(), +}; + +const data = crypto.randomBytes(256); + +let pems; +let keyObjects; + +const bench = common.createBenchmark(main, { + keyType: ['rsa', 'ec', 'ed25519'], + mode: ['sync', 'async', 'async-parallel'], + keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'], + n: [1e3], +}); + +function measureSync(n, digest, privateKey, keys) { + bench.start(); + for (let i = 0; i < n; ++i) { + crypto.sign( + digest, + data, + privateKey || keys[i]); + } + bench.end(n); +} + +function measureAsync(n, digest, privateKey, keys) { + let remaining = n; + function done() { + if (--remaining === 0) + bench.end(n); + else + one(); + } + + function one() { + crypto.sign( + digest, + data, + privateKey || keys[n - remaining], + done); + } + bench.start(); + one(); +} + +function measureAsyncParallel(n, digest, privateKey, keys) { + let remaining = n; + function done() { + if (--remaining === 0) + bench.end(n); + } + bench.start(); + for (let i = 0; i < n; ++i) { + crypto.sign( + digest, + data, + privateKey || keys[i], + done); + } +} + +function main({ n, mode, keyFormat, keyType }) { + // "keyObject.unique" allow to compare the result with "keyObject" to + // assess whether mutexes over the key material impact the operation + if (keyFormat === 'keyObject.unique' && mode !== 'async-parallel') { + return; + } + + pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType]); + keyObjects ||= pems.map(crypto.createPrivateKey); + + let privateKey, keys, digest; + + switch (keyType) { + case 'rsa': + case 'ec': + digest = 'sha256'; + break; + case 'ed25519': + break; + default: + throw new Error('not implemented'); + } + + switch (keyFormat) { + case 'keyObject': + privateKey = keyObjects[0]; + break; + case 'pem': + privateKey = pems[0]; + break; + case 'jwk': { + privateKey = { key: keyObjects[0].export({ format: 'jwk' }), format: 'jwk' }; + break; + } + case 'der': { + privateKey = { key: keyObjects[0].export({ format: 'der', type: 'pkcs8' }), format: 'der', type: 'pkcs8' }; + break; + } + case 'keyObject.unique': + keys = keyObjects; + break; + default: + throw new Error('not implemented'); + } + + switch (mode) { + case 'sync': + measureSync(n, digest, privateKey, keys); + break; + case 'async': + measureAsync(n, digest, privateKey, keys); + break; + case 'async-parallel': + measureAsyncParallel(n, digest, privateKey, keys); + break; + } +} diff --git a/benchmark/crypto/oneshot-verify.js b/benchmark/crypto/oneshot-verify.js new file mode 100644 index 00000000000000..ac8f47c6f3f82d --- /dev/null +++ b/benchmark/crypto/oneshot-verify.js @@ -0,0 +1,150 @@ +'use strict'; + +const common = require('../common.js'); +const crypto = require('crypto'); +const fs = require('fs'); +const path = require('path'); +const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/'); + +function readKey(name) { + return fs.readFileSync(`${fixtures_keydir}/${name}.pem`, 'utf8'); +} + +function readKeyPair(publicKeyName, privateKeyName) { + return { + publicKey: readKey(publicKeyName), + privateKey: readKey(privateKeyName), + }; +} + +const keyFixtures = { + ec: readKeyPair('ec_p256_public', 'ec_p256_private'), + rsa: readKeyPair('rsa_public_2048', 'rsa_private_2048'), + ed25519: readKeyPair('ed25519_public', 'ed25519_private'), +}; + +const data = crypto.randomBytes(256); + +let pems; +let keyObjects; + +const bench = common.createBenchmark(main, { + keyType: ['rsa', 'ec', 'ed25519'], + mode: ['sync', 'async', 'async-parallel'], + keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'], + n: [1e3], +}); + +function measureSync(n, digest, signature, publicKey, keys) { + bench.start(); + for (let i = 0; i < n; ++i) { + crypto.verify( + digest, + data, + publicKey || keys[i], + signature); + } + bench.end(n); +} + +function measureAsync(n, digest, signature, publicKey, keys) { + let remaining = n; + function done() { + if (--remaining === 0) + bench.end(n); + else + one(); + } + + function one() { + crypto.verify( + digest, + data, + publicKey || keys[n - remaining], + signature, + done); + } + bench.start(); + one(); +} + +function measureAsyncParallel(n, digest, signature, publicKey, keys) { + let remaining = n; + function done() { + if (--remaining === 0) + bench.end(n); + } + bench.start(); + for (let i = 0; i < n; ++i) { + crypto.verify( + digest, + data, + publicKey || keys[i], + signature, + done); + } +} + +function main({ n, mode, keyFormat, keyType }) { + // "keyObject.unique" allow to compare the result with "keyObject" to + // assess whether mutexes over the key material impact the operation + if (keyFormat === 'keyObject.unique' && mode !== 'async-parallel') { + return; + } + + pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType].publicKey); + keyObjects ||= pems.map(crypto.createPublicKey); + + let publicKey, keys, digest; + + switch (keyType) { + case 'rsa': + case 'ec': + digest = 'sha256'; + break; + case 'ed25519': + break; + default: + throw new Error('not implemented'); + } + + switch (keyFormat) { + case 'keyObject': + publicKey = keyObjects[0]; + break; + case 'pem': + publicKey = pems[0]; + break; + case 'jwk': { + publicKey = { key: keyObjects[0].export({ format: 'jwk' }), format: 'jwk' }; + break; + } + case 'der': { + publicKey = { key: keyObjects[0].export({ format: 'der', type: 'spki' }), format: 'der', type: 'spki' }; + break; + } + case 'keyObject.unique': + keys = keyObjects; + break; + default: + throw new Error('not implemented'); + } + + + const { privateKey } = keyFixtures[keyType]; + const signature = crypto.sign(digest, data, privateKey); + + switch (mode) { + case 'sync': + measureSync(n, digest, signature, publicKey, keys); + break; + case 'async': + measureAsync(n, digest, signature, publicKey, keys); + break; + case 'async-parallel': + measureAsyncParallel(n, digest, signature, publicKey, keys); + break; + default: + throw new Error('not implemented'); + } +} From adc13e0f06a49032ece8df0366c6b9f904249471 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Mon, 5 Jun 2023 18:18:58 +0200 Subject: [PATCH 2/2] fixup! benchmark: refactor crypto oneshot --- benchmark/crypto/oneshot-sign.js | 19 ++++++++++--------- benchmark/crypto/oneshot-verify.js | 13 +++++++------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/benchmark/crypto/oneshot-sign.js b/benchmark/crypto/oneshot-sign.js index 19fc75f5055aac..88e67b9dfb1cf9 100644 --- a/benchmark/crypto/oneshot-sign.js +++ b/benchmark/crypto/oneshot-sign.js @@ -7,9 +7,9 @@ const path = require('path'); const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/'); const keyFixtures = { - ec: fs.readFileSync(`${fixtures_keydir}/ec_p256_private.pem`).toString(), - rsa: fs.readFileSync(`${fixtures_keydir}/rsa_private_2048.pem`).toString(), - ed25519: fs.readFileSync(`${fixtures_keydir}/ed25519_private.pem`).toString(), + ec: fs.readFileSync(`${fixtures_keydir}/ec_p256_private.pem`, 'utf-8'), + rsa: fs.readFileSync(`${fixtures_keydir}/rsa_private_2048.pem`, 'utf-8'), + ed25519: fs.readFileSync(`${fixtures_keydir}/ed25519_private.pem`, 'utf-8'), }; const data = crypto.randomBytes(256); @@ -22,6 +22,13 @@ const bench = common.createBenchmark(main, { mode: ['sync', 'async', 'async-parallel'], keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'], n: [1e3], +}, { + combinationFilter(p) { + // "keyObject.unique" allows to compare the result with "keyObject" to + // assess whether mutexes over the key material impact the operation + return p.keyFormat !== 'keyObject.unique' || + (p.keyFormat === 'keyObject.unique' && p.mode === 'async-parallel'); + }, }); function measureSync(n, digest, privateKey, keys) { @@ -72,12 +79,6 @@ function measureAsyncParallel(n, digest, privateKey, keys) { } function main({ n, mode, keyFormat, keyType }) { - // "keyObject.unique" allow to compare the result with "keyObject" to - // assess whether mutexes over the key material impact the operation - if (keyFormat === 'keyObject.unique' && mode !== 'async-parallel') { - return; - } - pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType]); keyObjects ||= pems.map(crypto.createPrivateKey); diff --git a/benchmark/crypto/oneshot-verify.js b/benchmark/crypto/oneshot-verify.js index ac8f47c6f3f82d..121be28d4d9578 100644 --- a/benchmark/crypto/oneshot-verify.js +++ b/benchmark/crypto/oneshot-verify.js @@ -33,6 +33,13 @@ const bench = common.createBenchmark(main, { mode: ['sync', 'async', 'async-parallel'], keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'], n: [1e3], +}, { + combinationFilter(p) { + // "keyObject.unique" allows to compare the result with "keyObject" to + // assess whether mutexes over the key material impact the operation + return p.keyFormat !== 'keyObject.unique' || + (p.keyFormat === 'keyObject.unique' && p.mode === 'async-parallel'); + }, }); function measureSync(n, digest, signature, publicKey, keys) { @@ -86,12 +93,6 @@ function measureAsyncParallel(n, digest, signature, publicKey, keys) { } function main({ n, mode, keyFormat, keyType }) { - // "keyObject.unique" allow to compare the result with "keyObject" to - // assess whether mutexes over the key material impact the operation - if (keyFormat === 'keyObject.unique' && mode !== 'async-parallel') { - return; - } - pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType].publicKey); keyObjects ||= pems.map(crypto.createPublicKey);