use std::hint::black_box;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use aes_gcm::aead::Aead;
use aes_gcm::{Aes256Gcm, KeyInit, Nonce};
use encryption::contract::SymmetricCipher;
use encryption::encryptor::{Aes256CbcEncryptor, Aes256GcmEncryptor, SodiumXChaCha20Encryptor};
const KEY: [u8; 32] = [0x11; 32];
const IV: [u8; 12] = [0x22; 12];
const SHORT_LEN: usize = 11;
const LONG_LEN: usize = 1024;
fn payload(length: usize) -> Vec<u8> {
(0..length).map(|i| (i % 251) as u8).collect()
}
fn bench_wrapper_vs_raw(c: &mut Criterion) {
let mut group = c.benchmark_group("wrapper-vs-raw/aes-256-gcm/11B");
let wrapper = Aes256GcmEncryptor::new(KEY);
let short = payload(SHORT_LEN);
let nonce = Nonce::from_slice(&IV);
group.bench_function("wrapper (fresh IV per call)", |b| {
b.iter(|| wrapper.encrypt(black_box(&short)).unwrap())
});
group.bench_function("raw aes-gcm (fixed nonce)", |b| {
b.iter(|| {
let cipher = Aes256Gcm::new_from_slice(&KEY).expect("32 字节密钥");
cipher
.encrypt(nonce, black_box(short.as_slice()))
.expect("11 字节明文")
})
});
let blob = wrapper.encrypt(&short).unwrap();
let raw_blob = Aes256Gcm::new_from_slice(&KEY)
.expect("32 字节密钥")
.encrypt(nonce, short.as_slice())
.expect("11 字节明文");
group.bench_function("wrapper decrypt", |b| {
b.iter(|| wrapper.decrypt(black_box(&blob)).unwrap())
});
group.bench_function("raw aes-gcm decrypt", |b| {
b.iter(|| {
let cipher = Aes256Gcm::new_from_slice(&KEY).expect("32 字节密钥");
cipher
.decrypt(nonce, black_box(raw_blob.as_slice()))
.expect("tag 正确")
})
});
group.finish();
}
fn bench_payload_length(c: &mut Criterion) {
let mut group = c.benchmark_group("short-payload/aes-256-gcm");
let wrapper = Aes256GcmEncryptor::new(KEY);
for length in [SHORT_LEN, 64, LONG_LEN] {
let plaintext = payload(length);
group.bench_with_input(
BenchmarkId::new("encrypt", format!("{length}B")),
&plaintext,
|b, plaintext| b.iter(|| wrapper.encrypt(black_box(plaintext.as_slice())).unwrap()),
);
}
group.finish();
let mut group = c.benchmark_group("short-payload/sodium-xchacha20");
let xchacha = SodiumXChaCha20Encryptor::new(KEY);
for length in [SHORT_LEN, LONG_LEN] {
let plaintext = payload(length);
group.bench_with_input(
BenchmarkId::new("encrypt", format!("{length}B")),
&plaintext,
|b, plaintext| b.iter(|| xchacha.encrypt(black_box(plaintext.as_slice())).unwrap()),
);
}
group.finish();
}
fn bench_etm(c: &mut Criterion) {
let mut group = c.benchmark_group("etm/aes-256-cbc-hmac/1KiB");
let cipher = Aes256CbcEncryptor::new(KEY);
let plaintext = payload(LONG_LEN);
let blob = cipher.encrypt(&plaintext).unwrap();
group.bench_function("encrypt", |b| {
b.iter(|| cipher.encrypt(black_box(plaintext.as_slice())).unwrap())
});
group.bench_function("decrypt", |b| {
b.iter(|| cipher.decrypt(black_box(blob.as_slice())).unwrap())
});
group.finish();
}
fn bench_hex(c: &mut Criterion) {
use encryption::asymmetric::x25519::X25519Agreement;
use encryption::contract::{Hasher, KeyAgreement};
use encryption::hash::Sha256Hasher;
let mut group = c.benchmark_group("hex");
let hasher = Sha256Hasher::new();
let data = payload(LONG_LEN);
group.bench_function("sha256/digest/1KiB", |b| {
b.iter(|| hasher.digest(black_box(data.as_slice())).unwrap())
});
group.bench_function(
"sha256/digest_hex/1KiB (=digest+hex_encode 64 chars)",
|b| b.iter(|| hasher.digest_hex(black_box(data.as_slice())).unwrap()),
);
let agreement = X25519Agreement::new();
let alice = X25519Agreement::generate_key_pair_hex().unwrap();
let bob = X25519Agreement::generate_key_pair_hex().unwrap();
group.bench_function("x25519/agree (2x hex_decode 32B + DH)", |b| {
b.iter(|| {
agreement
.agree(
black_box(&alice.private_key_hex),
black_box(&bob.public_key_hex),
)
.unwrap()
})
});
group.finish();
}
criterion_group!(
benches,
bench_wrapper_vs_raw,
bench_payload_length,
bench_etm,
bench_hex
);
criterion_main!(benches);