mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
ML-DSA is a post-quantum signature scheme that was recently standardized by NIST. Keys and signatures are pretty large, not making it a drop-in replacement for classical signature schemes. But if you are shipping keys that may still be used in 10 years or whenever large quantum computers able to break ECC arrive, it that ever happens, and you don't have the ability to replace these keys, ML-DSA is for you. Performance is great, verification is faster than Ed25519 / ECDSA. I tried manual vectorization, but it wasn't worth it, the compiler does at good job at auto-vectorization already.
655 lines
23 KiB
Zig
655 lines
23 KiB
Zig
// zig run -O ReleaseFast --zig-lib-dir ../.. benchmark.zig
|
|
|
|
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const mem = std.mem;
|
|
const time = std.time;
|
|
const Timer = time.Timer;
|
|
const crypto = std.crypto;
|
|
|
|
const KiB = 1024;
|
|
const MiB = 1024 * KiB;
|
|
|
|
var prng = std.Random.DefaultPrng.init(0);
|
|
const random = prng.random();
|
|
|
|
const Crypto = struct {
|
|
ty: type,
|
|
name: []const u8,
|
|
};
|
|
|
|
const hashes = [_]Crypto{
|
|
Crypto{ .ty = crypto.hash.ascon.AsconHash256, .name = "ascon-256" },
|
|
Crypto{ .ty = crypto.hash.Md5, .name = "md5" },
|
|
Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" },
|
|
Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" },
|
|
Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" },
|
|
Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" },
|
|
Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" },
|
|
Crypto{ .ty = crypto.hash.sha3.Shake128, .name = "shake-128" },
|
|
Crypto{ .ty = crypto.hash.sha3.Shake256, .name = "shake-256" },
|
|
Crypto{ .ty = crypto.hash.sha3.TurboShake128(null), .name = "turboshake-128" },
|
|
Crypto{ .ty = crypto.hash.sha3.TurboShake256(null), .name = "turboshake-256" },
|
|
Crypto{ .ty = crypto.hash.sha3.KT128, .name = "kt128" },
|
|
Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
|
|
Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },
|
|
Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" },
|
|
};
|
|
|
|
const parallel_hashes = [_]Crypto{
|
|
Crypto{ .ty = crypto.hash.Blake3, .name = "blake3-parallel" },
|
|
Crypto{ .ty = crypto.hash.sha3.KT128, .name = "kt128-parallel" },
|
|
};
|
|
|
|
const block_size: usize = 8 * 8192;
|
|
|
|
pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 {
|
|
const blocks_count = bytes / block_size;
|
|
var block: [block_size]u8 = undefined;
|
|
random.bytes(&block);
|
|
|
|
var h = Hash.init(.{});
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
for (0..blocks_count) |_| {
|
|
h.update(&block);
|
|
}
|
|
var final: [Hash.digest_length]u8 = undefined;
|
|
h.final(&final);
|
|
std.mem.doNotOptimizeAway(final);
|
|
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
pub fn benchmarkHashParallel(comptime Hash: anytype, comptime bytes: comptime_int, allocator: mem.Allocator, io: std.Io) !u64 {
|
|
const data: []u8 = try allocator.alloc(u8, bytes);
|
|
defer allocator.free(data);
|
|
random.bytes(data);
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
var final: [Hash.digest_length]u8 = undefined;
|
|
try Hash.hashParallel(data, &final, .{}, allocator, io);
|
|
std.mem.doNotOptimizeAway(final);
|
|
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const macs = [_]Crypto{
|
|
Crypto{ .ty = crypto.onetimeauth.Ghash, .name = "ghash" },
|
|
Crypto{ .ty = crypto.onetimeauth.Polyval, .name = "polyval" },
|
|
Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" },
|
|
Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" },
|
|
Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" },
|
|
Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha256, .name = "hmac-sha256" },
|
|
Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha512, .name = "hmac-sha512" },
|
|
Crypto{ .ty = crypto.auth.siphash.SipHash64(2, 4), .name = "siphash-2-4" },
|
|
Crypto{ .ty = crypto.auth.siphash.SipHash64(1, 3), .name = "siphash-1-3" },
|
|
Crypto{ .ty = crypto.auth.siphash.SipHash128(2, 4), .name = "siphash128-2-4" },
|
|
Crypto{ .ty = crypto.auth.siphash.SipHash128(1, 3), .name = "siphash128-1-3" },
|
|
Crypto{ .ty = crypto.auth.aegis.Aegis128X4Mac, .name = "aegis-128x4 mac" },
|
|
Crypto{ .ty = crypto.auth.aegis.Aegis256X4Mac, .name = "aegis-256x4 mac" },
|
|
Crypto{ .ty = crypto.auth.aegis.Aegis128X2Mac, .name = "aegis-128x2 mac" },
|
|
Crypto{ .ty = crypto.auth.aegis.Aegis256X2Mac, .name = "aegis-256x2 mac" },
|
|
Crypto{ .ty = crypto.auth.aegis.Aegis128LMac, .name = "aegis-128l mac" },
|
|
Crypto{ .ty = crypto.auth.aegis.Aegis256Mac, .name = "aegis-256 mac" },
|
|
Crypto{ .ty = crypto.auth.cmac.CmacAes128, .name = "aes-cmac" },
|
|
};
|
|
|
|
pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
|
|
var in: [512 * KiB]u8 = undefined;
|
|
random.bytes(in[0..]);
|
|
|
|
const key_length = if (Mac.key_length == 0) 32 else Mac.key_length;
|
|
var key: [key_length]u8 = undefined;
|
|
random.bytes(key[0..]);
|
|
|
|
var mac: [Mac.mac_length]u8 = undefined;
|
|
var offset: usize = 0;
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
while (offset < bytes) : (offset += in.len) {
|
|
Mac.create(mac[0..], in[0..], key[0..]);
|
|
mem.doNotOptimizeAway(&mac);
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }};
|
|
|
|
pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 {
|
|
std.debug.assert(DhKeyExchange.shared_length >= DhKeyExchange.secret_length);
|
|
|
|
var secret: [DhKeyExchange.shared_length]u8 = undefined;
|
|
random.bytes(secret[0..]);
|
|
|
|
var public: [DhKeyExchange.shared_length]u8 = undefined;
|
|
random.bytes(public[0..]);
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < exchange_count) : (i += 1) {
|
|
const out = try DhKeyExchange.scalarmult(secret, public);
|
|
secret[0..16].* = out[0..16].*;
|
|
public[0..16].* = out[16..32].*;
|
|
mem.doNotOptimizeAway(&out);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(exchange_count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const signatures = [_]Crypto{
|
|
Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" },
|
|
Crypto{ .ty = crypto.sign.ecdsa.EcdsaP256Sha256, .name = "ecdsa-p256" },
|
|
Crypto{ .ty = crypto.sign.ecdsa.EcdsaP384Sha384, .name = "ecdsa-p384" },
|
|
Crypto{ .ty = crypto.sign.ecdsa.EcdsaSecp256k1Sha256, .name = "ecdsa-secp256k1" },
|
|
Crypto{ .ty = crypto.sign.mldsa.MLDSA44, .name = "ml-dsa-44" },
|
|
Crypto{ .ty = crypto.sign.mldsa.MLDSA65, .name = "ml-dsa-65" },
|
|
Crypto{ .ty = crypto.sign.mldsa.MLDSA87, .name = "ml-dsa-87" },
|
|
};
|
|
|
|
pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
|
const msg = [_]u8{0} ** 64;
|
|
const key_pair = Signature.KeyPair.generate();
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < signatures_count) : (i += 1) {
|
|
const sig = try key_pair.sign(&msg, null);
|
|
mem.doNotOptimizeAway(&sig);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(signatures_count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const signature_verifications = [_]Crypto{
|
|
Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" },
|
|
Crypto{ .ty = crypto.sign.mldsa.MLDSA44, .name = "ml-dsa-44" },
|
|
Crypto{ .ty = crypto.sign.mldsa.MLDSA65, .name = "ml-dsa-65" },
|
|
Crypto{ .ty = crypto.sign.mldsa.MLDSA87, .name = "ml-dsa-87" },
|
|
};
|
|
|
|
pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
|
const msg = [_]u8{0} ** 64;
|
|
const key_pair = Signature.KeyPair.generate();
|
|
const sig = try key_pair.sign(&msg, null);
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < signatures_count) : (i += 1) {
|
|
try sig.verify(&msg, key_pair.public_key);
|
|
mem.doNotOptimizeAway(&sig);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(signatures_count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const batch_signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
|
|
|
|
pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
|
const msg = [_]u8{0} ** 64;
|
|
const key_pair = Signature.KeyPair.generate();
|
|
const sig = try key_pair.sign(&msg, null);
|
|
|
|
var batch: [64]Signature.BatchElement = undefined;
|
|
for (&batch) |*element| {
|
|
element.* = Signature.BatchElement{ .sig = sig, .msg = &msg, .public_key = key_pair.public_key };
|
|
}
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < signatures_count) : (i += 1) {
|
|
try Signature.verifyBatch(batch.len, batch);
|
|
mem.doNotOptimizeAway(&sig);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = batch.len * @as(u64, @intFromFloat(signatures_count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const kems = [_]Crypto{
|
|
Crypto{ .ty = crypto.kem.kyber_d00.Kyber512, .name = "kyber512d00" },
|
|
Crypto{ .ty = crypto.kem.kyber_d00.Kyber768, .name = "kyber768d00" },
|
|
Crypto{ .ty = crypto.kem.kyber_d00.Kyber1024, .name = "kyber1024d00" },
|
|
};
|
|
|
|
pub fn benchmarkKem(comptime Kem: anytype, comptime kems_count: comptime_int) !u64 {
|
|
const key_pair = Kem.KeyPair.generate();
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < kems_count) : (i += 1) {
|
|
const e = key_pair.public_key.encaps(null);
|
|
mem.doNotOptimizeAway(&e);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
pub fn benchmarkKemDecaps(comptime Kem: anytype, comptime kems_count: comptime_int) !u64 {
|
|
const key_pair = Kem.KeyPair.generate();
|
|
|
|
const e = key_pair.public_key.encaps(null);
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < kems_count) : (i += 1) {
|
|
const ss2 = try key_pair.secret_key.decaps(&e.ciphertext);
|
|
mem.doNotOptimizeAway(&ss2);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
pub fn benchmarkKemKeyGen(comptime Kem: anytype, comptime kems_count: comptime_int) !u64 {
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < kems_count) : (i += 1) {
|
|
const key_pair = Kem.KeyPair.generate();
|
|
mem.doNotOptimizeAway(&key_pair);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const aeads = [_]Crypto{
|
|
Crypto{ .ty = crypto.aead.ascon.AsconAead128, .name = "ascon-aead-128" },
|
|
Crypto{ .ty = crypto.aead.chacha_poly.ChaCha20Poly1305, .name = "chacha20Poly1305" },
|
|
Crypto{ .ty = crypto.aead.chacha_poly.XChaCha20Poly1305, .name = "xchacha20Poly1305" },
|
|
Crypto{ .ty = crypto.aead.chacha_poly.XChaCha8Poly1305, .name = "xchacha8Poly1305" },
|
|
Crypto{ .ty = crypto.aead.salsa_poly.XSalsa20Poly1305, .name = "xsalsa20Poly1305" },
|
|
Crypto{ .ty = crypto.aead.aegis.Aegis128X4, .name = "aegis-128x4" },
|
|
Crypto{ .ty = crypto.aead.aegis.Aegis128X2, .name = "aegis-128x2" },
|
|
Crypto{ .ty = crypto.aead.aegis.Aegis128L, .name = "aegis-128l" },
|
|
Crypto{ .ty = crypto.aead.aegis.Aegis256X4, .name = "aegis-256x4" },
|
|
Crypto{ .ty = crypto.aead.aegis.Aegis256X2, .name = "aegis-256x2" },
|
|
Crypto{ .ty = crypto.aead.aegis.Aegis256, .name = "aegis-256" },
|
|
Crypto{ .ty = crypto.aead.aes_gcm.Aes128Gcm, .name = "aes128-gcm" },
|
|
Crypto{ .ty = crypto.aead.aes_gcm.Aes256Gcm, .name = "aes256-gcm" },
|
|
Crypto{ .ty = crypto.aead.aes_ocb.Aes128Ocb, .name = "aes128-ocb" },
|
|
Crypto{ .ty = crypto.aead.aes_ocb.Aes256Ocb, .name = "aes256-ocb" },
|
|
Crypto{ .ty = crypto.aead.isap.IsapA128A, .name = "isapa128a" },
|
|
};
|
|
|
|
pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 {
|
|
var in: [512 * KiB]u8 = undefined;
|
|
random.bytes(in[0..]);
|
|
|
|
var tag: [Aead.tag_length]u8 = undefined;
|
|
|
|
var key: [Aead.key_length]u8 = undefined;
|
|
random.bytes(key[0..]);
|
|
|
|
var nonce: [Aead.nonce_length]u8 = undefined;
|
|
random.bytes(nonce[0..]);
|
|
|
|
var offset: usize = 0;
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
while (offset < bytes) : (offset += in.len) {
|
|
Aead.encrypt(in[0..], tag[0..], in[0..], &[_]u8{}, nonce, key);
|
|
try Aead.decrypt(in[0..], in[0..], tag, &[_]u8{}, nonce, key);
|
|
}
|
|
mem.doNotOptimizeAway(&in);
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(2 * bytes / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const aes = [_]Crypto{
|
|
Crypto{ .ty = crypto.core.aes.Aes128, .name = "aes128-single" },
|
|
Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-single" },
|
|
};
|
|
|
|
pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 {
|
|
var key: [Aes.key_bits / 8]u8 = undefined;
|
|
random.bytes(key[0..]);
|
|
const ctx = Aes.initEnc(key);
|
|
|
|
var in = [_]u8{0} ** 16;
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < count) : (i += 1) {
|
|
ctx.encrypt(&in, &in);
|
|
}
|
|
}
|
|
mem.doNotOptimizeAway(&in);
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const aes8 = [_]Crypto{
|
|
Crypto{ .ty = crypto.core.aes.Aes128, .name = "aes128-8" },
|
|
Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-8" },
|
|
};
|
|
|
|
pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {
|
|
var key: [Aes.key_bits / 8]u8 = undefined;
|
|
random.bytes(key[0..]);
|
|
const ctx = Aes.initEnc(key);
|
|
|
|
var in = [_]u8{0} ** (8 * 16);
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < count) : (i += 1) {
|
|
ctx.encryptWide(8, &in, &in);
|
|
}
|
|
}
|
|
mem.doNotOptimizeAway(&in);
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = @as(u64, @intFromFloat(8 * count / elapsed_s));
|
|
|
|
return throughput;
|
|
}
|
|
|
|
const CryptoPwhash = struct {
|
|
ty: type,
|
|
params: *const anyopaque,
|
|
name: []const u8,
|
|
};
|
|
const bcrypt_params = crypto.pwhash.bcrypt.Params{ .rounds_log = 8, .silently_truncate_password = true };
|
|
const pwhashes = [_]CryptoPwhash{
|
|
.{
|
|
.ty = crypto.pwhash.bcrypt,
|
|
.params = &bcrypt_params,
|
|
.name = "bcrypt",
|
|
},
|
|
.{
|
|
.ty = crypto.pwhash.scrypt,
|
|
.params = &crypto.pwhash.scrypt.Params.interactive,
|
|
.name = "scrypt",
|
|
},
|
|
.{
|
|
.ty = crypto.pwhash.argon2,
|
|
.params = &crypto.pwhash.argon2.Params.interactive_2id,
|
|
.name = "argon2",
|
|
},
|
|
};
|
|
|
|
fn benchmarkPwhash(
|
|
allocator: mem.Allocator,
|
|
comptime ty: anytype,
|
|
comptime params: *const anyopaque,
|
|
comptime count: comptime_int,
|
|
) !f64 {
|
|
const password = "testpass" ** 2;
|
|
const opts = ty.HashOptions{
|
|
.allocator = allocator,
|
|
.params = @as(*const ty.Params, @ptrCast(@alignCast(params))).*,
|
|
.encoding = .phc,
|
|
};
|
|
var buf: [256]u8 = undefined;
|
|
|
|
var timer = try Timer.start();
|
|
const start = timer.lap();
|
|
{
|
|
var i: usize = 0;
|
|
while (i < count) : (i += 1) {
|
|
_ = try ty.strHash(password, opts, &buf);
|
|
mem.doNotOptimizeAway(&buf);
|
|
}
|
|
}
|
|
const end = timer.read();
|
|
|
|
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
|
|
const throughput = elapsed_s / count;
|
|
|
|
return throughput;
|
|
}
|
|
|
|
fn usage() void {
|
|
std.debug.print(
|
|
\\throughput_test [options]
|
|
\\
|
|
\\Options:
|
|
\\ --filter [test-name]
|
|
\\ --seed [int]
|
|
\\ --help
|
|
\\
|
|
, .{});
|
|
}
|
|
|
|
fn mode(comptime x: comptime_int) comptime_int {
|
|
return if (builtin.mode == .Debug) x / 64 else x;
|
|
}
|
|
|
|
pub fn main() !void {
|
|
// Size of buffer is about size of printed message.
|
|
var stdout_buffer: [0x100]u8 = undefined;
|
|
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
|
const stdout = &stdout_writer.interface;
|
|
|
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
defer arena.deinit();
|
|
const arena_allocator = arena.allocator();
|
|
const args = try std.process.argsAlloc(arena_allocator);
|
|
|
|
var filter: ?[]u8 = "";
|
|
|
|
var i: usize = 1;
|
|
while (i < args.len) : (i += 1) {
|
|
if (std.mem.eql(u8, args[i], "--mode")) {
|
|
try stdout.print("{}\n", .{builtin.mode});
|
|
try stdout.flush();
|
|
return;
|
|
} else if (std.mem.eql(u8, args[i], "--seed")) {
|
|
i += 1;
|
|
if (i == args.len) {
|
|
usage();
|
|
std.process.exit(1);
|
|
}
|
|
|
|
const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
|
|
prng.seed(seed);
|
|
} else if (std.mem.eql(u8, args[i], "--filter")) {
|
|
i += 1;
|
|
if (i == args.len) {
|
|
usage();
|
|
std.process.exit(1);
|
|
}
|
|
|
|
filter = args[i];
|
|
} else if (std.mem.eql(u8, args[i], "--help")) {
|
|
usage();
|
|
return;
|
|
} else {
|
|
usage();
|
|
std.process.exit(1);
|
|
}
|
|
}
|
|
|
|
inline for (hashes) |H| {
|
|
if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
|
|
const throughput = try benchmarkHash(H.ty, mode(128 * MiB));
|
|
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
var io_threaded = std.Io.Threaded.init(arena_allocator);
|
|
defer io_threaded.deinit();
|
|
const io = io_threaded.io();
|
|
|
|
inline for (parallel_hashes) |H| {
|
|
if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
|
|
const throughput = try benchmarkHashParallel(H.ty, mode(128 * MiB), arena_allocator, io);
|
|
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (macs) |M| {
|
|
if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) {
|
|
const throughput = try benchmarkMac(M.ty, mode(128 * MiB));
|
|
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (exchanges) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkKeyExchange(E.ty, mode(1000));
|
|
try stdout.print("{s:>17}: {:10} exchanges/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (signatures) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkSignature(E.ty, mode(1000));
|
|
try stdout.print("{s:>17}: {:10} signatures/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (signature_verifications) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkSignatureVerification(E.ty, mode(1000));
|
|
try stdout.print("{s:>17}: {:10} verifications/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (batch_signature_verifications) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkBatchSignatureVerification(E.ty, mode(1000));
|
|
try stdout.print("{s:>17}: {:10} verifications/s (batch)\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (aeads) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkAead(E.ty, mode(128 * MiB));
|
|
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (aes) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkAes(E.ty, mode(100000000));
|
|
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (aes8) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkAes8(E.ty, mode(10000000));
|
|
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (pwhashes) |H| {
|
|
if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
|
|
const throughput = try benchmarkPwhash(arena_allocator, H.ty, H.params, mode(64));
|
|
try stdout.print("{s:>17}: {d:10.3} s/ops\n", .{ H.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (kems) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkKem(E.ty, mode(1000));
|
|
try stdout.print("{s:>17}: {:10} encaps/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (kems) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkKemDecaps(E.ty, mode(25000));
|
|
try stdout.print("{s:>17}: {:10} decaps/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
|
|
inline for (kems) |E| {
|
|
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
|
const throughput = try benchmarkKemKeyGen(E.ty, mode(25000));
|
|
try stdout.print("{s:>17}: {:10} keygen/s\n", .{ E.name, throughput });
|
|
try stdout.flush();
|
|
}
|
|
}
|
|
}
|