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