use crate::crypto::sha3_256;
use crate::error::{QVError, QVResult};
pub struct MutationChain {
state: [u8; 32],
counter: u64,
}
impl MutationChain {
pub fn new(seed: [u8; 32]) -> Self {
MutationChain { state: seed, counter: 0 }
}
pub fn from_state(state: [u8; 32], counter: u64) -> Self {
MutationChain { state, counter }
}
pub fn advance(&mut self) -> [u8; 32] {
let mut input = [0u8; 40];
input[..32].copy_from_slice(&self.state);
input[32..].copy_from_slice(&self.counter.to_be_bytes());
self.state = sha3_256(&input);
self.counter += 1;
self.state
}
pub fn current_counter(&self) -> u64 { self.counter }
pub fn current_state(&self) -> &[u8; 32] { &self.state }
pub fn check_token_counter(&self, token_ctr: u64) -> QVResult<()> {
if token_ctr <= self.counter {
Err(QVError::ReplayDetected { token: token_ctr, chain: self.counter })
} else {
Ok(())
}
}
}
pub fn certify_entropy(data: &[u8]) -> QVResult<()> {
if data.len() < 8 {
return Ok(()); }
let total = data.len() - 3;
let mut seen = std::collections::HashSet::new();
for i in 0..total {
let gram: [u8; 4] = data[i..i + 4].try_into().unwrap();
seen.insert(gram);
}
let ratio = seen.len() as f64 / total as f64;
if ratio < 0.85 {
Err(QVError::LowEntropy(ratio))
} else {
Ok(())
}
}