1use serde::{Deserialize, Serialize};
6use sha2::{Sha256, Sha512, Digest as Sha2Digest};
7use sha3::{Sha3_256, Sha3_512};
8use thiserror::Error;
9
10#[derive(Error, Debug)]
12pub enum HashError {
13 #[error("Invalid hash length")]
14 InvalidLength,
15
16 #[error("Unsupported algorithm")]
17 UnsupportedAlgorithm,
18}
19
20#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
22pub enum HashAlgorithm {
23 Sha256,
24 Sha512,
25 Sha3_256,
26 Sha3_512,
27 Blake3,
28}
29
30impl HashAlgorithm {
31 pub fn output_length(&self) -> usize {
33 match self {
34 HashAlgorithm::Sha256 => 32,
35 HashAlgorithm::Sha512 => 64,
36 HashAlgorithm::Sha3_256 => 32,
37 HashAlgorithm::Sha3_512 => 64,
38 HashAlgorithm::Blake3 => 32,
39 }
40 }
41
42 pub fn name(&self) -> &'static str {
44 match self {
45 HashAlgorithm::Sha256 => "SHA-256",
46 HashAlgorithm::Sha512 => "SHA-512",
47 HashAlgorithm::Sha3_256 => "SHA3-256",
48 HashAlgorithm::Sha3_512 => "SHA3-512",
49 HashAlgorithm::Blake3 => "BLAKE3",
50 }
51 }
52}
53
54#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
56pub struct HashOutput {
57 algorithm: HashAlgorithm,
58 bytes: Vec<u8>,
59}
60
61impl HashOutput {
62 pub fn from_bytes(algorithm: HashAlgorithm, bytes: Vec<u8>) -> Result<Self, HashError> {
64 if bytes.len() != algorithm.output_length() {
65 return Err(HashError::InvalidLength);
66 }
67 Ok(Self { algorithm, bytes })
68 }
69
70 pub fn as_bytes(&self) -> &[u8] {
72 &self.bytes
73 }
74
75 pub fn to_hex(&self) -> String {
77 hex::encode(&self.bytes)
78 }
79
80 pub fn algorithm(&self) -> HashAlgorithm {
82 self.algorithm
83 }
84
85 pub fn verify(&self, expected: &[u8]) -> bool {
87 constant_time_eq::constant_time_eq(&self.bytes, expected)
88 }
89
90 pub fn verify_hex(&self, expected_hex: &str) -> bool {
92 if let Ok(expected) = hex::decode(expected_hex) {
93 self.verify(&expected)
94 } else {
95 false
96 }
97 }
98}
99
100impl std::fmt::Debug for HashOutput {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 write!(f, "HashOutput({}: {})", self.algorithm.name(), &self.to_hex()[..16])
103 }
104}
105
106pub struct Hasher {
108 algorithm: HashAlgorithm,
109}
110
111impl Hasher {
112 pub fn new(algorithm: HashAlgorithm) -> Self {
114 Self { algorithm }
115 }
116
117 pub fn hash(&self, data: &[u8]) -> HashOutput {
119 let bytes = match self.algorithm {
120 HashAlgorithm::Sha256 => {
121 let mut hasher = Sha256::new();
122 hasher.update(data);
123 hasher.finalize().to_vec()
124 }
125 HashAlgorithm::Sha512 => {
126 let mut hasher = Sha512::new();
127 hasher.update(data);
128 hasher.finalize().to_vec()
129 }
130 HashAlgorithm::Sha3_256 => {
131 let mut hasher = Sha3_256::new();
132 hasher.update(data);
133 hasher.finalize().to_vec()
134 }
135 HashAlgorithm::Sha3_512 => {
136 let mut hasher = Sha3_512::new();
137 hasher.update(data);
138 hasher.finalize().to_vec()
139 }
140 HashAlgorithm::Blake3 => {
141 let hash = blake3::hash(data);
142 hash.as_bytes().to_vec()
143 }
144 };
145
146 HashOutput {
147 algorithm: self.algorithm,
148 bytes,
149 }
150 }
151
152 pub fn hash_str(&self, data: &str) -> HashOutput {
154 self.hash(data.as_bytes())
155 }
156
157 pub fn hash_to_hex(&self, data: &[u8]) -> String {
159 self.hash(data).to_hex()
160 }
161}
162
163impl Default for Hasher {
164 fn default() -> Self {
165 Self::new(HashAlgorithm::Sha256)
166 }
167}
168
169pub struct IncrementalHasher {
171 state: IncrementalState,
172 algorithm: HashAlgorithm,
173}
174
175enum IncrementalState {
176 Sha256(Sha256),
177 Sha512(Sha512),
178 Sha3_256(Sha3_256),
179 Sha3_512(Sha3_512),
180 Blake3(blake3::Hasher),
181}
182
183impl IncrementalHasher {
184 pub fn new(algorithm: HashAlgorithm) -> Self {
186 let state = match algorithm {
187 HashAlgorithm::Sha256 => IncrementalState::Sha256(Sha256::new()),
188 HashAlgorithm::Sha512 => IncrementalState::Sha512(Sha512::new()),
189 HashAlgorithm::Sha3_256 => IncrementalState::Sha3_256(Sha3_256::new()),
190 HashAlgorithm::Sha3_512 => IncrementalState::Sha3_512(Sha3_512::new()),
191 HashAlgorithm::Blake3 => IncrementalState::Blake3(blake3::Hasher::new()),
192 };
193 Self { state, algorithm }
194 }
195
196 pub fn update(&mut self, data: &[u8]) {
198 match &mut self.state {
199 IncrementalState::Sha256(h) => h.update(data),
200 IncrementalState::Sha512(h) => h.update(data),
201 IncrementalState::Sha3_256(h) => h.update(data),
202 IncrementalState::Sha3_512(h) => h.update(data),
203 IncrementalState::Blake3(h) => { h.update(data); }
204 }
205 }
206
207 pub fn finalize(self) -> HashOutput {
209 let bytes = match self.state {
210 IncrementalState::Sha256(h) => h.finalize().to_vec(),
211 IncrementalState::Sha512(h) => h.finalize().to_vec(),
212 IncrementalState::Sha3_256(h) => h.finalize().to_vec(),
213 IncrementalState::Sha3_512(h) => h.finalize().to_vec(),
214 IncrementalState::Blake3(h) => h.finalize().as_bytes().to_vec(),
215 };
216
217 HashOutput {
218 algorithm: self.algorithm,
219 bytes,
220 }
221 }
222}
223
224pub fn sha256(data: &[u8]) -> HashOutput {
226 Hasher::new(HashAlgorithm::Sha256).hash(data)
227}
228
229pub fn sha3_256(data: &[u8]) -> HashOutput {
230 Hasher::new(HashAlgorithm::Sha3_256).hash(data)
231}
232
233pub fn blake3(data: &[u8]) -> HashOutput {
234 Hasher::new(HashAlgorithm::Blake3).hash(data)
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240
241 #[test]
242 fn test_sha256() {
243 let hasher = Hasher::new(HashAlgorithm::Sha256);
244 let hash = hasher.hash(b"hello world");
245 assert_eq!(hash.as_bytes().len(), 32);
246 assert_eq!(hash.algorithm(), HashAlgorithm::Sha256);
247 }
248
249 #[test]
250 fn test_sha3_256() {
251 let hasher = Hasher::new(HashAlgorithm::Sha3_256);
252 let hash = hasher.hash(b"hello world");
253 assert_eq!(hash.as_bytes().len(), 32);
254 assert_eq!(hash.algorithm(), HashAlgorithm::Sha3_256);
255 }
256
257 #[test]
258 fn test_blake3() {
259 let hasher = Hasher::new(HashAlgorithm::Blake3);
260 let hash = hasher.hash(b"hello world");
261 assert_eq!(hash.as_bytes().len(), 32);
262 assert_eq!(hash.algorithm(), HashAlgorithm::Blake3);
263 }
264
265 #[test]
266 fn test_different_algorithms_different_output() {
267 let data = b"test data";
268 let sha256 = Hasher::new(HashAlgorithm::Sha256).hash(data);
269 let sha3 = Hasher::new(HashAlgorithm::Sha3_256).hash(data);
270 let blake = Hasher::new(HashAlgorithm::Blake3).hash(data);
271
272 assert_ne!(sha256.as_bytes(), sha3.as_bytes());
273 assert_ne!(sha256.as_bytes(), blake.as_bytes());
274 assert_ne!(sha3.as_bytes(), blake.as_bytes());
275 }
276
277 #[test]
278 fn test_verify() {
279 let hasher = Hasher::new(HashAlgorithm::Sha256);
280 let hash = hasher.hash(b"password");
281
282 assert!(hash.verify(hash.as_bytes()));
283 assert!(!hash.verify(b"wrong hash"));
284 }
285
286 #[test]
287 fn test_verify_hex() {
288 let hasher = Hasher::new(HashAlgorithm::Sha256);
289 let hash = hasher.hash(b"test");
290 let hex = hash.to_hex();
291
292 assert!(hash.verify_hex(&hex));
293 assert!(!hash.verify_hex("0000"));
294 }
295
296 #[test]
297 fn test_incremental_hasher() {
298 let data = b"hello world";
299
300 let one_shot = Hasher::new(HashAlgorithm::Sha256).hash(data);
302
303 let mut incremental = IncrementalHasher::new(HashAlgorithm::Sha256);
305 incremental.update(b"hello ");
306 incremental.update(b"world");
307 let result = incremental.finalize();
308
309 assert_eq!(one_shot.as_bytes(), result.as_bytes());
310 }
311
312 #[test]
313 fn test_convenience_functions() {
314 let data = b"test";
315
316 let h1 = sha256(data);
317 let h2 = sha3_256(data);
318 let h3 = blake3(data);
319
320 assert_eq!(h1.algorithm(), HashAlgorithm::Sha256);
321 assert_eq!(h2.algorithm(), HashAlgorithm::Sha3_256);
322 assert_eq!(h3.algorithm(), HashAlgorithm::Blake3);
323 }
324
325 #[test]
326 fn test_hex_conversion() {
327 let hash = sha256(b"test");
328 let hex = hash.to_hex();
329 assert_eq!(hex.len(), 64); }
331}