#[cfg(feature = "hash-blake3")]
use crate::chunk::ChunkHash;
#[derive(Debug, Clone)]
pub struct Blake3Hasher {
state: blake3::Hasher,
}
impl Blake3Hasher {
pub fn new() -> Self {
Self {
state: blake3::Hasher::new(),
}
}
#[allow(dead_code)]
pub fn new_keyed(key: &[u8; 32]) -> Self {
Self {
state: blake3::Hasher::new_keyed(key),
}
}
#[allow(dead_code)]
pub fn update(&mut self, data: &[u8]) {
self.state.update(data);
}
#[allow(dead_code)]
pub fn finalize(&self) -> ChunkHash {
ChunkHash::new(self.state.finalize().into())
}
#[allow(dead_code)]
pub fn reset(&mut self) {
self.state.reset();
}
pub fn hash(data: &[u8]) -> ChunkHash {
ChunkHash::new(blake3::hash(data).into())
}
}
impl Default for Blake3Hasher {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_determinism() {
let hash1 = Blake3Hasher::hash(b"hello world");
let hash2 = Blake3Hasher::hash(b"hello world");
assert_eq!(hash1, hash2, "Same input must produce same hash");
assert_eq!(hash1.as_bytes().len(), 32, "Hash must be 32 bytes");
}
#[test]
fn test_hash_uniqueness() {
let hash1 = Blake3Hasher::hash(b"hello world");
let hash2 = Blake3Hasher::hash(b"hello world!");
assert_ne!(
hash1, hash2,
"Different inputs must produce different hashes"
);
}
#[test]
fn test_incremental_hashing() {
let mut hasher = Blake3Hasher::new();
hasher.update(b"hello ");
hasher.update(b"world");
let incremental_hash = hasher.finalize();
let one_shot_hash = Blake3Hasher::hash(b"hello world");
assert_eq!(
incremental_hash, one_shot_hash,
"Incremental hashing must match one-shot hashing"
);
}
#[test]
fn test_hasher_reset() {
let mut hasher = Blake3Hasher::new();
hasher.update(b"first data");
hasher.reset();
hasher.update(b"second data");
let hash2 = hasher.finalize();
let expected = Blake3Hasher::hash(b"second data");
assert_eq!(hash2, expected, "Reset must clear previous state");
}
#[test]
fn test_hasher_multiple_updates() {
let mut hasher = Blake3Hasher::new();
hasher.update(b"a");
hasher.update(b"b");
hasher.update(b"c");
let hash1 = hasher.finalize();
let hash2 = Blake3Hasher::hash(b"abc");
assert_eq!(hash1, hash2, "Multiple updates must produce correct hash");
}
}