use serde::{Deserialize, Serialize};
use std::fmt;
use crate::{PrimitiveError, Result};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub struct Hash([u8; 32]);
impl Hash {
pub const SIZE: usize = 32;
pub const ZERO: Hash = Hash([0u8; 32]);
pub fn new(bytes: [u8; 32]) -> Self {
Hash(bytes)
}
pub fn from_slice(slice: &[u8]) -> Result<Self> {
if slice.len() != Self::SIZE {
return Err(PrimitiveError::InvalidLength {
expected: Self::SIZE,
got: slice.len(),
});
}
let mut bytes = [0u8; 32];
bytes.copy_from_slice(slice);
Ok(Hash(bytes))
}
pub fn from_hex(s: &str) -> Result<Self> {
let s = s.strip_prefix("0x").unwrap_or(s);
let bytes = hex::decode(s).map_err(|e| PrimitiveError::InvalidHex(e.to_string()))?;
Self::from_slice(&bytes)
}
pub fn hash(data: &[u8]) -> Self {
let result = blake3::hash(data);
Hash(*result.as_bytes())
}
pub fn hash_many(data: &[&[u8]]) -> Self {
let mut hasher = blake3::Hasher::new();
for d in data {
hasher.update(d);
}
let result = hasher.finalize();
Hash(*result.as_bytes())
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub fn to_hex(&self) -> String {
format!("0x{}", hex::encode(self.0))
}
pub fn is_zero(&self) -> bool {
self.0 == [0u8; 32]
}
pub fn merkle_root(hashes: &[Hash]) -> Hash {
if hashes.is_empty() {
return Hash::ZERO;
}
if hashes.len() == 1 {
return hashes[0];
}
let mut current_level: Vec<Hash> = hashes.to_vec();
while current_level.len() > 1 {
let mut next_level = Vec::new();
for chunk in current_level.chunks(2) {
let left = &chunk[0];
let right = chunk.get(1).unwrap_or(left);
let combined = Hash::hash_many(&[left.as_bytes(), right.as_bytes()]);
next_level.push(combined);
}
current_level = next_level;
}
current_level[0]
}
}
impl fmt::Debug for Hash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Hash({})", self.to_hex())
}
}
impl fmt::Display for Hash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl AsRef<[u8]> for Hash {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl From<[u8; 32]> for Hash {
fn from(bytes: [u8; 32]) -> Self {
Hash(bytes)
}
}
impl PartialOrd for Hash {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Hash {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_consistency() {
let data = b"hello world";
let h1 = Hash::hash(data);
let h2 = Hash::hash(data);
assert_eq!(h1, h2);
}
#[test]
fn test_hash_different_data() {
let h1 = Hash::hash(b"hello");
let h2 = Hash::hash(b"world");
assert_ne!(h1, h2);
}
#[test]
fn test_hex_roundtrip() {
let h = Hash::hash(b"test data");
let hex = h.to_hex();
let h2 = Hash::from_hex(&hex).unwrap();
assert_eq!(h, h2);
}
#[test]
fn test_merkle_root_empty() {
assert_eq!(Hash::merkle_root(&[]), Hash::ZERO);
}
#[test]
fn test_merkle_root_single() {
let h = Hash::hash(b"single");
assert_eq!(Hash::merkle_root(&[h]), h);
}
#[test]
fn test_merkle_root_multiple() {
let hashes: Vec<Hash> = (0..4).map(|i| Hash::hash(&[i])).collect();
let root = Hash::merkle_root(&hashes);
assert_ne!(root, Hash::ZERO);
let root2 = Hash::merkle_root(&hashes);
assert_eq!(root, root2);
}
}