1use blake2::{Blake2b512, Blake2s256};
2use blake3::Hasher as Blake3Hasher;
3use md5::Md5;
4use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};
5use sha3::{Keccak224, Keccak256, Keccak384, Keccak512, Sha3_224, Sha3_256, Sha3_384, Sha3_512};
6use std::hash::Hasher;
7use twox_hash::xxhash3_64::Hasher as Xxh3Hash64;
8use twox_hash::xxhash3_128::Hasher as Xxh3Hash128;
9use twox_hash::{XxHash32, XxHash64};
10
11#[derive(Debug, Clone, Default)]
13pub struct XxHashConfig {
14 pub seed: u64,
16 pub secret: Option<Vec<u8>>,
18}
19
20impl XxHashConfig {
21 pub fn with_seed(seed: u64) -> Self {
23 Self { seed, secret: None }
24 }
25
26 pub fn with_secret(seed: u64, secret: Vec<u8>) -> Result<Self, String> {
29 if secret.len() < 136 {
30 return Err(format!(
31 "XXH3 secret must be >= 136 bytes, got {}",
32 secret.len()
33 ));
34 }
35 Ok(Self {
36 seed,
37 secret: Some(secret),
38 })
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum HashAlgorithm {
45 Md5,
46 Sha224,
47 Sha256,
48 Sha384,
49 Sha512,
50 Sha3_224,
51 Sha3_256,
52 Sha3_384,
53 Sha3_512,
54 Keccak224,
55 Keccak256,
56 Keccak384,
57 Keccak512,
58 Blake2b,
59 Blake2s,
60 Blake3,
61 Crc32,
63 Crc32c,
64 Crc16,
65 Crc64,
66 XxHash32,
68 XxHash64,
69 XxHash3_64,
70 XxHash3_128,
71}
72
73impl HashAlgorithm {
74 pub fn all() -> Vec<HashAlgorithm> {
76 vec![
77 HashAlgorithm::Md5,
78 HashAlgorithm::Sha224,
79 HashAlgorithm::Sha256,
80 HashAlgorithm::Sha384,
81 HashAlgorithm::Sha512,
82 HashAlgorithm::Sha3_224,
83 HashAlgorithm::Sha3_256,
84 HashAlgorithm::Sha3_384,
85 HashAlgorithm::Sha3_512,
86 HashAlgorithm::Keccak224,
87 HashAlgorithm::Keccak256,
88 HashAlgorithm::Keccak384,
89 HashAlgorithm::Keccak512,
90 HashAlgorithm::Blake2b,
91 HashAlgorithm::Blake2s,
92 HashAlgorithm::Blake3,
93 HashAlgorithm::Crc32,
94 HashAlgorithm::Crc32c,
95 HashAlgorithm::Crc16,
96 HashAlgorithm::Crc64,
97 HashAlgorithm::XxHash32,
98 HashAlgorithm::XxHash64,
99 HashAlgorithm::XxHash3_64,
100 HashAlgorithm::XxHash3_128,
101 ]
102 }
103
104 pub fn random() -> HashAlgorithm {
106 use rand::prelude::IndexedRandom;
107 let all = Self::all();
108 *all.choose(&mut rand::rng()).unwrap()
109 }
110
111 #[allow(clippy::should_implement_trait)]
113 pub fn from_str(s: &str) -> Result<Self, String> {
114 match s.to_lowercase().as_str() {
115 "md5" => Ok(HashAlgorithm::Md5),
116 "sha224" | "sha-224" => Ok(HashAlgorithm::Sha224),
117 "sha256" | "sha-256" => Ok(HashAlgorithm::Sha256),
118 "sha384" | "sha-384" => Ok(HashAlgorithm::Sha384),
119 "sha512" | "sha-512" => Ok(HashAlgorithm::Sha512),
120 "sha3-224" | "sha3_224" => Ok(HashAlgorithm::Sha3_224),
121 "sha3-256" | "sha3_256" => Ok(HashAlgorithm::Sha3_256),
122 "sha3-384" | "sha3_384" => Ok(HashAlgorithm::Sha3_384),
123 "sha3-512" | "sha3_512" => Ok(HashAlgorithm::Sha3_512),
124 "keccak224" | "keccak-224" => Ok(HashAlgorithm::Keccak224),
125 "keccak256" | "keccak-256" => Ok(HashAlgorithm::Keccak256),
126 "keccak384" | "keccak-384" => Ok(HashAlgorithm::Keccak384),
127 "keccak512" | "keccak-512" => Ok(HashAlgorithm::Keccak512),
128 "blake2b" | "blake2b-512" => Ok(HashAlgorithm::Blake2b),
129 "blake2s" | "blake2s-256" => Ok(HashAlgorithm::Blake2s),
130 "blake3" => Ok(HashAlgorithm::Blake3),
131 "crc32" => Ok(HashAlgorithm::Crc32),
132 "crc32c" => Ok(HashAlgorithm::Crc32c),
133 "crc16" => Ok(HashAlgorithm::Crc16),
134 "crc64" => Ok(HashAlgorithm::Crc64),
135 "xxhash32" | "xxh32" => Ok(HashAlgorithm::XxHash32),
136 "xxhash64" | "xxh64" => Ok(HashAlgorithm::XxHash64),
137 "xxhash3" | "xxh3" | "xxhash3-64" | "xxh3-64" => Ok(HashAlgorithm::XxHash3_64),
138 "xxhash3-128" | "xxh3-128" => Ok(HashAlgorithm::XxHash3_128),
139 _ => Err(format!("Unknown hash algorithm: {}", s)),
140 }
141 }
142
143 pub fn as_str(&self) -> &str {
144 match self {
145 HashAlgorithm::Md5 => "md5",
146 HashAlgorithm::Sha224 => "sha224",
147 HashAlgorithm::Sha256 => "sha256",
148 HashAlgorithm::Sha384 => "sha384",
149 HashAlgorithm::Sha512 => "sha512",
150 HashAlgorithm::Sha3_224 => "sha3-224",
151 HashAlgorithm::Sha3_256 => "sha3-256",
152 HashAlgorithm::Sha3_384 => "sha3-384",
153 HashAlgorithm::Sha3_512 => "sha3-512",
154 HashAlgorithm::Keccak224 => "keccak224",
155 HashAlgorithm::Keccak256 => "keccak256",
156 HashAlgorithm::Keccak384 => "keccak384",
157 HashAlgorithm::Keccak512 => "keccak512",
158 HashAlgorithm::Blake2b => "blake2b",
159 HashAlgorithm::Blake2s => "blake2s",
160 HashAlgorithm::Blake3 => "blake3",
161 HashAlgorithm::Crc32 => "crc32",
162 HashAlgorithm::Crc32c => "crc32c",
163 HashAlgorithm::Crc16 => "crc16",
164 HashAlgorithm::Crc64 => "crc64",
165 HashAlgorithm::XxHash32 => "xxhash32",
166 HashAlgorithm::XxHash64 => "xxhash64",
167 HashAlgorithm::XxHash3_64 => "xxhash3-64",
168 HashAlgorithm::XxHash3_128 => "xxhash3-128",
169 }
170 }
171
172 pub fn output_size(&self) -> usize {
174 match self {
175 HashAlgorithm::Md5 => 16,
176 HashAlgorithm::Sha224 => 28,
177 HashAlgorithm::Sha256 => 32,
178 HashAlgorithm::Sha384 => 48,
179 HashAlgorithm::Sha512 => 64,
180 HashAlgorithm::Sha3_224 => 28,
181 HashAlgorithm::Sha3_256 => 32,
182 HashAlgorithm::Sha3_384 => 48,
183 HashAlgorithm::Sha3_512 => 64,
184 HashAlgorithm::Keccak224 => 28,
185 HashAlgorithm::Keccak256 => 32,
186 HashAlgorithm::Keccak384 => 48,
187 HashAlgorithm::Keccak512 => 64,
188 HashAlgorithm::Blake2b => 64,
189 HashAlgorithm::Blake2s => 32,
190 HashAlgorithm::Blake3 => 32,
191 HashAlgorithm::Crc16 => 2,
192 HashAlgorithm::Crc32 => 4,
193 HashAlgorithm::Crc32c => 4,
194 HashAlgorithm::Crc64 => 8,
195 HashAlgorithm::XxHash32 => 4,
196 HashAlgorithm::XxHash64 => 8,
197 HashAlgorithm::XxHash3_64 => 8,
198 HashAlgorithm::XxHash3_128 => 16,
199 }
200 }
201}
202
203pub fn hash(data: &[u8], algorithm: HashAlgorithm) -> Vec<u8> {
206 hash_with_config(data, algorithm, &XxHashConfig::default())
207}
208
209pub fn hash_with_config(data: &[u8], algorithm: HashAlgorithm, config: &XxHashConfig) -> Vec<u8> {
211 match algorithm {
212 HashAlgorithm::Md5 => {
213 let mut hasher = Md5::new();
214 hasher.update(data);
215 hasher.finalize().to_vec()
216 }
217 HashAlgorithm::Sha224 => {
218 let mut hasher = Sha224::new();
219 hasher.update(data);
220 hasher.finalize().to_vec()
221 }
222 HashAlgorithm::Sha256 => {
223 let mut hasher = Sha256::new();
224 hasher.update(data);
225 hasher.finalize().to_vec()
226 }
227 HashAlgorithm::Sha384 => {
228 let mut hasher = Sha384::new();
229 hasher.update(data);
230 hasher.finalize().to_vec()
231 }
232 HashAlgorithm::Sha512 => {
233 let mut hasher = Sha512::new();
234 hasher.update(data);
235 hasher.finalize().to_vec()
236 }
237 HashAlgorithm::Sha3_224 => {
238 let mut hasher = Sha3_224::new();
239 hasher.update(data);
240 hasher.finalize().to_vec()
241 }
242 HashAlgorithm::Sha3_256 => {
243 let mut hasher = Sha3_256::new();
244 hasher.update(data);
245 hasher.finalize().to_vec()
246 }
247 HashAlgorithm::Sha3_384 => {
248 let mut hasher = Sha3_384::new();
249 hasher.update(data);
250 hasher.finalize().to_vec()
251 }
252 HashAlgorithm::Sha3_512 => {
253 let mut hasher = Sha3_512::new();
254 hasher.update(data);
255 hasher.finalize().to_vec()
256 }
257 HashAlgorithm::Keccak224 => {
258 let mut hasher = Keccak224::new();
259 hasher.update(data);
260 hasher.finalize().to_vec()
261 }
262 HashAlgorithm::Keccak256 => {
263 let mut hasher = Keccak256::new();
264 hasher.update(data);
265 hasher.finalize().to_vec()
266 }
267 HashAlgorithm::Keccak384 => {
268 let mut hasher = Keccak384::new();
269 hasher.update(data);
270 hasher.finalize().to_vec()
271 }
272 HashAlgorithm::Keccak512 => {
273 let mut hasher = Keccak512::new();
274 hasher.update(data);
275 hasher.finalize().to_vec()
276 }
277 HashAlgorithm::Blake2b => {
278 let mut hasher = Blake2b512::new();
279 hasher.update(data);
280 hasher.finalize().to_vec()
281 }
282 HashAlgorithm::Blake2s => {
283 let mut hasher = Blake2s256::new();
284 hasher.update(data);
285 hasher.finalize().to_vec()
286 }
287 HashAlgorithm::Blake3 => {
288 let mut hasher = Blake3Hasher::new();
289 hasher.update(data);
290 hasher.finalize().as_bytes().to_vec()
291 }
292 HashAlgorithm::Crc16 => {
293 let crc = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC);
294 let result = crc.checksum(data);
295 result.to_be_bytes().to_vec()
296 }
297 HashAlgorithm::Crc32 => {
298 let crc = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
299 let result = crc.checksum(data);
300 result.to_be_bytes().to_vec()
301 }
302 HashAlgorithm::Crc32c => {
303 let crc = crc::Crc::<u32>::new(&crc::CRC_32_ISCSI);
304 let result = crc.checksum(data);
305 result.to_be_bytes().to_vec()
306 }
307 HashAlgorithm::Crc64 => {
308 let crc = crc::Crc::<u64>::new(&crc::CRC_64_ECMA_182);
309 let result = crc.checksum(data);
310 result.to_be_bytes().to_vec()
311 }
312 HashAlgorithm::XxHash32 => {
313 let mut hasher = XxHash32::with_seed(config.seed as u32);
314 hasher.write(data);
315 (hasher.finish() as u32).to_be_bytes().to_vec()
316 }
317 HashAlgorithm::XxHash64 => {
318 let mut hasher = XxHash64::with_seed(config.seed);
319 hasher.write(data);
320 hasher.finish().to_be_bytes().to_vec()
321 }
322 HashAlgorithm::XxHash3_64 => {
323 let mut hasher = if let Some(ref secret) = config.secret {
324 Xxh3Hash64::with_seed_and_secret(config.seed, secret.as_slice()).expect(
325 "XXH3 secret validation should have been done in XxHashConfig::with_secret",
326 )
327 } else {
328 Xxh3Hash64::with_seed(config.seed)
329 };
330 hasher.write(data);
331 hasher.finish().to_be_bytes().to_vec()
332 }
333 HashAlgorithm::XxHash3_128 => {
334 let mut hasher = if let Some(ref secret) = config.secret {
335 Xxh3Hash128::with_seed_and_secret(config.seed, secret.as_slice()).expect(
336 "XXH3 secret validation should have been done in XxHashConfig::with_secret",
337 )
338 } else {
339 Xxh3Hash128::with_seed(config.seed)
340 };
341 hasher.write(data);
342 hasher.finish_128().to_be_bytes().to_vec()
343 }
344 }
345}
346
347#[cfg(test)]
348#[allow(deprecated)]
349mod tests {
350 use super::*;
351
352 #[test]
353 fn test_md5() {
354 let data = b"hello world";
355 let hash = hash(data, HashAlgorithm::Md5);
356 assert_eq!(hash.len(), 16);
357 assert_eq!(hex::encode(&hash), "5eb63bbbe01eeed093cb22bb8f5acdc3");
359 }
360
361 #[test]
362 fn test_sha256() {
363 let data = b"hello world";
364 let hash = hash(data, HashAlgorithm::Sha256);
365 assert_eq!(hash.len(), 32);
366 assert_eq!(
368 hex::encode(&hash),
369 "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
370 );
371 }
372
373 #[test]
374 fn test_sha512() {
375 let data = b"hello world";
376 let hash = hash(data, HashAlgorithm::Sha512);
377 assert_eq!(hash.len(), 64);
378 }
379
380 #[test]
381 fn test_sha3_256() {
382 let data = b"hello world";
383 let hash = hash(data, HashAlgorithm::Sha3_256);
384 assert_eq!(hash.len(), 32);
385 }
386
387 #[test]
388 fn test_blake2b() {
389 let data = b"hello world";
390 let hash = hash(data, HashAlgorithm::Blake2b);
391 assert_eq!(hash.len(), 64);
392 }
393
394 #[test]
395 fn test_blake2s() {
396 let data = b"hello world";
397 let hash = hash(data, HashAlgorithm::Blake2s);
398 assert_eq!(hash.len(), 32);
399 }
400
401 #[test]
402 fn test_blake3() {
403 let data = b"hello world";
404 let hash = hash(data, HashAlgorithm::Blake3);
405 assert_eq!(hash.len(), 32);
406 }
407
408 #[test]
409 fn test_empty_input() {
410 let data = b"";
411 let hash = hash(data, HashAlgorithm::Sha256);
412 assert_eq!(hash.len(), 32);
413 assert_eq!(
415 hex::encode(&hash),
416 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
417 );
418 }
419
420 #[test]
421 fn test_output_sizes() {
422 assert_eq!(HashAlgorithm::Md5.output_size(), 16);
423 assert_eq!(HashAlgorithm::Sha256.output_size(), 32);
424 assert_eq!(HashAlgorithm::Sha512.output_size(), 64);
425 assert_eq!(HashAlgorithm::Blake3.output_size(), 32);
426 assert_eq!(HashAlgorithm::Crc16.output_size(), 2);
427 assert_eq!(HashAlgorithm::Crc32.output_size(), 4);
428 assert_eq!(HashAlgorithm::Crc64.output_size(), 8);
429 assert_eq!(HashAlgorithm::XxHash32.output_size(), 4);
430 assert_eq!(HashAlgorithm::XxHash64.output_size(), 8);
431 assert_eq!(HashAlgorithm::XxHash3_64.output_size(), 8);
432 assert_eq!(HashAlgorithm::XxHash3_128.output_size(), 16);
433 }
434
435 #[test]
436 fn test_crc32() {
437 let data = b"hello world";
438 let result = hash(data, HashAlgorithm::Crc32);
439 assert_eq!(result.len(), 4);
440 let result2 = hash(data, HashAlgorithm::Crc32);
442 assert_eq!(result, result2);
443 }
444
445 #[test]
446 fn test_crc32c() {
447 let data = b"hello world";
448 let result = hash(data, HashAlgorithm::Crc32c);
449 assert_eq!(result.len(), 4);
450 }
451
452 #[test]
453 fn test_crc16() {
454 let data = b"hello world";
455 let result = hash(data, HashAlgorithm::Crc16);
456 assert_eq!(result.len(), 2);
457 }
458
459 #[test]
460 fn test_crc64() {
461 let data = b"hello world";
462 let result = hash(data, HashAlgorithm::Crc64);
463 assert_eq!(result.len(), 8);
464 }
465
466 #[test]
467 fn test_xxhash32() {
468 let data = b"hello world";
469 let result = hash(data, HashAlgorithm::XxHash32);
470 assert_eq!(result.len(), 4);
471 let result2 = hash(data, HashAlgorithm::XxHash32);
473 assert_eq!(result, result2);
474 }
475
476 #[test]
477 fn test_xxhash64() {
478 let data = b"hello world";
479 let result = hash(data, HashAlgorithm::XxHash64);
480 assert_eq!(result.len(), 8);
481 }
482
483 #[test]
484 fn test_xxhash3_64() {
485 let data = b"hello world";
486 let result = hash(data, HashAlgorithm::XxHash3_64);
487 assert_eq!(result.len(), 8);
488 }
489
490 #[test]
491 fn test_xxhash3_128() {
492 let data = b"hello world";
493 let result = hash(data, HashAlgorithm::XxHash3_128);
494 assert_eq!(result.len(), 16);
495 }
496
497 #[test]
498 fn test_xxhash_config_default() {
499 let config = XxHashConfig::default();
500 assert_eq!(config.seed, 0);
501 assert!(config.secret.is_none());
502 }
503
504 #[test]
505 fn test_xxhash_config_secret_too_short() {
506 let result = XxHashConfig::with_secret(0, vec![0u8; 100]);
507 assert!(result.is_err());
508 assert!(result.unwrap_err().contains("136 bytes"));
509 }
510
511 #[test]
512 fn test_xxhash_config_secret_valid() {
513 let result = XxHashConfig::with_secret(42, vec![0u8; 136]);
514 assert!(result.is_ok());
515 let config = result.unwrap();
516 assert_eq!(config.seed, 42);
517 assert_eq!(config.secret.as_ref().unwrap().len(), 136);
518 }
519
520 #[test]
521 fn test_hash_seed_changes_output() {
522 let data = b"test";
523 let h1 = hash_with_config(data, HashAlgorithm::XxHash64, &XxHashConfig::with_seed(0));
524 let h2 = hash_with_config(data, HashAlgorithm::XxHash64, &XxHashConfig::with_seed(42));
525 assert_ne!(h1, h2);
526 }
527
528 #[test]
529 fn test_backward_compatibility() {
530 let data = b"test";
531 let old = hash(data, HashAlgorithm::XxHash64);
532 let new = hash_with_config(data, HashAlgorithm::XxHash64, &XxHashConfig::default());
533 assert_eq!(old, new);
534 }
535
536 #[test]
537 fn test_xxhash3_with_seed() {
538 let data = b"test data for secret hashing";
539
540 let h1 = hash_with_config(data, HashAlgorithm::XxHash3_64, &XxHashConfig::with_seed(0));
542 let h2 = hash_with_config(
543 data,
544 HashAlgorithm::XxHash3_64,
545 &XxHashConfig::with_seed(123),
546 );
547 assert_ne!(h1, h2, "Different seeds should produce different hashes");
548
549 let h3 = hash_with_config(
551 data,
552 HashAlgorithm::XxHash3_64,
553 &XxHashConfig::with_seed(123),
554 );
555 assert_eq!(h2, h3, "Same seed should produce same hash");
556 }
557
558 #[test]
559 fn test_xxhash32_with_seed() {
560 let data = b"test";
561 let h1 = hash_with_config(data, HashAlgorithm::XxHash32, &XxHashConfig::with_seed(0));
562 let h2 = hash_with_config(data, HashAlgorithm::XxHash32, &XxHashConfig::with_seed(999));
563 assert_ne!(h1, h2);
564 }
565}