use alloy_primitives::B256;
use sha2::{Digest, Sha256};
pub trait Hasher: Clone + Default + Send + Sync {
fn hash_32(&self, value: &B256) -> B256;
fn hash_64(&self, left: &B256, right: &B256) -> B256;
fn hash_stem_node(&self, stem: &[u8; 31], subtree_root: &B256) -> B256 {
let mut input = [0u8; 64];
input[..31].copy_from_slice(stem);
input[31] = 0x00;
input[32..].copy_from_slice(subtree_root.as_slice());
self.hash_raw(&input)
}
fn hash_raw(&self, input: &[u8]) -> B256;
}
#[derive(Clone, Default)]
pub struct Sha256Hasher;
impl Hasher for Sha256Hasher {
fn hash_32(&self, value: &B256) -> B256 {
if value.is_zero() {
return B256::ZERO;
}
let hash = Sha256::digest(value.as_slice());
B256::from_slice(&hash)
}
fn hash_64(&self, left: &B256, right: &B256) -> B256 {
if left.is_zero() && right.is_zero() {
return B256::ZERO;
}
let mut hasher = Sha256::new();
hasher.update(left.as_slice());
hasher.update(right.as_slice());
B256::from_slice(&hasher.finalize())
}
fn hash_raw(&self, input: &[u8]) -> B256 {
if input.iter().all(|&b| b == 0) {
return B256::ZERO;
}
B256::from_slice(&Sha256::digest(input))
}
}
#[derive(Clone, Default)]
pub struct Blake3Hasher;
impl Hasher for Blake3Hasher {
fn hash_32(&self, value: &B256) -> B256 {
if value.is_zero() {
return B256::ZERO;
}
B256::from_slice(blake3::hash(value.as_slice()).as_bytes())
}
fn hash_64(&self, left: &B256, right: &B256) -> B256 {
if left.is_zero() && right.is_zero() {
return B256::ZERO;
}
let mut input = [0u8; 64];
input[..32].copy_from_slice(left.as_slice());
input[32..].copy_from_slice(right.as_slice());
B256::from_slice(blake3::hash(&input).as_bytes())
}
fn hash_raw(&self, input: &[u8]) -> B256 {
if input.iter().all(|&b| b == 0) {
return B256::ZERO;
}
B256::from_slice(blake3::hash(input).as_bytes())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zero_hash_special_case_sha256() {
let hasher = Sha256Hasher;
assert_eq!(hasher.hash_32(&B256::ZERO), B256::ZERO);
assert_eq!(hasher.hash_64(&B256::ZERO, &B256::ZERO), B256::ZERO);
}
#[test]
fn test_zero_hash_special_case_blake3() {
let hasher = Blake3Hasher;
assert_eq!(hasher.hash_32(&B256::ZERO), B256::ZERO);
assert_eq!(hasher.hash_64(&B256::ZERO, &B256::ZERO), B256::ZERO);
}
#[test]
fn test_non_zero_hash_sha256() {
let hasher = Sha256Hasher;
let value = B256::repeat_byte(0x42);
let hash = hasher.hash_32(&value);
assert_ne!(hash, B256::ZERO);
let hash2 = hasher.hash_64(&value, &B256::ZERO);
assert_ne!(hash2, B256::ZERO);
}
#[test]
fn test_non_zero_hash_blake3() {
let hasher = Blake3Hasher;
let value = B256::repeat_byte(0x42);
let hash = hasher.hash_32(&value);
assert_ne!(hash, B256::ZERO);
let hash2 = hasher.hash_64(&value, &B256::ZERO);
assert_ne!(hash2, B256::ZERO);
}
#[test]
fn test_sha256_deterministic() {
let hasher = Sha256Hasher;
let value = B256::repeat_byte(0x42);
let hash1 = hasher.hash_32(&value);
let hash2 = hasher.hash_32(&value);
assert_eq!(hash1, hash2);
}
}