base_d/
hashing.rs

1use sha2::{Sha224, Sha256, Sha384, Sha512, Digest};
2use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512, Keccak224, Keccak256, Keccak384, Keccak512};
3use blake2::{Blake2b512, Blake2s256};
4use blake3::Hasher as Blake3Hasher;
5use md5::Md5;
6use twox_hash::{XxHash32, XxHash64};
7use twox_hash::xxhash3_64::Hasher as Xxh3Hash64;
8use twox_hash::xxhash3_128::Hasher as Xxh3Hash128;
9use std::hash::Hasher;
10
11/// Supported hash algorithms.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum HashAlgorithm {
14    Md5,
15    Sha224,
16    Sha256,
17    Sha384,
18    Sha512,
19    Sha3_224,
20    Sha3_256,
21    Sha3_384,
22    Sha3_512,
23    Keccak224,
24    Keccak256,
25    Keccak384,
26    Keccak512,
27    Blake2b,
28    Blake2s,
29    Blake3,
30    // CRC variants
31    Crc32,
32    Crc32c,
33    Crc16,
34    Crc64,
35    // xxHash variants
36    XxHash32,
37    XxHash64,
38    XxHash3_64,
39    XxHash3_128,
40}
41
42impl HashAlgorithm {
43    /// Parse hash algorithm from string.
44    pub fn from_str(s: &str) -> Result<Self, String> {
45        match s.to_lowercase().as_str() {
46            "md5" => Ok(HashAlgorithm::Md5),
47            "sha224" | "sha-224" => Ok(HashAlgorithm::Sha224),
48            "sha256" | "sha-256" => Ok(HashAlgorithm::Sha256),
49            "sha384" | "sha-384" => Ok(HashAlgorithm::Sha384),
50            "sha512" | "sha-512" => Ok(HashAlgorithm::Sha512),
51            "sha3-224" | "sha3_224" => Ok(HashAlgorithm::Sha3_224),
52            "sha3-256" | "sha3_256" => Ok(HashAlgorithm::Sha3_256),
53            "sha3-384" | "sha3_384" => Ok(HashAlgorithm::Sha3_384),
54            "sha3-512" | "sha3_512" => Ok(HashAlgorithm::Sha3_512),
55            "keccak224" | "keccak-224" => Ok(HashAlgorithm::Keccak224),
56            "keccak256" | "keccak-256" => Ok(HashAlgorithm::Keccak256),
57            "keccak384" | "keccak-384" => Ok(HashAlgorithm::Keccak384),
58            "keccak512" | "keccak-512" => Ok(HashAlgorithm::Keccak512),
59            "blake2b" | "blake2b-512" => Ok(HashAlgorithm::Blake2b),
60            "blake2s" | "blake2s-256" => Ok(HashAlgorithm::Blake2s),
61            "blake3" => Ok(HashAlgorithm::Blake3),
62            "crc32" => Ok(HashAlgorithm::Crc32),
63            "crc32c" => Ok(HashAlgorithm::Crc32c),
64            "crc16" => Ok(HashAlgorithm::Crc16),
65            "crc64" => Ok(HashAlgorithm::Crc64),
66            "xxhash32" | "xxh32" => Ok(HashAlgorithm::XxHash32),
67            "xxhash64" | "xxh64" => Ok(HashAlgorithm::XxHash64),
68            "xxhash3" | "xxh3" | "xxhash3-64" | "xxh3-64" => Ok(HashAlgorithm::XxHash3_64),
69            "xxhash3-128" | "xxh3-128" => Ok(HashAlgorithm::XxHash3_128),
70            _ => Err(format!("Unknown hash algorithm: {}", s)),
71        }
72    }
73    
74    pub fn as_str(&self) -> &str {
75        match self {
76            HashAlgorithm::Md5 => "md5",
77            HashAlgorithm::Sha224 => "sha224",
78            HashAlgorithm::Sha256 => "sha256",
79            HashAlgorithm::Sha384 => "sha384",
80            HashAlgorithm::Sha512 => "sha512",
81            HashAlgorithm::Sha3_224 => "sha3-224",
82            HashAlgorithm::Sha3_256 => "sha3-256",
83            HashAlgorithm::Sha3_384 => "sha3-384",
84            HashAlgorithm::Sha3_512 => "sha3-512",
85            HashAlgorithm::Keccak224 => "keccak224",
86            HashAlgorithm::Keccak256 => "keccak256",
87            HashAlgorithm::Keccak384 => "keccak384",
88            HashAlgorithm::Keccak512 => "keccak512",
89            HashAlgorithm::Blake2b => "blake2b",
90            HashAlgorithm::Blake2s => "blake2s",
91            HashAlgorithm::Blake3 => "blake3",
92            HashAlgorithm::Crc32 => "crc32",
93            HashAlgorithm::Crc32c => "crc32c",
94            HashAlgorithm::Crc16 => "crc16",
95            HashAlgorithm::Crc64 => "crc64",
96            HashAlgorithm::XxHash32 => "xxhash32",
97            HashAlgorithm::XxHash64 => "xxhash64",
98            HashAlgorithm::XxHash3_64 => "xxhash3-64",
99            HashAlgorithm::XxHash3_128 => "xxhash3-128",
100        }
101    }
102
103    /// Get the output size in bytes for this algorithm.
104    pub fn output_size(&self) -> usize {
105        match self {
106            HashAlgorithm::Md5 => 16,
107            HashAlgorithm::Sha224 => 28,
108            HashAlgorithm::Sha256 => 32,
109            HashAlgorithm::Sha384 => 48,
110            HashAlgorithm::Sha512 => 64,
111            HashAlgorithm::Sha3_224 => 28,
112            HashAlgorithm::Sha3_256 => 32,
113            HashAlgorithm::Sha3_384 => 48,
114            HashAlgorithm::Sha3_512 => 64,
115            HashAlgorithm::Keccak224 => 28,
116            HashAlgorithm::Keccak256 => 32,
117            HashAlgorithm::Keccak384 => 48,
118            HashAlgorithm::Keccak512 => 64,
119            HashAlgorithm::Blake2b => 64,
120            HashAlgorithm::Blake2s => 32,
121            HashAlgorithm::Blake3 => 32,
122            HashAlgorithm::Crc16 => 2,
123            HashAlgorithm::Crc32 => 4,
124            HashAlgorithm::Crc32c => 4,
125            HashAlgorithm::Crc64 => 8,
126            HashAlgorithm::XxHash32 => 4,
127            HashAlgorithm::XxHash64 => 8,
128            HashAlgorithm::XxHash3_64 => 8,
129            HashAlgorithm::XxHash3_128 => 16,
130        }
131    }
132}
133
134/// Compute hash of data using the specified algorithm.
135pub fn hash(data: &[u8], algorithm: HashAlgorithm) -> Vec<u8> {
136    match algorithm {
137        HashAlgorithm::Md5 => {
138            let mut hasher = Md5::new();
139            hasher.update(data);
140            hasher.finalize().to_vec()
141        }
142        HashAlgorithm::Sha224 => {
143            let mut hasher = Sha224::new();
144            hasher.update(data);
145            hasher.finalize().to_vec()
146        }
147        HashAlgorithm::Sha256 => {
148            let mut hasher = Sha256::new();
149            hasher.update(data);
150            hasher.finalize().to_vec()
151        }
152        HashAlgorithm::Sha384 => {
153            let mut hasher = Sha384::new();
154            hasher.update(data);
155            hasher.finalize().to_vec()
156        }
157        HashAlgorithm::Sha512 => {
158            let mut hasher = Sha512::new();
159            hasher.update(data);
160            hasher.finalize().to_vec()
161        }
162        HashAlgorithm::Sha3_224 => {
163            let mut hasher = Sha3_224::new();
164            hasher.update(data);
165            hasher.finalize().to_vec()
166        }
167        HashAlgorithm::Sha3_256 => {
168            let mut hasher = Sha3_256::new();
169            hasher.update(data);
170            hasher.finalize().to_vec()
171        }
172        HashAlgorithm::Sha3_384 => {
173            let mut hasher = Sha3_384::new();
174            hasher.update(data);
175            hasher.finalize().to_vec()
176        }
177        HashAlgorithm::Sha3_512 => {
178            let mut hasher = Sha3_512::new();
179            hasher.update(data);
180            hasher.finalize().to_vec()
181        }
182        HashAlgorithm::Keccak224 => {
183            let mut hasher = Keccak224::new();
184            hasher.update(data);
185            hasher.finalize().to_vec()
186        }
187        HashAlgorithm::Keccak256 => {
188            let mut hasher = Keccak256::new();
189            hasher.update(data);
190            hasher.finalize().to_vec()
191        }
192        HashAlgorithm::Keccak384 => {
193            let mut hasher = Keccak384::new();
194            hasher.update(data);
195            hasher.finalize().to_vec()
196        }
197        HashAlgorithm::Keccak512 => {
198            let mut hasher = Keccak512::new();
199            hasher.update(data);
200            hasher.finalize().to_vec()
201        }
202        HashAlgorithm::Blake2b => {
203            let mut hasher = Blake2b512::new();
204            hasher.update(data);
205            hasher.finalize().to_vec()
206        }
207        HashAlgorithm::Blake2s => {
208            let mut hasher = Blake2s256::new();
209            hasher.update(data);
210            hasher.finalize().to_vec()
211        }
212        HashAlgorithm::Blake3 => {
213            let mut hasher = Blake3Hasher::new();
214            hasher.update(data);
215            hasher.finalize().as_bytes().to_vec()
216        }
217        HashAlgorithm::Crc16 => {
218            let crc = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC);
219            let result = crc.checksum(data);
220            result.to_be_bytes().to_vec()
221        }
222        HashAlgorithm::Crc32 => {
223            let crc = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
224            let result = crc.checksum(data);
225            result.to_be_bytes().to_vec()
226        }
227        HashAlgorithm::Crc32c => {
228            let crc = crc::Crc::<u32>::new(&crc::CRC_32_ISCSI);
229            let result = crc.checksum(data);
230            result.to_be_bytes().to_vec()
231        }
232        HashAlgorithm::Crc64 => {
233            let crc = crc::Crc::<u64>::new(&crc::CRC_64_ECMA_182);
234            let result = crc.checksum(data);
235            result.to_be_bytes().to_vec()
236        }
237        HashAlgorithm::XxHash32 => {
238            let mut hasher = XxHash32::with_seed(0);
239            hasher.write(data);
240            (hasher.finish() as u32).to_be_bytes().to_vec()
241        }
242        HashAlgorithm::XxHash64 => {
243            let mut hasher = XxHash64::with_seed(0);
244            hasher.write(data);
245            hasher.finish().to_be_bytes().to_vec()
246        }
247        HashAlgorithm::XxHash3_64 => {
248            let mut hasher = Xxh3Hash64::with_seed(0);
249            hasher.write(data);
250            hasher.finish().to_be_bytes().to_vec()
251        }
252        HashAlgorithm::XxHash3_128 => {
253            let mut hasher = Xxh3Hash128::with_seed(0);
254            hasher.write(data);
255            hasher.finish_128().to_be_bytes().to_vec()
256        }
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    use super::*;
263    
264    #[test]
265    fn test_md5() {
266        let data = b"hello world";
267        let hash = hash(data, HashAlgorithm::Md5);
268        assert_eq!(hash.len(), 16);
269        // MD5 of "hello world" is 5eb63bbbe01eeed093cb22bb8f5acdc3
270        assert_eq!(hex::encode(&hash), "5eb63bbbe01eeed093cb22bb8f5acdc3");
271    }
272    
273    #[test]
274    fn test_sha256() {
275        let data = b"hello world";
276        let hash = hash(data, HashAlgorithm::Sha256);
277        assert_eq!(hash.len(), 32);
278        // SHA-256 of "hello world"
279        assert_eq!(
280            hex::encode(&hash),
281            "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
282        );
283    }
284    
285    #[test]
286    fn test_sha512() {
287        let data = b"hello world";
288        let hash = hash(data, HashAlgorithm::Sha512);
289        assert_eq!(hash.len(), 64);
290    }
291    
292    #[test]
293    fn test_sha3_256() {
294        let data = b"hello world";
295        let hash = hash(data, HashAlgorithm::Sha3_256);
296        assert_eq!(hash.len(), 32);
297    }
298    
299    #[test]
300    fn test_blake2b() {
301        let data = b"hello world";
302        let hash = hash(data, HashAlgorithm::Blake2b);
303        assert_eq!(hash.len(), 64);
304    }
305    
306    #[test]
307    fn test_blake2s() {
308        let data = b"hello world";
309        let hash = hash(data, HashAlgorithm::Blake2s);
310        assert_eq!(hash.len(), 32);
311    }
312    
313    #[test]
314    fn test_blake3() {
315        let data = b"hello world";
316        let hash = hash(data, HashAlgorithm::Blake3);
317        assert_eq!(hash.len(), 32);
318    }
319    
320    #[test]
321    fn test_empty_input() {
322        let data = b"";
323        let hash = hash(data, HashAlgorithm::Sha256);
324        assert_eq!(hash.len(), 32);
325        // SHA-256 of empty string
326        assert_eq!(
327            hex::encode(&hash),
328            "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
329        );
330    }
331    
332    #[test]
333    fn test_output_sizes() {
334        assert_eq!(HashAlgorithm::Md5.output_size(), 16);
335        assert_eq!(HashAlgorithm::Sha256.output_size(), 32);
336        assert_eq!(HashAlgorithm::Sha512.output_size(), 64);
337        assert_eq!(HashAlgorithm::Blake3.output_size(), 32);
338        assert_eq!(HashAlgorithm::Crc16.output_size(), 2);
339        assert_eq!(HashAlgorithm::Crc32.output_size(), 4);
340        assert_eq!(HashAlgorithm::Crc64.output_size(), 8);
341        assert_eq!(HashAlgorithm::XxHash32.output_size(), 4);
342        assert_eq!(HashAlgorithm::XxHash64.output_size(), 8);
343        assert_eq!(HashAlgorithm::XxHash3_64.output_size(), 8);
344        assert_eq!(HashAlgorithm::XxHash3_128.output_size(), 16);
345    }
346    
347    #[test]
348    fn test_crc32() {
349        let data = b"hello world";
350        let result = hash(data, HashAlgorithm::Crc32);
351        assert_eq!(result.len(), 4);
352        // CRC32 is deterministic
353        let result2 = hash(data, HashAlgorithm::Crc32);
354        assert_eq!(result, result2);
355    }
356    
357    #[test]
358    fn test_crc32c() {
359        let data = b"hello world";
360        let result = hash(data, HashAlgorithm::Crc32c);
361        assert_eq!(result.len(), 4);
362    }
363    
364    #[test]
365    fn test_crc16() {
366        let data = b"hello world";
367        let result = hash(data, HashAlgorithm::Crc16);
368        assert_eq!(result.len(), 2);
369    }
370    
371    #[test]
372    fn test_crc64() {
373        let data = b"hello world";
374        let result = hash(data, HashAlgorithm::Crc64);
375        assert_eq!(result.len(), 8);
376    }
377    
378    #[test]
379    fn test_xxhash32() {
380        let data = b"hello world";
381        let result = hash(data, HashAlgorithm::XxHash32);
382        assert_eq!(result.len(), 4);
383        // xxHash is deterministic with same seed
384        let result2 = hash(data, HashAlgorithm::XxHash32);
385        assert_eq!(result, result2);
386    }
387    
388    #[test]
389    fn test_xxhash64() {
390        let data = b"hello world";
391        let result = hash(data, HashAlgorithm::XxHash64);
392        assert_eq!(result.len(), 8);
393    }
394    
395    #[test]
396    fn test_xxhash3_64() {
397        let data = b"hello world";
398        let result = hash(data, HashAlgorithm::XxHash3_64);
399        assert_eq!(result.len(), 8);
400    }
401    
402    #[test]
403    fn test_xxhash3_128() {
404        let data = b"hello world";
405        let result = hash(data, HashAlgorithm::XxHash3_128);
406        assert_eq!(result.len(), 16);
407    }
408}