// Argon2id wall-time bench — verifies the OWASP-2026 cost params land in // the [200ms, 500ms] target band on the host that runs prod (CONTEXT D-07). // Phase 4 HUMAN-UAT Test 3. import argon2 from 'argon2'; // Inlined from src/argon2-opts.ts to avoid TS resolution in node bench const ARGON2_OPTS = { memoryCost: 131072, timeCost: 3, parallelism: 4, type: 2, }; import { performance } from 'node:perf_hooks'; const N = parseInt(process.env.N ?? '10', 10); const password = 'correct horse battery staple'; console.log(`Argon2id bench — ${N} iterations`); console.log(`Params: ${JSON.stringify(ARGON2_OPTS)}`); console.log(`Host: ${process.platform} ${process.arch} node ${process.version}`); console.log(''); const samples = []; for (let i = 0; i < N; i++) { const t0 = performance.now(); await argon2.hash(password, ARGON2_OPTS); const dt = performance.now() - t0; samples.push(dt); process.stdout.write(` ${i + 1}/${N}: ${dt.toFixed(1)}ms\n`); } samples.sort((a, b) => a - b); const sum = samples.reduce((a, b) => a + b, 0); const mean = sum / N; const min = samples[0]; const max = samples[N - 1]; const median = samples[Math.floor(N / 2)]; const variance = samples.reduce((a, b) => a + (b - mean) ** 2, 0) / N; const stdev = Math.sqrt(variance); console.log(''); console.log(`mean: ${mean.toFixed(1)}ms`); console.log(`stdev: ${stdev.toFixed(1)}ms`); console.log(`median: ${median.toFixed(1)}ms`); console.log(`min: ${min.toFixed(1)}ms`); console.log(`max: ${max.toFixed(1)}ms`); const TARGET_LOW = 200; const TARGET_HIGH = 500; console.log(''); console.log(`target band: [${TARGET_LOW}ms, ${TARGET_HIGH}ms]`); if (mean >= TARGET_LOW && mean <= TARGET_HIGH) { console.log(`STATUS: IN BAND`); } else if (mean < TARGET_LOW) { console.log(`STATUS: TOO FAST — bump memoryCost or timeCost`); } else { console.log(`STATUS: TOO SLOW — drop memoryCost or timeCost`); }