sumchain_primitives/
hash.rs1use serde::{Deserialize, Serialize};
10use std::fmt;
11
12use crate::{PrimitiveError, Result};
13
14#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
16pub struct Hash([u8; 32]);
17
18impl Hash {
19 pub const SIZE: usize = 32;
21
22 pub const ZERO: Hash = Hash([0u8; 32]);
24
25 pub fn new(bytes: [u8; 32]) -> Self {
27 Hash(bytes)
28 }
29
30 pub fn from_slice(slice: &[u8]) -> Result<Self> {
32 if slice.len() != Self::SIZE {
33 return Err(PrimitiveError::InvalidLength {
34 expected: Self::SIZE,
35 got: slice.len(),
36 });
37 }
38 let mut bytes = [0u8; 32];
39 bytes.copy_from_slice(slice);
40 Ok(Hash(bytes))
41 }
42
43 pub fn from_hex(s: &str) -> Result<Self> {
45 let s = s.strip_prefix("0x").unwrap_or(s);
46 let bytes = hex::decode(s).map_err(|e| PrimitiveError::InvalidHex(e.to_string()))?;
47 Self::from_slice(&bytes)
48 }
49
50 pub fn hash(data: &[u8]) -> Self {
52 let result = blake3::hash(data);
53 Hash(*result.as_bytes())
54 }
55
56 pub fn hash_many(data: &[&[u8]]) -> Self {
58 let mut hasher = blake3::Hasher::new();
59 for d in data {
60 hasher.update(d);
61 }
62 let result = hasher.finalize();
63 Hash(*result.as_bytes())
64 }
65
66 pub fn as_bytes(&self) -> &[u8; 32] {
68 &self.0
69 }
70
71 pub fn to_hex(&self) -> String {
73 format!("0x{}", hex::encode(self.0))
74 }
75
76 pub fn is_zero(&self) -> bool {
78 self.0 == [0u8; 32]
79 }
80
81 pub fn merkle_root(hashes: &[Hash]) -> Hash {
84 if hashes.is_empty() {
85 return Hash::ZERO;
86 }
87 if hashes.len() == 1 {
88 return hashes[0];
89 }
90
91 let mut current_level: Vec<Hash> = hashes.to_vec();
92
93 while current_level.len() > 1 {
94 let mut next_level = Vec::new();
95
96 for chunk in current_level.chunks(2) {
97 let left = &chunk[0];
98 let right = chunk.get(1).unwrap_or(left); let combined = Hash::hash_many(&[left.as_bytes(), right.as_bytes()]);
101 next_level.push(combined);
102 }
103
104 current_level = next_level;
105 }
106
107 current_level[0]
108 }
109}
110
111impl fmt::Debug for Hash {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(f, "Hash({})", self.to_hex())
114 }
115}
116
117impl fmt::Display for Hash {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(f, "{}", self.to_hex())
120 }
121}
122
123impl AsRef<[u8]> for Hash {
124 fn as_ref(&self) -> &[u8] {
125 &self.0
126 }
127}
128
129impl From<[u8; 32]> for Hash {
130 fn from(bytes: [u8; 32]) -> Self {
131 Hash(bytes)
132 }
133}
134
135impl PartialOrd for Hash {
136 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
137 Some(self.cmp(other))
138 }
139}
140
141impl Ord for Hash {
142 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
143 self.0.cmp(&other.0)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_hash_consistency() {
153 let data = b"hello world";
154 let h1 = Hash::hash(data);
155 let h2 = Hash::hash(data);
156 assert_eq!(h1, h2);
157 }
158
159 #[test]
160 fn test_hash_different_data() {
161 let h1 = Hash::hash(b"hello");
162 let h2 = Hash::hash(b"world");
163 assert_ne!(h1, h2);
164 }
165
166 #[test]
167 fn test_hex_roundtrip() {
168 let h = Hash::hash(b"test data");
169 let hex = h.to_hex();
170 let h2 = Hash::from_hex(&hex).unwrap();
171 assert_eq!(h, h2);
172 }
173
174 #[test]
175 fn test_merkle_root_empty() {
176 assert_eq!(Hash::merkle_root(&[]), Hash::ZERO);
177 }
178
179 #[test]
180 fn test_merkle_root_single() {
181 let h = Hash::hash(b"single");
182 assert_eq!(Hash::merkle_root(&[h]), h);
183 }
184
185 #[test]
186 fn test_merkle_root_multiple() {
187 let hashes: Vec<Hash> = (0..4).map(|i| Hash::hash(&[i])).collect();
188 let root = Hash::merkle_root(&hashes);
189 assert_ne!(root, Hash::ZERO);
190
191 let root2 = Hash::merkle_root(&hashes);
193 assert_eq!(root, root2);
194 }
195}