use anyhash::{Hasher, HasherWrite};
use crate::{
CHUNK_SIZE, HashChunkContext, HashInnerContext, WIDTH, William3Digest,
generic::{BabHasher as GenericHasher, BabInstantiation},
hash_chunk, hash_inner,
};
pub struct William3Hasher {
hasher: GenericHasher<WIDTH, CHUNK_SIZE, HashChunkContext, HashInnerContext>,
}
impl William3Hasher {
pub fn new() -> Self {
let bab_instantiation = BabInstantiation {
hash_chunk,
hash_inner,
hash_chunk_context: HashChunkContext::new(),
hash_inner_context: HashInnerContext::new(),
};
Self {
hasher: GenericHasher::new(bab_instantiation),
}
}
pub fn new_keyed(key: [u32; 8]) -> Self {
let bab_instantiation = BabInstantiation {
hash_chunk,
hash_inner,
hash_chunk_context: HashChunkContext::new_keyed(key),
hash_inner_context: HashInnerContext::new_keyed(key),
};
Self {
hasher: GenericHasher::new(bab_instantiation),
}
}
}
impl HasherWrite for William3Hasher {
fn write(&mut self, bytes: &[u8]) {
self.hasher.write(bytes)
}
}
impl Hasher<William3Digest> for William3Hasher {
fn finish(&self) -> William3Digest {
self.hasher.finish().into()
}
}
impl Default for William3Hasher {
fn default() -> Self {
Self::new()
}
}
#[test]
fn test_hasher() {
let data = [17u8; CHUNK_SIZE * 16];
for len in 0..data.len() {
let mut digest_batch = [0; WIDTH].into();
crate::batch_hash(&data[..len], &mut digest_batch);
let mut hasher = William3Hasher::new();
hasher.write(&data[..len]);
let digest_hasher = hasher.finish();
assert_eq!(digest_hasher, digest_batch);
}
}
#[cfg(all(feature = "william3", feature = "std"))]
#[test]
fn generate_test_data() {
let mut data = vec![];
data.push(vec![]);
data.push(vec![0]);
data.push(vec![1; 1024]);
data.push(vec![2; 1025]);
data.push(vec![3; 4097]);
for bytes in data {
let mut digest_batch = [0; WIDTH].into();
crate::batch_hash(&bytes[..], &mut digest_batch);
println!(
"input ({:?} repeated bytes):\n{:?}\n\ndigest:\n{:?}\n\n======\n\n",
bytes.len(),
&bytes[..],
digest_batch.as_bytes()
);
}
}