1use crate::error::Result;
30use blake2::{Blake2b512 as Blake2b512Impl, Blake2s256 as Blake2s256Impl, Digest as Blake2Digest};
31use multihash_codetable::Code;
32#[allow(unused_imports)]
33use sha2::{Digest, Sha256 as Sha256Impl, Sha512 as Sha512Impl};
34use sha3::{Sha3_256 as Sha3_256Impl, Sha3_512 as Sha3_512Impl};
35use std::sync::Arc;
36
37pub trait HashEngine: Send + Sync {
39 fn digest(&self, data: &[u8]) -> Vec<u8>;
41
42 fn code(&self) -> Code;
44
45 fn name(&self) -> &'static str;
47
48 #[inline]
50 fn is_simd_enabled(&self) -> bool {
51 false
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub struct CpuFeatures {
58 pub avx2: bool,
60 pub neon: bool,
62}
63
64impl CpuFeatures {
65 pub fn detect() -> Self {
67 #[cfg(target_arch = "x86_64")]
68 {
69 Self {
70 avx2: is_x86_feature_detected!("avx2"),
71 neon: false,
72 }
73 }
74
75 #[cfg(target_arch = "aarch64")]
76 {
77 Self {
78 avx2: false,
79 neon: true,
81 }
82 }
83
84 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
85 {
86 Self {
87 avx2: false,
88 neon: false,
89 }
90 }
91 }
92}
93
94pub struct Sha256Engine {
96 features: CpuFeatures,
97}
98
99impl Sha256Engine {
100 pub fn new() -> Self {
102 Self {
103 features: CpuFeatures::detect(),
104 }
105 }
106
107 #[cfg(target_arch = "x86_64")]
112 #[target_feature(enable = "avx2")]
113 unsafe fn digest_avx2(&self, data: &[u8]) -> Vec<u8> {
114 let mut hasher = Sha256Impl::new();
117 hasher.update(data);
118 hasher.finalize().to_vec()
119 }
120
121 #[cfg(target_arch = "aarch64")]
125 fn digest_neon(&self, data: &[u8]) -> Vec<u8> {
126 let mut hasher = Sha256Impl::new();
128 hasher.update(data);
129 hasher.finalize().to_vec()
130 }
131
132 fn digest_scalar(&self, data: &[u8]) -> Vec<u8> {
136 let mut hasher = Sha256Impl::new();
137 hasher.update(data);
138 hasher.finalize().to_vec()
139 }
140}
141
142impl Default for Sha256Engine {
143 fn default() -> Self {
144 Self::new()
145 }
146}
147
148impl HashEngine for Sha256Engine {
149 fn digest(&self, data: &[u8]) -> Vec<u8> {
150 #[cfg(target_arch = "x86_64")]
151 {
152 if self.features.avx2 {
153 unsafe { self.digest_avx2(data) }
155 } else {
156 self.digest_scalar(data)
157 }
158 }
159
160 #[cfg(target_arch = "aarch64")]
161 {
162 if self.features.neon {
163 self.digest_neon(data)
164 } else {
165 self.digest_scalar(data)
166 }
167 }
168
169 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
170 {
171 self.digest_scalar(data)
172 }
173 }
174
175 #[inline]
176 fn code(&self) -> Code {
177 Code::Sha2_256
178 }
179
180 #[inline]
181 fn name(&self) -> &'static str {
182 "sha2-256"
183 }
184
185 #[inline]
186 fn is_simd_enabled(&self) -> bool {
187 self.features.avx2 || self.features.neon
188 }
189}
190
191pub struct Sha512Engine {
196 features: CpuFeatures,
197}
198
199impl Sha512Engine {
200 pub fn new() -> Self {
202 Self {
203 features: CpuFeatures::detect(),
204 }
205 }
206
207 fn digest_scalar(&self, data: &[u8]) -> Vec<u8> {
209 let mut hasher = Sha512Impl::new();
210 hasher.update(data);
211 hasher.finalize().to_vec()
212 }
213}
214
215impl Default for Sha512Engine {
216 fn default() -> Self {
217 Self::new()
218 }
219}
220
221impl HashEngine for Sha512Engine {
222 fn digest(&self, data: &[u8]) -> Vec<u8> {
223 self.digest_scalar(data)
225 }
226
227 #[inline]
228 fn code(&self) -> Code {
229 Code::Sha2_512
230 }
231
232 #[inline]
233 fn name(&self) -> &'static str {
234 "sha2-512"
235 }
236
237 #[inline]
238 fn is_simd_enabled(&self) -> bool {
239 self.features.avx2 || self.features.neon
240 }
241}
242
243pub struct Sha3_256Engine;
248
249impl Sha3_256Engine {
250 pub fn new() -> Self {
252 Self
253 }
254
255 fn digest_impl(&self, data: &[u8]) -> Vec<u8> {
259 let mut hasher = Sha3_256Impl::new();
260 hasher.update(data);
261 hasher.finalize().to_vec()
262 }
263}
264
265impl Default for Sha3_256Engine {
266 fn default() -> Self {
267 Self::new()
268 }
269}
270
271impl HashEngine for Sha3_256Engine {
272 fn digest(&self, data: &[u8]) -> Vec<u8> {
273 self.digest_impl(data)
274 }
275
276 #[inline]
277 fn code(&self) -> Code {
278 Code::Sha3_256
279 }
280
281 #[inline]
282 fn name(&self) -> &'static str {
283 "sha3-256"
284 }
285
286 #[inline]
287 fn is_simd_enabled(&self) -> bool {
288 false
291 }
292}
293
294pub struct Sha3_512Engine;
299
300impl Sha3_512Engine {
301 pub fn new() -> Self {
303 Self
304 }
305
306 fn digest_impl(&self, data: &[u8]) -> Vec<u8> {
308 let mut hasher = Sha3_512Impl::new();
309 hasher.update(data);
310 hasher.finalize().to_vec()
311 }
312}
313
314impl Default for Sha3_512Engine {
315 fn default() -> Self {
316 Self::new()
317 }
318}
319
320impl HashEngine for Sha3_512Engine {
321 fn digest(&self, data: &[u8]) -> Vec<u8> {
322 self.digest_impl(data)
323 }
324
325 #[inline]
326 fn code(&self) -> Code {
327 Code::Sha3_512
328 }
329
330 #[inline]
331 fn name(&self) -> &'static str {
332 "sha3-512"
333 }
334
335 #[inline]
336 fn is_simd_enabled(&self) -> bool {
337 false
340 }
341}
342
343pub struct Blake3Engine;
354
355impl Blake3Engine {
356 pub fn new() -> Self {
358 Self
359 }
360}
361
362impl Default for Blake3Engine {
363 fn default() -> Self {
364 Self::new()
365 }
366}
367
368impl HashEngine for Blake3Engine {
369 fn digest(&self, data: &[u8]) -> Vec<u8> {
370 let mut hasher = blake3::Hasher::new();
372 hasher.update(data);
373 hasher.finalize().as_bytes().to_vec()
374 }
375
376 #[inline]
377 fn code(&self) -> Code {
378 Code::Blake3_256
380 }
381
382 #[inline]
383 fn name(&self) -> &'static str {
384 "blake3"
385 }
386
387 #[inline]
388 fn is_simd_enabled(&self) -> bool {
389 true
391 }
392}
393
394#[derive(Debug, Clone, Copy, Default)]
405pub struct Blake2b256Engine;
406
407impl Blake2b256Engine {
408 pub fn new() -> Self {
410 Self
411 }
412}
413
414impl HashEngine for Blake2b256Engine {
415 fn digest(&self, data: &[u8]) -> Vec<u8> {
416 use blake2::digest::FixedOutput;
417
418 let mut hasher = Blake2b512Impl::new();
420 Blake2Digest::update(&mut hasher, data);
421 let result = hasher.finalize_fixed();
422 result[..32].to_vec()
423 }
424
425 #[inline]
426 fn code(&self) -> Code {
427 Code::Blake2b256
428 }
429
430 #[inline]
431 fn name(&self) -> &'static str {
432 "blake2b-256"
433 }
434
435 #[inline]
436 fn is_simd_enabled(&self) -> bool {
437 true
439 }
440}
441
442#[derive(Debug, Clone, Copy, Default)]
449pub struct Blake2b512Engine;
450
451impl Blake2b512Engine {
452 pub fn new() -> Self {
454 Self
455 }
456}
457
458impl HashEngine for Blake2b512Engine {
459 fn digest(&self, data: &[u8]) -> Vec<u8> {
460 let mut hasher = Blake2b512Impl::new();
461 Blake2Digest::update(&mut hasher, data);
462 hasher.finalize().to_vec()
463 }
464
465 #[inline]
466 fn code(&self) -> Code {
467 Code::Blake2b512
468 }
469
470 #[inline]
471 fn name(&self) -> &'static str {
472 "blake2b-512"
473 }
474
475 #[inline]
476 fn is_simd_enabled(&self) -> bool {
477 true
479 }
480}
481
482#[derive(Debug, Clone, Copy, Default)]
490pub struct Blake2s256Engine;
491
492impl Blake2s256Engine {
493 pub fn new() -> Self {
495 Self
496 }
497}
498
499impl HashEngine for Blake2s256Engine {
500 fn digest(&self, data: &[u8]) -> Vec<u8> {
501 let mut hasher = Blake2s256Impl::new();
502 Blake2Digest::update(&mut hasher, data);
503 hasher.finalize().to_vec()
504 }
505
506 #[inline]
507 fn code(&self) -> Code {
508 Code::Blake2s256
509 }
510
511 #[inline]
512 fn name(&self) -> &'static str {
513 "blake2s-256"
514 }
515
516 #[inline]
517 fn is_simd_enabled(&self) -> bool {
518 true
520 }
521}
522
523pub struct HashRegistry {
525 algorithms: std::collections::HashMap<u64, Arc<dyn HashEngine>>,
526}
527
528impl HashRegistry {
529 pub fn new() -> Self {
531 let mut registry = Self {
532 algorithms: std::collections::HashMap::new(),
533 };
534
535 registry.register(Arc::new(Sha256Engine::new()));
537 registry.register(Arc::new(Sha512Engine::new()));
538 registry.register(Arc::new(Sha3_256Engine::new()));
539 registry.register(Arc::new(Sha3_512Engine::new()));
540 registry.register(Arc::new(Blake2b256Engine::new()));
541 registry.register(Arc::new(Blake2b512Engine::new()));
542 registry.register(Arc::new(Blake2s256Engine::new()));
543 registry.register(Arc::new(Blake3Engine::new()));
544
545 registry
546 }
547
548 pub fn register(&mut self, engine: Arc<dyn HashEngine>) {
550 let code_u64 = engine.code() as u64;
551 self.algorithms.insert(code_u64, engine);
552 }
553
554 pub fn get(&self, code: Code) -> Option<Arc<dyn HashEngine>> {
556 let code_u64 = code as u64;
557 self.algorithms.get(&code_u64).cloned()
558 }
559
560 pub fn digest(&self, code: Code, data: &[u8]) -> Result<Vec<u8>> {
562 let engine = self.get(code).ok_or_else(|| {
563 crate::error::Error::InvalidInput(format!("Unsupported hash algorithm: {:?}", code))
564 })?;
565 Ok(engine.digest(data))
566 }
567}
568
569impl Default for HashRegistry {
570 fn default() -> Self {
571 Self::new()
572 }
573}
574
575static HASH_REGISTRY: once_cell::sync::Lazy<HashRegistry> =
577 once_cell::sync::Lazy::new(HashRegistry::new);
578
579pub fn global_hash_registry() -> &'static HashRegistry {
581 &HASH_REGISTRY
582}
583
584#[cfg(test)]
585mod tests {
586 use super::*;
587
588 #[test]
589 fn test_cpu_feature_detection() {
590 let features = CpuFeatures::detect();
591
592 #[cfg(target_arch = "x86_64")]
593 {
594 assert!(!features.neon);
596 }
597
598 #[cfg(target_arch = "aarch64")]
599 {
600 assert!(features.neon);
601 assert!(!features.avx2);
602 }
603 }
604
605 #[test]
606 fn test_sha256_engine() {
607 let engine = Sha256Engine::new();
608 let hash = engine.digest(b"hello world");
609
610 assert_eq!(hash.len(), 32);
612
613 let hash2 = engine.digest(b"hello world");
615 assert_eq!(hash, hash2);
616
617 let hash3 = engine.digest(b"hello mars");
619 assert_ne!(hash, hash3);
620 }
621
622 #[test]
623 fn test_sha3_256_engine() {
624 let engine = Sha3_256Engine::new();
625 let hash = engine.digest(b"test data");
626
627 assert_eq!(hash.len(), 32);
629
630 let hash2 = engine.digest(b"test data");
632 assert_eq!(hash, hash2);
633 }
634
635 #[test]
636 fn test_hash_registry() {
637 let registry = HashRegistry::new();
638
639 let sha256 = registry.get(Code::Sha2_256);
641 assert!(sha256.is_some());
642
643 let sha512 = registry.get(Code::Sha2_512);
645 assert!(sha512.is_some());
646
647 let sha3_256 = registry.get(Code::Sha3_256);
649 assert!(sha3_256.is_some());
650
651 let sha3_512 = registry.get(Code::Sha3_512);
653 assert!(sha3_512.is_some());
654 }
655
656 #[test]
657 fn test_registry_digest() {
658 let registry = HashRegistry::new();
659
660 let hash = registry.digest(Code::Sha2_256, b"test").unwrap();
661 assert_eq!(hash.len(), 32);
662 }
663
664 #[test]
665 fn test_global_registry() {
666 let registry = global_hash_registry();
667
668 let hash = registry.digest(Code::Sha2_256, b"global test").unwrap();
669 assert_eq!(hash.len(), 32);
670 }
671
672 #[test]
673 fn test_sha256_deterministic() {
674 let engine = Sha256Engine::new();
675
676 for size in [0, 1, 64, 256, 1024, 4096] {
678 let data = vec![42u8; size];
679 let hash1 = engine.digest(&data);
680 let hash2 = engine.digest(&data);
681 assert_eq!(hash1, hash2, "Failed for size {}", size);
682 }
683 }
684
685 #[test]
686 fn test_sha512_engine() {
687 let engine = Sha512Engine::new();
688 let hash = engine.digest(b"hello world");
689
690 assert_eq!(hash.len(), 64);
692
693 let hash2 = engine.digest(b"hello world");
695 assert_eq!(hash, hash2);
696
697 let hash3 = engine.digest(b"hello mars");
699 assert_ne!(hash, hash3);
700 }
701
702 #[test]
703 fn test_sha3_512_engine() {
704 let engine = Sha3_512Engine::new();
705 let hash = engine.digest(b"hello world");
706
707 assert_eq!(hash.len(), 64);
709
710 let hash2 = engine.digest(b"hello world");
712 assert_eq!(hash, hash2);
713
714 let hash3 = engine.digest(b"hello mars");
716 assert_ne!(hash, hash3);
717 }
718
719 #[test]
720 fn test_sha512_deterministic() {
721 let engine = Sha512Engine::new();
722
723 for size in [0, 1, 64, 256, 1024, 4096] {
725 let data = vec![42u8; size];
726 let hash1 = engine.digest(&data);
727 let hash2 = engine.digest(&data);
728 assert_eq!(hash1, hash2, "Failed for size {}", size);
729 }
730 }
731
732 #[test]
733 fn test_sha3_512_deterministic() {
734 let engine = Sha3_512Engine::new();
735
736 for size in [0, 1, 64, 256, 1024, 4096] {
738 let data = vec![42u8; size];
739 let hash1 = engine.digest(&data);
740 let hash2 = engine.digest(&data);
741 assert_eq!(hash1, hash2, "Failed for size {}", size);
742 }
743 }
744
745 #[test]
746 fn test_sha512_vs_sha256() {
747 let sha512 = Sha512Engine::new();
748 let sha256 = Sha256Engine::new();
749
750 let data = b"test data";
751 let hash512 = sha512.digest(data);
752 let hash256 = sha256.digest(data);
753
754 assert_eq!(hash512.len(), 64);
756 assert_eq!(hash256.len(), 32);
757
758 assert_ne!(&hash512[..32], &hash256[..]);
760 }
761
762 #[test]
763 fn test_sha3_512_vs_sha3_256() {
764 let sha3_512 = Sha3_512Engine::new();
765 let sha3_256 = Sha3_256Engine::new();
766
767 let data = b"test data";
768 let hash512 = sha3_512.digest(data);
769 let hash256 = sha3_256.digest(data);
770
771 assert_eq!(hash512.len(), 64);
773 assert_eq!(hash256.len(), 32);
774
775 assert_ne!(&hash512[..32], &hash256[..]);
777 }
778
779 #[test]
780 fn test_blake3_engine() {
781 let engine = Blake3Engine::new();
782 let hash = engine.digest(b"hello world");
783
784 assert_eq!(hash.len(), 32);
786
787 let hash2 = engine.digest(b"hello world");
789 assert_eq!(hash, hash2);
790
791 let hash3 = engine.digest(b"hello mars");
793 assert_ne!(hash, hash3);
794 }
795
796 #[test]
797 fn test_blake3_deterministic() {
798 let engine = Blake3Engine::new();
799
800 for size in [0, 1, 64, 256, 1024, 4096] {
802 let data = vec![42u8; size];
803 let hash1 = engine.digest(&data);
804 let hash2 = engine.digest(&data);
805 assert_eq!(hash1, hash2, "Failed for size {}", size);
806 }
807 }
808
809 #[test]
810 fn test_blake3_simd_enabled() {
811 let engine = Blake3Engine::new();
812 assert!(engine.is_simd_enabled());
814 }
815
816 #[test]
817 fn test_blake3_vs_sha256() {
818 let blake3 = Blake3Engine::new();
819 let sha256 = Sha256Engine::new();
820
821 let data = b"test data for comparison";
822
823 let blake3_hash = blake3.digest(data);
824 let sha256_hash = sha256.digest(data);
825
826 assert_eq!(blake3_hash.len(), 32);
828 assert_eq!(sha256_hash.len(), 32);
829
830 assert_ne!(blake3_hash, sha256_hash);
832 }
833
834 #[test]
835 fn test_blake3_empty_input() {
836 let engine = Blake3Engine::new();
837 let hash = engine.digest(b"");
838
839 assert_eq!(hash.len(), 32);
841
842 let hash2 = engine.digest(b"");
844 assert_eq!(hash, hash2);
845 }
846
847 #[test]
848 fn test_blake2b256_engine() {
849 let engine = Blake2b256Engine::new();
850 let hash = engine.digest(b"hello world");
851
852 assert_eq!(hash.len(), 32);
854
855 let hash2 = engine.digest(b"hello world");
857 assert_eq!(hash, hash2);
858
859 let hash3 = engine.digest(b"hello mars");
861 assert_ne!(hash, hash3);
862 }
863
864 #[test]
865 fn test_blake2b512_engine() {
866 let engine = Blake2b512Engine::new();
867 let hash = engine.digest(b"hello world");
868
869 assert_eq!(hash.len(), 64);
871
872 let hash2 = engine.digest(b"hello world");
874 assert_eq!(hash, hash2);
875
876 let hash3 = engine.digest(b"hello mars");
878 assert_ne!(hash, hash3);
879 }
880
881 #[test]
882 fn test_blake2s256_engine() {
883 let engine = Blake2s256Engine::new();
884 let hash = engine.digest(b"test data");
885
886 assert_eq!(hash.len(), 32);
888
889 let hash2 = engine.digest(b"test data");
891 assert_eq!(hash, hash2);
892 }
893
894 #[test]
895 fn test_blake2b256_deterministic() {
896 let engine = Blake2b256Engine::new();
897
898 for size in [0, 1, 64, 256, 1024, 4096] {
900 let data = vec![42u8; size];
901 let hash1 = engine.digest(&data);
902 let hash2 = engine.digest(&data);
903 assert_eq!(hash1, hash2, "Failed for size {}", size);
904 }
905 }
906
907 #[test]
908 fn test_blake2b512_deterministic() {
909 let engine = Blake2b512Engine::new();
910
911 for size in [0, 1, 64, 256, 1024, 4096] {
913 let data = vec![42u8; size];
914 let hash1 = engine.digest(&data);
915 let hash2 = engine.digest(&data);
916 assert_eq!(hash1, hash2, "Failed for size {}", size);
917 assert_eq!(hash1.len(), 64);
918 }
919 }
920
921 #[test]
922 fn test_blake2s256_deterministic() {
923 let engine = Blake2s256Engine::new();
924
925 for size in [0, 1, 64, 256, 1024] {
927 let data = vec![42u8; size];
928 let hash1 = engine.digest(&data);
929 let hash2 = engine.digest(&data);
930 assert_eq!(hash1, hash2, "Failed for size {}", size);
931 }
932 }
933
934 #[test]
935 fn test_blake2b_vs_blake2s() {
936 let blake2b = Blake2b256Engine::new();
937 let blake2s = Blake2s256Engine::new();
938
939 let data = b"test data for comparison";
940
941 let blake2b_hash = blake2b.digest(data);
942 let blake2s_hash = blake2s.digest(data);
943
944 assert_eq!(blake2b_hash.len(), 32);
946 assert_eq!(blake2s_hash.len(), 32);
947
948 assert_ne!(blake2b_hash, blake2s_hash);
950 }
951
952 #[test]
953 fn test_blake2_empty_input() {
954 let blake2b256 = Blake2b256Engine::new();
955 let blake2b512 = Blake2b512Engine::new();
956 let blake2s = Blake2s256Engine::new();
957
958 let hash256 = blake2b256.digest(b"");
959 let hash512 = blake2b512.digest(b"");
960 let hashs = blake2s.digest(b"");
961
962 assert_eq!(hash256.len(), 32);
963 assert_eq!(hash512.len(), 64);
964 assert_eq!(hashs.len(), 32);
965
966 assert_eq!(hash256, blake2b256.digest(b""));
968 assert_eq!(hash512, blake2b512.digest(b""));
969 assert_eq!(hashs, blake2s.digest(b""));
970 }
971
972 #[test]
973 fn test_blake2_simd_enabled() {
974 let blake2b256 = Blake2b256Engine::new();
975 let blake2b512 = Blake2b512Engine::new();
976 let blake2s = Blake2s256Engine::new();
977
978 assert!(blake2b256.is_simd_enabled());
980 assert!(blake2b512.is_simd_enabled());
981 assert!(blake2s.is_simd_enabled());
982 }
983
984 #[test]
985 fn test_hash_registry_blake2() {
986 let registry = HashRegistry::new();
987
988 let blake2b256 = registry.get(Code::Blake2b256);
990 assert!(blake2b256.is_some());
991
992 let blake2b512 = registry.get(Code::Blake2b512);
994 assert!(blake2b512.is_some());
995
996 let blake2s256 = registry.get(Code::Blake2s256);
998 assert!(blake2s256.is_some());
999 }
1000
1001 #[test]
1002 fn test_registry_digest_blake2() {
1003 let registry = HashRegistry::new();
1004
1005 let hash256 = registry.digest(Code::Blake2b256, b"test").unwrap();
1006 assert_eq!(hash256.len(), 32);
1007
1008 let hash512 = registry.digest(Code::Blake2b512, b"test").unwrap();
1009 assert_eq!(hash512.len(), 64);
1010
1011 let hashs = registry.digest(Code::Blake2s256, b"test").unwrap();
1012 assert_eq!(hashs.len(), 32);
1013 }
1014
1015 #[test]
1016 fn test_blake2_names() {
1017 assert_eq!(Blake2b256Engine::new().name(), "blake2b-256");
1018 assert_eq!(Blake2b512Engine::new().name(), "blake2b-512");
1019 assert_eq!(Blake2s256Engine::new().name(), "blake2s-256");
1020 }
1021
1022 #[test]
1023 fn test_blake2_codes() {
1024 assert_eq!(Blake2b256Engine::new().code(), Code::Blake2b256);
1025 assert_eq!(Blake2b512Engine::new().code(), Code::Blake2b512);
1026 assert_eq!(Blake2s256Engine::new().code(), Code::Blake2s256);
1027 }
1028}