use digest::typenum::U4;
use digest::{Digest, FixedOutput, HashMarker, Output, OutputSizeUser, Update};
#[derive(Default)]
pub struct OneAtATime {
state: u32,
}
impl OneAtATime {
pub fn digest_unchecked(data: &[u8]) -> u32 {
let hash = Self::digest(data);
u32::from_le_bytes(hash[..].try_into().unwrap())
}
}
impl HashMarker for OneAtATime {}
impl OutputSizeUser for OneAtATime {
type OutputSize = U4;
}
impl Update for OneAtATime {
fn update(&mut self, data: &[u8]) {
for &b in data {
self.state = self.state.wrapping_add(b as u32);
self.state = self.state.wrapping_add(self.state << 10);
self.state ^= self.state >> 6;
}
}
}
impl FixedOutput for OneAtATime {
fn finalize_into(mut self, out: &mut Output<Self>) {
self.state = self.state.wrapping_add(self.state << 3);
self.state ^= self.state >> 11;
self.state = self.state.wrapping_add(self.state << 15);
let hash = self.state.to_le_bytes();
out.copy_from_slice(&hash)
}
}
#[cfg(test)]
mod tests {
use super::*;
use digest::Digest;
#[test]
fn test_simple() {
let mut hasher = OneAtATime::new();
Digest::update(&mut hasher, b"kt1_lod_1_2_5_6_17");
let hash = hasher.finalize();
assert_eq!(u32::from_le_bytes(hash[..].try_into().unwrap()), 373823972);
}
#[test]
fn test_digest() {
let hash = OneAtATime::digest_unchecked(b"kt1_lod_1_2_5_6_17");
assert_eq!(hash, 373823972);
}
}