1#![forbid(unsafe_code)]
2#![no_std]
3
4extern crate alloc;
28
29#[cfg(feature = "std")]
30extern crate std;
31
32mod hash_builder;
33mod parallelhash;
34mod xof;
35pub use hash_builder::{DynStreamingHash, HashAlgorithm, HashBuilder, StreamingHashBuilder};
36pub use parallelhash::{
37 parallel_hash128, parallel_hash128_xof, parallel_hash256, parallel_hash256_xof,
38 ParallelHash128, ParallelHash256,
39};
40pub use xof::{
41 blake2b_keyed, cshake128, cshake256, shake128, shake128_start, shake256, shake256_start,
42 tuple_hash128, tuple_hash256, Blake2bKeyed, Shake128Reader, Shake256Reader,
43};
44
45#[cfg(feature = "std")]
46pub use xof::{hash_file_blake3, hash_file_sha256, hash_file_sha512};
47
48use alloc::vec::Vec;
49
50use digest::Digest;
51use oxicrypto_core::{CryptoError, Hash, StreamingHash};
52
53pub struct DigestStreamingAdapter<D: Digest + Default> {
60 inner: D,
61}
62
63impl<D: Digest + Default> DigestStreamingAdapter<D> {
64 pub fn new() -> Self {
66 Self {
67 inner: D::default(),
68 }
69 }
70}
71
72impl<D: Digest + Default> Default for DigestStreamingAdapter<D> {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl<D: Digest + Default + Clone> Clone for DigestStreamingAdapter<D> {
79 fn clone(&self) -> Self {
80 Self {
81 inner: self.inner.clone(),
82 }
83 }
84}
85
86impl<D: Digest + Default + Send> StreamingHash for DigestStreamingAdapter<D> {
87 fn update(&mut self, data: &[u8]) {
88 Digest::update(&mut self.inner, data);
89 }
90
91 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
92 let result = Digest::finalize(self.inner);
93 if out.len() < result.len() {
94 return Err(CryptoError::BufferTooSmall);
95 }
96 out[..result.len()].copy_from_slice(&result);
97 Ok(())
98 }
99
100 fn reset(&mut self) {
101 self.inner = D::default();
102 }
103}
104
105#[derive(Debug, Default, Clone, Copy)]
109pub struct Sha256;
110
111#[derive(Debug, Default, Clone, Copy)]
113pub struct Sha384;
114
115#[derive(Debug, Default, Clone, Copy)]
117pub struct Sha512;
118
119#[derive(Debug, Default, Clone, Copy)]
121pub struct Sha512_256;
122
123impl Hash for Sha256 {
124 fn name(&self) -> &'static str {
125 "SHA-256"
126 }
127 fn output_len(&self) -> usize {
128 32
129 }
130 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
131 if out.len() < 32 {
132 return Err(CryptoError::BufferTooSmall);
133 }
134 let digest = sha2::Sha256::digest(msg);
135 out[..32].copy_from_slice(&digest);
136 Ok(())
137 }
138}
139
140impl Hash for Sha384 {
141 fn name(&self) -> &'static str {
142 "SHA-384"
143 }
144 fn output_len(&self) -> usize {
145 48
146 }
147 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
148 if out.len() < 48 {
149 return Err(CryptoError::BufferTooSmall);
150 }
151 let digest = sha2::Sha384::digest(msg);
152 out[..48].copy_from_slice(&digest);
153 Ok(())
154 }
155}
156
157impl Hash for Sha512 {
158 fn name(&self) -> &'static str {
159 "SHA-512"
160 }
161 fn output_len(&self) -> usize {
162 64
163 }
164 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
165 if out.len() < 64 {
166 return Err(CryptoError::BufferTooSmall);
167 }
168 let digest = sha2::Sha512::digest(msg);
169 out[..64].copy_from_slice(&digest);
170 Ok(())
171 }
172}
173
174impl Hash for Sha512_256 {
175 fn name(&self) -> &'static str {
176 "SHA-512/256"
177 }
178 fn output_len(&self) -> usize {
179 32
180 }
181 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
182 if out.len() < 32 {
183 return Err(CryptoError::BufferTooSmall);
184 }
185 let digest = sha2::Sha512_256::digest(msg);
186 out[..32].copy_from_slice(&digest);
187 Ok(())
188 }
189}
190
191impl Sha256 {
194 pub const DIGEST_LEN: usize = 32;
196 pub const OUTPUT_LEN: usize = 32;
198 pub const BLOCK_SIZE: usize = 64;
200}
201
202impl Sha384 {
203 pub const DIGEST_LEN: usize = 48;
205 pub const OUTPUT_LEN: usize = 48;
207 pub const BLOCK_SIZE: usize = 128;
209}
210
211impl Sha512 {
212 pub const DIGEST_LEN: usize = 64;
214 pub const OUTPUT_LEN: usize = 64;
216 pub const BLOCK_SIZE: usize = 128;
218}
219
220impl Sha512_256 {
221 pub const DIGEST_LEN: usize = 32;
223 pub const OUTPUT_LEN: usize = 32;
225 pub const BLOCK_SIZE: usize = 128;
227}
228
229pub type Sha256Streaming = DigestStreamingAdapter<sha2::Sha256>;
233pub type Sha384Streaming = DigestStreamingAdapter<sha2::Sha384>;
235pub type Sha512Streaming = DigestStreamingAdapter<sha2::Sha512>;
237pub type Sha512_256Streaming = DigestStreamingAdapter<sha2::Sha512_256>;
239
240#[derive(Debug, Default, Clone, Copy)]
244pub struct Sha3_256;
245
246#[derive(Debug, Default, Clone, Copy)]
248pub struct Sha3_384;
249
250#[derive(Debug, Default, Clone, Copy)]
252pub struct Sha3_512;
253
254impl Hash for Sha3_256 {
255 fn name(&self) -> &'static str {
256 "SHA3-256"
257 }
258 fn output_len(&self) -> usize {
259 32
260 }
261 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
262 if out.len() < 32 {
263 return Err(CryptoError::BufferTooSmall);
264 }
265 let digest = sha3::Sha3_256::digest(msg);
266 out[..32].copy_from_slice(&digest);
267 Ok(())
268 }
269}
270
271impl Hash for Sha3_384 {
272 fn name(&self) -> &'static str {
273 "SHA3-384"
274 }
275 fn output_len(&self) -> usize {
276 48
277 }
278 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
279 if out.len() < 48 {
280 return Err(CryptoError::BufferTooSmall);
281 }
282 let digest = sha3::Sha3_384::digest(msg);
283 out[..48].copy_from_slice(&digest);
284 Ok(())
285 }
286}
287
288impl Hash for Sha3_512 {
289 fn name(&self) -> &'static str {
290 "SHA3-512"
291 }
292 fn output_len(&self) -> usize {
293 64
294 }
295 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
296 if out.len() < 64 {
297 return Err(CryptoError::BufferTooSmall);
298 }
299 let digest = sha3::Sha3_512::digest(msg);
300 out[..64].copy_from_slice(&digest);
301 Ok(())
302 }
303}
304
305impl Sha3_256 {
308 pub const DIGEST_LEN: usize = 32;
310 pub const OUTPUT_LEN: usize = 32;
312 pub const BLOCK_SIZE: usize = 136;
314}
315
316impl Sha3_384 {
317 pub const DIGEST_LEN: usize = 48;
319 pub const OUTPUT_LEN: usize = 48;
321 pub const BLOCK_SIZE: usize = 104;
323}
324
325impl Sha3_512 {
326 pub const DIGEST_LEN: usize = 64;
328 pub const OUTPUT_LEN: usize = 64;
330 pub const BLOCK_SIZE: usize = 72;
332}
333
334pub type Sha3_256Streaming = DigestStreamingAdapter<sha3::Sha3_256>;
338pub type Sha3_384Streaming = DigestStreamingAdapter<sha3::Sha3_384>;
340pub type Sha3_512Streaming = DigestStreamingAdapter<sha3::Sha3_512>;
342
343#[derive(Debug, Default, Clone, Copy)]
347pub struct Blake2b256;
348
349#[derive(Debug, Default, Clone, Copy)]
351pub struct Blake2b512;
352
353#[derive(Debug, Default, Clone, Copy)]
355pub struct Blake2s256;
356
357impl Hash for Blake2b256 {
358 fn name(&self) -> &'static str {
359 "BLAKE2b-256"
360 }
361 fn output_len(&self) -> usize {
362 32
363 }
364 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
365 if out.len() < 32 {
366 return Err(CryptoError::BufferTooSmall);
367 }
368 let result = blake2::Blake2b256::digest(msg);
369 out[..32].copy_from_slice(&result);
370 Ok(())
371 }
372}
373
374impl Hash for Blake2b512 {
375 fn name(&self) -> &'static str {
376 "BLAKE2b-512"
377 }
378 fn output_len(&self) -> usize {
379 64
380 }
381 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
382 if out.len() < 64 {
383 return Err(CryptoError::BufferTooSmall);
384 }
385 let result = blake2::Blake2b512::digest(msg);
386 out[..64].copy_from_slice(&result);
387 Ok(())
388 }
389}
390
391impl Hash for Blake2s256 {
392 fn name(&self) -> &'static str {
393 "BLAKE2s-256"
394 }
395 fn output_len(&self) -> usize {
396 32
397 }
398 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
399 if out.len() < 32 {
400 return Err(CryptoError::BufferTooSmall);
401 }
402 let result = blake2::Blake2s256::digest(msg);
403 out[..32].copy_from_slice(&result);
404 Ok(())
405 }
406}
407
408impl Blake2b256 {
411 pub const DIGEST_LEN: usize = 32;
413 pub const OUTPUT_LEN: usize = 32;
415 pub const BLOCK_SIZE: usize = 128;
417}
418
419impl Blake2b512 {
420 pub const DIGEST_LEN: usize = 64;
422 pub const OUTPUT_LEN: usize = 64;
424 pub const BLOCK_SIZE: usize = 128;
426}
427
428impl Blake2s256 {
429 pub const DIGEST_LEN: usize = 32;
431 pub const OUTPUT_LEN: usize = 32;
433 pub const BLOCK_SIZE: usize = 64;
435}
436
437pub type Blake2b256Streaming = DigestStreamingAdapter<blake2::Blake2b256>;
441pub type Blake2b512Streaming = DigestStreamingAdapter<blake2::Blake2b512>;
443pub type Blake2s256Streaming = DigestStreamingAdapter<blake2::Blake2s256>;
445
446#[derive(Debug, Default, Clone, Copy)]
450pub struct Blake3;
451
452impl Hash for Blake3 {
453 fn name(&self) -> &'static str {
454 "BLAKE3"
455 }
456 fn output_len(&self) -> usize {
457 32
458 }
459 fn hash(&self, msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
460 if out.len() < 32 {
461 return Err(CryptoError::BufferTooSmall);
462 }
463 let digest = blake3::hash(msg);
464 out[..32].copy_from_slice(digest.as_bytes());
465 Ok(())
466 }
467}
468
469impl Blake3 {
470 pub const DIGEST_LEN: usize = 32;
472 pub const OUTPUT_LEN: usize = 32;
474 pub const BLOCK_SIZE: usize = 64;
476}
477
478pub struct Blake3Streaming {
484 inner: blake3::Hasher,
485}
486
487impl Blake3Streaming {
488 pub fn new() -> Self {
490 Self {
491 inner: blake3::Hasher::new(),
492 }
493 }
494}
495
496impl Default for Blake3Streaming {
497 fn default() -> Self {
498 Self::new()
499 }
500}
501
502impl Clone for Blake3Streaming {
503 fn clone(&self) -> Self {
504 Self {
505 inner: self.inner.clone(),
506 }
507 }
508}
509
510impl StreamingHash for Blake3Streaming {
511 fn update(&mut self, data: &[u8]) {
512 self.inner.update(data);
513 }
514
515 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
516 if out.len() < 32 {
517 return Err(CryptoError::BufferTooSmall);
518 }
519 let result = self.inner.finalize();
520 out[..32].copy_from_slice(result.as_bytes());
521 Ok(())
522 }
523
524 fn reset(&mut self) {
525 self.inner.reset();
526 }
527}
528
529#[cfg(feature = "std")]
534impl<D: Digest + Default + Send> std::io::Write for DigestStreamingAdapter<D> {
535 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
536 self.update(buf);
537 Ok(buf.len())
538 }
539
540 fn flush(&mut self) -> std::io::Result<()> {
541 Ok(())
542 }
543}
544
545#[cfg(feature = "std")]
548impl std::io::Write for Blake3Streaming {
549 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
550 self.update(buf);
551 Ok(buf.len())
552 }
553
554 fn flush(&mut self) -> std::io::Result<()> {
555 Ok(())
556 }
557}
558
559#[cfg(feature = "std")]
565pub fn sha256_hex(msg: &[u8]) -> std::string::String {
566 let digest = sha2::Sha256::digest(msg);
567 bytes_to_hex(digest.as_ref())
568}
569
570#[cfg(feature = "std")]
572pub fn sha384_hex(msg: &[u8]) -> std::string::String {
573 let digest = sha2::Sha384::digest(msg);
574 bytes_to_hex(digest.as_ref())
575}
576
577#[cfg(feature = "std")]
579pub fn sha512_hex(msg: &[u8]) -> std::string::String {
580 let digest = sha2::Sha512::digest(msg);
581 bytes_to_hex(digest.as_ref())
582}
583
584#[cfg(feature = "std")]
586pub fn sha3_256_hex(msg: &[u8]) -> std::string::String {
587 let digest = sha3::Sha3_256::digest(msg);
588 bytes_to_hex(digest.as_ref())
589}
590
591#[cfg(feature = "std")]
593pub fn blake3_hex(msg: &[u8]) -> std::string::String {
594 let digest = blake3::hash(msg);
595 bytes_to_hex(digest.as_bytes())
596}
597
598#[cfg(feature = "std")]
600fn bytes_to_hex(bytes: &[u8]) -> std::string::String {
601 bytes.iter().fold(
602 std::string::String::with_capacity(bytes.len() * 2),
603 |mut s, b| {
604 let _ = std::fmt::write(&mut s, format_args!("{b:02x}"));
605 s
606 },
607 )
608}
609
610pub struct Blake3Keyed {
617 key: [u8; 32],
618}
619
620impl Blake3Keyed {
621 pub fn new(key: [u8; 32]) -> Self {
623 Self { key }
624 }
625
626 pub fn hash(&self, msg: &[u8]) -> [u8; 32] {
628 *blake3::keyed_hash(&self.key, msg).as_bytes()
629 }
630}
631
632pub fn blake3_keyed_hash(key: &[u8; 32], msg: &[u8]) -> [u8; 32] {
636 *blake3::keyed_hash(key, msg).as_bytes()
637}
638
639pub fn blake3_derive_key(context: &str, key_material: &[u8]) -> [u8; 32] {
647 blake3::derive_key(context, key_material)
648}
649
650impl Sha256 {
675 #[inline]
684 #[must_use]
685 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 32] {
686 sha2::Sha256::digest(msg).into()
687 }
688}
689
690impl Sha384 {
691 #[inline]
695 #[must_use]
696 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 48] {
697 sha2::Sha384::digest(msg).into()
698 }
699}
700
701impl Sha512 {
702 #[inline]
706 #[must_use]
707 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 64] {
708 sha2::Sha512::digest(msg).into()
709 }
710}
711
712impl Sha512_256 {
713 #[inline]
717 #[must_use]
718 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 32] {
719 sha2::Sha512_256::digest(msg).into()
720 }
721}
722
723impl Sha3_256 {
724 #[inline]
728 #[must_use]
729 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 32] {
730 sha3::Sha3_256::digest(msg).into()
731 }
732}
733
734impl Sha3_384 {
735 #[inline]
739 #[must_use]
740 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 48] {
741 sha3::Sha3_384::digest(msg).into()
742 }
743}
744
745impl Sha3_512 {
746 #[inline]
750 #[must_use]
751 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 64] {
752 sha3::Sha3_512::digest(msg).into()
753 }
754}
755
756impl Blake2b256 {
757 #[inline]
761 #[must_use]
762 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 32] {
763 blake2::Blake2b256::digest(msg).into()
764 }
765}
766
767impl Blake2b512 {
768 #[inline]
772 #[must_use]
773 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 64] {
774 blake2::Blake2b512::digest(msg).into()
775 }
776}
777
778impl Blake2s256 {
779 #[inline]
783 #[must_use]
784 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 32] {
785 blake2::Blake2s256::digest(msg).into()
786 }
787}
788
789impl Blake3 {
790 #[inline]
800 #[must_use]
801 pub fn hash_fixed(&self, msg: &[u8]) -> [u8; 32] {
802 *blake3::hash(msg).as_bytes()
803 }
804}
805
806pub fn blake3_xof(msg: &[u8], output_len: usize) -> Vec<u8> {
821 let mut out = alloc::vec![0u8; output_len];
822 let mut reader = blake3::Hasher::new().update(msg).finalize_xof();
823 reader.fill(&mut out);
824 out
825}
826
827#[cfg(test)]
830mod tests {
831 use super::*;
832
833 fn hex_decode(s: &str) -> Vec<u8> {
834 hex::decode(s).unwrap_or_else(|e| panic!("invalid hex string {s:?}: {e}"))
835 }
836
837 #[test]
840 fn sha256_empty() {
841 let hasher = Sha256;
842 let result = hasher.hash_to_vec(b"").unwrap();
843 let expected =
844 hex_decode("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
845 assert_eq!(result, expected, "SHA-256 of empty string mismatch");
846 }
847
848 #[test]
849 fn sha256_abc() {
850 let hasher = Sha256;
851 let result = hasher.hash_to_vec(b"abc").unwrap();
852 let expected =
854 hex_decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
855 assert_eq!(result, expected, "SHA-256 of 'abc' mismatch");
856 }
857
858 #[test]
859 fn sha384_abc() {
860 let hasher = Sha384;
861 let result = hasher.hash_to_vec(b"abc").unwrap();
862 assert_eq!(result.len(), 48);
863 }
864
865 #[test]
866 fn sha512_abc() {
867 let hasher = Sha512;
868 let result = hasher.hash_to_vec(b"abc").unwrap();
869 assert_eq!(result.len(), 64);
870 }
871
872 #[test]
873 fn sha3_256_output_len() {
874 let hasher = Sha3_256;
875 assert_eq!(hasher.output_len(), 32);
876 let result = hasher.hash_to_vec(b"abc").unwrap();
877 assert_eq!(result.len(), 32);
878 }
879
880 #[test]
881 fn sha3_384_output_len() {
882 let hasher = Sha3_384;
883 assert_eq!(hasher.output_len(), 48);
884 let result = hasher.hash_to_vec(b"abc").unwrap();
885 assert_eq!(result.len(), 48);
886 }
887
888 #[test]
889 fn sha3_512_output_len() {
890 let hasher = Sha3_512;
891 assert_eq!(hasher.output_len(), 64);
892 let result = hasher.hash_to_vec(b"abc").unwrap();
893 assert_eq!(result.len(), 64);
894 }
895
896 #[test]
897 fn blake3_abc() {
898 let hasher = Blake3;
899 let result = hasher.hash_to_vec(b"abc").unwrap();
900 let expected =
903 hex_decode("6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85");
904 assert_eq!(result, expected, "BLAKE3 of 'abc' mismatch");
905 }
906
907 #[test]
908 fn buffer_too_small_error() {
909 let hasher = Sha256;
910 let mut out = [0u8; 16];
911 let err = hasher.hash(b"test", &mut out).unwrap_err();
912 assert_eq!(err, CryptoError::BufferTooSmall);
913 }
914
915 #[test]
918 fn sha256_streaming_hello_world() {
919 let one_shot = Sha256.hash_to_vec(b"hello world").unwrap();
921
922 let mut streamer = Sha256Streaming::new();
923 StreamingHash::update(&mut streamer, b"hello");
924 StreamingHash::update(&mut streamer, b" world");
925 let mut buf = [0u8; 32];
926 StreamingHash::finalize(streamer, &mut buf).unwrap();
927
928 assert_eq!(buf.as_ref(), one_shot.as_slice());
929 }
930
931 #[test]
932 fn sha256_streaming_one_byte_chunks() {
933 let one_shot = Sha256.hash_to_vec(b"abc").unwrap();
935
936 let mut streamer = Sha256Streaming::new();
937 for byte in b"abc" {
938 StreamingHash::update(&mut streamer, core::slice::from_ref(byte));
939 }
940 let mut buf = [0u8; 32];
941 StreamingHash::finalize(streamer, &mut buf).unwrap();
942
943 assert_eq!(buf.as_ref(), one_shot.as_slice());
944 }
945
946 #[test]
947 fn sha256_streaming_reset() {
948 let expected = Sha256.hash_to_vec(b"world").unwrap();
950
951 let mut streamer = Sha256Streaming::new();
952 StreamingHash::update(&mut streamer, b"hello");
953 StreamingHash::reset(&mut streamer);
954 StreamingHash::update(&mut streamer, b"world");
955 let mut buf = [0u8; 32];
956 StreamingHash::finalize(streamer, &mut buf).unwrap();
957
958 assert_eq!(buf.as_ref(), expected.as_slice());
959 }
960
961 #[test]
962 fn sha256_streaming_buffer_too_small() {
963 let mut streamer = Sha256Streaming::new();
964 StreamingHash::update(&mut streamer, b"test");
965 let mut buf = [0u8; 16];
966 let err = StreamingHash::finalize(streamer, &mut buf).unwrap_err();
967 assert_eq!(err, CryptoError::BufferTooSmall);
968 }
969
970 #[test]
973 fn blake3_streaming_equivalence() {
974 let one_shot = Blake3.hash_to_vec(b"hello world").unwrap();
975
976 let mut streamer = Blake3Streaming::new();
977 StreamingHash::update(&mut streamer, b"hello");
978 StreamingHash::update(&mut streamer, b" world");
979 let mut buf = [0u8; 32];
980 StreamingHash::finalize(streamer, &mut buf).unwrap();
981
982 assert_eq!(buf.as_ref(), one_shot.as_slice());
983 }
984
985 #[test]
986 fn blake3_streaming_reset() {
987 let expected = Blake3.hash_to_vec(b"world").unwrap();
988
989 let mut streamer = Blake3Streaming::new();
990 StreamingHash::update(&mut streamer, b"hello");
991 StreamingHash::reset(&mut streamer);
992 StreamingHash::update(&mut streamer, b"world");
993 let mut buf = [0u8; 32];
994 StreamingHash::finalize(streamer, &mut buf).unwrap();
995
996 assert_eq!(buf.as_ref(), expected.as_slice());
997 }
998
999 #[test]
1002 fn blake2b256_output_len() {
1003 let hasher = Blake2b256;
1004 assert_eq!(hasher.output_len(), 32);
1005 let result = hasher.hash_to_vec(b"abc").unwrap();
1006 assert_eq!(result.len(), 32);
1007 }
1008
1009 #[test]
1010 fn blake2b256_empty_nonzero() {
1011 let result = Blake2b256.hash_to_vec(b"").unwrap();
1013 assert_eq!(result.len(), 32);
1014 assert!(
1015 result.iter().any(|&b| b != 0),
1016 "BLAKE2b-256 of empty should be non-zero"
1017 );
1018 }
1019
1020 #[test]
1021 fn blake2b256_streaming_equivalence() {
1022 let one_shot = Blake2b256.hash_to_vec(b"hello world").unwrap();
1023
1024 let mut streamer = Blake2b256Streaming::new();
1025 StreamingHash::update(&mut streamer, b"hello");
1026 StreamingHash::update(&mut streamer, b" world");
1027 let mut buf = [0u8; 32];
1028 StreamingHash::finalize(streamer, &mut buf).unwrap();
1029
1030 assert_eq!(buf.as_ref(), one_shot.as_slice());
1031 }
1032
1033 #[test]
1036 fn blake2b512_output_len() {
1037 let hasher = Blake2b512;
1038 assert_eq!(hasher.output_len(), 64);
1039 let result = hasher.hash_to_vec(b"abc").unwrap();
1040 assert_eq!(result.len(), 64);
1041 }
1042
1043 #[test]
1044 fn blake2b512_streaming_equivalence() {
1045 let one_shot = Blake2b512.hash_to_vec(b"hello world").unwrap();
1046
1047 let mut streamer = Blake2b512Streaming::new();
1048 StreamingHash::update(&mut streamer, b"hello");
1049 StreamingHash::update(&mut streamer, b" world");
1050 let mut buf = [0u8; 64];
1051 StreamingHash::finalize(streamer, &mut buf).unwrap();
1052
1053 assert_eq!(buf.as_ref(), one_shot.as_slice());
1054 }
1055
1056 #[test]
1059 fn blake2s256_output_len() {
1060 let hasher = Blake2s256;
1061 assert_eq!(hasher.output_len(), 32);
1062 let result = hasher.hash_to_vec(b"abc").unwrap();
1063 assert_eq!(result.len(), 32);
1064 }
1065
1066 #[test]
1067 fn blake2s256_streaming_equivalence() {
1068 let one_shot = Blake2s256.hash_to_vec(b"hello world").unwrap();
1069
1070 let mut streamer = Blake2s256Streaming::new();
1071 StreamingHash::update(&mut streamer, b"hello");
1072 StreamingHash::update(&mut streamer, b" world");
1073 let mut buf = [0u8; 32];
1074 StreamingHash::finalize(streamer, &mut buf).unwrap();
1075
1076 assert_eq!(buf.as_ref(), one_shot.as_slice());
1077 }
1078
1079 #[test]
1082 fn sha512_256_output_len() {
1083 let hasher = Sha512_256;
1084 assert_eq!(hasher.output_len(), 32);
1085 let result = hasher.hash_to_vec(b"abc").unwrap();
1086 assert_eq!(result.len(), 32);
1087 }
1088
1089 #[test]
1090 fn sha512_256_known_vector() {
1091 let result = Sha512_256.hash_to_vec(b"abc").unwrap();
1093 let expected =
1094 hex_decode("53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23");
1095 assert_eq!(result, expected, "SHA-512/256 of 'abc' mismatch");
1096 }
1097
1098 #[test]
1099 fn sha512_256_streaming_equivalence() {
1100 let one_shot = Sha512_256.hash_to_vec(b"hello world").unwrap();
1101
1102 let mut streamer = Sha512_256Streaming::new();
1103 StreamingHash::update(&mut streamer, b"hello");
1104 StreamingHash::update(&mut streamer, b" world");
1105 let mut buf = [0u8; 32];
1106 StreamingHash::finalize(streamer, &mut buf).unwrap();
1107
1108 assert_eq!(buf.as_ref(), one_shot.as_slice());
1109 }
1110
1111 #[test]
1114 fn blake3_keyed_different_keys() {
1115 let key1 = [1u8; 32];
1116 let key2 = [2u8; 32];
1117 let msg = b"same message";
1118
1119 let out1 = Blake3Keyed::new(key1).hash(msg);
1120 let out2 = Blake3Keyed::new(key2).hash(msg);
1121
1122 assert_ne!(out1, out2, "Different keys must produce different outputs");
1123 }
1124
1125 #[test]
1126 fn blake3_keyed_different_messages() {
1127 let key = [42u8; 32];
1128 let out1 = Blake3Keyed::new(key).hash(b"message1");
1129 let out2 = Blake3Keyed::new(key).hash(b"message2");
1130
1131 assert_ne!(
1132 out1, out2,
1133 "Different messages must produce different outputs"
1134 );
1135 }
1136
1137 #[test]
1138 fn blake3_keyed_deterministic() {
1139 let key = [7u8; 32];
1140 let msg = b"deterministic";
1141 let out1 = Blake3Keyed::new(key).hash(msg);
1142 let out2 = blake3_keyed_hash(&key, msg);
1143
1144 assert_eq!(out1, out2, "Method and free function must agree");
1145 }
1146
1147 #[test]
1150 fn blake3_derive_key_different_contexts() {
1151 let material = b"shared key material";
1152 let out1 = blake3_derive_key("context A", material);
1153 let out2 = blake3_derive_key("context B", material);
1154
1155 assert_ne!(
1156 out1, out2,
1157 "Different contexts must produce different derived keys"
1158 );
1159 }
1160
1161 #[test]
1162 fn blake3_derive_key_deterministic() {
1163 let material = b"deterministic material";
1164 let out1 = blake3_derive_key("test context", material);
1165 let out2 = blake3_derive_key("test context", material);
1166
1167 assert_eq!(out1, out2, "derive_key must be deterministic");
1168 }
1169
1170 #[test]
1171 fn blake3_derive_key_output_len() {
1172 let out = blake3_derive_key("oxicrypto test", b"material");
1173 assert_eq!(out.len(), 32);
1174 }
1175
1176 #[test]
1179 fn blake3_xof_64_bytes() {
1180 let out = blake3_xof(b"hello", 64);
1181 assert_eq!(out.len(), 64);
1182 }
1183
1184 #[test]
1185 fn blake3_xof_first_32_match_standard_hash() {
1186 let msg = b"xof test";
1187 let standard = Blake3.hash_to_vec(msg).unwrap();
1188 let extended = blake3_xof(msg, 64);
1189
1190 assert_eq!(
1191 &extended[..32],
1192 standard.as_slice(),
1193 "First 32 bytes of XOF must match standard BLAKE3 hash"
1194 );
1195 }
1196
1197 #[test]
1198 fn blake3_xof_prefix_consistency() {
1199 let msg = b"prefix test";
1200 let out64 = blake3_xof(msg, 64);
1201 let out128 = blake3_xof(msg, 128);
1202
1203 assert_eq!(
1204 &out128[..64],
1205 out64.as_slice(),
1206 "128-byte XOF must be prefixed by 64-byte XOF"
1207 );
1208 }
1209
1210 #[test]
1211 fn blake3_xof_zero_len() {
1212 let out = blake3_xof(b"anything", 0);
1213 assert!(out.is_empty());
1214 }
1215
1216 #[test]
1219 fn test_output_len_consts() {
1220 assert_eq!(Sha256::OUTPUT_LEN, 32);
1221 assert_eq!(Sha384::OUTPUT_LEN, 48);
1222 assert_eq!(Sha512::OUTPUT_LEN, 64);
1223 assert_eq!(Sha512_256::OUTPUT_LEN, 32);
1224 assert_eq!(Sha3_256::OUTPUT_LEN, 32);
1225 assert_eq!(Sha3_384::OUTPUT_LEN, 48);
1226 assert_eq!(Sha3_512::OUTPUT_LEN, 64);
1227 assert_eq!(Blake2b256::OUTPUT_LEN, 32);
1228 assert_eq!(Blake2b512::OUTPUT_LEN, 64);
1229 assert_eq!(Blake2s256::OUTPUT_LEN, 32);
1230 assert_eq!(Blake3::OUTPUT_LEN, 32);
1231 }
1232
1233 #[test]
1234 fn test_output_len_matches_runtime_output_len() {
1235 assert_eq!(Sha256::OUTPUT_LEN, Sha256.output_len());
1236 assert_eq!(Sha384::OUTPUT_LEN, Sha384.output_len());
1237 assert_eq!(Sha512::OUTPUT_LEN, Sha512.output_len());
1238 assert_eq!(Sha512_256::OUTPUT_LEN, Sha512_256.output_len());
1239 assert_eq!(Sha3_256::OUTPUT_LEN, Sha3_256.output_len());
1240 assert_eq!(Sha3_384::OUTPUT_LEN, Sha3_384.output_len());
1241 assert_eq!(Sha3_512::OUTPUT_LEN, Sha3_512.output_len());
1242 assert_eq!(Blake2b256::OUTPUT_LEN, Blake2b256.output_len());
1243 assert_eq!(Blake2b512::OUTPUT_LEN, Blake2b512.output_len());
1244 assert_eq!(Blake2s256::OUTPUT_LEN, Blake2s256.output_len());
1245 assert_eq!(Blake3::OUTPUT_LEN, Blake3.output_len());
1246 }
1247
1248 #[test]
1251 fn sha256_digest_len_constant() {
1252 assert_eq!(Sha256::DIGEST_LEN, 32);
1253 assert_eq!(Sha256::BLOCK_SIZE, 64);
1254 }
1255
1256 #[test]
1257 fn sha384_digest_len_constant() {
1258 assert_eq!(Sha384::DIGEST_LEN, 48);
1259 assert_eq!(Sha384::BLOCK_SIZE, 128);
1260 }
1261
1262 #[test]
1263 fn sha512_digest_len_constant() {
1264 assert_eq!(Sha512::DIGEST_LEN, 64);
1265 assert_eq!(Sha512::BLOCK_SIZE, 128);
1266 }
1267
1268 #[test]
1269 fn sha3_256_digest_len_constant() {
1270 assert_eq!(Sha3_256::DIGEST_LEN, 32);
1271 }
1272
1273 #[test]
1274 fn blake3_digest_len_constant() {
1275 assert_eq!(Blake3::DIGEST_LEN, 32);
1276 assert_eq!(Blake3::BLOCK_SIZE, 64);
1277 }
1278
1279 #[test]
1280 fn blake2b256_digest_len_constant() {
1281 assert_eq!(Blake2b256::DIGEST_LEN, 32);
1282 assert_eq!(Blake2b256::BLOCK_SIZE, 128);
1283 }
1284
1285 #[test]
1286 fn blake2b512_digest_len_constant() {
1287 assert_eq!(Blake2b512::DIGEST_LEN, 64);
1288 assert_eq!(Blake2b512::BLOCK_SIZE, 128);
1289 }
1290
1291 #[test]
1292 fn blake2s256_digest_len_constant() {
1293 assert_eq!(Blake2s256::DIGEST_LEN, 32);
1294 assert_eq!(Blake2s256::BLOCK_SIZE, 64);
1295 }
1296
1297 #[test]
1300 fn constants_match_runtime_output_len() {
1301 assert_eq!(Sha256::DIGEST_LEN, Sha256.output_len());
1302 assert_eq!(Sha384::DIGEST_LEN, Sha384.output_len());
1303 assert_eq!(Sha512::DIGEST_LEN, Sha512.output_len());
1304 assert_eq!(Blake3::DIGEST_LEN, Blake3.output_len());
1305 assert_eq!(Blake2b256::DIGEST_LEN, Blake2b256.output_len());
1306 assert_eq!(Blake2b512::DIGEST_LEN, Blake2b512.output_len());
1307 assert_eq!(Blake2s256::DIGEST_LEN, Blake2s256.output_len());
1308 }
1309
1310 #[test]
1313 fn sha256_streaming_clone_independent() {
1314 let mut streamer = Sha256Streaming::new();
1315 StreamingHash::update(&mut streamer, b"hello");
1316 let mut cloned = streamer.clone();
1317 StreamingHash::update(&mut streamer, b" world");
1319 StreamingHash::update(&mut cloned, b" clone");
1320
1321 let mut buf1 = [0u8; 32];
1322 let mut buf2 = [0u8; 32];
1323 StreamingHash::finalize(streamer, &mut buf1).expect("finalize original");
1324 StreamingHash::finalize(cloned, &mut buf2).expect("finalize clone");
1325
1326 assert_ne!(
1328 buf1, buf2,
1329 "cloned streamer with different data must differ"
1330 );
1331 }
1332
1333 #[test]
1334 fn blake3_streaming_clone_independent() {
1335 let mut streamer = Blake3Streaming::new();
1336 StreamingHash::update(&mut streamer, b"hello");
1337 let mut cloned = streamer.clone();
1338 StreamingHash::update(&mut streamer, b" a");
1339 StreamingHash::update(&mut cloned, b" b");
1340
1341 let mut buf1 = [0u8; 32];
1342 let mut buf2 = [0u8; 32];
1343 StreamingHash::finalize(streamer, &mut buf1).expect("finalize original");
1344 StreamingHash::finalize(cloned, &mut buf2).expect("finalize clone");
1345
1346 assert_ne!(
1347 buf1, buf2,
1348 "cloned Blake3Streaming with different data must differ"
1349 );
1350 }
1351
1352 #[cfg(feature = "std")]
1355 #[test]
1356 fn sha256_hex_known_vector() {
1357 let hex = sha256_hex(b"");
1359 assert_eq!(
1360 hex,
1361 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
1362 );
1363 }
1364
1365 #[cfg(feature = "std")]
1366 #[test]
1367 fn sha256_hex_length() {
1368 let hex = sha256_hex(b"abc");
1369 assert_eq!(hex.len(), 64, "SHA-256 hex string must be 64 characters");
1370 assert!(hex
1372 .chars()
1373 .all(|c| c.is_ascii_digit() || ('a'..='f').contains(&c)));
1374 }
1375
1376 #[cfg(feature = "std")]
1377 #[test]
1378 fn sha512_hex_length() {
1379 let hex = sha512_hex(b"abc");
1380 assert_eq!(hex.len(), 128, "SHA-512 hex string must be 128 characters");
1381 }
1382
1383 #[cfg(feature = "std")]
1384 #[test]
1385 fn blake3_hex_known_vector() {
1386 let hex = blake3_hex(b"abc");
1388 assert_eq!(
1389 hex,
1390 "6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85"
1391 );
1392 }
1393
1394 #[cfg(feature = "std")]
1397 #[test]
1398 fn sha256_streaming_io_write() {
1399 use std::io::Write;
1400 let mut streamer = Sha256Streaming::new();
1401 streamer.write_all(b"hello").expect("write_all hello");
1402 streamer.write_all(b" world").expect("write_all world");
1403 let mut buf = [0u8; 32];
1404 StreamingHash::finalize(streamer, &mut buf).expect("finalize");
1405
1406 let expected = Sha256.hash_to_vec(b"hello world").expect("one-shot");
1407 assert_eq!(
1408 &buf[..],
1409 expected.as_slice(),
1410 "io::Write result must match one-shot"
1411 );
1412 }
1413
1414 #[cfg(feature = "std")]
1415 #[test]
1416 fn blake3_streaming_io_write() {
1417 use std::io::Write;
1418 let mut streamer = Blake3Streaming::new();
1419 streamer.write_all(b"test data").expect("write_all");
1420 let mut buf = [0u8; 32];
1421 StreamingHash::finalize(streamer, &mut buf).expect("finalize");
1422
1423 let expected = Blake3.hash_to_vec(b"test data").expect("one-shot");
1424 assert_eq!(
1425 &buf[..],
1426 expected.as_slice(),
1427 "io::Write result must match one-shot"
1428 );
1429 }
1430
1431 #[test]
1439 fn sha256_hash_fixed_matches_hash_trait() {
1440 let msg = b"alloc-free sha256 test";
1442 let fixed: [u8; 32] = Sha256.hash_fixed(msg);
1443 let via_trait = Sha256.hash_to_vec(msg).expect("hash_to_vec");
1444 assert_eq!(&fixed[..], via_trait.as_slice());
1445 }
1446
1447 #[test]
1448 fn sha384_hash_fixed_matches_hash_trait() {
1449 let msg = b"alloc-free sha384 test";
1450 let fixed: [u8; 48] = Sha384.hash_fixed(msg);
1451 let via_trait = Sha384.hash_to_vec(msg).expect("hash_to_vec");
1452 assert_eq!(&fixed[..], via_trait.as_slice());
1453 }
1454
1455 #[test]
1456 fn sha512_hash_fixed_matches_hash_trait() {
1457 let msg = b"alloc-free sha512 test";
1458 let fixed: [u8; 64] = Sha512.hash_fixed(msg);
1459 let via_trait = Sha512.hash_to_vec(msg).expect("hash_to_vec");
1460 assert_eq!(&fixed[..], via_trait.as_slice());
1461 }
1462
1463 #[test]
1464 fn sha512_256_hash_fixed_matches_hash_trait() {
1465 let msg = b"alloc-free sha512/256 test";
1466 let fixed: [u8; 32] = Sha512_256.hash_fixed(msg);
1467 let via_trait = Sha512_256.hash_to_vec(msg).expect("hash_to_vec");
1468 assert_eq!(&fixed[..], via_trait.as_slice());
1469 }
1470
1471 #[test]
1472 fn sha3_256_hash_fixed_matches_hash_trait() {
1473 let msg = b"alloc-free sha3-256 test";
1474 let fixed: [u8; 32] = Sha3_256.hash_fixed(msg);
1475 let via_trait = Sha3_256.hash_to_vec(msg).expect("hash_to_vec");
1476 assert_eq!(&fixed[..], via_trait.as_slice());
1477 }
1478
1479 #[test]
1480 fn sha3_384_hash_fixed_matches_hash_trait() {
1481 let msg = b"alloc-free sha3-384 test";
1482 let fixed: [u8; 48] = Sha3_384.hash_fixed(msg);
1483 let via_trait = Sha3_384.hash_to_vec(msg).expect("hash_to_vec");
1484 assert_eq!(&fixed[..], via_trait.as_slice());
1485 }
1486
1487 #[test]
1488 fn sha3_512_hash_fixed_matches_hash_trait() {
1489 let msg = b"alloc-free sha3-512 test";
1490 let fixed: [u8; 64] = Sha3_512.hash_fixed(msg);
1491 let via_trait = Sha3_512.hash_to_vec(msg).expect("hash_to_vec");
1492 assert_eq!(&fixed[..], via_trait.as_slice());
1493 }
1494
1495 #[test]
1496 fn blake2b256_hash_fixed_matches_hash_trait() {
1497 let msg = b"alloc-free blake2b256 test";
1498 let fixed: [u8; 32] = Blake2b256.hash_fixed(msg);
1499 let via_trait = Blake2b256.hash_to_vec(msg).expect("hash_to_vec");
1500 assert_eq!(&fixed[..], via_trait.as_slice());
1501 }
1502
1503 #[test]
1504 fn blake2b512_hash_fixed_matches_hash_trait() {
1505 let msg = b"alloc-free blake2b512 test";
1506 let fixed: [u8; 64] = Blake2b512.hash_fixed(msg);
1507 let via_trait = Blake2b512.hash_to_vec(msg).expect("hash_to_vec");
1508 assert_eq!(&fixed[..], via_trait.as_slice());
1509 }
1510
1511 #[test]
1512 fn blake2s256_hash_fixed_matches_hash_trait() {
1513 let msg = b"alloc-free blake2s256 test";
1514 let fixed: [u8; 32] = Blake2s256.hash_fixed(msg);
1515 let via_trait = Blake2s256.hash_to_vec(msg).expect("hash_to_vec");
1516 assert_eq!(&fixed[..], via_trait.as_slice());
1517 }
1518
1519 #[test]
1520 fn blake3_hash_fixed_matches_hash_trait() {
1521 let msg = b"alloc-free blake3 test";
1522 let fixed: [u8; 32] = Blake3.hash_fixed(msg);
1523 let via_trait = Blake3.hash_to_vec(msg).expect("hash_to_vec");
1524 assert_eq!(&fixed[..], via_trait.as_slice());
1525 }
1526
1527 #[test]
1528 fn hash_fixed_known_vectors() {
1529 let sha256_abc: [u8; 32] = Sha256.hash_fixed(b"abc");
1532 let expected_sha256 =
1533 hex_decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
1534 assert_eq!(sha256_abc.as_ref(), expected_sha256.as_slice());
1535 let blake3_abc: [u8; 32] = Blake3.hash_fixed(b"abc");
1537 let expected_blake3 =
1538 hex_decode("6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85");
1539 assert_eq!(blake3_abc.as_ref(), expected_blake3.as_slice());
1540 }
1541
1542 #[test]
1543 fn hash_fixed_empty_input() {
1544 let fixed: [u8; 32] = Sha256.hash_fixed(b"");
1546 let expected =
1547 hex_decode("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
1548 assert_eq!(fixed.as_ref(), expected.as_slice());
1549 }
1550}