use std::hint::black_box;
use std::sync::OnceLock;
use std::time::Instant;
use cryptography::public_key::ec_edwards::ed25519 as ed25519_curve;
use cryptography::vt::{
p256, BigUint, Cocks, Dsa, EcElGamal, Ecdh, Ecdsa, Ecies, Ed25519, EdwardsDh, EdwardsElGamal,
ElGamal, MlDsa, MlDsaParameterSet, MlKem, MlKemParameterSet, Paillier, Rabin, Rsa, RsaOaep,
RsaPss, SchmidtSamoa, X25519, X448,
};
use cryptography::{Csprng, CtrDrbgAes256, Sha256};
const MSG: [u8; 32] = [0x42; 32];
const EC_MSG: [u8; 16] = [0x24; 16];
const OAEP_LABEL: &[u8] = b"pilot-pk-oaep";
const OAEP_SEED: [u8; 32] = [0x11; 32];
const PSS_SALT: [u8; 32] = [0x22; 32];
fn ms_per_op(elapsed: std::time::Duration, n: usize) -> f64 {
elapsed.as_secs_f64() * 1000.0 / n as f64
}
fn pk_iters(base: usize) -> usize {
static SCALE_PERCENT: OnceLock<usize> = OnceLock::new();
let scale = *SCALE_PERCENT.get_or_init(|| {
std::env::var("PILOT_PK_ITERS_PERCENT")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.map(|v| v.clamp(1, 100))
.unwrap_or(25)
});
base.saturating_mul(scale).div_ceil(100).max(1)
}
const OPERATIONS: &[&str] = &[
"ecdsa_keygen",
"ecdsa_sign",
"ecdsa_verify",
"ecdh_keygen",
"ecdh_agree",
"ecdh_serialize",
"ecies_keygen",
"ecies_encrypt",
"ecies_decrypt",
"ec_elgamal_keygen",
"ec_elgamal_encrypt",
"ec_elgamal_decrypt",
"ed25519_keygen",
"ed25519_sign",
"ed25519_verify",
"edwards_dh_keygen",
"edwards_dh_agree",
"edwards_dh_serialize",
"edwards_elgamal_keygen",
"edwards_elgamal_encrypt",
"edwards_elgamal_decrypt",
"dsa_keygen_1024",
"dsa_sign_1024",
"dsa_verify_1024",
"elgamal_keygen_1024",
"elgamal_encrypt_1024",
"elgamal_decrypt_1024",
"paillier_keygen_1024",
"paillier_encrypt_1024",
"paillier_decrypt_1024",
"paillier_rerandomize_1024",
"paillier_add_1024",
"cocks_keygen_1024",
"cocks_encrypt_1024",
"cocks_decrypt_1024",
"rabin_keygen_1024",
"rabin_encrypt_1024",
"rabin_decrypt_1024",
"schmidt_samoa_keygen_1024",
"schmidt_samoa_encrypt_1024",
"schmidt_samoa_decrypt_1024",
"rsa_keygen_1024",
"rsa_encrypt_1024",
"rsa_decrypt_1024",
"rsa_sign_1024",
"rsa_verify_1024",
"rsa_keygen_2048",
"rsa_encrypt_2048",
"rsa_decrypt_2048",
"rsa_sign_2048",
"rsa_verify_2048",
"mlkem512_keygen",
"mlkem512_encaps",
"mlkem512_decaps",
"mlkem768_keygen",
"mlkem768_encaps",
"mlkem768_decaps",
"mlkem1024_keygen",
"mlkem1024_encaps",
"mlkem1024_decaps",
"mldsa44_keygen",
"mldsa44_sign",
"mldsa44_verify",
"mldsa65_keygen",
"mldsa65_sign",
"mldsa65_verify",
"mldsa87_keygen",
"mldsa87_sign",
"mldsa87_verify",
"x25519_keygen",
"x25519_agree",
"x25519_scalar_mult_base",
"x25519_scalar_mult",
"x448_keygen",
"x448_agree",
"x448_scalar_mult_base",
"x448_scalar_mult",
];
fn print_help() {
println!(
"pilot_pk — single-operation latency benchmark for public-key schemes.\n\n\
Usage: pilot_pk <operation>\n\
pilot_pk --help | -h\n\
pilot_pk --list\n\n\
Runs the named operation in a tight loop and prints the mean wall\n\
time per operation in milliseconds to stdout. Iteration counts auto\n\
scale, with `PILOT_PK_SCALE` (default 100) as a percentage knob:\n\
set it to 50 to halve the iterations or 200 to double them.\n\n\
Run with `--list` to see the supported operation names."
);
}
fn print_list() {
for op in OPERATIONS {
println!("{op}");
}
}
fn main() {
let op = std::env::args().nth(1).unwrap_or_else(|| {
eprintln!("usage: pilot_pk <operation> (try `--help`)");
std::process::exit(1);
});
match op.as_str() {
"-h" | "--help" => {
print_help();
return;
}
"--list" => {
print_list();
return;
}
_ => {}
}
let mut rng = CtrDrbgAes256::new(&[0x5a; 48]);
let ms: f64 = match op.to_ascii_lowercase().as_str() {
"ecdsa_keygen" => {
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(Ecdsa::generate(p256(), &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"ecdsa_sign" => {
let (_, priv_key) = Ecdsa::generate(p256(), &mut rng);
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.sign_message_bytes::<Sha256>(&MSG).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"ecdsa_verify" => {
let (pub_key, priv_key) = Ecdsa::generate(p256(), &mut rng);
let sig = priv_key.sign_message_bytes::<Sha256>(&MSG).unwrap();
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.verify_message_bytes::<Sha256>(&MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"ecdh_keygen" => {
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(Ecdh::generate(p256(), &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"ecdh_agree" => {
let (pub_a, _) = Ecdh::generate(p256(), &mut rng);
let (_, priv_b) = Ecdh::generate(p256(), &mut rng);
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_b.agree_x_coordinate(&pub_a).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"ecdh_serialize" => {
let (pub_key, _) = Ecdh::generate(p256(), &mut rng);
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.to_wire_bytes());
}
ms_per_op(t0.elapsed(), n)
}
"ecies_keygen" => {
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(Ecies::generate(p256(), &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"ecies_encrypt" => {
let (pub_key, _) = Ecies::generate(p256(), &mut rng);
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt(&MSG, &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"ecies_decrypt" => {
let (pub_key, priv_key) = Ecies::generate(p256(), &mut rng);
let ct = pub_key.encrypt(&MSG, &mut rng);
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt(&ct).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"ec_elgamal_keygen" => {
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(EcElGamal::generate(p256(), &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"ec_elgamal_encrypt" => {
let (pub_key, _) = EcElGamal::generate(p256(), &mut rng);
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt(&EC_MSG, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"ec_elgamal_decrypt" => {
let (pub_key, priv_key) = EcElGamal::generate(p256(), &mut rng);
let ct = pub_key.encrypt(&EC_MSG, &mut rng).unwrap();
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt(&ct));
}
ms_per_op(t0.elapsed(), n)
}
"ed25519_keygen" => {
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(Ed25519::generate(&mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"ed25519_sign" => {
let (_, priv_key) = Ed25519::generate(&mut rng);
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.sign_message_bytes(&MSG));
}
ms_per_op(t0.elapsed(), n)
}
"ed25519_verify" => {
let (pub_key, priv_key) = Ed25519::generate(&mut rng);
let sig = priv_key.sign_message_bytes(&MSG);
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.verify_message_bytes(&MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"edwards_dh_agree" => {
let (pub_a, _) = EdwardsDh::generate(ed25519_curve(), &mut rng);
let (_, priv_b) = EdwardsDh::generate(ed25519_curve(), &mut rng);
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_b.agree_compressed_point(&pub_a).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"edwards_dh_keygen" => {
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(EdwardsDh::generate(ed25519_curve(), &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"edwards_dh_serialize" => {
let (pub_key, _) = EdwardsDh::generate(ed25519_curve(), &mut rng);
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.to_wire_bytes());
}
ms_per_op(t0.elapsed(), n)
}
"edwards_elgamal_keygen" => {
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(EdwardsElGamal::generate(ed25519_curve(), &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"edwards_elgamal_encrypt" => {
let (pub_key, _) = EdwardsElGamal::generate(ed25519_curve(), &mut rng);
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt_int(7, &mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"edwards_elgamal_decrypt" => {
let (pub_key, priv_key) = EdwardsElGamal::generate(ed25519_curve(), &mut rng);
let ct = pub_key.encrypt_int(7, &mut rng);
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt_int(&ct, 32).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"dsa_keygen_1024" => {
let n = pk_iters(10);
let t0 = Instant::now();
for _ in 0..n {
black_box(Dsa::generate(&mut rng, 1024).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"dsa_sign_1024" => {
let (_, priv_key) = Dsa::generate(&mut rng, 1024).unwrap();
let n = pk_iters(100);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.sign_message_bytes::<Sha256>(&MSG).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"dsa_verify_1024" => {
let (pub_key, priv_key) = Dsa::generate(&mut rng, 1024).unwrap();
let sig = priv_key.sign_message_bytes::<Sha256>(&MSG).unwrap();
let n = pk_iters(100);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.verify_message_bytes::<Sha256>(&MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"elgamal_keygen_1024" => {
let n = pk_iters(5);
let t0 = Instant::now();
for _ in 0..n {
black_box(ElGamal::generate(&mut rng, 1024).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"elgamal_encrypt_1024" => {
let (pub_key, _) = ElGamal::generate(&mut rng, 1024).unwrap();
let n = pk_iters(100);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt(&MSG, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"elgamal_decrypt_1024" => {
let (pub_key, priv_key) = ElGamal::generate(&mut rng, 1024).unwrap();
let ct = pub_key.encrypt(&MSG, &mut rng).unwrap();
let n = pk_iters(100);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt(&ct));
}
ms_per_op(t0.elapsed(), n)
}
"paillier_keygen_1024" => {
let n = pk_iters(20);
let t0 = Instant::now();
for _ in 0..n {
black_box(Paillier::generate(&mut rng, 1024).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"paillier_encrypt_1024" => {
let (pub_key, _) = Paillier::generate(&mut rng, 1024).unwrap();
let n = pk_iters(30);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt(&MSG, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"paillier_decrypt_1024" => {
let (pub_key, priv_key) = Paillier::generate(&mut rng, 1024).unwrap();
let ct = pub_key.encrypt(&MSG, &mut rng).unwrap();
let n = pk_iters(30);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt(&ct));
}
ms_per_op(t0.elapsed(), n)
}
"paillier_rerandomize_1024" => {
let (pub_key, _) = Paillier::generate(&mut rng, 1024).unwrap();
let ct = pub_key.encrypt(&MSG, &mut rng).unwrap();
let n = pk_iters(50);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.rerandomize(&ct, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"paillier_add_1024" => {
let (pub_key, priv_key) = Paillier::generate(&mut rng, 1024).unwrap();
let ct_a = pub_key.encrypt(&MSG, &mut rng).unwrap();
let ct_b = pub_key.encrypt(&[0x01], &mut rng).unwrap();
let n = pk_iters(2000);
let mut combined = pub_key.add_ciphertexts(&ct_a, &ct_b).unwrap();
let t0 = Instant::now();
for _ in 0..n {
combined = black_box(pub_key.add_ciphertexts(&ct_a, &ct_b).unwrap());
}
let combined_plaintext = priv_key.decrypt(&combined);
let expected = BigUint::from_be_bytes(&MSG).add_ref(&BigUint::from_u64(1));
assert_eq!(combined_plaintext, expected.to_be_bytes());
ms_per_op(t0.elapsed(), n)
}
"cocks_keygen_1024" => {
let n = pk_iters(20);
let t0 = Instant::now();
for _ in 0..n {
black_box(Cocks::generate(&mut rng, 1024).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"cocks_encrypt_1024" => {
let (pub_key, _) = Cocks::generate(&mut rng, 1024).unwrap();
let n = pk_iters(300);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt(&MSG).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"cocks_decrypt_1024" => {
let (pub_key, priv_key) = Cocks::generate(&mut rng, 1024).unwrap();
let ct = pub_key.encrypt(&MSG).unwrap();
let n = pk_iters(1500);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt(&ct));
}
ms_per_op(t0.elapsed(), n)
}
"rabin_keygen_1024" => {
let n = pk_iters(20);
let t0 = Instant::now();
for _ in 0..n {
black_box(Rabin::generate(&mut rng, 1024).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rabin_encrypt_1024" => {
let (pub_key, _) = Rabin::generate(&mut rng, 1024).unwrap();
let n = pk_iters(5000);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt(&MSG).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rabin_decrypt_1024" => {
let (pub_key, priv_key) = Rabin::generate(&mut rng, 1024).unwrap();
let ct = pub_key.encrypt(&MSG).unwrap();
let n = pk_iters(200);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt(&ct).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"schmidt_samoa_keygen_1024" => {
let n = pk_iters(20);
let t0 = Instant::now();
for _ in 0..n {
black_box(SchmidtSamoa::generate(&mut rng, 1024).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"schmidt_samoa_encrypt_1024" => {
let (pub_key, _) = SchmidtSamoa::generate(&mut rng, 1024).unwrap();
let n = pk_iters(300);
let t0 = Instant::now();
for _ in 0..n {
black_box(pub_key.encrypt(&MSG).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"schmidt_samoa_decrypt_1024" => {
let (pub_key, priv_key) = SchmidtSamoa::generate(&mut rng, 1024).unwrap();
let ct = pub_key.encrypt(&MSG).unwrap();
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_key.decrypt(&ct));
}
ms_per_op(t0.elapsed(), n)
}
"rsa_keygen_1024" => {
let n = pk_iters(10);
let t0 = Instant::now();
for _ in 0..n {
black_box(Rsa::generate(&mut rng, 1024).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rsa_encrypt_1024" => {
let (pub_key, _) = Rsa::generate(&mut rng, 1024).unwrap();
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(
RsaOaep::<Sha256>::encrypt(&pub_key, OAEP_LABEL, &MSG, &OAEP_SEED).unwrap(),
);
}
ms_per_op(t0.elapsed(), n)
}
"rsa_decrypt_1024" => {
let (pub_key, priv_key) = Rsa::generate(&mut rng, 1024).unwrap();
let ct = RsaOaep::<Sha256>::encrypt(&pub_key, OAEP_LABEL, &MSG, &OAEP_SEED).unwrap();
let n = pk_iters(100);
let t0 = Instant::now();
for _ in 0..n {
black_box(RsaOaep::<Sha256>::decrypt(&priv_key, OAEP_LABEL, &ct).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rsa_sign_1024" => {
let (_, priv_key) = Rsa::generate(&mut rng, 1024).unwrap();
let n = pk_iters(100);
let t0 = Instant::now();
for _ in 0..n {
black_box(RsaPss::<Sha256>::sign(&priv_key, &MSG, &PSS_SALT).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rsa_verify_1024" => {
let (pub_key, priv_key) = Rsa::generate(&mut rng, 1024).unwrap();
let sig = RsaPss::<Sha256>::sign(&priv_key, &MSG, &PSS_SALT).unwrap();
let n = pk_iters(1000);
let t0 = Instant::now();
for _ in 0..n {
black_box(RsaPss::<Sha256>::verify(&pub_key, &MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"rsa_keygen_2048" => {
let n = pk_iters(3);
let t0 = Instant::now();
for _ in 0..n {
black_box(Rsa::generate(&mut rng, 2048).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rsa_encrypt_2048" => {
let (pub_key, _) = Rsa::generate(&mut rng, 2048).unwrap();
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(
RsaOaep::<Sha256>::encrypt(&pub_key, OAEP_LABEL, &MSG, &OAEP_SEED).unwrap(),
);
}
ms_per_op(t0.elapsed(), n)
}
"rsa_decrypt_2048" => {
let (pub_key, priv_key) = Rsa::generate(&mut rng, 2048).unwrap();
let ct = RsaOaep::<Sha256>::encrypt(&pub_key, OAEP_LABEL, &MSG, &OAEP_SEED).unwrap();
let n = pk_iters(20);
let t0 = Instant::now();
for _ in 0..n {
black_box(RsaOaep::<Sha256>::decrypt(&priv_key, OAEP_LABEL, &ct).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rsa_sign_2048" => {
let (_, priv_key) = Rsa::generate(&mut rng, 2048).unwrap();
let n = pk_iters(20);
let t0 = Instant::now();
for _ in 0..n {
black_box(RsaPss::<Sha256>::sign(&priv_key, &MSG, &PSS_SALT).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"rsa_verify_2048" => {
let (pub_key, priv_key) = Rsa::generate(&mut rng, 2048).unwrap();
let sig = RsaPss::<Sha256>::sign(&priv_key, &MSG, &PSS_SALT).unwrap();
let n = pk_iters(200);
let t0 = Instant::now();
for _ in 0..n {
black_box(RsaPss::<Sha256>::verify(&pub_key, &MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"mlkem512_keygen" => {
let n = pk_iters(200);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::keygen(MlKemParameterSet::MlKem512, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem512_encaps" => {
let (pk, _) = MlKem::keygen(MlKemParameterSet::MlKem512, &mut rng).unwrap();
let n = pk_iters(200);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::encaps(&pk, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem512_decaps" => {
let (pk, sk) = MlKem::keygen(MlKemParameterSet::MlKem512, &mut rng).unwrap();
let (ct, _) = MlKem::encaps(&pk, &mut rng).unwrap();
let n = pk_iters(200);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::decaps(&sk, &ct).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem768_keygen" => {
let n = pk_iters(120);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::keygen(MlKemParameterSet::MlKem768, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem768_encaps" => {
let (pk, _) = MlKem::keygen(MlKemParameterSet::MlKem768, &mut rng).unwrap();
let n = pk_iters(120);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::encaps(&pk, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem768_decaps" => {
let (pk, sk) = MlKem::keygen(MlKemParameterSet::MlKem768, &mut rng).unwrap();
let (ct, _) = MlKem::encaps(&pk, &mut rng).unwrap();
let n = pk_iters(120);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::decaps(&sk, &ct).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem1024_keygen" => {
let n = pk_iters(80);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::keygen(MlKemParameterSet::MlKem1024, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem1024_encaps" => {
let (pk, _) = MlKem::keygen(MlKemParameterSet::MlKem1024, &mut rng).unwrap();
let n = pk_iters(80);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::encaps(&pk, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mlkem1024_decaps" => {
let (pk, sk) = MlKem::keygen(MlKemParameterSet::MlKem1024, &mut rng).unwrap();
let (ct, _) = MlKem::encaps(&pk, &mut rng).unwrap();
let n = pk_iters(80);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlKem::decaps(&sk, &ct).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mldsa44_keygen" => {
let n = pk_iters(120);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::keygen(MlDsaParameterSet::MlDsa44, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mldsa44_sign" => {
let (_, sk) = MlDsa::keygen(MlDsaParameterSet::MlDsa44, &mut rng).unwrap();
let n = pk_iters(120);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::sign(&sk, &MSG, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mldsa44_verify" => {
let (pk, sk) = MlDsa::keygen(MlDsaParameterSet::MlDsa44, &mut rng).unwrap();
let sig = MlDsa::sign(&sk, &MSG, &mut rng).unwrap();
let n = pk_iters(120);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::verify(&pk, &MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"mldsa65_keygen" => {
let n = pk_iters(80);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::keygen(MlDsaParameterSet::MlDsa65, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mldsa65_sign" => {
let (_, sk) = MlDsa::keygen(MlDsaParameterSet::MlDsa65, &mut rng).unwrap();
let n = pk_iters(80);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::sign(&sk, &MSG, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mldsa65_verify" => {
let (pk, sk) = MlDsa::keygen(MlDsaParameterSet::MlDsa65, &mut rng).unwrap();
let sig = MlDsa::sign(&sk, &MSG, &mut rng).unwrap();
let n = pk_iters(80);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::verify(&pk, &MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"mldsa87_keygen" => {
let n = pk_iters(60);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::keygen(MlDsaParameterSet::MlDsa87, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mldsa87_sign" => {
let (_, sk) = MlDsa::keygen(MlDsaParameterSet::MlDsa87, &mut rng).unwrap();
let n = pk_iters(60);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::sign(&sk, &MSG, &mut rng).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"mldsa87_verify" => {
let (pk, sk) = MlDsa::keygen(MlDsaParameterSet::MlDsa87, &mut rng).unwrap();
let sig = MlDsa::sign(&sk, &MSG, &mut rng).unwrap();
let n = pk_iters(60);
let t0 = Instant::now();
for _ in 0..n {
black_box(MlDsa::verify(&pk, &MSG, &sig));
}
ms_per_op(t0.elapsed(), n)
}
"x25519_keygen" => {
let n = pk_iters(2000);
let t0 = Instant::now();
for _ in 0..n {
black_box(X25519::generate(&mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"x25519_agree" => {
let (pub_a, _) = X25519::generate(&mut rng);
let (_, priv_b) = X25519::generate(&mut rng);
let n = pk_iters(2000);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_b.agree(&pub_a).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"x25519_scalar_mult_base" => {
let mut secret = [0u8; 32];
rng.fill_bytes(&mut secret);
let n = pk_iters(2000);
let t0 = Instant::now();
for _ in 0..n {
black_box(X25519::scalar_mult_base(&secret));
}
ms_per_op(t0.elapsed(), n)
}
"x25519_scalar_mult" => {
let mut secret = [0u8; 32];
rng.fill_bytes(&mut secret);
let mut u = [0u8; 32];
u[0] = 9;
let n = pk_iters(2000);
let t0 = Instant::now();
for _ in 0..n {
black_box(X25519::scalar_mult(&secret, &u));
}
ms_per_op(t0.elapsed(), n)
}
"x448_keygen" => {
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(X448::generate(&mut rng));
}
ms_per_op(t0.elapsed(), n)
}
"x448_agree" => {
let (pub_a, _) = X448::generate(&mut rng);
let (_, priv_b) = X448::generate(&mut rng);
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(priv_b.agree(&pub_a).unwrap());
}
ms_per_op(t0.elapsed(), n)
}
"x448_scalar_mult_base" => {
let mut secret = [0u8; 56];
rng.fill_bytes(&mut secret);
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(X448::scalar_mult_base(&secret));
}
ms_per_op(t0.elapsed(), n)
}
"x448_scalar_mult" => {
let mut secret = [0u8; 56];
rng.fill_bytes(&mut secret);
let mut u = [0u8; 56];
u[0] = 5;
let n = pk_iters(500);
let t0 = Instant::now();
for _ in 0..n {
black_box(X448::scalar_mult(&secret, &u));
}
ms_per_op(t0.elapsed(), n)
}
_ => {
eprintln!("unknown operation: {op}");
eprintln!("run with `--list` to see the supported operation names");
std::process::exit(1);
}
};
println!("{:.6}", ms);
}