|
| 1 | +'use strict'; |
| 2 | + |
| 3 | +const common = require('../common.js'); |
| 4 | +const assert = require('node:assert'); |
| 5 | +const crypto = require('node:crypto'); |
| 6 | + |
| 7 | +const kCurve = 'prime256v1'; |
| 8 | +const kPeerPoolSize = 32; |
| 9 | +const scenarios = [ |
| 10 | + 'first-after-generate', |
| 11 | + 'full-lifecycle', |
| 12 | + 'reused-local-same-peer', |
| 13 | + 'reused-local-peer-pool', |
| 14 | +]; |
| 15 | + |
| 16 | +const bench = common.createBenchmark(main, { |
| 17 | + scenario: scenarios, |
| 18 | + n: [5_000], |
| 19 | +}, { |
| 20 | + test: { scenario: 'first-after-generate', n: 1 }, |
| 21 | +}); |
| 22 | + |
| 23 | +function generateContext() { |
| 24 | + const context = crypto.createECDH(kCurve); |
| 25 | + context.generateKeys(); |
| 26 | + return context; |
| 27 | +} |
| 28 | + |
| 29 | +function verifySecret(secret, local, peer) { |
| 30 | + assert.deepStrictEqual(secret, peer.computeSecret(local.getPublicKey())); |
| 31 | +} |
| 32 | + |
| 33 | +function firstAfterGenerate(n) { |
| 34 | + const peer = generateContext(); |
| 35 | + const peerPublicKey = peer.getPublicKey(); |
| 36 | + const warmup = generateContext(); |
| 37 | + warmup.computeSecret(peerPublicKey); |
| 38 | + |
| 39 | + const locals = Array.from({ length: n }, generateContext); |
| 40 | + const secrets = new Array(n); |
| 41 | + |
| 42 | + bench.start(); |
| 43 | + for (let i = 0; i < n; i++) |
| 44 | + secrets[i] = locals[i].computeSecret(peerPublicKey); |
| 45 | + bench.end(n); |
| 46 | + |
| 47 | + verifySecret(secrets[n - 1], locals[n - 1], peer); |
| 48 | +} |
| 49 | + |
| 50 | +function fullLifecycle(n) { |
| 51 | + const peer = generateContext(); |
| 52 | + const peerPublicKey = peer.getPublicKey(); |
| 53 | + const warmup = generateContext(); |
| 54 | + warmup.computeSecret(peerPublicKey); |
| 55 | + |
| 56 | + const locals = new Array(n); |
| 57 | + const secrets = new Array(n); |
| 58 | + |
| 59 | + bench.start(); |
| 60 | + for (let i = 0; i < n; i++) { |
| 61 | + const local = locals[i] = generateContext(); |
| 62 | + secrets[i] = local.computeSecret(peerPublicKey); |
| 63 | + } |
| 64 | + bench.end(n); |
| 65 | + |
| 66 | + verifySecret(secrets[n - 1], locals[n - 1], peer); |
| 67 | +} |
| 68 | + |
| 69 | +function reusedLocalSamePeer(n) { |
| 70 | + const local = generateContext(); |
| 71 | + const peer = generateContext(); |
| 72 | + const peerPublicKey = peer.getPublicKey(); |
| 73 | + local.computeSecret(peerPublicKey); |
| 74 | + |
| 75 | + const secrets = new Array(n); |
| 76 | + |
| 77 | + bench.start(); |
| 78 | + for (let i = 0; i < n; i++) |
| 79 | + secrets[i] = local.computeSecret(peerPublicKey); |
| 80 | + bench.end(n); |
| 81 | + |
| 82 | + verifySecret(secrets[n - 1], local, peer); |
| 83 | +} |
| 84 | + |
| 85 | +function reusedLocalPeerPool(n) { |
| 86 | + const local = generateContext(); |
| 87 | + const peers = Array.from( |
| 88 | + { length: Math.min(n, kPeerPoolSize) }, |
| 89 | + generateContext); |
| 90 | + const peerPublicKeys = peers.map((peer) => peer.getPublicKey()); |
| 91 | + local.computeSecret(peerPublicKeys[0]); |
| 92 | + |
| 93 | + const secrets = new Array(n); |
| 94 | + |
| 95 | + bench.start(); |
| 96 | + for (let i = 0; i < n; i++) |
| 97 | + secrets[i] = local.computeSecret(peerPublicKeys[i % peers.length]); |
| 98 | + bench.end(n); |
| 99 | + |
| 100 | + const lastPeer = peers[(n - 1) % peers.length]; |
| 101 | + verifySecret(secrets[n - 1], local, lastPeer); |
| 102 | +} |
| 103 | + |
| 104 | +function main({ scenario, n }) { |
| 105 | + switch (scenario) { |
| 106 | + case 'first-after-generate': |
| 107 | + return firstAfterGenerate(n); |
| 108 | + case 'full-lifecycle': |
| 109 | + return fullLifecycle(n); |
| 110 | + case 'reused-local-same-peer': |
| 111 | + return reusedLocalSamePeer(n); |
| 112 | + case 'reused-local-peer-pool': |
| 113 | + return reusedLocalPeerPool(n); |
| 114 | + default: |
| 115 | + throw new Error(`Unsupported scenario: ${scenario}`); |
| 116 | + } |
| 117 | +} |
0 commit comments