1use serde::{Deserialize, Serialize};
6use sha2::{Digest, Sha256};
7use std::fmt;
8
9#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
11pub struct Hash([u8; 32]);
12
13impl Hash {
14 pub fn from_bytes(bytes: [u8; 32]) -> Self {
16 Hash(bytes)
17 }
18
19 pub fn as_bytes(&self) -> &[u8; 32] {
21 &self.0
22 }
23
24 pub fn zero() -> Self {
26 Hash([0u8; 32])
27 }
28
29 pub fn is_zero(&self) -> bool {
31 self.0 == [0u8; 32]
32 }
33
34 pub fn to_hex(&self) -> String {
36 self.0.iter().map(|b| format!("{:02x}", b)).collect()
37 }
38
39 pub fn from_hex(s: &str) -> Option<Self> {
41 if s.len() != 64 {
42 return None;
43 }
44 let mut bytes = [0u8; 32];
45 for (i, chunk) in s.as_bytes().chunks(2).enumerate() {
46 let hex_str = std::str::from_utf8(chunk).ok()?;
47 bytes[i] = u8::from_str_radix(hex_str, 16).ok()?;
48 }
49 Some(Hash(bytes))
50 }
51
52 pub fn short(&self) -> String {
54 self.to_hex()[..8].to_string()
55 }
56}
57
58impl fmt::Debug for Hash {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(f, "Hash({}...)", &self.to_hex()[..8])
61 }
62}
63
64impl fmt::Display for Hash {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 write!(f, "{}", self.to_hex())
67 }
68}
69
70impl Default for Hash {
71 fn default() -> Self {
72 Hash::zero()
73 }
74}
75
76pub struct Hasher {
78 inner: Sha256,
79}
80
81impl Hasher {
82 pub fn new() -> Self {
84 Hasher {
85 inner: Sha256::new(),
86 }
87 }
88
89 pub fn update(&mut self, data: &[u8]) {
91 self.inner.update(data);
92 }
93
94 pub fn finalize(self) -> Hash {
96 let result = self.inner.finalize();
97 let mut bytes = [0u8; 32];
98 bytes.copy_from_slice(&result);
99 Hash(bytes)
100 }
101
102 pub fn hash(data: &[u8]) -> Hash {
104 let mut hasher = Self::new();
105 hasher.update(data);
106 hasher.finalize()
107 }
108
109 pub fn hash_all(parts: &[&[u8]]) -> Hash {
111 let mut hasher = Self::new();
112 for part in parts {
113 hasher.update(part);
114 }
115 hasher.finalize()
116 }
117}
118
119impl Default for Hasher {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_hash_deterministic() {
131 let data = b"hello world";
132 let h1 = Hasher::hash(data);
133 let h2 = Hasher::hash(data);
134 assert_eq!(h1, h2);
135 }
136
137 #[test]
138 fn test_hash_different_data() {
139 let h1 = Hasher::hash(b"hello");
140 let h2 = Hasher::hash(b"world");
141 assert_ne!(h1, h2);
142 }
143
144 #[test]
145 fn test_hex_roundtrip() {
146 let h1 = Hasher::hash(b"test data");
147 let hex = h1.to_hex();
148 let h2 = Hash::from_hex(&hex).unwrap();
149 assert_eq!(h1, h2);
150 }
151
152 #[test]
153 fn test_zero_hash() {
154 let zero = Hash::zero();
155 assert!(zero.is_zero());
156 assert!(!Hasher::hash(b"test").is_zero());
157 }
158
159 #[test]
160 fn test_hash_all() {
161 let h1 = Hasher::hash_all(&[b"hello", b"world"]);
162
163 let mut hasher = Hasher::new();
164 hasher.update(b"hello");
165 hasher.update(b"world");
166 let h2 = hasher.finalize();
167
168 assert_eq!(h1, h2);
169 }
170}