use criterion::{
black_box, criterion_group, criterion_main, BenchmarkId, Criterion,
Throughput,
};
use kyberlib::{
decapsulate, encapsulate, keypair, KemCore, MlKem768,
KYBER_CIPHERTEXT_BYTES,
};
use rand::thread_rng;
fn bench_keypair(c: &mut Criterion) {
let mut rng = thread_rng();
c.bench_function("legacy/keypair", |b| {
b.iter(|| {
let keys = keypair(black_box(&mut rng)).expect("keygen");
black_box(keys);
})
});
}
fn bench_encapsulate(c: &mut Criterion) {
let mut rng = thread_rng();
let keys = keypair(&mut rng).expect("setup keygen");
c.bench_function("legacy/encapsulate", |b| {
b.iter(|| {
let (ct, ss) = encapsulate(
black_box(&keys.public),
black_box(&mut rng),
)
.expect("encap");
black_box(ct);
black_box(ss);
})
});
}
fn bench_decapsulate_valid(c: &mut Criterion) {
let mut rng = thread_rng();
let keys = keypair(&mut rng).expect("setup keygen");
let (ct, _ss) =
encapsulate(&keys.public, &mut rng).expect("setup encap");
c.bench_function("legacy/decapsulate/valid", |b| {
b.iter(|| {
let ss =
decapsulate(black_box(&ct), black_box(&keys.secret))
.expect("decap");
black_box(ss);
})
});
}
fn bench_decapsulate_invalid(c: &mut Criterion) {
let mut rng = thread_rng();
let keys = keypair(&mut rng).expect("setup keygen");
let bogus_ct = [0xA5u8; KYBER_CIPHERTEXT_BYTES];
c.bench_function("legacy/decapsulate/invalid", |b| {
b.iter(|| {
let ss = decapsulate(
black_box(&bogus_ct),
black_box(&keys.secret),
)
.expect("implicit rejection always Ok");
black_box(ss);
})
});
}
fn bench_typed_generate(c: &mut Criterion) {
let mut rng = thread_rng();
c.bench_function("typed/MlKem768::generate", |b| {
b.iter(|| {
let (dk, ek) = MlKem768::generate(black_box(&mut rng))
.expect("keygen");
black_box(dk);
black_box(ek);
})
});
}
fn bench_typed_encapsulate(c: &mut Criterion) {
let mut rng = thread_rng();
let (_dk, ek) = MlKem768::generate(&mut rng).expect("setup keygen");
c.bench_function("typed/EncapKey::encapsulate", |b| {
b.iter(|| {
let (ct, ss) =
ek.encapsulate(black_box(&mut rng)).expect("encap");
black_box(ct);
black_box(ss);
})
});
}
fn bench_typed_decapsulate(c: &mut Criterion) {
let mut rng = thread_rng();
let (dk, ek) = MlKem768::generate(&mut rng).expect("setup keygen");
let (ct, _ss) = ek.encapsulate(&mut rng).expect("setup encap");
c.bench_function("typed/DecapKey::decapsulate", |b| {
b.iter(|| {
let ss = dk.decapsulate(black_box(&ct));
black_box(ss);
})
});
}
fn bench_full_handshake(c: &mut Criterion) {
let mut rng = thread_rng();
let mut group = c.benchmark_group("handshake/MlKem768");
group.throughput(Throughput::Bytes(1184 + 1088));
group.bench_function(BenchmarkId::from_parameter("full"), |b| {
b.iter(|| {
let (dk, ek) = MlKem768::generate(black_box(&mut rng))
.expect("keygen");
let (ct, ss_a) =
ek.encapsulate(black_box(&mut rng)).expect("encap");
let ss_b = dk.decapsulate(&ct);
black_box((ss_a, ss_b));
})
});
group.finish();
}
criterion_group!(
benches,
bench_keypair,
bench_encapsulate,
bench_decapsulate_valid,
bench_decapsulate_invalid,
bench_typed_generate,
bench_typed_encapsulate,
bench_typed_decapsulate,
bench_full_handshake,
);
criterion_main!(benches);