From ad1c6728521a2a89ee790cd12baaea73aa6041a2 Mon Sep 17 00:00:00 2001 From: Andreas Grois Date: Fri, 20 Jan 2023 00:16:57 +0100 Subject: Add benchmark for HMAC code. Also, simplify the function a bit. It's faster this way, even though there's an additional unconditional collect() call now. --- Cargo.toml | 4 +++ benches/hashrate_16_hmac.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++ src/passwordmaker/hmac.rs | 42 ++++---------------------- 3 files changed, 82 insertions(+), 37 deletions(-) create mode 100644 benches/hashrate_16_hmac.rs diff --git a/Cargo.toml b/Cargo.toml index 1f1d5c4..5d5ee1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,10 @@ harness = false name = "hashrate_16" harness = false +[[bench]] +name = "hashrate_16_hmac" +harness = false + [[bench]] name = "leet" harness = false diff --git a/benches/hashrate_16_hmac.rs b/benches/hashrate_16_hmac.rs new file mode 100644 index 0000000..9a8deb7 --- /dev/null +++ b/benches/hashrate_16_hmac.rs @@ -0,0 +1,73 @@ +mod mock_hashers; + +use std::time::Duration; + +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use passwordmaker_rs::HashAlgorithm; +use mock_hashers::Pwm; + +fn criterion_bench_16bytes_hmac_typical(c: &mut Criterion) { + let pwm = Pwm::new( + HashAlgorithm::HmacMd5, + passwordmaker_rs::UseLeetWhenGenerating::NotAtAll, + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()_-+={}|[]\\:\";'<>?,./", + "", + "", + 12, + "", + "" + ).unwrap(); + c.bench_function("16 bytes HMAC typical", |b| b.iter(|| { + pwm.generate( + black_box("This is a long string. With many, many characters. For no particular reason.".to_owned()), + black_box("And another relatively long string for no reason other than it being long.".to_owned()) + ) + })); +} + +fn criterion_bench_16bytes_hmac_full_divide(c: &mut Criterion) { + let pwm = Pwm::new( + HashAlgorithm::HmacMd5, + passwordmaker_rs::UseLeetWhenGenerating::NotAtAll, + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()_-+={}|[]\\:\";'<>?,./", + "", + "", + 20, + "", + "" + ).unwrap(); + c.bench_function("16 bytes HMAC full divide", |b| b.iter(|| { + pwm.generate( + black_box("This is a long string. With many, many characters. For no particular reason.".to_owned()), + black_box("And another relatively long string for no reason other than it being long.".to_owned()) + ) + })); +} + +fn criterion_bench_16bytes_hmac_worst_case(c: &mut Criterion) { + let pwm = Pwm::new( + HashAlgorithm::HmacMd5, + passwordmaker_rs::UseLeetWhenGenerating::NotAtAll, + "XY", + "", + "", + 128, + "", + "" + ).unwrap(); + c.bench_function("16 bytes HMAC worst case", |b| b.iter(|| { + pwm.generate( + black_box("This is a long string. With many, many characters. For no particular reason.".to_owned()), + black_box("And another relatively long string for no reason other than it being long.".to_owned()) + ) + })); +} + +criterion_group!(name = benches; + // This can be any expression that returns a `Criterion` object. + config = Criterion::default().significance_level(0.02).sample_size(500).measurement_time(Duration::from_secs(10)); + targets = criterion_bench_16bytes_hmac_typical, + criterion_bench_16bytes_hmac_full_divide, + criterion_bench_16bytes_hmac_worst_case, +); +criterion_main!(benches); diff --git a/src/passwordmaker/hmac.rs b/src/passwordmaker/hmac.rs index 4c9d6aa..62b77fd 100644 --- a/src/passwordmaker/hmac.rs +++ b/src/passwordmaker/hmac.rs @@ -3,15 +3,13 @@ use crate::Hasher; pub(super) fn hmac(key : K, data : M) -> T::Output where T : Hasher, T::Output : AsRef<[u8]>, - K : Iterator + Clone, + K : Iterator, M : Iterator, { - let key_len = key.clone().count(); - let key = if key_len > 64 { - KeyOrHash::from_hash(T::hash(&key.collect::>())) - } else { - KeyOrHash::from_key(key) - }; + let key = key.collect::>(); + let key_hash = if key.len() > 64 { Some(T::hash(&key)) } else { None }; + let key = key_hash.as_ref().map(T::Output::as_ref).map(<&[u8]>::into_iter).unwrap_or_else(|| (&key).into_iter()).copied(); + let key = key.chain(std::iter::repeat(0)); //if key[i] does not exist, use 0 instead. let mut inner_pad = [0u8;64]; @@ -25,34 +23,4 @@ pub(super) fn hmac(key : K, data : M) -> T::Output let hash = T::hash(&inner_pad.iter().copied().chain(data).collect::>()); T::hash(&outer_pad.iter().chain(hash.as_ref().iter()).copied().collect::>()) -} - -enum KeyOrHash, H: AsRef<[u8]>> { - Key(K), - Hash{ - hash : H, - idx : usize - } -} - -impl, H: AsRef<[u8]>> KeyOrHash{ - fn from_key(key : K) -> Self { - Self::Key(key) - } - fn from_hash(hash : H) -> Self { - Self::Hash { hash, idx: 0 } - } -} - -impl, H: AsRef<[u8]>> Iterator for KeyOrHash{ - type Item = u8; - fn next(&mut self) -> Option { - match self { - KeyOrHash::Key(k) => k.next(), - KeyOrHash::Hash { hash: owned, idx } => { - *idx += 1; - owned.as_ref().get(*idx-1).copied() - }, - } - } } \ No newline at end of file -- cgit v1.2.3