use hemera::{Hash, OUTPUT_BYTES};
pub trait HashBackend {
type Hash: AsRef<[u8]> + Clone + Eq + std::fmt::Debug;
fn chunk_hash(&self, data: &[u8], counter: u64, is_root: bool) -> Self::Hash;
fn parent_hash(
&self,
left: &Self::Hash,
right: &Self::Hash,
is_root: bool,
) -> Self::Hash;
fn hash_size(&self) -> usize;
fn zero_hash(&self) -> Self::Hash;
fn hash_from_bytes(&self, bytes: &[u8]) -> Self::Hash;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Poseidon2Backend;
impl HashBackend for Poseidon2Backend {
type Hash = Hash;
fn chunk_hash(&self, data: &[u8], counter: u64, is_root: bool) -> Hash {
hemera::tree::chunk_cv(data, counter, is_root)
}
fn parent_hash(&self, left: &Hash, right: &Hash, is_root: bool) -> Hash {
hemera::tree::parent_cv(left, right, is_root)
}
fn hash_size(&self) -> usize {
OUTPUT_BYTES
}
fn zero_hash(&self) -> Hash {
Hash::from_bytes([0u8; OUTPUT_BYTES])
}
fn hash_from_bytes(&self, bytes: &[u8]) -> Hash {
let mut arr = [0u8; OUTPUT_BYTES];
arr.copy_from_slice(&bytes[..OUTPUT_BYTES]);
Hash::from_bytes(arr)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn poseidon2_backend_basic() {
let backend = Poseidon2Backend;
let h1 = backend.chunk_hash(b"hello", 0, false);
let h2 = backend.chunk_hash(b"hello", 0, false);
assert_eq!(h1, h2);
let h3 = backend.chunk_hash(b"world", 0, false);
assert_ne!(h1, h3); }
#[test]
fn poseidon2_backend_counter() {
let backend = Poseidon2Backend;
let h0 = backend.chunk_hash(b"data", 0, false);
let h1 = backend.chunk_hash(b"data", 1, false);
assert_ne!(h0, h1); }
#[test]
fn poseidon2_backend_parent() {
let backend = Poseidon2Backend;
let left = backend.chunk_hash(b"left", 0, false);
let right = backend.chunk_hash(b"right", 1, false);
let parent = backend.parent_hash(&left, &right, false);
assert_ne!(parent, left);
assert_ne!(parent, right);
let parent_rev = backend.parent_hash(&right, &left, false);
assert_ne!(parent, parent_rev);
}
#[test]
fn poseidon2_backend_root_differs() {
let backend = Poseidon2Backend;
let left = backend.chunk_hash(b"left", 0, false);
let right = backend.chunk_hash(b"right", 1, false);
let non_root = backend.parent_hash(&left, &right, false);
let root = backend.parent_hash(&left, &right, true);
assert_ne!(non_root, root);
}
#[test]
fn hash_size() {
let backend = Poseidon2Backend;
assert_eq!(backend.hash_size(), OUTPUT_BYTES);
}
}