1#![forbid(unsafe_code)]
2#![no_std]
3
4extern crate alloc;
19
20#[cfg(feature = "std")]
21extern crate std;
22
23mod hash_builder;
24mod parallelhash;
25mod xof;
26pub use hash_builder::{DynStreamingHash, HashAlgorithm, HashBuilder, StreamingHashBuilder};
27pub use parallelhash::{
28 parallel_hash128, parallel_hash128_xof, parallel_hash256, parallel_hash256_xof,
29 ParallelHash128, ParallelHash256,
30};
31pub use xof::{
32 blake2b_keyed, cshake128, cshake256, shake128, shake128_start, shake256, shake256_start,
33 tuple_hash128, tuple_hash256, Blake2bKeyed, Shake128Reader, Shake256Reader,
34};
35
36#[cfg(feature = "std")]
37pub use xof::{hash_file_blake3, hash_file_sha256, hash_file_sha512};
38
39use alloc::vec::Vec;
40
41use digest::Digest;
42use oxicrypto_core::{CryptoError, Hash, StreamingHash};
43
44pub struct DigestStreamingAdapter<D: Digest + Default> {
51 inner: D,
52}
53
54impl<D: Digest + Default> DigestStreamingAdapter<D> {
55 pub fn new() -> Self {
57 Self {
58 inner: D::default(),
59 }
60 }
61}
62
63impl<D: Digest + Default> Default for DigestStreamingAdapter<D> {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl<D: Digest + Default + Clone> Clone for DigestStreamingAdapter<D> {
70 fn clone(&self) -> Self {
71 Self {
72 inner: self.inner.clone(),
73 }
74 }
75}
76
77impl<D: Digest + Default + Send> StreamingHash for DigestStreamingAdapter<D> {
78 fn update(&mut self, data: &[u8]) {
79 Digest::update(&mut self.inner, data);
80 }
81
82 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
83 let result = Digest::finalize(self.inner);
84 if out.len() < result.len() {
85 return Err(CryptoError::BufferTooSmall);
86 }
87 out[..result.len()].copy_from_slice(&result);
88 Ok(())
89 }
90
91 fn reset(&mut self) {
92 self.inner = D::default();
93 }
94}
95
96#[derive(Debug, Default, Clone, Copy)]
100pub struct Sha256;
101
102#[derive(Debug, Default, Clone, Copy)]
104pub struct Sha384;
105
106#[derive(Debug, Default, Clone, Copy)]
108pub struct Sha512;
109
110#[derive(Debug, Default, Clone, Copy)]
112pub struct Sha512_256;
113
114impl Hash for Sha256 {
115 fn name(&self) -> &'static str {
116 "SHA-256"
117 }
118 fn output_len(&self) -> usize {
119 32
120 }
121 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
122 if out.len() < 32 {
123 return Err(CryptoError::BufferTooSmall);
124 }
125 let digest = sha2::Sha256::digest(msg);
126 out[..32].copy_from_slice(&digest);
127 Ok(())
128 }
129}
130
131impl Hash for Sha384 {
132 fn name(&self) -> &'static str {
133 "SHA-384"
134 }
135 fn output_len(&self) -> usize {
136 48
137 }
138 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
139 if out.len() < 48 {
140 return Err(CryptoError::BufferTooSmall);
141 }
142 let digest = sha2::Sha384::digest(msg);
143 out[..48].copy_from_slice(&digest);
144 Ok(())
145 }
146}
147
148impl Hash for Sha512 {
149 fn name(&self) -> &'static str {
150 "SHA-512"
151 }
152 fn output_len(&self) -> usize {
153 64
154 }
155 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
156 if out.len() < 64 {
157 return Err(CryptoError::BufferTooSmall);
158 }
159 let digest = sha2::Sha512::digest(msg);
160 out[..64].copy_from_slice(&digest);
161 Ok(())
162 }
163}
164
165impl Hash for Sha512_256 {
166 fn name(&self) -> &'static str {
167 "SHA-512/256"
168 }
169 fn output_len(&self) -> usize {
170 32
171 }
172 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
173 if out.len() < 32 {
174 return Err(CryptoError::BufferTooSmall);
175 }
176 let digest = sha2::Sha512_256::digest(msg);
177 out[..32].copy_from_slice(&digest);
178 Ok(())
179 }
180}
181
182impl Sha256 {
185 pub const DIGEST_LEN: usize = 32;
187 pub const BLOCK_SIZE: usize = 64;
189}
190
191impl Sha384 {
192 pub const DIGEST_LEN: usize = 48;
194 pub const BLOCK_SIZE: usize = 128;
196}
197
198impl Sha512 {
199 pub const DIGEST_LEN: usize = 64;
201 pub const BLOCK_SIZE: usize = 128;
203}
204
205impl Sha512_256 {
206 pub const DIGEST_LEN: usize = 32;
208 pub const BLOCK_SIZE: usize = 128;
210}
211
212pub type Sha256Streaming = DigestStreamingAdapter<sha2::Sha256>;
216pub type Sha384Streaming = DigestStreamingAdapter<sha2::Sha384>;
218pub type Sha512Streaming = DigestStreamingAdapter<sha2::Sha512>;
220pub type Sha512_256Streaming = DigestStreamingAdapter<sha2::Sha512_256>;
222
223#[derive(Debug, Default, Clone, Copy)]
227pub struct Sha3_256;
228
229#[derive(Debug, Default, Clone, Copy)]
231pub struct Sha3_384;
232
233#[derive(Debug, Default, Clone, Copy)]
235pub struct Sha3_512;
236
237impl Hash for Sha3_256 {
238 fn name(&self) -> &'static str {
239 "SHA3-256"
240 }
241 fn output_len(&self) -> usize {
242 32
243 }
244 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
245 if out.len() < 32 {
246 return Err(CryptoError::BufferTooSmall);
247 }
248 let digest = sha3::Sha3_256::digest(msg);
249 out[..32].copy_from_slice(&digest);
250 Ok(())
251 }
252}
253
254impl Hash for Sha3_384 {
255 fn name(&self) -> &'static str {
256 "SHA3-384"
257 }
258 fn output_len(&self) -> usize {
259 48
260 }
261 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
262 if out.len() < 48 {
263 return Err(CryptoError::BufferTooSmall);
264 }
265 let digest = sha3::Sha3_384::digest(msg);
266 out[..48].copy_from_slice(&digest);
267 Ok(())
268 }
269}
270
271impl Hash for Sha3_512 {
272 fn name(&self) -> &'static str {
273 "SHA3-512"
274 }
275 fn output_len(&self) -> usize {
276 64
277 }
278 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
279 if out.len() < 64 {
280 return Err(CryptoError::BufferTooSmall);
281 }
282 let digest = sha3::Sha3_512::digest(msg);
283 out[..64].copy_from_slice(&digest);
284 Ok(())
285 }
286}
287
288impl Sha3_256 {
291 pub const DIGEST_LEN: usize = 32;
293 pub const BLOCK_SIZE: usize = 136;
295}
296
297impl Sha3_384 {
298 pub const DIGEST_LEN: usize = 48;
300 pub const BLOCK_SIZE: usize = 104;
302}
303
304impl Sha3_512 {
305 pub const DIGEST_LEN: usize = 64;
307 pub const BLOCK_SIZE: usize = 72;
309}
310
311pub type Sha3_256Streaming = DigestStreamingAdapter<sha3::Sha3_256>;
315pub type Sha3_384Streaming = DigestStreamingAdapter<sha3::Sha3_384>;
317pub type Sha3_512Streaming = DigestStreamingAdapter<sha3::Sha3_512>;
319
320#[derive(Debug, Default, Clone, Copy)]
324pub struct Blake2b256;
325
326#[derive(Debug, Default, Clone, Copy)]
328pub struct Blake2b512;
329
330#[derive(Debug, Default, Clone, Copy)]
332pub struct Blake2s256;
333
334impl Hash for Blake2b256 {
335 fn name(&self) -> &'static str {
336 "BLAKE2b-256"
337 }
338 fn output_len(&self) -> usize {
339 32
340 }
341 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
342 if out.len() < 32 {
343 return Err(CryptoError::BufferTooSmall);
344 }
345 let result = blake2::Blake2b256::digest(msg);
346 out[..32].copy_from_slice(&result);
347 Ok(())
348 }
349}
350
351impl Hash for Blake2b512 {
352 fn name(&self) -> &'static str {
353 "BLAKE2b-512"
354 }
355 fn output_len(&self) -> usize {
356 64
357 }
358 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
359 if out.len() < 64 {
360 return Err(CryptoError::BufferTooSmall);
361 }
362 let result = blake2::Blake2b512::digest(msg);
363 out[..64].copy_from_slice(&result);
364 Ok(())
365 }
366}
367
368impl Hash for Blake2s256 {
369 fn name(&self) -> &'static str {
370 "BLAKE2s-256"
371 }
372 fn output_len(&self) -> usize {
373 32
374 }
375 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
376 if out.len() < 32 {
377 return Err(CryptoError::BufferTooSmall);
378 }
379 let result = blake2::Blake2s256::digest(msg);
380 out[..32].copy_from_slice(&result);
381 Ok(())
382 }
383}
384
385impl Blake2b256 {
388 pub const DIGEST_LEN: usize = 32;
390 pub const BLOCK_SIZE: usize = 128;
392}
393
394impl Blake2b512 {
395 pub const DIGEST_LEN: usize = 64;
397 pub const BLOCK_SIZE: usize = 128;
399}
400
401impl Blake2s256 {
402 pub const DIGEST_LEN: usize = 32;
404 pub const BLOCK_SIZE: usize = 64;
406}
407
408pub type Blake2b256Streaming = DigestStreamingAdapter<blake2::Blake2b256>;
412pub type Blake2b512Streaming = DigestStreamingAdapter<blake2::Blake2b512>;
414pub type Blake2s256Streaming = DigestStreamingAdapter<blake2::Blake2s256>;
416
417#[derive(Debug, Default, Clone, Copy)]
421pub struct Blake3;
422
423impl Hash for Blake3 {
424 fn name(&self) -> &'static str {
425 "BLAKE3"
426 }
427 fn output_len(&self) -> usize {
428 32
429 }
430 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
431 if out.len() < 32 {
432 return Err(CryptoError::BufferTooSmall);
433 }
434 let digest = blake3::hash(msg);
435 out[..32].copy_from_slice(digest.as_bytes());
436 Ok(())
437 }
438}
439
440impl Blake3 {
441 pub const DIGEST_LEN: usize = 32;
443 pub const BLOCK_SIZE: usize = 64;
445}
446
447pub struct Blake3Streaming {
453 inner: blake3::Hasher,
454}
455
456impl Blake3Streaming {
457 pub fn new() -> Self {
459 Self {
460 inner: blake3::Hasher::new(),
461 }
462 }
463}
464
465impl Default for Blake3Streaming {
466 fn default() -> Self {
467 Self::new()
468 }
469}
470
471impl Clone for Blake3Streaming {
472 fn clone(&self) -> Self {
473 Self {
474 inner: self.inner.clone(),
475 }
476 }
477}
478
479impl StreamingHash for Blake3Streaming {
480 fn update(&mut self, data: &[u8]) {
481 self.inner.update(data);
482 }
483
484 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
485 if out.len() < 32 {
486 return Err(CryptoError::BufferTooSmall);
487 }
488 let result = self.inner.finalize();
489 out[..32].copy_from_slice(result.as_bytes());
490 Ok(())
491 }
492
493 fn reset(&mut self) {
494 self.inner.reset();
495 }
496}
497
498#[cfg(feature = "std")]
503impl<D: Digest + Default + Send> std::io::Write for DigestStreamingAdapter<D> {
504 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
505 self.update(buf);
506 Ok(buf.len())
507 }
508
509 fn flush(&mut self) -> std::io::Result<()> {
510 Ok(())
511 }
512}
513
514#[cfg(feature = "std")]
517impl std::io::Write for Blake3Streaming {
518 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
519 self.update(buf);
520 Ok(buf.len())
521 }
522
523 fn flush(&mut self) -> std::io::Result<()> {
524 Ok(())
525 }
526}
527
528#[cfg(feature = "std")]
534pub fn sha256_hex(msg: &[u8]) -> std::string::String {
535 let digest = sha2::Sha256::digest(msg);
536 bytes_to_hex(digest.as_ref())
537}
538
539#[cfg(feature = "std")]
541pub fn sha384_hex(msg: &[u8]) -> std::string::String {
542 let digest = sha2::Sha384::digest(msg);
543 bytes_to_hex(digest.as_ref())
544}
545
546#[cfg(feature = "std")]
548pub fn sha512_hex(msg: &[u8]) -> std::string::String {
549 let digest = sha2::Sha512::digest(msg);
550 bytes_to_hex(digest.as_ref())
551}
552
553#[cfg(feature = "std")]
555pub fn sha3_256_hex(msg: &[u8]) -> std::string::String {
556 let digest = sha3::Sha3_256::digest(msg);
557 bytes_to_hex(digest.as_ref())
558}
559
560#[cfg(feature = "std")]
562pub fn blake3_hex(msg: &[u8]) -> std::string::String {
563 let digest = blake3::hash(msg);
564 bytes_to_hex(digest.as_bytes())
565}
566
567#[cfg(feature = "std")]
569fn bytes_to_hex(bytes: &[u8]) -> std::string::String {
570 bytes.iter().fold(
571 std::string::String::with_capacity(bytes.len() * 2),
572 |mut s, b| {
573 let _ = std::fmt::write(&mut s, format_args!("{b:02x}"));
574 s
575 },
576 )
577}
578
579pub struct Blake3Keyed {
586 key: [u8; 32],
587}
588
589impl Blake3Keyed {
590 pub fn new(key: [u8; 32]) -> Self {
592 Self { key }
593 }
594
595 pub fn hash(&self, msg: &[u8]) -> [u8; 32] {
597 *blake3::keyed_hash(&self.key, msg).as_bytes()
598 }
599}
600
601pub fn blake3_keyed_hash(key: &[u8; 32], msg: &[u8]) -> [u8; 32] {
605 *blake3::keyed_hash(key, msg).as_bytes()
606}
607
608pub fn blake3_derive_key(context: &str, key_material: &[u8]) -> [u8; 32] {
616 blake3::derive_key(context, key_material)
617}
618
619pub fn blake3_xof(msg: &[u8], output_len: usize) -> Vec<u8> {
627 let mut out = alloc::vec![0u8; output_len];
628 let mut reader = blake3::Hasher::new().update(msg).finalize_xof();
629 reader.fill(&mut out);
630 out
631}
632
633#[cfg(test)]
636mod tests {
637 use super::*;
638
639 fn hex_decode(s: &str) -> Vec<u8> {
640 (0..s.len())
641 .step_by(2)
642 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid hex"))
643 .collect()
644 }
645
646 #[test]
649 fn sha256_empty() {
650 let hasher = Sha256;
651 let result = hasher.hash_to_vec(b"").unwrap();
652 let expected =
653 hex_decode("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
654 assert_eq!(result, expected, "SHA-256 of empty string mismatch");
655 }
656
657 #[test]
658 fn sha256_abc() {
659 let hasher = Sha256;
660 let result = hasher.hash_to_vec(b"abc").unwrap();
661 let expected =
663 hex_decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
664 assert_eq!(result, expected, "SHA-256 of 'abc' mismatch");
665 }
666
667 #[test]
668 fn sha384_abc() {
669 let hasher = Sha384;
670 let result = hasher.hash_to_vec(b"abc").unwrap();
671 assert_eq!(result.len(), 48);
672 }
673
674 #[test]
675 fn sha512_abc() {
676 let hasher = Sha512;
677 let result = hasher.hash_to_vec(b"abc").unwrap();
678 assert_eq!(result.len(), 64);
679 }
680
681 #[test]
682 fn sha3_256_output_len() {
683 let hasher = Sha3_256;
684 assert_eq!(hasher.output_len(), 32);
685 let result = hasher.hash_to_vec(b"abc").unwrap();
686 assert_eq!(result.len(), 32);
687 }
688
689 #[test]
690 fn sha3_384_output_len() {
691 let hasher = Sha3_384;
692 assert_eq!(hasher.output_len(), 48);
693 let result = hasher.hash_to_vec(b"abc").unwrap();
694 assert_eq!(result.len(), 48);
695 }
696
697 #[test]
698 fn sha3_512_output_len() {
699 let hasher = Sha3_512;
700 assert_eq!(hasher.output_len(), 64);
701 let result = hasher.hash_to_vec(b"abc").unwrap();
702 assert_eq!(result.len(), 64);
703 }
704
705 #[test]
706 fn blake3_abc() {
707 let hasher = Blake3;
708 let result = hasher.hash_to_vec(b"abc").unwrap();
709 let expected =
712 hex_decode("6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85");
713 assert_eq!(result, expected, "BLAKE3 of 'abc' mismatch");
714 }
715
716 #[test]
717 fn buffer_too_small_error() {
718 let hasher = Sha256;
719 let mut out = [0u8; 16];
720 let err = hasher.hash(b"test", &mut out).unwrap_err();
721 assert_eq!(err, CryptoError::BufferTooSmall);
722 }
723
724 #[test]
727 fn sha256_streaming_hello_world() {
728 let one_shot = Sha256.hash_to_vec(b"hello world").unwrap();
730
731 let mut streamer = Sha256Streaming::new();
732 StreamingHash::update(&mut streamer, b"hello");
733 StreamingHash::update(&mut streamer, b" world");
734 let mut buf = [0u8; 32];
735 StreamingHash::finalize(streamer, &mut buf).unwrap();
736
737 assert_eq!(buf.as_ref(), one_shot.as_slice());
738 }
739
740 #[test]
741 fn sha256_streaming_one_byte_chunks() {
742 let one_shot = Sha256.hash_to_vec(b"abc").unwrap();
744
745 let mut streamer = Sha256Streaming::new();
746 for byte in b"abc" {
747 StreamingHash::update(&mut streamer, core::slice::from_ref(byte));
748 }
749 let mut buf = [0u8; 32];
750 StreamingHash::finalize(streamer, &mut buf).unwrap();
751
752 assert_eq!(buf.as_ref(), one_shot.as_slice());
753 }
754
755 #[test]
756 fn sha256_streaming_reset() {
757 let expected = Sha256.hash_to_vec(b"world").unwrap();
759
760 let mut streamer = Sha256Streaming::new();
761 StreamingHash::update(&mut streamer, b"hello");
762 StreamingHash::reset(&mut streamer);
763 StreamingHash::update(&mut streamer, b"world");
764 let mut buf = [0u8; 32];
765 StreamingHash::finalize(streamer, &mut buf).unwrap();
766
767 assert_eq!(buf.as_ref(), expected.as_slice());
768 }
769
770 #[test]
771 fn sha256_streaming_buffer_too_small() {
772 let mut streamer = Sha256Streaming::new();
773 StreamingHash::update(&mut streamer, b"test");
774 let mut buf = [0u8; 16];
775 let err = StreamingHash::finalize(streamer, &mut buf).unwrap_err();
776 assert_eq!(err, CryptoError::BufferTooSmall);
777 }
778
779 #[test]
782 fn blake3_streaming_equivalence() {
783 let one_shot = Blake3.hash_to_vec(b"hello world").unwrap();
784
785 let mut streamer = Blake3Streaming::new();
786 StreamingHash::update(&mut streamer, b"hello");
787 StreamingHash::update(&mut streamer, b" world");
788 let mut buf = [0u8; 32];
789 StreamingHash::finalize(streamer, &mut buf).unwrap();
790
791 assert_eq!(buf.as_ref(), one_shot.as_slice());
792 }
793
794 #[test]
795 fn blake3_streaming_reset() {
796 let expected = Blake3.hash_to_vec(b"world").unwrap();
797
798 let mut streamer = Blake3Streaming::new();
799 StreamingHash::update(&mut streamer, b"hello");
800 StreamingHash::reset(&mut streamer);
801 StreamingHash::update(&mut streamer, b"world");
802 let mut buf = [0u8; 32];
803 StreamingHash::finalize(streamer, &mut buf).unwrap();
804
805 assert_eq!(buf.as_ref(), expected.as_slice());
806 }
807
808 #[test]
811 fn blake2b256_output_len() {
812 let hasher = Blake2b256;
813 assert_eq!(hasher.output_len(), 32);
814 let result = hasher.hash_to_vec(b"abc").unwrap();
815 assert_eq!(result.len(), 32);
816 }
817
818 #[test]
819 fn blake2b256_empty_nonzero() {
820 let result = Blake2b256.hash_to_vec(b"").unwrap();
822 assert_eq!(result.len(), 32);
823 assert!(
824 result.iter().any(|&b| b != 0),
825 "BLAKE2b-256 of empty should be non-zero"
826 );
827 }
828
829 #[test]
830 fn blake2b256_streaming_equivalence() {
831 let one_shot = Blake2b256.hash_to_vec(b"hello world").unwrap();
832
833 let mut streamer = Blake2b256Streaming::new();
834 StreamingHash::update(&mut streamer, b"hello");
835 StreamingHash::update(&mut streamer, b" world");
836 let mut buf = [0u8; 32];
837 StreamingHash::finalize(streamer, &mut buf).unwrap();
838
839 assert_eq!(buf.as_ref(), one_shot.as_slice());
840 }
841
842 #[test]
845 fn blake2b512_output_len() {
846 let hasher = Blake2b512;
847 assert_eq!(hasher.output_len(), 64);
848 let result = hasher.hash_to_vec(b"abc").unwrap();
849 assert_eq!(result.len(), 64);
850 }
851
852 #[test]
853 fn blake2b512_streaming_equivalence() {
854 let one_shot = Blake2b512.hash_to_vec(b"hello world").unwrap();
855
856 let mut streamer = Blake2b512Streaming::new();
857 StreamingHash::update(&mut streamer, b"hello");
858 StreamingHash::update(&mut streamer, b" world");
859 let mut buf = [0u8; 64];
860 StreamingHash::finalize(streamer, &mut buf).unwrap();
861
862 assert_eq!(buf.as_ref(), one_shot.as_slice());
863 }
864
865 #[test]
868 fn blake2s256_output_len() {
869 let hasher = Blake2s256;
870 assert_eq!(hasher.output_len(), 32);
871 let result = hasher.hash_to_vec(b"abc").unwrap();
872 assert_eq!(result.len(), 32);
873 }
874
875 #[test]
876 fn blake2s256_streaming_equivalence() {
877 let one_shot = Blake2s256.hash_to_vec(b"hello world").unwrap();
878
879 let mut streamer = Blake2s256Streaming::new();
880 StreamingHash::update(&mut streamer, b"hello");
881 StreamingHash::update(&mut streamer, b" world");
882 let mut buf = [0u8; 32];
883 StreamingHash::finalize(streamer, &mut buf).unwrap();
884
885 assert_eq!(buf.as_ref(), one_shot.as_slice());
886 }
887
888 #[test]
891 fn sha512_256_output_len() {
892 let hasher = Sha512_256;
893 assert_eq!(hasher.output_len(), 32);
894 let result = hasher.hash_to_vec(b"abc").unwrap();
895 assert_eq!(result.len(), 32);
896 }
897
898 #[test]
899 fn sha512_256_known_vector() {
900 let result = Sha512_256.hash_to_vec(b"abc").unwrap();
902 let expected =
903 hex_decode("53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23");
904 assert_eq!(result, expected, "SHA-512/256 of 'abc' mismatch");
905 }
906
907 #[test]
908 fn sha512_256_streaming_equivalence() {
909 let one_shot = Sha512_256.hash_to_vec(b"hello world").unwrap();
910
911 let mut streamer = Sha512_256Streaming::new();
912 StreamingHash::update(&mut streamer, b"hello");
913 StreamingHash::update(&mut streamer, b" world");
914 let mut buf = [0u8; 32];
915 StreamingHash::finalize(streamer, &mut buf).unwrap();
916
917 assert_eq!(buf.as_ref(), one_shot.as_slice());
918 }
919
920 #[test]
923 fn blake3_keyed_different_keys() {
924 let key1 = [1u8; 32];
925 let key2 = [2u8; 32];
926 let msg = b"same message";
927
928 let out1 = Blake3Keyed::new(key1).hash(msg);
929 let out2 = Blake3Keyed::new(key2).hash(msg);
930
931 assert_ne!(out1, out2, "Different keys must produce different outputs");
932 }
933
934 #[test]
935 fn blake3_keyed_different_messages() {
936 let key = [42u8; 32];
937 let out1 = Blake3Keyed::new(key).hash(b"message1");
938 let out2 = Blake3Keyed::new(key).hash(b"message2");
939
940 assert_ne!(
941 out1, out2,
942 "Different messages must produce different outputs"
943 );
944 }
945
946 #[test]
947 fn blake3_keyed_deterministic() {
948 let key = [7u8; 32];
949 let msg = b"deterministic";
950 let out1 = Blake3Keyed::new(key).hash(msg);
951 let out2 = blake3_keyed_hash(&key, msg);
952
953 assert_eq!(out1, out2, "Method and free function must agree");
954 }
955
956 #[test]
959 fn blake3_derive_key_different_contexts() {
960 let material = b"shared key material";
961 let out1 = blake3_derive_key("context A", material);
962 let out2 = blake3_derive_key("context B", material);
963
964 assert_ne!(
965 out1, out2,
966 "Different contexts must produce different derived keys"
967 );
968 }
969
970 #[test]
971 fn blake3_derive_key_deterministic() {
972 let material = b"deterministic material";
973 let out1 = blake3_derive_key("test context", material);
974 let out2 = blake3_derive_key("test context", material);
975
976 assert_eq!(out1, out2, "derive_key must be deterministic");
977 }
978
979 #[test]
980 fn blake3_derive_key_output_len() {
981 let out = blake3_derive_key("oxicrypto test", b"material");
982 assert_eq!(out.len(), 32);
983 }
984
985 #[test]
988 fn blake3_xof_64_bytes() {
989 let out = blake3_xof(b"hello", 64);
990 assert_eq!(out.len(), 64);
991 }
992
993 #[test]
994 fn blake3_xof_first_32_match_standard_hash() {
995 let msg = b"xof test";
996 let standard = Blake3.hash_to_vec(msg).unwrap();
997 let extended = blake3_xof(msg, 64);
998
999 assert_eq!(
1000 &extended[..32],
1001 standard.as_slice(),
1002 "First 32 bytes of XOF must match standard BLAKE3 hash"
1003 );
1004 }
1005
1006 #[test]
1007 fn blake3_xof_prefix_consistency() {
1008 let msg = b"prefix test";
1009 let out64 = blake3_xof(msg, 64);
1010 let out128 = blake3_xof(msg, 128);
1011
1012 assert_eq!(
1013 &out128[..64],
1014 out64.as_slice(),
1015 "128-byte XOF must be prefixed by 64-byte XOF"
1016 );
1017 }
1018
1019 #[test]
1020 fn blake3_xof_zero_len() {
1021 let out = blake3_xof(b"anything", 0);
1022 assert!(out.is_empty());
1023 }
1024
1025 #[test]
1028 fn sha256_digest_len_constant() {
1029 assert_eq!(Sha256::DIGEST_LEN, 32);
1030 assert_eq!(Sha256::BLOCK_SIZE, 64);
1031 }
1032
1033 #[test]
1034 fn sha384_digest_len_constant() {
1035 assert_eq!(Sha384::DIGEST_LEN, 48);
1036 assert_eq!(Sha384::BLOCK_SIZE, 128);
1037 }
1038
1039 #[test]
1040 fn sha512_digest_len_constant() {
1041 assert_eq!(Sha512::DIGEST_LEN, 64);
1042 assert_eq!(Sha512::BLOCK_SIZE, 128);
1043 }
1044
1045 #[test]
1046 fn sha3_256_digest_len_constant() {
1047 assert_eq!(Sha3_256::DIGEST_LEN, 32);
1048 }
1049
1050 #[test]
1051 fn blake3_digest_len_constant() {
1052 assert_eq!(Blake3::DIGEST_LEN, 32);
1053 assert_eq!(Blake3::BLOCK_SIZE, 64);
1054 }
1055
1056 #[test]
1057 fn blake2b256_digest_len_constant() {
1058 assert_eq!(Blake2b256::DIGEST_LEN, 32);
1059 assert_eq!(Blake2b256::BLOCK_SIZE, 128);
1060 }
1061
1062 #[test]
1063 fn blake2b512_digest_len_constant() {
1064 assert_eq!(Blake2b512::DIGEST_LEN, 64);
1065 assert_eq!(Blake2b512::BLOCK_SIZE, 128);
1066 }
1067
1068 #[test]
1069 fn blake2s256_digest_len_constant() {
1070 assert_eq!(Blake2s256::DIGEST_LEN, 32);
1071 assert_eq!(Blake2s256::BLOCK_SIZE, 64);
1072 }
1073
1074 #[test]
1077 fn constants_match_runtime_output_len() {
1078 assert_eq!(Sha256::DIGEST_LEN, Sha256.output_len());
1079 assert_eq!(Sha384::DIGEST_LEN, Sha384.output_len());
1080 assert_eq!(Sha512::DIGEST_LEN, Sha512.output_len());
1081 assert_eq!(Blake3::DIGEST_LEN, Blake3.output_len());
1082 assert_eq!(Blake2b256::DIGEST_LEN, Blake2b256.output_len());
1083 assert_eq!(Blake2b512::DIGEST_LEN, Blake2b512.output_len());
1084 assert_eq!(Blake2s256::DIGEST_LEN, Blake2s256.output_len());
1085 }
1086
1087 #[test]
1090 fn sha256_streaming_clone_independent() {
1091 let mut streamer = Sha256Streaming::new();
1092 StreamingHash::update(&mut streamer, b"hello");
1093 let mut cloned = streamer.clone();
1094 StreamingHash::update(&mut streamer, b" world");
1096 StreamingHash::update(&mut cloned, b" clone");
1097
1098 let mut buf1 = [0u8; 32];
1099 let mut buf2 = [0u8; 32];
1100 StreamingHash::finalize(streamer, &mut buf1).expect("finalize original");
1101 StreamingHash::finalize(cloned, &mut buf2).expect("finalize clone");
1102
1103 assert_ne!(
1105 buf1, buf2,
1106 "cloned streamer with different data must differ"
1107 );
1108 }
1109
1110 #[test]
1111 fn blake3_streaming_clone_independent() {
1112 let mut streamer = Blake3Streaming::new();
1113 StreamingHash::update(&mut streamer, b"hello");
1114 let mut cloned = streamer.clone();
1115 StreamingHash::update(&mut streamer, b" a");
1116 StreamingHash::update(&mut cloned, b" b");
1117
1118 let mut buf1 = [0u8; 32];
1119 let mut buf2 = [0u8; 32];
1120 StreamingHash::finalize(streamer, &mut buf1).expect("finalize original");
1121 StreamingHash::finalize(cloned, &mut buf2).expect("finalize clone");
1122
1123 assert_ne!(
1124 buf1, buf2,
1125 "cloned Blake3Streaming with different data must differ"
1126 );
1127 }
1128
1129 #[cfg(feature = "std")]
1132 #[test]
1133 fn sha256_hex_known_vector() {
1134 let hex = sha256_hex(b"");
1136 assert_eq!(
1137 hex,
1138 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
1139 );
1140 }
1141
1142 #[cfg(feature = "std")]
1143 #[test]
1144 fn sha256_hex_length() {
1145 let hex = sha256_hex(b"abc");
1146 assert_eq!(hex.len(), 64, "SHA-256 hex string must be 64 characters");
1147 assert!(hex
1149 .chars()
1150 .all(|c| c.is_ascii_digit() || ('a'..='f').contains(&c)));
1151 }
1152
1153 #[cfg(feature = "std")]
1154 #[test]
1155 fn sha512_hex_length() {
1156 let hex = sha512_hex(b"abc");
1157 assert_eq!(hex.len(), 128, "SHA-512 hex string must be 128 characters");
1158 }
1159
1160 #[cfg(feature = "std")]
1161 #[test]
1162 fn blake3_hex_known_vector() {
1163 let hex = blake3_hex(b"abc");
1165 assert_eq!(
1166 hex,
1167 "6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85"
1168 );
1169 }
1170
1171 #[cfg(feature = "std")]
1174 #[test]
1175 fn sha256_streaming_io_write() {
1176 use std::io::Write;
1177 let mut streamer = Sha256Streaming::new();
1178 streamer.write_all(b"hello").expect("write_all hello");
1179 streamer.write_all(b" world").expect("write_all world");
1180 let mut buf = [0u8; 32];
1181 StreamingHash::finalize(streamer, &mut buf).expect("finalize");
1182
1183 let expected = Sha256.hash_to_vec(b"hello world").expect("one-shot");
1184 assert_eq!(
1185 &buf[..],
1186 expected.as_slice(),
1187 "io::Write result must match one-shot"
1188 );
1189 }
1190
1191 #[cfg(feature = "std")]
1192 #[test]
1193 fn blake3_streaming_io_write() {
1194 use std::io::Write;
1195 let mut streamer = Blake3Streaming::new();
1196 streamer.write_all(b"test data").expect("write_all");
1197 let mut buf = [0u8; 32];
1198 StreamingHash::finalize(streamer, &mut buf).expect("finalize");
1199
1200 let expected = Blake3.hash_to_vec(b"test data").expect("one-shot");
1201 assert_eq!(
1202 &buf[..],
1203 expected.as_slice(),
1204 "io::Write result must match one-shot"
1205 );
1206 }
1207}