qssm_utils/
entropy_audit.rs1#![forbid(unsafe_code)]
4
5use thiserror::Error;
6
7use crate::entropy_density::verify_density;
8use crate::entropy_stats::{validate_entropy_distribution, EntropyStatsError};
9
10#[non_exhaustive]
12#[derive(Debug, Clone, PartialEq, Error)]
13pub enum EntropyAuditError {
14 #[error("hardware-style density screen failed (too short or pathological pattern)")]
15 DensityHeuristic,
16 #[error(transparent)]
17 Stats(#[from] EntropyStatsError),
18}
19
20pub fn validate_entropy_full(bytes: &[u8]) -> Result<(), EntropyAuditError> {
24 if !verify_density(bytes) {
25 return Err(EntropyAuditError::DensityHeuristic);
26 }
27 validate_entropy_distribution(bytes)?;
28 Ok(())
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34
35 #[test]
36 fn short_fails_density() {
37 assert!(matches!(
38 validate_entropy_full(&[1u8; 64]),
39 Err(EntropyAuditError::DensityHeuristic)
40 ));
41 }
42
43 #[test]
44 fn zeros_fail() {
45 let v = vec![0u8; 300];
46 assert!(validate_entropy_full(&v).is_err());
47 }
48
49 #[test]
50 fn uniform_random_passes_smoke() {
51 let v: Vec<u8> = (0u32..400)
52 .map(|i| (i.wrapping_mul(2_654_435_761) >> 8) as u8)
53 .collect();
54 assert!(validate_entropy_full(&v).is_ok());
55 }
56}