I’ve never really done much with benchmarking before, in an official fashion. This is mostly a thing I argue with everybody about hypothetically and run away from IRL (just yell that something is slow and run out of the room - nobody will think you’re anything other than a genius).
But anyway, the idea of any of my code being less than optimal for all of the information I have at any given time horrifies me and keeps me up at night; the bogeyman that is “stuff could be slow and you’re too stupid to systematically evaluate how” has made me …better?
Okay, so below is what the benchmark file looks like in code… https://problemchild.engineering.com/benchmarks/crypto/2023-08-13/report is where the generated html stats from my local benchmark tool are posted.
benches/lib.rs
use criterion::{criterion_group, criterion_main, Criterion};
use lazy_static::lazy_static;
lazy_static! {
static ref PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK: (
[u8; 32],
[u8; 32],
[u8; 32],
[u8; 32],
Vec<u8>,
Vec<u8>,
[u8; 64],
[u8; 24],
[u8; 32],
[u8; 32],
) = {
let (priv_exchange_key, pub_exchange_key) = crypto::generate_exchange_keys();
let (signing_key, verifying_key) = crypto::generate_signing_keys();
let content = vec![0u8; 1024];
let (nonce, key_sets, encrypted_content, sender_public_key, encrypted_content_signature) =
crypto::encrypt_and_sign_content(
signing_key,
content.clone(),
pub_exchange_key.to_vec(),
)
.unwrap();
let mut encrypted_content_key: [u8; 32] = [0u8; 32];
encrypted_content_key[0..32].copy_from_slice(&key_sets[32..64]);
(
priv_exchange_key,
pub_exchange_key,
signing_key,
verifying_key,
content,
encrypted_content,
encrypted_content_signature,
nonce,
encrypted_content_key,
sender_public_key,
)
};
}
fn hash_to_32_bytes_benchmark(c: &mut Criterion) {
c.bench_function("hash_to_32_bytes", |b| {
let val = "testing hash to 32 bytes".to_string();
b.iter(move || {
crypto::hash_to_32_bytes(val.clone());
})
});
}
fn hash_to_string_benchmark(c: &mut Criterion) {
c.bench_function("hash_to_string", |b| {
let val = "testing hash to string".to_string();
b.iter(move || {
crypto::hash_to_string(val.clone());
})
});
}
fn block_encrypt_key_benchmark(c: &mut Criterion) {
let (pub_key, priv_key, _, _, _, _, _, _, _, _) =
&*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("block_encrypt_key", |b| {
b.iter(|| {
crypto::block_encrypt_key(*pub_key, *priv_key);
})
});
}
fn block_decrypt_key_benchmark(c: &mut Criterion) {
let (pub_key, priv_key, _, _, _, _, _, _, _, _) =
&*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("block_decrypt_key", |b| {
b.iter(|| {
crypto::block_decrypt_key(*pub_key, *priv_key);
})
});
}
fn generate_signing_keys_benchmark(c: &mut Criterion) {
c.bench_function("generate_signing_keys", |b| {
b.iter(move || {
crypto::generate_signing_keys();
})
});
}
fn sign_content_benchmark(c: &mut Criterion) {
let (_, _, sign, _, _, enc, _, _, _, _) = &*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("sign_content", |b| {
b.iter(move || {
crypto::sign_content(enc.clone(), *sign);
})
});
}
fn get_32_byte_key_from_string_benchmark(c: &mut Criterion) {
let (_, _, sign, _, _, _, _, _, _, _) = &*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("get_32_byte_key_from_string", |b| {
let val = hex::encode(sign);
b.iter(move || {
crypto::get_32_byte_key_from_string(val.clone());
})
});
}
fn convert_32_byte_key_to_string_benchmark(c: &mut Criterion) {
let (_, _, sign, _, _, _, _, _, _, _) = &*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("convert_32_byte_key_to_string", |b| {
b.iter(move || {
crypto::convert_32_byte_key_to_string(*sign);
})
});
}
fn verify_signature_benchmark(c: &mut Criterion) {
let (_, _, _, ver, _, enc, sig, _, _, _) = &*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("verify_signature", |b| {
b.iter(move || {
crypto::verify_signature(*sig, *ver, enc.clone()).unwrap();
})
});
}
fn generate_exchange_keys_benchmark(c: &mut Criterion) {
c.bench_function("generate_exchange_keys", |b| {
b.iter(move || {
crypto::generate_exchange_keys();
})
});
}
fn encrypt_and_sign_content_benchmark(c: &mut Criterion) {
let (pub_key, _, sign, _, cont, _, _, _, _, _) = &*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("encrypt_and_sign_content", |b| {
b.iter(move || {
crypto::encrypt_and_sign_content(*sign, cont.clone(), pub_key.to_vec())
.unwrap();
})
});
}
fn decrypt_and_verify_benchmark(c: &mut Criterion) {
let (_, priv_key, _, _, _, enc, _, nonce, eck, spk) =
&*PUB_PRIV_SIGN_VER_CONT_ENC_SIG_NONCE_ECK_SPK;
c.bench_function("decrypt_and_verify", |b| {
b.iter(move || {
crypto::decrypt_and_verify(*spk, *priv_key, *eck, *nonce, enc.clone()).unwrap();
})
});
}
criterion_group!(
benches,
hash_to_32_bytes_benchmark,
hash_to_string_benchmark,
block_encrypt_key_benchmark,
block_decrypt_key_benchmark,
generate_signing_keys_benchmark,
sign_content_benchmark,
get_32_byte_key_from_string_benchmark,
convert_32_byte_key_to_string_benchmark,
verify_signature_benchmark,
generate_exchange_keys_benchmark,
encrypt_and_sign_content_benchmark,
decrypt_and_verify_benchmark,
);
criterion_main!(benches);
Conclusion
I think I still need to do some better integration testing, but this is actually a pretty exhaustive test of all the functionality in this crate, IN the benchmarks, and I’m kinda content with that level of confidence right now.
Also there were some bugs in the guts of a vew functions (ahem… block encryption was not something I understood well
when I wrote those out first), but that’s what theses tests benchmarks are for.
Will share more on crypto lib later if I test in file.
P.S for those of you who’re like “why the hell did you do that stupid thing with not using a struct and instead just using a giant tuple?” and the answer to your question is: at first I thought it was going to be fewer values, then it grew but I made a judgement call that was “is this becoming more or less readable? and how often will I have to write to this? (which is what I actually think this makes harder, and it’s mostly hard to remember how you worked with it last time because it was easier the first time your wrote it).”
Caveats
I was doing a bunch of shit on my computer while those benchmarks were running so they could be wildly inaccurate or look goofy AF, but this is just an example of what is neat and new that I haven’t explored with this curiosity before.