use keyhog_scanner::entropy_fast::{shannon_entropy_scalar, shannon_entropy_simd};
fn reference_entropy(data: &[u8]) -> f64 {
let mut counts = [0u64; 256];
for &b in data {
counts[b as usize] += 1;
}
if data.is_empty() {
return 0.0;
}
let len = data.len() as f64;
let mut e = 0.0;
for &c in &counts {
if c > 0 {
let p = c as f64 / len;
e -= p * p.log2();
}
}
e
}
#[test]
fn simd_matches_scalar_on_misaligned_slices() {
let mut backing = vec![0u8; 4096];
for (i, slot) in backing.iter_mut().enumerate() {
*slot = ((i * 131 + 7) % 250 + 1) as u8;
}
for offset in 0..8usize {
for len in 0..200usize {
if offset + len > backing.len() {
continue;
}
let slice = &backing[offset..offset + len];
let simd = shannon_entropy_simd(slice);
let scalar = shannon_entropy_scalar(slice);
let reference = reference_entropy(slice);
assert!(
(simd - scalar).abs() < 2e-2,
"SIMD/scalar entropy diverged at offset={offset} len={len}: \
simd={simd} scalar={scalar}"
);
assert!(
(simd - reference).abs() < 2e-2,
"SIMD entropy left the reference band at offset={offset} \
len={len}: simd={simd} reference={reference}"
);
}
}
}
#[test]
fn simd_known_entropy_value_misaligned() {
let mut backing = vec![0xAAu8; 1]; for i in 0..64u8 {
backing.push(b"ABCD"[(i % 4) as usize]);
}
let slice = &backing[1..]; let e = shannon_entropy_simd(slice);
assert!(
(e - 2.0).abs() < 2e-2,
"expected ~2.0 bits/byte for 4 equal symbols, got {e}"
);
}
#[test]
fn simd_null_bytes_match_scalar_semantics() {
let data = b"\0\0\0ABCDABCD\0EFGH1234\0";
let simd = shannon_entropy_simd(data);
let scalar = shannon_entropy_scalar(data);
assert!(
(simd - scalar).abs() < f64::EPSILON,
"SIMD/scalar null-byte entropy diverged: simd={simd} scalar={scalar}"
);
}