@sebastienrousseau/crypto-benchmarks 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ This project is dual-licensed under either of:
2
+
3
+ * Apache License, Version 2.0 — see LICENSE-APACHE
4
+ * MIT license — see LICENSE-MIT
5
+
6
+ at your option.
7
+
8
+ SPDX-License-Identifier: Apache-2.0 OR MIT
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 OR MIT -->
2
+
3
+ # `@sebastienrousseau/crypto-benchmarks`
4
+
5
+ > Performance benchmarking and latency profiling harness comparing classical vs post-quantum cryptographic primitives across JavaScript, WebAssembly, and native runtimes.
6
+
7
+ [![Version](https://img.shields.io/npm/v/@sebastienrousseau/crypto-benchmarks.svg)](https://www.npmjs.com/package/@sebastienrousseau/crypto-benchmarks)
8
+ [![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ---
11
+
12
+ ## Overview
13
+
14
+ `@sebastienrousseau/crypto-benchmarks` provides high-precision latency, throughput (MB/s), and operations-per-second (ops/sec) profiling across classical algorithms (RSA, ECDSA, AES, SHA-2) and post-quantum standards (NIST FIPS 203 ML-KEM, FIPS 204 ML-DSA, FIPS 205 SLH-DSA).
15
+
16
+ ## Features
17
+
18
+ - **High-Precision Timing Harness**: Sub-microsecond timing using `process.hrtime.bigint()` with statistical distribution metrics (mean, median, p95, p99, standard deviation, ops/sec).
19
+ - **Comparative Profiling**:
20
+ - Symmetric Encryption: `AES-256-GCM` vs `ChaCha20-Poly1305` vs `AES-128-CBC`.
21
+ - Asymmetric Signatures: `ML-DSA-65` vs `Ed25519` vs `ECDSA-P256` vs `RSA-2048`.
22
+ - Key Encapsulation: `ML-KEM-768` vs `ECDH` vs `RSA-3072`.
23
+ - Cryptographic Hashing: `SHA-256` vs `SHA-512` vs `SHA3-256` vs `BLAKE2b`.
24
+ - **Multiple Output Formats**: Human-readable tables, JSON reports, and Markdown summaries suitable for CI performance tracking.
25
+
26
+ ## CLI Usage
27
+
28
+ ```bash
29
+ # Run all benchmark suites
30
+ crypto-benchmarks --suite all
31
+
32
+ # Run specific suite with custom iterations
33
+ crypto-benchmarks --suite pqc --iterations 100 --format markdown
34
+
35
+ # Output JSON report for automated monitoring
36
+ crypto-benchmarks --suite symmetric --format json > report.json
37
+ ```
38
+
39
+ ## Programmatic API
40
+
41
+ ```typescript
42
+ import {
43
+ runSuite,
44
+ benchmarkSymmetric,
45
+ benchmarkPqc,
46
+ } from "@sebastienrousseau/crypto-benchmarks";
47
+
48
+ // Run comprehensive benchmark
49
+ const report = await runSuite({ suite: "all", iterations: 50 });
50
+ console.log(report.summaryMarkdown);
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Development
56
+
57
+ ```bash
58
+ pnpm --filter @sebastienrousseau/crypto-benchmarks run build
59
+ pnpm --filter @sebastienrousseau/crypto-benchmarks run test
60
+ pnpm --filter @sebastienrousseau/crypto-benchmarks run lint
61
+ pnpm --filter @sebastienrousseau/crypto-benchmarks run format
62
+ ```
63
+
64
+ All 18 packages in the Crypto Service workspace maintain a **100% coverage floor** across statements, branches, functions, and lines.
65
+
66
+ ---
67
+
68
+ ## Documentation
69
+
70
+ - [Full Suite Documentation](https://docs.crypto-service.co/)
71
+ - [API Reference (TypeDoc)](https://docs.crypto-service.co/packages/crypto-benchmarks/)
72
+ - [Developer Guide](../../DEVELOPMENT.md)
73
+ - [Security Policy](../../SECURITY.md)
74
+ - [Architecture & Design](../../ARCHITECTURE.md)
75
+
76
+ ---
77
+
78
+ ## Stability guarantees
79
+
80
+ Versions advance strictly one step at a time on the `0.0.x` line (`v0.0.1` → `v0.0.2` → `v0.0.3` ... → `v0.0.999` → `v0.1.0`). Work for every release iteration begins on a dedicated `feat/v<version>` branch.
81
+
82
+ All 18 packages in the workspace move in lockstep. Public API signatures, cipher output formats, and serialization schemas are strictly versioned. Breaking changes to serialized formats or algorithm defaults are considered major breaking changes. Minimum toolchain upgrades (e.g. Node.js LTS floor) are governed by [POLICIES.md](../../docs/POLICIES.md).
83
+
84
+ ---
85
+
86
+ ## License
87
+
88
+ Dual-licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) or [MIT](https://opensource.org/licenses/MIT), at your option.
89
+
90
+ Copyright (c) 2022-2026 Sebastien Rousseau and The Crypto Service Suite contributors.
@@ -0,0 +1,3 @@
1
+ import { BenchmarkItemResult } from "../types";
2
+ export declare function runAsymmetricBenchmarks(iterations?: number): Promise<BenchmarkItemResult[]>;
3
+ //# sourceMappingURL=asymmetric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asymmetric.d.ts","sourceRoot":"","sources":["../../src/benchmarks/asymmetric.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAM/C,wBAAsB,uBAAuB,CAC3C,UAAU,SAAK,GACd,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAsFhC"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runAsymmetricBenchmarks = runAsymmetricBenchmarks;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ const timer_1 = require("../timer");
9
+ async function runAsymmetricBenchmarks(iterations = 20) {
10
+ const results = [];
11
+ const message = Buffer.from("Financial Transaction ISO 20022 Compliance Payload");
12
+ const edKeys = node_crypto_1.default.generateKeyPairSync("ed25519");
13
+ let edSig = Buffer.alloc(0);
14
+ const edSignStats = await (0, timer_1.benchmarkOperation)(() => {
15
+ edSig = node_crypto_1.default.sign(null, message, edKeys.privateKey);
16
+ }, { iterations, warmup: 3 });
17
+ results.push({
18
+ name: "Ed25519 Digital Signing",
19
+ category: "asymmetric",
20
+ algorithm: "Ed25519",
21
+ operation: "sign",
22
+ quantumSafe: false,
23
+ stats: edSignStats,
24
+ });
25
+ const edVerifyStats = await (0, timer_1.benchmarkOperation)(() => {
26
+ node_crypto_1.default.verify(null, message, edKeys.publicKey, edSig);
27
+ }, { iterations, warmup: 3 });
28
+ results.push({
29
+ name: "Ed25519 Signature Verification",
30
+ category: "asymmetric",
31
+ algorithm: "Ed25519",
32
+ operation: "verify",
33
+ quantumSafe: false,
34
+ stats: edVerifyStats,
35
+ });
36
+ const ecKeys = node_crypto_1.default.generateKeyPairSync("ec", { namedCurve: "prime256v1" });
37
+ const ecSignStats = await (0, timer_1.benchmarkOperation)(() => {
38
+ const sign = node_crypto_1.default.createSign("SHA256");
39
+ sign.update(message);
40
+ sign.end();
41
+ sign.sign(ecKeys.privateKey);
42
+ }, { iterations, warmup: 3 });
43
+ results.push({
44
+ name: "ECDSA (P-256) Digital Signing",
45
+ category: "asymmetric",
46
+ algorithm: "ECDSA-P256",
47
+ operation: "sign",
48
+ quantumSafe: false,
49
+ stats: ecSignStats,
50
+ });
51
+ const rsaKeys = node_crypto_1.default.generateKeyPairSync("rsa", { modulusLength: 2048 });
52
+ const rsaSignStats = await (0, timer_1.benchmarkOperation)(() => {
53
+ const sign = node_crypto_1.default.createSign("SHA256");
54
+ sign.update(message);
55
+ sign.end();
56
+ sign.sign(rsaKeys.privateKey);
57
+ }, { iterations: Math.min(iterations, 10), warmup: 2 });
58
+ results.push({
59
+ name: "RSA-2048 Digital Signing",
60
+ category: "asymmetric",
61
+ algorithm: "RSA-2048",
62
+ operation: "sign",
63
+ quantumSafe: false,
64
+ stats: rsaSignStats,
65
+ });
66
+ return results;
67
+ }
68
+ //# sourceMappingURL=asymmetric.js.map
@@ -0,0 +1,3 @@
1
+ import { BenchmarkItemResult } from "../types";
2
+ export declare function runHashBenchmarks(iterations?: number): Promise<BenchmarkItemResult[]>;
3
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/benchmarks/hash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAM/C,wBAAsB,iBAAiB,CACrC,UAAU,SAAK,GACd,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAwDhC"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runHashBenchmarks = runHashBenchmarks;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ const timer_1 = require("../timer");
9
+ async function runHashBenchmarks(iterations = 50) {
10
+ const results = [];
11
+ const payload = node_crypto_1.default.randomBytes(4096);
12
+ const sha256Stats = await (0, timer_1.benchmarkOperation)(() => {
13
+ node_crypto_1.default.createHash("sha256").update(payload).digest();
14
+ }, { iterations, warmup: 5 });
15
+ results.push({
16
+ name: "SHA-256 Throughput (4KB)",
17
+ category: "hash",
18
+ algorithm: "SHA-256",
19
+ operation: "hash",
20
+ quantumSafe: true,
21
+ stats: sha256Stats,
22
+ });
23
+ const sha512Stats = await (0, timer_1.benchmarkOperation)(() => {
24
+ node_crypto_1.default.createHash("sha512").update(payload).digest();
25
+ }, { iterations, warmup: 5 });
26
+ results.push({
27
+ name: "SHA-512 Throughput (4KB)",
28
+ category: "hash",
29
+ algorithm: "SHA-512",
30
+ operation: "hash",
31
+ quantumSafe: true,
32
+ stats: sha512Stats,
33
+ });
34
+ const sha3Stats = await (0, timer_1.benchmarkOperation)(() => {
35
+ node_crypto_1.default.createHash("sha3-256").update(payload).digest();
36
+ }, { iterations, warmup: 5 });
37
+ results.push({
38
+ name: "SHA3-256 (Keccak) Throughput (4KB)",
39
+ category: "hash",
40
+ algorithm: "SHA3-256",
41
+ operation: "hash",
42
+ quantumSafe: true,
43
+ stats: sha3Stats,
44
+ });
45
+ return results;
46
+ }
47
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1,10 @@
1
+ import type { MlKemEncapResult, MlDsaVerifyResult } from "@sebastienrousseau/crypto-lib";
2
+ import { BenchmarkItemResult } from "../types";
3
+ export interface PqcOperations {
4
+ mlKem768Encapsulate: () => MlKemEncapResult;
5
+ mlKem768SecretKey: string;
6
+ mlDsa65Verify: () => MlDsaVerifyResult;
7
+ }
8
+ export declare function createPqcOperations(): PqcOperations;
9
+ export declare function runPqcBenchmarks(iterations?: number): Promise<BenchmarkItemResult[]>;
10
+ //# sourceMappingURL=pqc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pqc.d.ts","sourceRoot":"","sources":["../../src/benchmarks/pqc.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAI/C,MAAM,WAAW,aAAa;IAE5B,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;IAE5C,iBAAiB,EAAE,MAAM,CAAC;IAE1B,aAAa,EAAE,MAAM,iBAAiB,CAAC;CACxC;AAOD,wBAAgB,mBAAmB,IAAI,aAAa,CAWnD;AAOD,wBAAsB,gBAAgB,CACpC,UAAU,SAAK,GACd,OAAO,CAAC,mBAAmB,EAAE,CAAC,CA+DhC"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createPqcOperations = createPqcOperations;
7
+ exports.runPqcBenchmarks = runPqcBenchmarks;
8
+ const node_crypto_1 = __importDefault(require("node:crypto"));
9
+ const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
10
+ const timer_1 = require("../timer");
11
+ function createPqcOperations() {
12
+ const kem = (0, crypto_lib_1.mlKemKeygen)(768);
13
+ const dsa = (0, crypto_lib_1.mlDsaKeygen)(65);
14
+ const message = node_crypto_1.default.randomBytes(32);
15
+ const { signature } = (0, crypto_lib_1.mlDsaSign)(65, dsa.secretKey, message);
16
+ return {
17
+ mlKem768Encapsulate: () => (0, crypto_lib_1.mlKemEncap)(768, kem.publicKey),
18
+ mlKem768SecretKey: kem.secretKey,
19
+ mlDsa65Verify: () => (0, crypto_lib_1.mlDsaVerify)(65, dsa.publicKey, message, signature),
20
+ };
21
+ }
22
+ async function runPqcBenchmarks(iterations = 30) {
23
+ const results = [];
24
+ const ecdh1 = node_crypto_1.default.createECDH("prime256v1");
25
+ const ecdh2 = node_crypto_1.default.createECDH("prime256v1");
26
+ ecdh1.generateKeys();
27
+ ecdh2.generateKeys();
28
+ const pub2 = ecdh2.getPublicKey();
29
+ const ecdhStats = await (0, timer_1.benchmarkOperation)(() => {
30
+ ecdh1.computeSecret(pub2);
31
+ }, { iterations, warmup: 5 });
32
+ results.push({
33
+ name: "Classical ECDH Key Agreement (P-256)",
34
+ category: "pqc",
35
+ algorithm: "ECDH-P256",
36
+ operation: "key-exchange",
37
+ quantumSafe: false,
38
+ stats: ecdhStats,
39
+ });
40
+ const ops = createPqcOperations();
41
+ const kemStats = await (0, timer_1.benchmarkOperation)(() => {
42
+ ops.mlKem768Encapsulate();
43
+ }, { iterations, warmup: 5 });
44
+ results.push({
45
+ name: "Post-Quantum ML-KEM-768 Key Encapsulation",
46
+ category: "pqc",
47
+ algorithm: "ML-KEM-768",
48
+ operation: "encapsulate",
49
+ quantumSafe: true,
50
+ stats: kemStats,
51
+ });
52
+ const dsaStats = await (0, timer_1.benchmarkOperation)(() => {
53
+ ops.mlDsa65Verify();
54
+ }, { iterations, warmup: 5 });
55
+ results.push({
56
+ name: "Post-Quantum ML-DSA-65 Verification",
57
+ category: "pqc",
58
+ algorithm: "ML-DSA-65",
59
+ operation: "verify",
60
+ quantumSafe: true,
61
+ stats: dsaStats,
62
+ });
63
+ return results;
64
+ }
65
+ //# sourceMappingURL=pqc.js.map
@@ -0,0 +1,3 @@
1
+ import { BenchmarkItemResult } from "../types";
2
+ export declare function runSymmetricBenchmarks(iterations?: number): Promise<BenchmarkItemResult[]>;
3
+ //# sourceMappingURL=symmetric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symmetric.d.ts","sourceRoot":"","sources":["../../src/benchmarks/symmetric.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAM/C,wBAAsB,sBAAsB,CAC1C,UAAU,SAAK,GACd,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAsEhC"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runSymmetricBenchmarks = runSymmetricBenchmarks;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ const timer_1 = require("../timer");
9
+ async function runSymmetricBenchmarks(iterations = 50) {
10
+ const results = [];
11
+ const payload = node_crypto_1.default.randomBytes(1024);
12
+ const key32 = node_crypto_1.default.randomBytes(32);
13
+ const key16 = node_crypto_1.default.randomBytes(16);
14
+ const iv12 = node_crypto_1.default.randomBytes(12);
15
+ const iv16 = node_crypto_1.default.randomBytes(16);
16
+ const aesGcmEncStats = await (0, timer_1.benchmarkOperation)(() => {
17
+ const cipher = node_crypto_1.default.createCipheriv("aes-256-gcm", key32, iv12);
18
+ cipher.update(payload);
19
+ cipher.final();
20
+ cipher.getAuthTag();
21
+ }, { iterations, warmup: 5 });
22
+ results.push({
23
+ name: "AES-256-GCM Encryption (1KB)",
24
+ category: "symmetric",
25
+ algorithm: "AES-256-GCM",
26
+ operation: "encrypt",
27
+ quantumSafe: true,
28
+ stats: aesGcmEncStats,
29
+ });
30
+ const chachaEncStats = await (0, timer_1.benchmarkOperation)(() => {
31
+ const cipher = node_crypto_1.default.createCipheriv("chacha20-poly1305", key32, iv12, {
32
+ authTagLength: 16,
33
+ });
34
+ cipher.update(payload);
35
+ cipher.final();
36
+ cipher.getAuthTag();
37
+ }, { iterations, warmup: 5 });
38
+ results.push({
39
+ name: "ChaCha20-Poly1305 Encryption (1KB)",
40
+ category: "symmetric",
41
+ algorithm: "ChaCha20-Poly1305",
42
+ operation: "encrypt",
43
+ quantumSafe: true,
44
+ stats: chachaEncStats,
45
+ });
46
+ const aesCbcEncStats = await (0, timer_1.benchmarkOperation)(() => {
47
+ const cipher = node_crypto_1.default.createCipheriv("aes-128-cbc", key16, iv16);
48
+ cipher.update(payload);
49
+ cipher.final();
50
+ }, { iterations, warmup: 5 });
51
+ results.push({
52
+ name: "AES-128-CBC Encryption (1KB)",
53
+ category: "symmetric",
54
+ algorithm: "AES-128-CBC",
55
+ operation: "encrypt",
56
+ quantumSafe: false,
57
+ stats: aesCbcEncStats,
58
+ });
59
+ return results;
60
+ }
61
+ //# sourceMappingURL=symmetric.js.map
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function run(args?: string[]): Promise<number>;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAOA,wBAAsB,GAAG,CACvB,IAAI,GAAE,MAAM,EAA0B,GACrC,OAAO,CAAC,MAAM,CAAC,CAsDjB"}
package/dist/cli.js ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.run = run;
8
+ const node_process_1 = __importDefault(require("node:process"));
9
+ const runner_1 = require("./runner");
10
+ async function run(args = node_process_1.default.argv.slice(2)) {
11
+ if (args.includes("--help") || args.includes("-h")) {
12
+ node_process_1.default.stdout.write("Usage: crypto-benchmarks [options]\n");
13
+ node_process_1.default.stdout.write("Options:\n");
14
+ node_process_1.default.stdout.write(" --suite <all|symmetric|asymmetric|pqc|hash> Benchmark suite to run (default: all)\n");
15
+ node_process_1.default.stdout.write(" --iterations <N> Number of iterations (default: 30)\n");
16
+ node_process_1.default.stdout.write(" --format <table|json|markdown> Output format (default: table)\n");
17
+ return 0;
18
+ }
19
+ let suite = "all";
20
+ const suiteIdx = args.indexOf("--suite");
21
+ if (suiteIdx !== -1 && args[suiteIdx + 1]) {
22
+ const s = args[suiteIdx + 1].toLowerCase();
23
+ if (["all", "symmetric", "asymmetric", "pqc", "hash"].includes(s)) {
24
+ suite = s;
25
+ }
26
+ }
27
+ let iterations = 30;
28
+ const iterIdx = args.indexOf("--iterations");
29
+ if (iterIdx !== -1 && args[iterIdx + 1]) {
30
+ const parsed = parseInt(args[iterIdx + 1], 10);
31
+ if (!isNaN(parsed) && parsed > 0) {
32
+ iterations = parsed;
33
+ }
34
+ }
35
+ let format = "table";
36
+ const formatIdx = args.indexOf("--format");
37
+ if (formatIdx !== -1 && args[formatIdx + 1]) {
38
+ const f = args[formatIdx + 1].toLowerCase();
39
+ if (["table", "json", "markdown"].includes(f)) {
40
+ format = f;
41
+ }
42
+ }
43
+ const report = await (0, runner_1.runSuite)({ suite, iterations, format });
44
+ if (format === "json") {
45
+ node_process_1.default.stdout.write(JSON.stringify(report, null, 2) + "\n");
46
+ }
47
+ else if (format === "markdown") {
48
+ node_process_1.default.stdout.write(report.summaryMarkdown + "\n");
49
+ }
50
+ else {
51
+ node_process_1.default.stdout.write(report.summaryTable + "\n");
52
+ }
53
+ return 0;
54
+ }
55
+ if (require.main === module) {
56
+ run().then((code) => node_process_1.default.exit(code));
57
+ }
58
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,9 @@
1
+ export * from "./types";
2
+ export * from "./timer";
3
+ export * from "./benchmarks/symmetric";
4
+ export * from "./benchmarks/asymmetric";
5
+ export * from "./benchmarks/pqc";
6
+ export * from "./benchmarks/hash";
7
+ export * from "./runner";
8
+ export * from "./cli";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./timer"), exports);
19
+ __exportStar(require("./benchmarks/symmetric"), exports);
20
+ __exportStar(require("./benchmarks/asymmetric"), exports);
21
+ __exportStar(require("./benchmarks/pqc"), exports);
22
+ __exportStar(require("./benchmarks/hash"), exports);
23
+ __exportStar(require("./runner"), exports);
24
+ __exportStar(require("./cli"), exports);
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import { BenchmarkConfig, BenchmarkReport } from "./types";
2
+ export declare function runSuite(config?: BenchmarkConfig): Promise<BenchmarkReport>;
3
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAuB,eAAe,EAAE,MAAM,SAAS,CAAC;AAShF,wBAAsB,QAAQ,CAC5B,MAAM,GAAE,eAAoB,GAC3B,OAAO,CAAC,eAAe,CAAC,CAsE1B"}
package/dist/runner.js ADDED
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runSuite = runSuite;
7
+ const node_process_1 = __importDefault(require("node:process"));
8
+ const node_os_1 = __importDefault(require("node:os"));
9
+ const symmetric_1 = require("./benchmarks/symmetric");
10
+ const asymmetric_1 = require("./benchmarks/asymmetric");
11
+ const pqc_1 = require("./benchmarks/pqc");
12
+ const hash_1 = require("./benchmarks/hash");
13
+ async function runSuite(config = {}) {
14
+ const suite = config.suite || "all";
15
+ const iterations = config.iterations || 30;
16
+ const results = [];
17
+ if (suite === "all" || suite === "symmetric") {
18
+ results.push(...(await (0, symmetric_1.runSymmetricBenchmarks)(iterations)));
19
+ }
20
+ if (suite === "all" || suite === "asymmetric") {
21
+ results.push(...(await (0, asymmetric_1.runAsymmetricBenchmarks)(iterations)));
22
+ }
23
+ if (suite === "all" || suite === "pqc") {
24
+ results.push(...(await (0, pqc_1.runPqcBenchmarks)(iterations)));
25
+ }
26
+ if (suite === "all" || suite === "hash") {
27
+ results.push(...(await (0, hash_1.runHashBenchmarks)(iterations)));
28
+ }
29
+ const timestamp = new Date().toISOString();
30
+ const platform = `${node_os_1.default.platform()} ${node_os_1.default.arch()}`;
31
+ const nodeVersion = node_process_1.default.version;
32
+ const mdRows = results.map((r) => {
33
+ const qs = r.quantumSafe ? "✅ Yes" : "❌ No";
34
+ return `| ${r.name} | ${r.algorithm} | ${r.stats.meanMs.toFixed(3)} | ${r.stats.p95Ms.toFixed(3)} | ${r.stats.opsPerSec.toLocaleString()} | ${qs} |`;
35
+ });
36
+ const summaryMarkdown = [
37
+ `# Cryptographic Performance Benchmark Report`,
38
+ ``,
39
+ `- **Date:** ${timestamp}`,
40
+ `- **Platform:** ${platform}`,
41
+ `- **Node.js:** ${nodeVersion}`,
42
+ `- **Total Benchmarks:** ${results.length}`,
43
+ ``,
44
+ `| Benchmark | Algorithm | Mean (ms) | p95 (ms) | Ops/sec | Quantum Safe |`,
45
+ `| :--- | :--- | :--- | :--- | :--- | :--- |`,
46
+ ...mdRows,
47
+ ``,
48
+ ].join("\n");
49
+ const tableHeader = `Name Algorithm Mean(ms) Ops/sec QuantumSafe`;
50
+ const tableDivider = `--------------------------------------------------------------------------------`;
51
+ const tableRows = results.map((r) => {
52
+ const name = r.name.padEnd(32).slice(0, 32);
53
+ const alg = r.algorithm.padEnd(14).slice(0, 14);
54
+ const mean = r.stats.meanMs.toFixed(3).padStart(8);
55
+ const ops = r.stats.opsPerSec.toLocaleString().padStart(10);
56
+ const qs = (r.quantumSafe ? "Yes" : "No").padStart(10);
57
+ return `${name} ${alg} ${mean} ${ops} ${qs}`;
58
+ });
59
+ const summaryTable = [
60
+ tableHeader,
61
+ tableDivider,
62
+ ...tableRows,
63
+ tableDivider,
64
+ ].join("\n");
65
+ return {
66
+ timestamp,
67
+ platform,
68
+ nodeVersion,
69
+ totalBenchmarks: results.length,
70
+ results,
71
+ summaryMarkdown,
72
+ summaryTable,
73
+ };
74
+ }
75
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1,7 @@
1
+ import { BenchmarkStats } from "./types";
2
+ export interface TimerOptions {
3
+ iterations?: number | undefined;
4
+ warmup?: number | undefined;
5
+ }
6
+ export declare function benchmarkOperation(fn: () => void | Promise<void>, options?: TimerOptions): Promise<BenchmarkStats>;
7
+ //# sourceMappingURL=timer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timer.d.ts","sourceRoot":"","sources":["../src/timer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAKD,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAC9B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,cAAc,CAAC,CAmEzB"}
package/dist/timer.js ADDED
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.benchmarkOperation = benchmarkOperation;
7
+ const node_process_1 = __importDefault(require("node:process"));
8
+ async function benchmarkOperation(fn, options = {}) {
9
+ const iterations = options.iterations && options.iterations > 0 ? options.iterations : 10;
10
+ const warmup = options.warmup !== undefined && options.warmup >= 0 ? options.warmup : 2;
11
+ for (let i = 0; i < warmup; i++) {
12
+ const res = fn();
13
+ if (res instanceof Promise) {
14
+ await res;
15
+ }
16
+ }
17
+ const timesMs = [];
18
+ const startTotal = node_process_1.default.hrtime.bigint();
19
+ for (let i = 0; i < iterations; i++) {
20
+ const start = node_process_1.default.hrtime.bigint();
21
+ const res = fn();
22
+ if (res instanceof Promise) {
23
+ await res;
24
+ }
25
+ const end = node_process_1.default.hrtime.bigint();
26
+ const diffMs = Number(end - start) / 1_000_000;
27
+ timesMs.push(diffMs);
28
+ }
29
+ const endTotal = node_process_1.default.hrtime.bigint();
30
+ const totalDurationMs = Number(endTotal - startTotal) / 1_000_000;
31
+ timesMs.sort((a, b) => a - b);
32
+ const minMs = timesMs[0];
33
+ const maxMs = timesMs[timesMs.length - 1];
34
+ const sumMs = timesMs.reduce((acc, val) => acc + val, 0);
35
+ const meanMs = sumMs / iterations;
36
+ const mid = Math.floor(timesMs.length / 2);
37
+ const medianMs = timesMs.length % 2 !== 0
38
+ ? timesMs[mid]
39
+ : (timesMs[mid - 1] + timesMs[mid]) / 2;
40
+ const p95Idx = Math.min(timesMs.length - 1, Math.floor(timesMs.length * 0.95));
41
+ const p99Idx = Math.min(timesMs.length - 1, Math.floor(timesMs.length * 0.99));
42
+ const p95Ms = timesMs[p95Idx];
43
+ const p99Ms = timesMs[p99Idx];
44
+ const opsPerSec = (iterations / totalDurationMs) * 1000;
45
+ return {
46
+ meanMs: Number(meanMs.toFixed(4)),
47
+ medianMs: Number(medianMs.toFixed(4)),
48
+ minMs: Number(minMs.toFixed(4)),
49
+ maxMs: Number(maxMs.toFixed(4)),
50
+ p95Ms: Number(p95Ms.toFixed(4)),
51
+ p99Ms: Number(p99Ms.toFixed(4)),
52
+ opsPerSec: Math.round(opsPerSec),
53
+ totalDurationMs: Number(totalDurationMs.toFixed(4)),
54
+ iterations,
55
+ };
56
+ }
57
+ //# sourceMappingURL=timer.js.map
@@ -0,0 +1,37 @@
1
+ export type SuiteName = "all" | "symmetric" | "asymmetric" | "pqc" | "hash";
2
+ export type OutputFormat = "table" | "json" | "markdown";
3
+ export interface BenchmarkConfig {
4
+ suite?: SuiteName | undefined;
5
+ iterations?: number | undefined;
6
+ warmup?: number | undefined;
7
+ format?: OutputFormat | undefined;
8
+ }
9
+ export interface BenchmarkStats {
10
+ meanMs: number;
11
+ medianMs: number;
12
+ minMs: number;
13
+ maxMs: number;
14
+ p95Ms: number;
15
+ p99Ms: number;
16
+ opsPerSec: number;
17
+ totalDurationMs: number;
18
+ iterations: number;
19
+ }
20
+ export interface BenchmarkItemResult {
21
+ name: string;
22
+ category: "symmetric" | "asymmetric" | "pqc" | "hash";
23
+ algorithm: string;
24
+ operation: string;
25
+ quantumSafe: boolean;
26
+ stats: BenchmarkStats;
27
+ }
28
+ export interface BenchmarkReport {
29
+ timestamp: string;
30
+ platform: string;
31
+ nodeVersion: string;
32
+ totalBenchmarks: number;
33
+ results: BenchmarkItemResult[];
34
+ summaryMarkdown: string;
35
+ summaryTable: string;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,CAAC;AAC5E,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,CAAC;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@sebastienrousseau/crypto-benchmarks",
3
+ "version": "0.0.8",
4
+ "description": "Performance benchmarking and latency profiling harness comparing classical vs post-quantum cryptographic primitives across JavaScript, WebAssembly, and native runtimes.",
5
+ "author": "Sebastien Rousseau <sebastienrousseau@users.noreply.github.com>",
6
+ "license": "MIT OR Apache-2.0",
7
+ "homepage": "https://crypto-service.co",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/sebastienrousseau/crypto-service.git",
11
+ "directory": "packages/crypto-benchmarks"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/sebastienrousseau/crypto-service/issues"
15
+ },
16
+ "engines": {
17
+ "node": ">=22.0.0"
18
+ },
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "sideEffects": false,
22
+ "bin": {
23
+ "crypto-benchmarks": "./dist/cli.js"
24
+ },
25
+ "files": [
26
+ "dist/**/*.js",
27
+ "dist/**/*.d.ts",
28
+ "dist/**/*.d.ts.map"
29
+ ],
30
+ "dependencies": {
31
+ "@sebastienrousseau/crypto-lib": "0.0.8"
32
+ },
33
+ "devDependencies": {
34
+ "@types/chai": "^4.3.7",
35
+ "@types/chai-as-promised": "^8.0.2",
36
+ "@types/mocha": "^10.0.2",
37
+ "@types/node": "^26.6.3",
38
+ "c8": "^12.0.0",
39
+ "chai": "^4.5.0",
40
+ "chai-as-promised": "^7.1.2",
41
+ "mocha": "^10.8.2",
42
+ "rimraf": "^6.1.3",
43
+ "ts-node": "^10.9.2",
44
+ "typedoc": "^0.28.20",
45
+ "typescript": "~5.9.3"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "scripts": {
51
+ "build": "tsc --build tsconfig.json",
52
+ "clean": "rimraf ./coverage ./dist ./docs",
53
+ "lint": "eslint --ext .ts src __tests__",
54
+ "lint:fix": "eslint --cache --fix --ext .ts src __tests__",
55
+ "format": "prettier --write src/**/*.ts",
56
+ "format:check": "prettier --check \"src/**/*.ts\"",
57
+ "test": "c8 --check-coverage --lines 100 --branches 100 --functions 100 --reporter=lcov --reporter=text mocha --config=.mocharc.cjs",
58
+ "docs": "typedoc"
59
+ }
60
+ }