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