1// zig run -O ReleaseFast --zig-lib-dir ../.. benchmark.zig
2
3const builtin = @import("builtin");
4
5const std = @import("std");
6const Io = std.Io;
7const mem = std.mem;
8const time = std.time;
9const crypto = std.crypto;
10
11const KiB = 1024;
12const MiB = 1024 * KiB;
13
14var prng = std.Random.DefaultPrng.init(0);
15const random = prng.random();
16
17const Crypto = struct {
18 ty: type,
19 name: []const u8,
20};
21
22const hashes = [_]Crypto{
23 Crypto{ .ty = crypto.hash.ascon.AsconHash256, .name = "ascon-256" },
24 Crypto{ .ty = crypto.hash.Md5, .name = "md5" },
25 Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" },
26 Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" },
27 Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" },
28 Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" },
29 Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" },
30 Crypto{ .ty = crypto.hash.sha3.Shake128, .name = "shake-128" },
31 Crypto{ .ty = crypto.hash.sha3.Shake256, .name = "shake-256" },
32 Crypto{ .ty = crypto.hash.sha3.TurboShake128(null), .name = "turboshake-128" },
33 Crypto{ .ty = crypto.hash.sha3.TurboShake256(null), .name = "turboshake-256" },
34 Crypto{ .ty = crypto.hash.sha3.KT128, .name = "kt128" },
35 Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
36 Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },
37 Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" },
38};
39
40const parallel_hashes = [_]Crypto{
41 Crypto{ .ty = crypto.hash.Blake3, .name = "blake3-parallel" },
42 Crypto{ .ty = crypto.hash.sha3.KT128, .name = "kt128-parallel" },
43};
44
45const block_size: usize = 8 * 8192;
46
47pub fn benchTime(io: Io) i96 {
48 return Io.Clock.awake.now(io).nanoseconds;
49}
50
51pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int, io: Io) !u64 {
52 const blocks_count = bytes / block_size;
53 var block: [block_size]u8 = undefined;
54 random.bytes(&block);
55
56 var h = Hash.init(.{});
57
58 const start = benchTime(io);
59 for (0..blocks_count) |_| {
60 h.update(&block);
61 }
62 var final: [Hash.digest_length]u8 = undefined;
63 h.final(&final);
64 std.mem.doNotOptimizeAway(final);
65
66 const end = benchTime(io);
67
68 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
69 const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
70
71 return throughput;
72}
73
74pub fn benchmarkHashParallel(comptime Hash: anytype, comptime bytes: comptime_int, allocator: mem.Allocator, io: std.Io) !u64 {
75 const data: []u8 = try allocator.alloc(u8, bytes);
76 defer allocator.free(data);
77 random.bytes(data);
78
79 const start = benchTime(io);
80 var final: [Hash.digest_length]u8 = undefined;
81 try Hash.hashParallel(data, &final, .{}, allocator, io);
82 std.mem.doNotOptimizeAway(final);
83
84 const end = benchTime(io);
85
86 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
87 const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
88
89 return throughput;
90}
91
92const macs = [_]Crypto{
93 Crypto{ .ty = crypto.onetimeauth.Ghash, .name = "ghash" },
94 Crypto{ .ty = crypto.onetimeauth.Polyval, .name = "polyval" },
95 Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" },
96 Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" },
97 Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" },
98 Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha256, .name = "hmac-sha256" },
99 Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha512, .name = "hmac-sha512" },
100 Crypto{ .ty = crypto.auth.siphash.SipHash64(2, 4), .name = "siphash-2-4" },
101 Crypto{ .ty = crypto.auth.siphash.SipHash64(1, 3), .name = "siphash-1-3" },
102 Crypto{ .ty = crypto.auth.siphash.SipHash128(2, 4), .name = "siphash128-2-4" },
103 Crypto{ .ty = crypto.auth.siphash.SipHash128(1, 3), .name = "siphash128-1-3" },
104 Crypto{ .ty = crypto.auth.aegis.Aegis128X4Mac, .name = "aegis-128x4 mac" },
105 Crypto{ .ty = crypto.auth.aegis.Aegis256X4Mac, .name = "aegis-256x4 mac" },
106 Crypto{ .ty = crypto.auth.aegis.Aegis128X2Mac, .name = "aegis-128x2 mac" },
107 Crypto{ .ty = crypto.auth.aegis.Aegis256X2Mac, .name = "aegis-256x2 mac" },
108 Crypto{ .ty = crypto.auth.aegis.Aegis128LMac, .name = "aegis-128l mac" },
109 Crypto{ .ty = crypto.auth.aegis.Aegis256Mac, .name = "aegis-256 mac" },
110 Crypto{ .ty = crypto.auth.cmac.CmacAes128, .name = "aes-cmac" },
111};
112
113pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int, io: Io) !u64 {
114 var in: [512 * KiB]u8 = undefined;
115 random.bytes(in[0..]);
116
117 const key_length = if (Mac.key_length == 0) 32 else Mac.key_length;
118 var key: [key_length]u8 = undefined;
119 random.bytes(key[0..]);
120
121 var mac: [Mac.mac_length]u8 = undefined;
122 var offset: usize = 0;
123 const start = benchTime(io);
124 while (offset < bytes) : (offset += in.len) {
125 Mac.create(mac[0..], in[0..], key[0..]);
126 mem.doNotOptimizeAway(&mac);
127 }
128 const end = benchTime(io);
129
130 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
131 const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
132
133 return throughput;
134}
135
136const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }};
137
138pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int, io: Io) !u64 {
139 std.debug.assert(DhKeyExchange.shared_length >= DhKeyExchange.secret_length);
140
141 var secret: [DhKeyExchange.shared_length]u8 = undefined;
142 random.bytes(secret[0..]);
143
144 var public: [DhKeyExchange.shared_length]u8 = undefined;
145 random.bytes(public[0..]);
146
147 const start = benchTime(io);
148 {
149 var i: usize = 0;
150 while (i < exchange_count) : (i += 1) {
151 const out = try DhKeyExchange.scalarmult(secret, public);
152 secret[0..16].* = out[0..16].*;
153 public[0..16].* = out[16..32].*;
154 mem.doNotOptimizeAway(&out);
155 }
156 }
157 const end = benchTime(io);
158
159 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
160 const throughput = @as(u64, @intFromFloat(exchange_count / elapsed_s));
161
162 return throughput;
163}
164
165const signatures = [_]Crypto{
166 Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" },
167 Crypto{ .ty = crypto.sign.ecdsa.EcdsaP256Sha256, .name = "ecdsa-p256" },
168 Crypto{ .ty = crypto.sign.ecdsa.EcdsaP384Sha384, .name = "ecdsa-p384" },
169 Crypto{ .ty = crypto.sign.ecdsa.EcdsaSecp256k1Sha256, .name = "ecdsa-secp256k1" },
170 Crypto{ .ty = crypto.sign.mldsa.MLDSA44, .name = "ml-dsa-44" },
171 Crypto{ .ty = crypto.sign.mldsa.MLDSA65, .name = "ml-dsa-65" },
172 Crypto{ .ty = crypto.sign.mldsa.MLDSA87, .name = "ml-dsa-87" },
173};
174
175pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int, io: std.Io) !u64 {
176 const msg: [64]u8 = @splat(0);
177 const key_pair = Signature.KeyPair.generate(io);
178
179 const start = benchTime(io);
180 {
181 var i: usize = 0;
182 while (i < signatures_count) : (i += 1) {
183 const sig = try key_pair.sign(&msg, null);
184 mem.doNotOptimizeAway(&sig);
185 }
186 }
187 const end = benchTime(io);
188
189 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
190 const throughput = @as(u64, @intFromFloat(signatures_count / elapsed_s));
191
192 return throughput;
193}
194
195const signature_verifications = [_]Crypto{
196 Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" },
197 Crypto{ .ty = crypto.sign.mldsa.MLDSA44, .name = "ml-dsa-44" },
198 Crypto{ .ty = crypto.sign.mldsa.MLDSA65, .name = "ml-dsa-65" },
199 Crypto{ .ty = crypto.sign.mldsa.MLDSA87, .name = "ml-dsa-87" },
200};
201
202pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int, io: std.Io) !u64 {
203 const msg: [64]u8 = @splat(0);
204 const key_pair = Signature.KeyPair.generate(io);
205 const sig = try key_pair.sign(&msg, null);
206
207 const start = benchTime(io);
208 {
209 var i: usize = 0;
210 while (i < signatures_count) : (i += 1) {
211 try sig.verify(&msg, key_pair.public_key);
212 mem.doNotOptimizeAway(&sig);
213 }
214 }
215 const end = benchTime(io);
216
217 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
218 const throughput = @as(u64, @intFromFloat(signatures_count / elapsed_s));
219
220 return throughput;
221}
222
223const batch_signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
224
225pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int, io: std.Io) !u64 {
226 const msg: [64]u8 = @splat(0);
227 const key_pair = Signature.KeyPair.generate(io);
228 const sig = try key_pair.sign(&msg, null);
229
230 var batch: [64]Signature.BatchElement = undefined;
231 for (&batch) |*element| {
232 element.* = Signature.BatchElement{ .sig = sig, .msg = &msg, .public_key = key_pair.public_key };
233 }
234
235 const start = benchTime(io);
236 {
237 var i: usize = 0;
238 while (i < signatures_count) : (i += 1) {
239 try Signature.verifyBatch(io, batch.len, batch);
240 mem.doNotOptimizeAway(&sig);
241 }
242 }
243 const end = benchTime(io);
244
245 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
246 const throughput = batch.len * @as(u64, @intFromFloat(signatures_count / elapsed_s));
247
248 return throughput;
249}
250
251const kems = [_]Crypto{
252 Crypto{ .ty = crypto.kem.kyber_d00.Kyber512, .name = "kyber512d00" },
253 Crypto{ .ty = crypto.kem.kyber_d00.Kyber768, .name = "kyber768d00" },
254 Crypto{ .ty = crypto.kem.kyber_d00.Kyber1024, .name = "kyber1024d00" },
255};
256
257pub fn benchmarkKem(comptime Kem: anytype, comptime kems_count: comptime_int, io: std.Io) !u64 {
258 const key_pair = Kem.KeyPair.generate(io);
259
260 const start = benchTime(io);
261 {
262 var i: usize = 0;
263 while (i < kems_count) : (i += 1) {
264 const e = key_pair.public_key.encaps(io);
265 mem.doNotOptimizeAway(&e);
266 }
267 }
268 const end = benchTime(io);
269
270 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
271 const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
272
273 return throughput;
274}
275
276pub fn benchmarkKemDecaps(comptime Kem: anytype, comptime kems_count: comptime_int, io: std.Io) !u64 {
277 const key_pair = Kem.KeyPair.generate(io);
278
279 const e = key_pair.public_key.encaps(io);
280
281 const start = benchTime(io);
282 {
283 var i: usize = 0;
284 while (i < kems_count) : (i += 1) {
285 const ss2 = try key_pair.secret_key.decaps(&e.ciphertext);
286 mem.doNotOptimizeAway(&ss2);
287 }
288 }
289 const end = benchTime(io);
290
291 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
292 const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
293
294 return throughput;
295}
296
297pub fn benchmarkKemKeyGen(comptime Kem: anytype, comptime kems_count: comptime_int, io: std.Io) !u64 {
298 const start = benchTime(io);
299 {
300 var i: usize = 0;
301 while (i < kems_count) : (i += 1) {
302 const key_pair = Kem.KeyPair.generate(io);
303 mem.doNotOptimizeAway(&key_pair);
304 }
305 }
306 const end = benchTime(io);
307
308 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
309 const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
310
311 return throughput;
312}
313
314const aeads = [_]Crypto{
315 Crypto{ .ty = crypto.aead.ascon.AsconAead128, .name = "ascon-aead-128" },
316 Crypto{ .ty = crypto.aead.chacha_poly.ChaCha20Poly1305, .name = "chacha20Poly1305" },
317 Crypto{ .ty = crypto.aead.chacha_poly.XChaCha20Poly1305, .name = "xchacha20Poly1305" },
318 Crypto{ .ty = crypto.aead.chacha_poly.XChaCha8Poly1305, .name = "xchacha8Poly1305" },
319 Crypto{ .ty = crypto.aead.salsa_poly.XSalsa20Poly1305, .name = "xsalsa20Poly1305" },
320 Crypto{ .ty = crypto.aead.aegis.Aegis128X4, .name = "aegis-128x4" },
321 Crypto{ .ty = crypto.aead.aegis.Aegis128X2, .name = "aegis-128x2" },
322 Crypto{ .ty = crypto.aead.aegis.Aegis128L, .name = "aegis-128l" },
323 Crypto{ .ty = crypto.aead.aegis.Aegis256X4, .name = "aegis-256x4" },
324 Crypto{ .ty = crypto.aead.aegis.Aegis256X2, .name = "aegis-256x2" },
325 Crypto{ .ty = crypto.aead.aegis.Aegis256, .name = "aegis-256" },
326 Crypto{ .ty = crypto.aead.aes_gcm.Aes128Gcm, .name = "aes128-gcm" },
327 Crypto{ .ty = crypto.aead.aes_gcm.Aes256Gcm, .name = "aes256-gcm" },
328 Crypto{ .ty = crypto.aead.aes_ocb.Aes128Ocb, .name = "aes128-ocb" },
329 Crypto{ .ty = crypto.aead.aes_ocb.Aes256Ocb, .name = "aes256-ocb" },
330 Crypto{ .ty = crypto.aead.isap.IsapA128A, .name = "isapa128a" },
331};
332
333pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int, io: Io) !u64 {
334 var in: [512 * KiB]u8 = undefined;
335 random.bytes(in[0..]);
336
337 var tag: [Aead.tag_length]u8 = undefined;
338
339 var key: [Aead.key_length]u8 = undefined;
340 random.bytes(key[0..]);
341
342 var nonce: [Aead.nonce_length]u8 = undefined;
343 random.bytes(nonce[0..]);
344
345 var offset: usize = 0;
346 const start = benchTime(io);
347 while (offset < bytes) : (offset += in.len) {
348 Aead.encrypt(in[0..], tag[0..], in[0..], &[_]u8{}, nonce, key);
349 try Aead.decrypt(in[0..], in[0..], tag, &[_]u8{}, nonce, key);
350 }
351 mem.doNotOptimizeAway(&in);
352 const end = benchTime(io);
353
354 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
355 const throughput = @as(u64, @intFromFloat(2 * bytes / elapsed_s));
356
357 return throughput;
358}
359
360const aes = [_]Crypto{
361 Crypto{ .ty = crypto.core.aes.Aes128, .name = "aes128-single" },
362 Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-single" },
363};
364
365pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int, io: Io) !u64 {
366 var key: [Aes.key_bits / 8]u8 = undefined;
367 random.bytes(key[0..]);
368 const ctx = Aes.initEnc(key);
369
370 var in: [16]u8 = @splat(0);
371
372 const start = benchTime(io);
373 {
374 var i: usize = 0;
375 while (i < count) : (i += 1) {
376 ctx.encrypt(&in, &in);
377 }
378 }
379 mem.doNotOptimizeAway(&in);
380 const end = benchTime(io);
381
382 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
383 const throughput = @as(u64, @intFromFloat(count / elapsed_s));
384
385 return throughput;
386}
387
388const aes8 = [_]Crypto{
389 Crypto{ .ty = crypto.core.aes.Aes128, .name = "aes128-8" },
390 Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-8" },
391};
392
393pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int, io: Io) !u64 {
394 var key: [Aes.key_bits / 8]u8 = undefined;
395 random.bytes(key[0..]);
396 const ctx = Aes.initEnc(key);
397
398 var in: [8 * 16]u8 = @splat(0);
399
400 const start = benchTime(io);
401 {
402 var i: usize = 0;
403 while (i < count) : (i += 1) {
404 ctx.encryptWide(8, &in, &in);
405 }
406 }
407 mem.doNotOptimizeAway(&in);
408 const end = benchTime(io);
409
410 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
411 const throughput = @as(u64, @intFromFloat(8 * count / elapsed_s));
412
413 return throughput;
414}
415
416const CryptoPwhash = struct {
417 ty: type,
418 params: *const anyopaque,
419 name: []const u8,
420};
421const bcrypt_params = crypto.pwhash.bcrypt.Params{ .rounds_log = 8, .silently_truncate_password = true };
422const pwhashes = [_]CryptoPwhash{
423 .{
424 .ty = crypto.pwhash.bcrypt,
425 .params = &bcrypt_params,
426 .name = "bcrypt",
427 },
428 .{
429 .ty = crypto.pwhash.scrypt,
430 .params = &crypto.pwhash.scrypt.Params.interactive,
431 .name = "scrypt",
432 },
433 .{
434 .ty = crypto.pwhash.argon2,
435 .params = &crypto.pwhash.argon2.Params.interactive_2id,
436 .name = "argon2",
437 },
438};
439
440fn benchmarkPwhash(
441 allocator: mem.Allocator,
442 comptime ty: anytype,
443 comptime params: *const anyopaque,
444 comptime count: comptime_int,
445 io: std.Io,
446) !f64 {
447 const password = "testpasstestpass";
448 const opts = ty.HashOptions{
449 .allocator = allocator,
450 .params = @as(*const ty.Params, @ptrCast(@alignCast(params))).*,
451 .encoding = .phc,
452 };
453 var buf: [256]u8 = undefined;
454
455 const strHash = ty.strHash;
456 const strHashFnInfo = @typeInfo(@TypeOf(strHash)).@"fn";
457 const needs_io = strHashFnInfo.param_types.len == 4 and strHashFnInfo.param_types[3].? == std.Io;
458 const needs_salt = strHashFnInfo.param_types.len == 4 and strHashFnInfo.param_types[3].? != std.Io;
459 const salt: [16]u8 = @splat(0);
460
461 const start = benchTime(io);
462 {
463 var i: usize = 0;
464 while (i < count) : (i += 1) {
465 if (needs_io) {
466 _ = try strHash(password, opts, &buf, io);
467 } else if (needs_salt) {
468 _ = try strHash(password, opts, &buf, &salt);
469 } else {
470 _ = try strHash(password, opts, &buf);
471 }
472 mem.doNotOptimizeAway(&buf);
473 }
474 }
475 const end = benchTime(io);
476
477 const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
478 const throughput = elapsed_s / count;
479
480 return throughput;
481}
482
483fn usage() void {
484 std.debug.print(
485 \\throughput_test [options]
486 \\
487 \\Options:
488 \\ --filter [test-name]
489 \\ --seed [int]
490 \\ --help
491 \\
492 , .{});
493}
494
495fn mode(comptime x: comptime_int) comptime_int {
496 return if (builtin.mode == .debug) x / 64 else x;
497}
498
499pub fn main(init: std.process.Init) !void {
500 const io = init.io;
501 const arena = init.arena.allocator();
502
503 // Size of buffer is about size of printed message.
504 var stdout_buffer: [0x100]u8 = undefined;
505 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
506 const stdout = &stdout_writer.interface;
507
508 const args = try init.minimal.args.toSlice(arena);
509
510 var filter: ?[]const u8 = null;
511
512 var i: usize = 1;
513 while (i < args.len) : (i += 1) {
514 if (std.mem.eql(u8, args[i], "--mode")) {
515 try stdout.print("{}\n", .{builtin.mode});
516 try stdout.flush();
517 return;
518 } else if (std.mem.eql(u8, args[i], "--seed")) {
519 i += 1;
520 if (i == args.len) {
521 usage();
522 std.process.exit(1);
523 }
524
525 const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
526 prng.seed(seed);
527 } else if (std.mem.eql(u8, args[i], "--filter")) {
528 i += 1;
529 if (i == args.len) {
530 usage();
531 std.process.exit(1);
532 }
533
534 filter = args[i];
535 } else if (std.mem.eql(u8, args[i], "--help")) {
536 usage();
537 return;
538 } else {
539 usage();
540 std.process.exit(1);
541 }
542 }
543
544 inline for (hashes) |H| {
545 if (filter == null or std.mem.find(u8, H.name, filter.?) != null) {
546 const throughput = try benchmarkHash(H.ty, mode(128 * MiB), io);
547 try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
548 try stdout.flush();
549 }
550 }
551
552 inline for (parallel_hashes) |H| {
553 if (filter == null or std.mem.find(u8, H.name, filter.?) != null) {
554 const throughput = try benchmarkHashParallel(H.ty, mode(128 * MiB), arena, io);
555 try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
556 try stdout.flush();
557 }
558 }
559
560 inline for (macs) |M| {
561 if (filter == null or std.mem.find(u8, M.name, filter.?) != null) {
562 const throughput = try benchmarkMac(M.ty, mode(128 * MiB), io);
563 try stdout.print("{s:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) });
564 try stdout.flush();
565 }
566 }
567
568 inline for (exchanges) |E| {
569 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
570 const throughput = try benchmarkKeyExchange(E.ty, mode(1000), io);
571 try stdout.print("{s:>17}: {:10} exchanges/s\n", .{ E.name, throughput });
572 try stdout.flush();
573 }
574 }
575
576 inline for (signatures) |E| {
577 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
578 const throughput = try benchmarkSignature(E.ty, mode(1000), io);
579 try stdout.print("{s:>17}: {:10} signatures/s\n", .{ E.name, throughput });
580 try stdout.flush();
581 }
582 }
583
584 inline for (signature_verifications) |E| {
585 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
586 const throughput = try benchmarkSignatureVerification(E.ty, mode(1000), io);
587 try stdout.print("{s:>17}: {:10} verifications/s\n", .{ E.name, throughput });
588 try stdout.flush();
589 }
590 }
591
592 inline for (batch_signature_verifications) |E| {
593 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
594 const throughput = try benchmarkBatchSignatureVerification(E.ty, mode(1000), io);
595 try stdout.print("{s:>17}: {:10} verifications/s (batch)\n", .{ E.name, throughput });
596 try stdout.flush();
597 }
598 }
599
600 inline for (aeads) |E| {
601 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
602 const throughput = try benchmarkAead(E.ty, mode(128 * MiB), io);
603 try stdout.print("{s:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) });
604 try stdout.flush();
605 }
606 }
607
608 inline for (aes) |E| {
609 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
610 const throughput = try benchmarkAes(E.ty, mode(100000000), io);
611 try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
612 try stdout.flush();
613 }
614 }
615
616 inline for (aes8) |E| {
617 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
618 const throughput = try benchmarkAes8(E.ty, mode(10000000), io);
619 try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
620 try stdout.flush();
621 }
622 }
623
624 inline for (pwhashes) |H| {
625 if (filter == null or std.mem.find(u8, H.name, filter.?) != null) {
626 const throughput = try benchmarkPwhash(arena, H.ty, H.params, mode(64), io);
627 try stdout.print("{s:>17}: {d:10.3} s/ops\n", .{ H.name, throughput });
628 try stdout.flush();
629 }
630 }
631
632 inline for (kems) |E| {
633 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
634 const throughput = try benchmarkKem(E.ty, mode(1000), io);
635 try stdout.print("{s:>17}: {:10} encaps/s\n", .{ E.name, throughput });
636 try stdout.flush();
637 }
638 }
639
640 inline for (kems) |E| {
641 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
642 const throughput = try benchmarkKemDecaps(E.ty, mode(25000), io);
643 try stdout.print("{s:>17}: {:10} decaps/s\n", .{ E.name, throughput });
644 try stdout.flush();
645 }
646 }
647
648 inline for (kems) |E| {
649 if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
650 const throughput = try benchmarkKemKeyGen(E.ty, mode(25000), io);
651 try stdout.print("{s:>17}: {:10} keygen/s\n", .{ E.name, throughput });
652 try stdout.flush();
653 }
654 }
655}