use std::time::{
Duration,
Instant,
};
use digest::Digest;
#[cfg(not(tarpaulin))]
use lib_q_sha3::{
Sha3_224,
Sha3_384,
};
use lib_q_sha3::{
Sha3_256,
Sha3_512,
};
#[cfg(not(tarpaulin))]
const BASELINE_SHA3_256_NS: u64 = 220_000;
#[test]
#[cfg(not(tarpaulin))]
fn test_sha3_256_performance() {
let test_input = b"test input for performance analysis";
const ITERATIONS: usize = 10000;
for _ in 0..1000 {
let mut hasher = Sha3_256::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_256::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let total_time = start.elapsed();
let avg_time_ns = total_time.as_nanos() / ITERATIONS as u128;
assert!(
avg_time_ns < BASELINE_SHA3_256_NS as u128,
"SHA3-256 too slow: {} ns per operation (baseline: {} ns)",
avg_time_ns,
BASELINE_SHA3_256_NS
);
}
#[test]
#[cfg(not(tarpaulin))]
fn test_sha3_224_performance() {
let test_input = b"test input for SHA3-224 performance analysis";
const ITERATIONS: usize = 10000;
for _ in 0..1000 {
let mut hasher = Sha3_224::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_224::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let total_time = start.elapsed();
let avg_time_ns = total_time.as_nanos() / ITERATIONS as u128;
assert!(
avg_time_ns < BASELINE_SHA3_256_NS as u128,
"SHA3-224 too slow: {} ns per operation (baseline: {} ns)",
avg_time_ns,
BASELINE_SHA3_256_NS
);
}
#[test]
#[cfg(not(tarpaulin))]
fn test_sha3_384_performance() {
let test_input = b"test input for SHA3-384 performance analysis";
const ITERATIONS: usize = 10000;
for _ in 0..1000 {
let mut hasher = Sha3_384::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_384::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let total_time = start.elapsed();
let avg_time_ns = total_time.as_nanos() / ITERATIONS as u128;
assert!(
avg_time_ns < (BASELINE_SHA3_256_NS * 2) as u128,
"SHA3-384 too slow: {} ns per operation (baseline: {} ns)",
avg_time_ns,
BASELINE_SHA3_256_NS * 2
);
}
#[test]
#[cfg(not(tarpaulin))]
fn test_sha3_512_performance() {
let test_input = b"test input for SHA3-512 performance analysis";
const ITERATIONS: usize = 10000;
for _ in 0..1000 {
let mut hasher = Sha3_512::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_512::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let total_time = start.elapsed();
let avg_time_ns = total_time.as_nanos() / ITERATIONS as u128;
assert!(
avg_time_ns < (BASELINE_SHA3_256_NS * 3) as u128,
"SHA3-512 too slow: {} ns per operation (baseline: {} ns)",
avg_time_ns,
BASELINE_SHA3_256_NS * 3
);
}
#[test]
fn test_performance_scaling() {
const ITERATIONS: usize = 1000;
let small_input = b"small input";
let medium_input = &[0x42u8; 1000];
let large_input = &[0x42u8; 10000];
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_256::new();
hasher.update(small_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let small_time = start.elapsed();
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_256::new();
hasher.update(medium_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let medium_time = start.elapsed();
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_256::new();
hasher.update(large_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let large_time = start.elapsed();
let small_to_medium_ratio = medium_time.as_nanos() as f64 / small_time.as_nanos() as f64;
let medium_to_large_ratio = large_time.as_nanos() as f64 / medium_time.as_nanos() as f64;
assert!(
small_to_medium_ratio > 1.5,
"Medium input should be slower than small input, got ratio: {}",
small_to_medium_ratio
);
assert!(
medium_to_large_ratio > 1.5,
"Large input should be slower than medium input, got ratio: {}",
medium_to_large_ratio
);
}
#[test]
fn test_performance_consistency() {
let test_input = b"test input for performance consistency";
const ITERATIONS: usize = 10_000;
const RUNS: usize = 12;
const WARMUP: usize = 2000;
const TRIM_EACH_SIDE: usize = 2;
let measure_cv = || -> (f64, Vec<u128>) {
for _ in 0..WARMUP {
let mut hasher = Sha3_256::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
let mut run_times = Vec::with_capacity(RUNS);
for _run in 0..RUNS {
let start = Instant::now();
for _ in 0..ITERATIONS {
let mut hasher = Sha3_256::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
}
run_times.push(start.elapsed());
}
run_times.sort();
let trimmed = &run_times[TRIM_EACH_SIDE..run_times.len() - TRIM_EACH_SIDE];
let avg_time = trimmed.iter().copied().sum::<Duration>() / trimmed.len() as u32;
let variance = trimmed
.iter()
.map(|&t| {
let diff = t.abs_diff(avg_time);
diff.as_nanos() as f64 * diff.as_nanos() as f64
})
.sum::<f64>() /
trimmed.len() as f64;
let std_dev = variance.sqrt();
let cv = std_dev / avg_time.as_nanos() as f64;
let run_times_ns = run_times.iter().map(Duration::as_nanos).collect::<Vec<_>>();
(cv, run_times_ns)
};
let (first_cv, first_times_ns) = measure_cv();
eprintln!(
"consistency check attempt 1: cv={:.6}, run_times_ns={:?}",
first_cv, first_times_ns
);
let (second_cv, second_times_ns) = measure_cv();
eprintln!(
"consistency check attempt 2: cv={:.6}, run_times_ns={:?}",
second_cv, second_times_ns
);
let best_cv = first_cv.min(second_cv);
const MAX_CV: f64 = 0.35;
assert!(
best_cv < MAX_CV,
"Performance too inconsistent: best coefficient of variation {} (expected < {}), attempt1={}, attempt2={}",
best_cv,
MAX_CV,
first_cv,
second_cv
);
}
#[test]
fn test_algorithm_performance_relationships() {
let test_input = b"test input for algorithm performance relationships";
const ITERATIONS: usize = 10_000;
const WARMUP: usize = 500;
for _ in 0..WARMUP {
let mut h = Sha3_256::new();
h.update(test_input);
std::hint::black_box(h.finalize());
let mut h = Sha3_512::new();
h.update(test_input);
std::hint::black_box(h.finalize());
}
let mut sha3_256_time = Duration::ZERO;
let mut sha3_512_time = Duration::ZERO;
for _ in 0..ITERATIONS {
let start = Instant::now();
let mut hasher = Sha3_256::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
sha3_256_time += start.elapsed();
let start = Instant::now();
let mut hasher = Sha3_512::new();
hasher.update(test_input);
let _result = hasher.finalize();
std::hint::black_box(_result);
sha3_512_time += start.elapsed();
}
const MAX_RATIO_512_TO_256: f64 = 5.0;
let ratio_512_to_256 = sha3_512_time.as_nanos() as f64 / sha3_256_time.as_nanos() as f64;
assert!(
ratio_512_to_256 > 0.5 && ratio_512_to_256 < MAX_RATIO_512_TO_256,
"SHA3-512 vs SHA3-256 time ratio out of range (expected < {}), got: {}",
MAX_RATIO_512_TO_256,
ratio_512_to_256
);
}