1#![doc(
14 html_logo_url = "https://commonware.xyz/imgs/rustdoc_logo.svg",
15 html_favicon_url = "https://commonware.xyz/favicon.ico"
16)]
17#![cfg_attr(not(any(feature = "std", test)), no_std)]
18
19#[cfg(not(feature = "std"))]
20extern crate alloc;
21
22#[cfg(all(
25 feature = "bls12381",
26 not(any(
27 commonware_stability_GAMMA,
28 commonware_stability_DELTA,
29 commonware_stability_EPSILON,
30 commonware_stability_RESERVED
31 ))
32))] pub mod bls12381;
34#[cfg(not(any(
35 commonware_stability_GAMMA,
36 commonware_stability_DELTA,
37 commonware_stability_EPSILON,
38 commonware_stability_RESERVED
39)))] pub mod ed25519;
41#[cfg(not(any(
42 commonware_stability_BETA,
43 commonware_stability_GAMMA,
44 commonware_stability_DELTA,
45 commonware_stability_EPSILON,
46 commonware_stability_RESERVED
47)))] pub mod secp256r1;
49
50commonware_macros::stability_scope!(ALPHA {
51 #[cfg(feature = "std")]
52 pub mod banderwagon;
53 pub mod bloomfilter;
54 pub use crate::bloomfilter::BloomFilter;
55
56 #[cfg(any(test, feature = "fuzz"))]
57 pub mod fuzz;
58
59 pub mod keccak256;
60 pub use crate::keccak256::{CoreKeccak256, Keccak256};
61
62 pub mod lthash;
63 pub use crate::lthash::LtHash;
64
65 pub mod reed_solomon;
66
67 pub mod sha512;
68 pub use crate::sha512::{CoreSha512, Sha512};
69
70 pub mod zk;
71});
72commonware_macros::stability_scope!(BETA {
73 #[cfg(not(feature = "std"))]
74 use alloc::{sync::Arc, vec::Vec};
75 use commonware_codec::{BufsMut, Encode, EncodeSize, ReadExt, Write};
76 use commonware_math::algebra::Random;
77 use commonware_parallel::Strategy;
78 use commonware_utils::Array;
79 use core::{fmt, future::Future, num::NonZeroUsize};
80 use rand_chacha::ChaCha20Rng;
81 use rand_core::{CryptoRng, SeedableRng as _};
82 #[cfg(feature = "std")]
83 use std::{sync::Arc, vec::Vec};
84
85 pub mod secret;
86 pub use crate::secret::Secret;
87
88 pub mod certificate;
89 pub mod transcript;
90
91 pub mod sha256;
92 pub use crate::sha256::{CoreSha256, Sha256};
93 pub mod blake3;
94 pub use crate::blake3::{Blake3, CoreBlake3};
95 #[cfg(feature = "std")]
96 pub mod crc32;
97 #[cfg(feature = "std")]
98 pub use crate::crc32::Crc32;
99
100 #[cfg(feature = "std")]
101 pub mod chacha20_poly1305;
102 #[cfg(feature = "std")]
103 pub use crate::chacha20_poly1305::ChaCha20Poly1305;
104
105 #[cfg(feature = "std")]
106 pub mod handshake;
107
108 pub trait Signer: Random + Send + Sync + Clone + 'static {
110 type Signature: Signature;
112
113 type PublicKey: PublicKey<Signature = Self::Signature>;
115
116 fn public_key(&self) -> Self::PublicKey;
118
119 fn sign(&self, namespace: &[u8], msg: &[u8]) -> Self::Signature;
130
131 fn from_seed(seed: u64) -> Self {
138 Self::random(ChaCha20Rng::seed_from_u64(seed))
139 }
140 }
141
142 pub trait PrivateKey: Signer + Sized + ReadExt + Encode {}
144
145 pub trait Verifier {
147 type Signature: Signature;
149
150 fn verify(&self, namespace: &[u8], msg: &[u8], sig: &Self::Signature) -> bool;
158 }
159
160 pub trait PublicKey: Verifier + Sized + ReadExt + Array {}
162
163 pub trait Signature: Sized + ReadExt + Array {}
165
166 pub trait Recoverable: Signature {
168 type PublicKey: PublicKey<Signature = Self>;
170
171 fn recover_signer(&self, namespace: &[u8], msg: &[u8]) -> Option<Self::PublicKey>;
178 }
179
180 #[derive(Clone)]
182 pub struct BatchEntry<'a, P: PublicKey> {
183 pub namespace: &'a [u8],
185 pub message: &'a [u8],
187 pub public_key: &'a P,
189 pub signature: &'a P::Signature,
191 }
192
193 impl<P: PublicKey> Copy for BatchEntry<'_, P> {}
194
195 pub trait BatchVerifier: PublicKey {
197 fn verify_batch<'a, R, T, F>(
250 rng: &mut R,
251 items: &'a [T],
252 project: F,
253 strategy: &impl Strategy,
254 ) -> bool
255 where
256 R: CryptoRng,
257 T: Sync,
258 F: Fn(usize, &'a T) -> BatchEntry<'a, Self> + Sync;
259 }
260
261 pub trait Digest: Array + Copy + Random {
269 const EMPTY: Self;
271 }
272
273 pub trait Digestible: Clone + Sized + Send + Sync + 'static {
275 type Digest: Digest;
277
278 fn digest(&self) -> Self::Digest;
283
284 fn digest_across(&self, _strategy: &impl Strategy) -> Self::Digest {
286 self.digest()
287 }
288 }
289
290 impl<T: Digestible> Digestible for Arc<T> {
291 type Digest = T::Digest;
292
293 fn digest(&self) -> Self::Digest {
294 self.as_ref().digest()
295 }
296
297 fn digest_across(&self, strategy: &impl Strategy) -> Self::Digest {
298 self.as_ref().digest_across(strategy)
299 }
300 }
301
302 pub struct Digested<T: Digestible> {
314 inner: Arc<T>,
315 digest: T::Digest,
316 }
317
318 impl<T: Digestible> Digested<T> {
319 #[track_caller]
321 pub fn compute(
322 inner: impl Into<Arc<T>>,
323 strategy: &impl Strategy,
324 ) -> impl Future<Output = Self> + Send + 'static
325 where
326 T: EncodeSize,
327 {
328 let inner: Arc<T> = inner.into();
329 strategy.spawn(inner.encode_size(), move |strategy| {
330 let digest = inner.digest_across(&strategy);
331 Self { inner, digest }
332 })
333 }
334
335 pub fn precomputed(inner: impl Into<Arc<T>>, digest: T::Digest) -> Self {
341 Self {
342 inner: inner.into(),
343 digest,
344 }
345 }
346
347 pub fn inner(&self) -> &T {
349 &self.inner
350 }
351
352 pub fn inner_shared(&self) -> Arc<T> {
354 Arc::clone(&self.inner)
355 }
356 }
357
358 impl<T: Digestible> Clone for Digested<T> {
359 fn clone(&self) -> Self {
360 Self {
361 inner: Arc::clone(&self.inner),
362 digest: self.digest,
363 }
364 }
365 }
366
367 impl<T: Digestible + fmt::Debug> fmt::Debug for Digested<T> {
368 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369 f.debug_struct("Digested")
370 .field("digest", &self.digest)
371 .field("inner", &self.inner)
372 .finish()
373 }
374 }
375
376 impl<T: Digestible> PartialEq for Digested<T> {
377 fn eq(&self, other: &Self) -> bool {
378 self.digest == other.digest
379 }
380 }
381
382 impl<T: Digestible> Eq for Digested<T> {}
383
384 impl<T: Digestible> Digestible for Digested<T> {
385 type Digest = T::Digest;
386
387 fn digest(&self) -> Self::Digest {
388 self.digest
389 }
390 }
391
392 impl<T: Digestible + Write> Write for Digested<T> {
393 fn write(&self, buf: &mut impl bytes::BufMut) {
394 self.inner.write(buf);
395 }
396
397 fn write_bufs(&self, buf: &mut impl BufsMut) {
398 self.inner.write_bufs(buf);
399 }
400 }
401
402 impl<T: Digestible + EncodeSize> EncodeSize for Digested<T> {
403 fn encode_size(&self) -> usize {
404 self.inner.encode_size()
405 }
406
407 fn encode_inline_size(&self) -> usize {
408 self.inner.encode_inline_size()
409 }
410 }
411
412 impl<T: Digestible> From<Digested<T>> for Arc<T> {
413 fn from(digested: Digested<T>) -> Self {
414 digested.inner
415 }
416 }
417
418 #[cfg(feature = "arbitrary")]
419 impl<'a, T> arbitrary::Arbitrary<'a> for Digested<T>
420 where
421 T: Digestible + arbitrary::Arbitrary<'a>,
422 {
423 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
424 let inner = T::arbitrary(u)?;
425 let digest = inner.digest();
426 Ok(Self::precomputed(inner, digest))
427 }
428 }
429
430 pub trait Committable: Clone + Sized + Send + Sync + 'static {
432 type Commitment: Digest;
434
435 fn commitment(&self) -> Self::Commitment;
448 }
449
450 pub type DigestOf<H> = <H as Hasher>::Digest;
451
452 pub trait Hasher: Default + Send + Sync + 'static {
463 type Digest: Digest;
465
466 fn hash(parts: &[&[u8]]) -> Self::Digest;
473
474 fn hash_across(parts: &[&[u8]], _strategy: &impl Strategy) -> Self::Digest {
480 Self::hash(parts)
481 }
482
483 fn hash_pair(
489 left: &[&[u8]],
490 right: &[&[u8]],
491 strategy: &impl Strategy,
492 ) -> (Self::Digest, Self::Digest);
493
494 fn hash_many<M: AsRef<[u8]> + Sync>(
501 messages: &[M],
502 strategy: &impl Strategy,
503 ) -> Vec<Self::Digest> {
504 hash_batches(messages, 1, strategy, |batch| {
505 batch
506 .iter()
507 .map(|message| Self::hash_across(&[message.as_ref()], strategy))
508 .collect()
509 })
510 }
511
512 fn update(&mut self, bytes: &[u8]) -> &mut Self;
514
515 fn finalize(self) -> (Self, Self::Digest);
518 }
519
520 pub(crate) fn hash_batches<D, M>(
527 messages: &[M],
528 lanes: usize,
529 strategy: &impl Strategy,
530 hash: impl Fn(&[M]) -> Vec<D> + Sync,
531 ) -> Vec<D>
532 where
533 D: Clone + Send,
534 M: AsRef<[u8]> + Sync,
535 {
536 if messages.is_empty() {
537 return Vec::new();
538 }
539 let units = messages.len().div_ceil(lanes);
540 let bytes = messages.iter().fold(0usize, |bytes, message| {
541 bytes.saturating_add(message.as_ref().len())
542 });
543 strategy.run_batches(units, NonZeroUsize::MIN, bytes.div_ceil(units), |batches| {
544 if batches.is_whole() {
546 return hash(messages);
547 }
548 batches
549 .map_collect_vec(
550 |ranges| {
551 ranges.into_iter().map(|range| {
552 let end = range.end.saturating_mul(lanes).min(messages.len());
553 &messages[range.start * lanes..end]
554 })
555 },
556 &hash,
557 )
558 .concat()
559 })
560 }
561
562 pub trait Cipher: Random + Sized + Send + Sync + 'static {
569 type Tag: Array;
571
572 #[must_use = "the cipher is returned only if sealing succeeds"]
577 fn seal(self, aad: &[u8], data: &mut [u8]) -> Option<(Self, Self::Tag)>;
578
579 #[must_use = "data is authentic only if opening succeeds"]
584 fn open(self, aad: &[u8], data: &mut [u8], tag: &Self::Tag) -> Option<Self>;
585 }
586});
587
588#[cfg(test)]
589mod tests {
590 use super::*;
591 use commonware_codec::{DecodeExt, FixedSize};
592 use commonware_parallel::mocks::{Explorer, pooled};
593 use commonware_utils::{NZUsize, test_rng};
594 use std::collections::HashSet;
595
596 fn test_validate<C: PrivateKey>() {
597 let mut rng = test_rng();
598 let private_key = C::random(&mut rng);
599 let public_key = private_key.public_key();
600 let decoded = C::PublicKey::decode(commonware_codec::Copying(public_key.as_ref())).unwrap();
601 assert_eq!(public_key, decoded);
602 assert_eq!(public_key.cmp(&decoded), core::cmp::Ordering::Equal);
603
604 let other = C::random(&mut rng).public_key();
605 assert_ne!(public_key, other);
606 let mut keys = HashSet::from([public_key]);
607 assert!(!keys.insert(decoded));
608 assert!(keys.insert(other));
609 }
610
611 fn test_public_key_order<C: PrivateKey>() {
612 let mut rng = test_rng();
613 let mut keys = Vec::new();
614 for _ in 0..16 {
615 let key = C::random(&mut rng).public_key();
616 let decoded = C::PublicKey::decode(commonware_codec::Copying(key.as_ref())).unwrap();
617 keys.extend([key, decoded]);
618 }
619
620 for a in &keys {
621 for b in &keys {
622 let expected = a.as_ref().cmp(b.as_ref());
623 assert_eq!(a.cmp(b), expected);
624 assert_eq!(a.partial_cmp(b), Some(expected));
625 assert_eq!(a == b, expected.is_eq());
626 }
627 }
628 }
629
630 fn test_validate_invalid_public_key<C: Signer>() {
631 let result = C::PublicKey::decode(vec![0; 1024]);
632 assert!(result.is_err());
633 }
634
635 fn test_sign_and_verify<C: PrivateKey>() {
636 let private_key = C::from_seed(0);
637 let namespace = b"test_namespace";
638 let message = b"test_message";
639 let signature = private_key.sign(namespace, message);
640 let public_key = private_key.public_key();
641 assert!(public_key.verify(namespace, message, &signature));
642 }
643
644 fn test_sign_and_verify_wrong_message<C: PrivateKey>() {
645 let private_key = C::from_seed(0);
646 let namespace = b"test_namespace";
647 let message = b"test_message";
648 let wrong_message = b"wrong_message";
649 let signature = private_key.sign(namespace, message);
650 let public_key = private_key.public_key();
651 assert!(!public_key.verify(namespace, wrong_message, &signature));
652 }
653
654 fn test_sign_and_verify_wrong_namespace<C: PrivateKey>() {
655 let private_key = C::from_seed(0);
656 let namespace = b"test_namespace";
657 let wrong_namespace = b"wrong_namespace";
658 let message = b"test_message";
659 let signature = private_key.sign(namespace, message);
660 let public_key = private_key.public_key();
661 assert!(!public_key.verify(wrong_namespace, message, &signature));
662 }
663
664 fn test_empty_namespace<C: PrivateKey>() {
665 let private_key = C::from_seed(0);
666 let empty_namespace = b"";
667 let message = b"test_message";
668 let signature = private_key.sign(empty_namespace, message);
669 let public_key = private_key.public_key();
670 assert!(public_key.verify(empty_namespace, message, &signature));
671 }
672
673 fn test_signature_determinism<C: PrivateKey>() {
674 let private_key_1 = C::from_seed(0);
675 let private_key_2 = C::from_seed(0);
676 let namespace = b"test_namespace";
677 let message = b"test_message";
678 let signature_1 = private_key_1.sign(namespace, message);
679 let signature_2 = private_key_2.sign(namespace, message);
680 assert_eq!(private_key_1.public_key(), private_key_2.public_key());
681 assert_eq!(signature_1, signature_2);
682 }
683
684 fn test_invalid_signature_publickey_pair<C: PrivateKey>() {
685 let private_key = C::from_seed(0);
686 let private_key_2 = C::from_seed(1);
687 let namespace = b"test_namespace";
688 let message = b"test_message";
689 let signature = private_key.sign(namespace, message);
690 let public_key = private_key_2.public_key();
691 assert!(!public_key.verify(namespace, message, &signature));
692 }
693
694 #[test]
695 fn test_ed25519_validate() {
696 test_validate::<ed25519::PrivateKey>();
697 }
698
699 #[test]
700 fn test_ed25519_validate_invalid_public_key() {
701 test_validate_invalid_public_key::<ed25519::PrivateKey>();
702 }
703
704 #[test]
705 fn test_ed25519_sign_and_verify() {
706 test_sign_and_verify::<ed25519::PrivateKey>();
707 }
708
709 #[test]
710 fn test_ed25519_sign_and_verify_wrong_message() {
711 test_sign_and_verify_wrong_message::<ed25519::PrivateKey>();
712 }
713
714 #[test]
715 fn test_ed25519_sign_and_verify_wrong_namespace() {
716 test_sign_and_verify_wrong_namespace::<ed25519::PrivateKey>();
717 }
718
719 #[test]
720 fn test_ed25519_empty_namespace() {
721 test_empty_namespace::<ed25519::PrivateKey>();
722 }
723
724 #[test]
725 fn test_ed25519_signature_determinism() {
726 test_signature_determinism::<ed25519::PrivateKey>();
727 }
728
729 #[test]
730 fn test_ed25519_invalid_signature_publickey_pair() {
731 test_invalid_signature_publickey_pair::<ed25519::PrivateKey>();
732 }
733
734 #[test]
735 fn test_ed25519_len() {
736 assert_eq!(ed25519::PublicKey::SIZE, 32);
737 assert_eq!(ed25519::Signature::SIZE, 64);
738 }
739
740 #[test]
741 #[cfg(feature = "bls12381")]
742 fn test_bls12381_validate() {
743 test_validate::<bls12381::PrivateKey>();
744 }
745
746 #[test]
747 #[cfg(feature = "bls12381")]
748 fn test_bls12381_validate_invalid_public_key() {
749 test_validate_invalid_public_key::<bls12381::PrivateKey>();
750 }
751
752 #[test]
753 #[cfg(feature = "bls12381")]
754 fn test_bls12381_sign_and_verify() {
755 test_sign_and_verify::<bls12381::PrivateKey>();
756 }
757
758 #[test]
759 #[cfg(feature = "bls12381")]
760 fn test_bls12381_sign_and_verify_wrong_message() {
761 test_sign_and_verify_wrong_message::<bls12381::PrivateKey>();
762 }
763
764 #[test]
765 #[cfg(feature = "bls12381")]
766 fn test_bls12381_sign_and_verify_wrong_namespace() {
767 test_sign_and_verify_wrong_namespace::<bls12381::PrivateKey>();
768 }
769
770 #[test]
771 #[cfg(feature = "bls12381")]
772 fn test_bls12381_empty_namespace() {
773 test_empty_namespace::<bls12381::PrivateKey>();
774 }
775
776 #[test]
777 #[cfg(feature = "bls12381")]
778 fn test_bls12381_signature_determinism() {
779 test_signature_determinism::<bls12381::PrivateKey>();
780 }
781
782 #[test]
783 #[cfg(feature = "bls12381")]
784 fn test_bls12381_invalid_signature_publickey_pair() {
785 test_invalid_signature_publickey_pair::<bls12381::PrivateKey>();
786 }
787
788 #[test]
789 #[cfg(feature = "bls12381")]
790 fn test_bls12381_len() {
791 assert_eq!(bls12381::PublicKey::SIZE, 48);
792 assert_eq!(bls12381::Signature::SIZE, 96);
793 }
794
795 #[test]
796 fn test_secp256r1_standard_validate() {
797 test_validate::<secp256r1::standard::PrivateKey>();
798 }
799
800 #[test]
801 fn test_secp256r1_standard_public_key_order() {
802 test_public_key_order::<secp256r1::standard::PrivateKey>();
803 }
804
805 #[test]
806 fn test_secp256r1_standard_validate_invalid_public_key() {
807 test_validate_invalid_public_key::<secp256r1::standard::PrivateKey>();
808 }
809
810 #[test]
811 fn test_secp256r1_standard_sign_and_verify() {
812 test_sign_and_verify::<secp256r1::standard::PrivateKey>();
813 }
814
815 #[test]
816 fn test_secp256r1_standard_sign_and_verify_wrong_message() {
817 test_sign_and_verify_wrong_message::<secp256r1::standard::PrivateKey>();
818 }
819
820 #[test]
821 fn test_secp256r1_standard_sign_and_verify_wrong_namespace() {
822 test_sign_and_verify_wrong_namespace::<secp256r1::standard::PrivateKey>();
823 }
824
825 #[test]
826 fn test_secp256r1_standard_empty_namespace() {
827 test_empty_namespace::<secp256r1::standard::PrivateKey>();
828 }
829
830 #[test]
831 fn test_secp256r1_standard_signature_determinism() {
832 test_signature_determinism::<secp256r1::standard::PrivateKey>();
833 }
834
835 #[test]
836 fn test_secp256r1_standard_invalid_signature_publickey_pair() {
837 test_invalid_signature_publickey_pair::<secp256r1::standard::PrivateKey>();
838 }
839
840 #[test]
841 fn test_secp256r1_standard_len() {
842 assert_eq!(secp256r1::standard::PublicKey::SIZE, 33);
843 assert_eq!(secp256r1::standard::Signature::SIZE, 64);
844 }
845
846 #[test]
847 fn test_secp256r1_recoverable_validate() {
848 test_validate::<secp256r1::recoverable::PrivateKey>();
849 }
850
851 #[test]
852 fn test_secp256r1_recoverable_public_key_order() {
853 test_public_key_order::<secp256r1::recoverable::PrivateKey>();
854 }
855
856 #[test]
857 fn test_secp256r1_recoverable_validate_invalid_public_key() {
858 test_validate_invalid_public_key::<secp256r1::recoverable::PrivateKey>();
859 }
860
861 #[test]
862 fn test_secp256r1_recoverable_sign_and_verify() {
863 test_sign_and_verify::<secp256r1::recoverable::PrivateKey>();
864 }
865
866 #[test]
867 fn test_secp256r1_recoverable_sign_and_verify_wrong_message() {
868 test_sign_and_verify_wrong_message::<secp256r1::recoverable::PrivateKey>();
869 }
870
871 #[test]
872 fn test_secp256r1_recoverable_sign_and_verify_wrong_namespace() {
873 test_sign_and_verify_wrong_namespace::<secp256r1::recoverable::PrivateKey>();
874 }
875
876 #[test]
877 fn test_secp256r1_recoverable_empty_namespace() {
878 test_empty_namespace::<secp256r1::recoverable::PrivateKey>();
879 }
880
881 #[test]
882 fn test_secp256r1_recoverable_signature_determinism() {
883 test_signature_determinism::<secp256r1::recoverable::PrivateKey>();
884 }
885
886 #[test]
887 fn test_secp256r1_recoverable_invalid_signature_publickey_pair() {
888 test_invalid_signature_publickey_pair::<secp256r1::recoverable::PrivateKey>();
889 }
890
891 #[test]
892 fn test_secp256r1_recoverable_len() {
893 assert_eq!(secp256r1::recoverable::PublicKey::SIZE, 33);
894 assert_eq!(secp256r1::recoverable::Signature::SIZE, 65);
895 }
896
897 fn test_hasher_multiple_runs<H: Hasher>() {
898 let mut hasher = H::default();
900 hasher.update(b"hello world");
901 let (hasher, digest) = hasher.finalize();
902 assert!(H::Digest::decode(commonware_codec::Copying(digest.as_ref())).is_ok());
903 assert_eq!(digest.as_ref().len(), H::Digest::SIZE);
904
905 let mut hasher = hasher;
907 hasher.update(b"hello world");
908 let (hasher, digest_again) = hasher.finalize();
909 assert!(H::Digest::decode(commonware_codec::Copying(digest_again.as_ref())).is_ok());
910 assert_eq!(digest, digest_again);
911
912 let digest_oneshot = H::hash(&[b"hello world"]);
914 assert!(H::Digest::decode(commonware_codec::Copying(digest_oneshot.as_ref())).is_ok());
915 assert_eq!(digest, digest_oneshot);
916
917 let mut hasher = hasher;
919 hasher.update(b"hello mars");
920 let (_, digest_mars) = hasher.finalize();
921 assert!(H::Digest::decode(commonware_codec::Copying(digest_mars.as_ref())).is_ok());
922 assert_ne!(digest, digest_mars);
923 }
924
925 #[test]
926 fn test_keccak256_hasher_multiple_runs() {
927 test_hasher_multiple_runs::<Keccak256>();
928 }
929
930 #[test]
931 fn test_sha256_hasher_multiple_runs() {
932 test_hasher_multiple_runs::<Sha256>();
933 }
934
935 #[test]
936 fn test_sha512_hasher_multiple_runs() {
937 test_hasher_multiple_runs::<Sha512>();
938 }
939
940 #[test]
943 fn test_hash_batches_shares_whole_units() {
944 let strategy = Explorer::parallel(&pooled(NZUsize!(4), NZUsize!(8)));
945 for lanes in [1, 2, 8, 16] {
946 for count in [0, 1, lanes + 1, 3 * lanes, 7 * lanes + 1, 9 * lanes, 100] {
947 let messages: Vec<[u8; 4]> = (0..count as u32).map(u32::to_le_bytes).collect();
950 let digests = hash_batches(&messages, lanes, &strategy, |batch| {
951 let first = u32::from_le_bytes(batch[0]);
952 batch
953 .iter()
954 .map(|message| (u32::from_le_bytes(*message), first))
955 .collect()
956 });
957 assert!(digests.iter().map(|&(index, _)| index).eq(0..count as u32));
958
959 let shares: Vec<_> = digests.chunk_by(|a, b| a.1 == b.1).collect();
962 assert_eq!(shares.len(), count.div_ceil(lanes).min(8));
963 if let Some((_, rest)) = shares.split_last() {
964 assert!(rest.iter().all(|share| share.len() % lanes == 0));
965 }
966 }
967 }
968 }
969}