1#![cfg_attr(
20 feature = "bls12381",
21 doc = "
22- [`bls12381_multisig`]: Attributable signatures with aggregated verification. Signatures
23 can be aggregated into a single multi-signature for compact certificates while preserving
24 attribution (signer indices are stored alongside the aggregated signature). Callers must verify
25 a proof of possession for every BLS signing key before constructing the scheme.
26
27- [`bls12381_threshold`]: Non-attributable threshold signatures. Produces succinct
28 certificates that are constant-size regardless of committee size. Requires a trusted
29 setup (distributed key generation) and cannot attribute signatures to individual signers.
30"
31)]
32#![cfg_attr(
57 feature = "bls12381",
58 doc = "Some cryptographic schemes are only performant when used in batch verification (like
59[`bls12381_multisig`]) and/or are refreshed frequently (like [`bls12381_threshold`])."
60)]
61#[cfg(feature = "bls12381")]
64pub use crate::bls12381::certificate::{
65 multisig as bls12381_multisig, threshold as bls12381_threshold,
66};
67pub use crate::ed25519::certificate as ed25519;
68#[commonware_macros::stability(ALPHA)]
69pub use crate::secp256r1::certificate as secp256r1;
70use crate::{Digest, PublicKey};
71#[cfg(not(feature = "std"))]
72use alloc::{collections::BTreeSet, sync::Arc, vec, vec::Vec};
73use bytes::{Buf, BufMut, Bytes};
74use commonware_codec::{
75 Codec, CodecFixed, EncodeSize, Error as CodecError, Read, ReadExt, Write, types::lazy::Lazy,
76};
77use commonware_parallel::Strategy;
78use commonware_utils::{Faults, Participant, bitmap::BitMap, iter::NonEmpty, ordered::Set};
79use core::{fmt::Debug, hash::Hash};
80use rand_core::CryptoRng;
81#[cfg(feature = "std")]
82use std::{collections::BTreeSet, sync::Arc, vec::Vec};
83use thiserror::Error;
84
85#[derive(Clone, Debug)]
87pub struct Attestation<S: Scheme> {
88 pub signer: Participant,
90 pub signature: Lazy<S::Signature>,
92}
93
94impl<S: Scheme> PartialEq for Attestation<S> {
95 fn eq(&self, other: &Self) -> bool {
96 self.signer == other.signer && self.signature == other.signature
97 }
98}
99
100impl<S: Scheme> Eq for Attestation<S> {}
101
102impl<S: Scheme> Hash for Attestation<S> {
103 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
104 self.signer.hash(state);
105 self.signature.hash(state);
106 }
107}
108
109impl<S: Scheme> Write for Attestation<S> {
110 fn write(&self, writer: &mut impl BufMut) {
111 self.signer.write(writer);
112 self.signature.write(writer);
113 }
114}
115
116impl<S: Scheme> EncodeSize for Attestation<S> {
117 fn encode_size(&self) -> usize {
118 self.signer.encode_size() + self.signature.encode_size()
119 }
120}
121
122impl<S: Scheme> Read for Attestation<S> {
123 type Cfg = ();
124
125 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
126 let signer = Participant::read(reader)?;
127 let signature = ReadExt::read(reader)?;
128
129 Ok(Self { signer, signature })
130 }
131}
132
133#[cfg(feature = "arbitrary")]
134impl<S: Scheme> arbitrary::Arbitrary<'_> for Attestation<S>
135where
136 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
137{
138 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
139 let signer = Participant::arbitrary(u)?;
140 let signature = S::Signature::arbitrary(u)?;
141 Ok(Self {
142 signer,
143 signature: signature.into(),
144 })
145 }
146}
147
148pub struct Verification<S: Scheme> {
150 pub verified: Vec<Attestation<S>>,
152 pub invalid: Vec<Participant>,
154}
155
156impl<S: Scheme> Verification<S> {
157 pub const fn new(verified: Vec<Attestation<S>>, invalid: Vec<Participant>) -> Self {
159 Self { verified, invalid }
160 }
161}
162
163#[derive(Debug, Error, PartialEq, Eq)]
165pub enum AssemblyError {
166 #[error("insufficient attestations: expected={0}, found={1}")]
168 InsufficientAttestations(u32, u32),
169 #[error("unknown signer: {0}")]
171 UnknownSigner(Participant),
172 #[error("duplicate signer: {0}")]
174 DuplicateSigner(Participant),
175 #[error("malformed signature from signer: {0}")]
177 MalformedSignature(Participant),
178 #[error("certificate recovery failed")]
180 RecoveryFailed,
181}
182
183pub trait Namespace: Clone + Send + Sync {
188 fn derive(namespace: &[u8]) -> Self;
190}
191
192impl Namespace for Vec<u8> {
193 fn derive(namespace: &[u8]) -> Self {
194 namespace.to_vec()
195 }
196}
197
198pub trait Subject: Clone + Debug + Send + Sync {
200 type Namespace: Namespace;
202
203 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8];
205
206 fn message(&self) -> Bytes;
208}
209
210pub trait Verifier: Clone + Debug + Send + Sync + 'static {
215 type Subject<'a, D: Digest>: Subject;
217
218 type Faults: Faults;
220
221 type PublicKey: PublicKey;
223
224 type Certificate: Clone + Debug + PartialEq + Eq + Hash + Send + Sync + Codec;
226
227 fn verify_certificate<R, D>(
229 &self,
230 rng: &mut R,
231 subject: Self::Subject<'_, D>,
232 certificate: &Self::Certificate,
233 strategy: &impl Strategy,
234 ) -> bool
235 where
236 R: CryptoRng,
237 D: Digest;
238
239 fn verify_certificates<'a, R, D, I>(
242 &self,
243 rng: &mut R,
244 certificates: NonEmpty<I>,
245 strategy: &impl Strategy,
246 ) -> bool
247 where
248 R: CryptoRng,
249 D: Digest,
250 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
251 {
252 for (subject, certificate) in certificates {
253 if !self.verify_certificate(rng, subject, certificate, strategy) {
254 return false;
255 }
256 }
257
258 true
259 }
260
261 fn verify_certificates_bisect<'a, R, D>(
268 &self,
269 rng: &mut R,
270 certificates: &[(Self::Subject<'a, D>, &'a Self::Certificate)],
271 strategy: &impl Strategy,
272 ) -> Vec<bool>
273 where
274 R: CryptoRng,
275 D: Digest,
276 Self::Subject<'a, D>: Copy,
277 Self::Certificate: 'a,
278 {
279 let len = certificates.len();
280 let mut verified = vec![false; len];
281 if len == 0 {
282 return verified;
283 }
284
285 if !Self::is_batchable() {
288 for (i, (subject, certificate)) in certificates.iter().enumerate() {
289 verified[i] = self.verify_certificate(rng, *subject, certificate, strategy);
290 }
291 return verified;
292 }
293
294 let mut stack = vec![(0, len)];
306 while let Some((start, end)) = stack.pop() {
307 let (first, rest) = certificates[start..end]
308 .split_first()
309 .expect("bisection ranges are non-empty");
310 let certificates = NonEmpty::new(*first, rest.iter().copied());
311 if self.verify_certificates(rng, certificates, strategy) {
312 verified[start..end].fill(true);
313 } else if end - start > 1 {
314 let mid = start + (end - start) / 2;
315 stack.push((mid, end));
316 stack.push((start, mid));
317 }
318 }
319
320 verified
321 }
322
323 fn is_batchable() -> bool;
331
332 fn certificate_codec_config(&self) -> <Self::Certificate as Read>::Cfg;
334
335 fn certificate_codec_config_unbounded() -> <Self::Certificate as Read>::Cfg;
340}
341
342pub trait Scheme: Verifier {
348 type Signature: Clone + Debug + PartialEq + Eq + Hash + Send + Sync + CodecFixed<Cfg = ()>;
350
351 fn me(&self) -> Option<Participant>;
354
355 fn participants(&self) -> &Set<Self::PublicKey>;
357
358 fn sign<D: Digest>(&self, subject: Self::Subject<'_, D>) -> Option<Attestation<Self>>;
361
362 fn verify_attestation<R, D>(
364 &self,
365 rng: &mut R,
366 subject: Self::Subject<'_, D>,
367 attestation: &Attestation<Self>,
368 strategy: &impl Strategy,
369 ) -> bool
370 where
371 R: CryptoRng,
372 D: Digest;
373
374 fn verify_attestations<R, D, I>(
380 &self,
381 rng: &mut R,
382 subject: Self::Subject<'_, D>,
383 attestations: I,
384 strategy: &impl Strategy,
385 ) -> Verification<Self>
386 where
387 R: CryptoRng,
388 D: Digest,
389 I: IntoIterator<Item = Attestation<Self>>,
390 I::IntoIter: Send,
391 {
392 let mut invalid = BTreeSet::new();
393
394 let verified = attestations.into_iter().filter_map(|attestation| {
395 if self.verify_attestation(&mut *rng, subject.clone(), &attestation, strategy) {
396 Some(attestation)
397 } else {
398 invalid.insert(attestation.signer);
399 None
400 }
401 });
402
403 Verification::new(verified.collect(), invalid.into_iter().collect())
404 }
405
406 fn assemble<I>(
411 &self,
412 attestations: NonEmpty<I>,
413 strategy: &impl Strategy,
414 ) -> Result<Self::Certificate, AssemblyError>
415 where
416 I: Iterator<Item = Attestation<Self>> + Send;
417
418 fn is_attributable() -> bool;
423}
424
425#[derive(Clone, Debug)]
431pub struct Scoped<S: Scheme> {
432 scheme: Arc<S>,
433 can_sign: bool,
434}
435
436impl<S: Scheme> Scoped<S> {
437 pub const fn verifier(scheme: Arc<S>) -> Self {
439 Self {
440 scheme,
441 can_sign: false,
442 }
443 }
444
445 pub const fn scheme(scheme: Arc<S>) -> Self {
447 Self {
448 scheme,
449 can_sign: true,
450 }
451 }
452
453 pub fn into_scheme(self) -> Option<Arc<S>> {
455 self.can_sign.then_some(self.scheme)
456 }
457}
458
459impl<S: Scheme> Verifier for Scoped<S> {
460 type Subject<'a, D: Digest> = S::Subject<'a, D>;
461 type Faults = S::Faults;
462 type PublicKey = S::PublicKey;
463 type Certificate = S::Certificate;
464
465 fn verify_certificate<R, D>(
466 &self,
467 rng: &mut R,
468 subject: Self::Subject<'_, D>,
469 certificate: &Self::Certificate,
470 strategy: &impl Strategy,
471 ) -> bool
472 where
473 R: CryptoRng,
474 D: Digest,
475 {
476 self.scheme
477 .verify_certificate(rng, subject, certificate, strategy)
478 }
479
480 fn verify_certificates<'a, R, D, I>(
481 &self,
482 rng: &mut R,
483 certificates: NonEmpty<I>,
484 strategy: &impl Strategy,
485 ) -> bool
486 where
487 R: CryptoRng,
488 D: Digest,
489 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
490 {
491 self.scheme.verify_certificates(rng, certificates, strategy)
492 }
493
494 fn is_batchable() -> bool {
495 S::is_batchable()
496 }
497
498 fn certificate_codec_config(&self) -> <Self::Certificate as Read>::Cfg {
499 self.scheme.certificate_codec_config()
500 }
501
502 fn certificate_codec_config_unbounded() -> <Self::Certificate as Read>::Cfg {
503 S::certificate_codec_config_unbounded()
504 }
505}
506
507pub trait Provider: Clone + Send + Sync + 'static {
512 type Scope: Clone + Send + Sync + 'static;
514 type Scheme: Scheme;
516
517 fn scoped(&self, scope: Self::Scope) -> Option<Scoped<Self::Scheme>>;
524
525 fn scheme(&self, scope: Self::Scope) -> Option<Arc<Self::Scheme>> {
531 self.scoped(scope).and_then(Scoped::into_scheme)
532 }
533}
534
535#[derive(Clone, Debug, PartialEq, Eq, Hash)]
539pub struct Signers {
540 bitmap: BitMap<1>,
541}
542
543impl Signers {
544 pub fn new(
549 participants: u32,
550 signers: impl IntoIterator<Item = Participant>,
551 ) -> Result<Self, AssemblyError> {
552 let mut bitmap = BitMap::zeroes(u64::from(participants));
553 for signer in signers.into_iter() {
554 let index = u64::from(signer.get());
555 if index >= bitmap.len() {
556 return Err(AssemblyError::UnknownSigner(signer));
557 }
558 if bitmap.get(index) {
559 return Err(AssemblyError::DuplicateSigner(signer));
560 }
561 bitmap.set(index, true);
562 }
563
564 Ok(Self { bitmap })
565 }
566
567 pub(crate) fn require(self, required: u32) -> Result<Self, AssemblyError> {
569 let found = u32::try_from(self.count()).expect("signer count exceeds u32::MAX");
570 if found < required {
571 return Err(AssemblyError::InsufficientAttestations(required, found));
572 }
573
574 Ok(self)
575 }
576
577 #[allow(clippy::len_without_is_empty)]
579 pub const fn len(&self) -> usize {
580 self.bitmap.len() as usize
581 }
582
583 pub fn count(&self) -> usize {
585 self.bitmap.count_ones() as usize
586 }
587
588 pub fn iter(&self) -> impl Iterator<Item = Participant> + '_ {
590 self.bitmap
591 .ones_iter()
592 .map(|index| Participant::from_usize(index as usize))
593 }
594}
595
596impl<'a, P, I> TryFrom<(&'a Set<P>, I)> for Signers
602where
603 I: IntoIterator<Item = Participant>,
604{
605 type Error = AssemblyError;
606
607 fn try_from((participants, signers): (&'a Set<P>, I)) -> Result<Self, Self::Error> {
608 let total = u32::try_from(participants.len()).expect("participant count exceeds u32::MAX");
609 Self::new(total, signers)
610 }
611}
612
613impl Write for Signers {
614 fn write(&self, writer: &mut impl BufMut) {
615 self.bitmap.write(writer);
616 }
617}
618
619impl EncodeSize for Signers {
620 fn encode_size(&self) -> usize {
621 self.bitmap.encode_size()
622 }
623}
624
625impl Read for Signers {
626 type Cfg = usize;
627
628 fn read_cfg(reader: &mut impl Buf, max_participants: &usize) -> Result<Self, CodecError> {
629 let bitmap = BitMap::read_cfg(reader, &(*max_participants as u64))?;
630 Ok(Self { bitmap })
637 }
638}
639
640#[cfg(feature = "arbitrary")]
641impl arbitrary::Arbitrary<'_> for Signers {
642 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
643 let participants = u.arbitrary_len::<u8>()? % 10;
644 let signer_count = u.arbitrary_len::<u8>()?.min(participants);
645 let signers = (0..u32::try_from(signer_count).expect("signer count exceeds u32::MAX"))
646 .map(Participant::new)
647 .collect::<Vec<_>>();
648 Ok(Self::new(participants.try_into().unwrap(), signers)
649 .expect("indices are unique and in range"))
650 }
651}
652
653#[derive(Clone, Debug)]
655pub struct ConstantProvider<S: Scheme, Sc = ()> {
656 scheme: Arc<S>,
657 _scope: core::marker::PhantomData<Sc>,
658}
659
660impl<S: Scheme, Sc> ConstantProvider<S, Sc> {
661 pub fn new(scheme: S) -> Self {
663 Self {
664 scheme: Arc::new(scheme),
665 _scope: core::marker::PhantomData,
666 }
667 }
668}
669
670impl<S: Scheme, Sc: Clone + Send + Sync + 'static> crate::certificate::Provider
671 for ConstantProvider<S, Sc>
672{
673 type Scope = Sc;
674 type Scheme = S;
675
676 fn scoped(&self, _: Sc) -> Option<Scoped<S>> {
677 Some(Scoped::scheme(self.scheme.clone()))
678 }
679}
680
681#[cfg(feature = "mocks")]
682pub mod mocks;
683
684#[cfg(test)]
685mod tests {
686 use super::*;
687 use crate::{Signer as _, ed25519::PrivateKey, sha256::Digest as Sha256Digest};
688 use commonware_codec::{Decode, Encode};
689 use commonware_math::algebra::Random;
690 use commonware_parallel::Sequential;
691 use commonware_utils::{TryCollect, non_empty, ordered::Set, test_rng};
692 use ed25519_fixture::{Scheme as Ed25519Scheme, TestSubject};
693
694 #[test]
695 fn test_new_signers() {
696 let signers = Signers::new(6, [0, 3, 5].map(Participant::new)).unwrap();
697 let collected: Vec<_> = signers.iter().collect();
698 assert_eq!(
699 collected,
700 vec![0, 3, 5]
701 .into_iter()
702 .map(Participant::new)
703 .collect::<Vec<_>>()
704 );
705 assert_eq!(signers.count(), 3);
706 }
707
708 #[test]
709 fn test_new_out_of_bounds() {
710 assert_eq!(
711 Signers::new(4, [0, 4].map(Participant::new)),
712 Err(AssemblyError::UnknownSigner(Participant::new(4)))
713 );
714 }
715
716 #[test]
717 fn test_new_duplicate() {
718 assert_eq!(
719 Signers::new(4, [0, 0, 1].map(Participant::new)),
720 Err(AssemblyError::DuplicateSigner(Participant::new(0)))
721 );
722 }
723
724 #[test]
725 fn test_new_not_increasing() {
726 assert!(Signers::new(4, [2, 1].map(Participant::new)).is_ok());
727 }
728
729 #[test]
730 fn test_try_from_set_and_require() {
731 let participants = Set::from_iter_dedup(0..4);
732 let signers = Signers::try_from((&participants, [0, 2, 3].map(Participant::new)))
733 .unwrap()
734 .require(3)
735 .unwrap();
736 assert_eq!(signers.count(), 3);
737 assert_eq!(
738 Signers::try_from((&participants, [0, 2].map(Participant::new)))
739 .unwrap()
740 .require(3),
741 Err(AssemblyError::InsufficientAttestations(3, 2))
742 );
743 }
744
745 #[test]
746 fn test_try_from_set_checks_signer_bounds() {
747 let participants = Set::<u8>::default();
748 let signer = Participant::new(0);
749 assert_eq!(
750 Signers::try_from((&participants, [signer])),
751 Err(AssemblyError::UnknownSigner(signer))
752 );
753 }
754
755 #[test]
756 fn test_codec_round_trip() {
757 let signers = Signers::new(9, [1, 6].map(Participant::new)).unwrap();
758 let encoded = signers.encode();
759 let decoded = Signers::decode_cfg(encoded, &9).unwrap();
760 assert_eq!(decoded, signers);
761 }
762
763 #[test]
764 fn test_decode_respects_participant_limit() {
765 let signers = Signers::new(8, [0, 3, 7].map(Participant::new)).unwrap();
766 let encoded = signers.encode();
767 assert!(Signers::decode_cfg(encoded.clone(), &2).is_err());
769 assert!(Signers::decode_cfg(encoded.clone(), &8).is_ok());
771 assert!(Signers::decode_cfg(encoded, &10).is_ok());
773 }
774
775 mod ed25519_fixture {
776 use crate::{certificate::Subject, impl_certificate_ed25519};
777 use commonware_utils::N3f1;
778
779 #[derive(Copy, Clone, Debug)]
781 pub struct TestSubject {
782 pub message: &'static [u8],
783 }
784
785 impl Subject for TestSubject {
786 type Namespace = Vec<u8>;
787
788 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8] {
789 derived
790 }
791
792 fn message(&self) -> bytes::Bytes {
793 bytes::Bytes::from_static(self.message)
794 }
795 }
796
797 impl_certificate_ed25519!(TestSubject, Vec<u8>, N3f1);
799 }
800
801 const NAMESPACE: &[u8] = b"test-bisect";
802 const MESSAGE: &[u8] = b"good message";
803 const BAD_MESSAGE: &[u8] = b"bad message";
804
805 fn make_certificate(
806 schemes: &[Ed25519Scheme],
807 message: &'static [u8],
808 ) -> <Ed25519Scheme as Verifier>::Certificate {
809 let attestations: Vec<_> = schemes
810 .iter()
811 .filter_map(|s| s.sign::<Sha256Digest>(TestSubject { message }))
812 .collect();
813 schemes[0]
814 .assemble(non_empty![@attestations], &Sequential)
815 .expect("assembly failed")
816 }
817
818 fn setup_ed25519(n: u32) -> (Vec<Ed25519Scheme>, Ed25519Scheme) {
819 let mut rng = test_rng();
820 let private_keys: Vec<_> = (0..n).map(|_| PrivateKey::random(&mut rng)).collect();
821 let participants: Set<crate::ed25519::PublicKey> = private_keys
822 .iter()
823 .map(|sk| sk.public_key())
824 .try_collect()
825 .unwrap();
826 let signers: Vec<_> = private_keys
827 .into_iter()
828 .map(|sk| Ed25519Scheme::signer(NAMESPACE, participants.clone(), sk).unwrap())
829 .collect();
830 let verifier = Ed25519Scheme::verifier(NAMESPACE, participants);
831 (signers, verifier)
832 }
833
834 #[test]
835 fn test_bisect_empty() {
836 let mut rng = test_rng();
837 let (_, verifier) = setup_ed25519(4);
838 let result =
839 verifier.verify_certificates_bisect::<_, Sha256Digest>(&mut rng, &[], &Sequential);
840 assert!(result.is_empty());
841 }
842
843 #[test]
844 fn test_bisect_all_valid() {
845 let mut rng = test_rng();
846 let (schemes, verifier) = setup_ed25519(4);
847 let cert = make_certificate(&schemes, MESSAGE);
848 let good = TestSubject { message: MESSAGE };
849 let pairs: Vec<_> = (0..5).map(|_| (good, &cert)).collect();
850 let result =
851 verifier.verify_certificates_bisect::<_, Sha256Digest>(&mut rng, &pairs, &Sequential);
852 assert_eq!(result, vec![true; 5]);
853 }
854
855 #[test]
856 fn test_bisect_mixed() {
857 let mut rng = test_rng();
858 let (schemes, verifier) = setup_ed25519(4);
859 let cert = make_certificate(&schemes, MESSAGE);
860 let good = TestSubject { message: MESSAGE };
861 let bad = TestSubject {
862 message: BAD_MESSAGE,
863 };
864 let pairs = vec![
865 (good, &cert),
866 (bad, &cert),
867 (good, &cert),
868 (bad, &cert),
869 (good, &cert),
870 (good, &cert),
871 (bad, &cert),
872 (bad, &cert),
873 ];
874 let expected = vec![true, false, true, false, true, true, false, false];
875 let result =
876 verifier.verify_certificates_bisect::<_, Sha256Digest>(&mut rng, &pairs, &Sequential);
877 assert_eq!(result, expected);
878 }
879
880 #[test]
881 fn test_bisect_all_invalid() {
882 let mut rng = test_rng();
883 let (schemes, verifier) = setup_ed25519(4);
884 let cert = make_certificate(&schemes, MESSAGE);
885 let bad = TestSubject {
886 message: BAD_MESSAGE,
887 };
888 let pairs: Vec<_> = (0..4).map(|_| (bad, &cert)).collect();
889 let result =
890 verifier.verify_certificates_bisect::<_, Sha256Digest>(&mut rng, &pairs, &Sequential);
891 assert_eq!(result, vec![false; 4]);
892 }
893
894 #[test]
895 fn test_bisect_single_valid() {
896 let mut rng = test_rng();
897 let (schemes, verifier) = setup_ed25519(4);
898 let cert = make_certificate(&schemes, MESSAGE);
899 let pairs = vec![(TestSubject { message: MESSAGE }, &cert)];
900 let result =
901 verifier.verify_certificates_bisect::<_, Sha256Digest>(&mut rng, &pairs, &Sequential);
902 assert_eq!(result, vec![true]);
903 }
904
905 #[test]
906 fn test_bisect_single_invalid() {
907 let mut rng = test_rng();
908 let (schemes, verifier) = setup_ed25519(4);
909 let cert = make_certificate(&schemes, MESSAGE);
910 let pairs = vec![(
911 TestSubject {
912 message: BAD_MESSAGE,
913 },
914 &cert,
915 )];
916 let result =
917 verifier.verify_certificates_bisect::<_, Sha256Digest>(&mut rng, &pairs, &Sequential);
918 assert_eq!(result, vec![false]);
919 }
920
921 #[test]
922 fn test_scoped_verifies_and_into_scheme() {
923 let mut rng = test_rng();
924 let (schemes, verifier) = setup_ed25519(4);
925 let cert = make_certificate(&schemes, MESSAGE);
926 let subject = TestSubject { message: MESSAGE };
927
928 let as_verifier = Scoped::verifier(Arc::new(verifier));
929 let as_scheme = Scoped::scheme(Arc::new(schemes[0].clone()));
930
931 assert!(as_verifier.verify_certificate::<_, Sha256Digest>(
933 &mut rng,
934 subject,
935 &cert,
936 &Sequential,
937 ));
938 assert!(as_scheme.verify_certificate::<_, Sha256Digest>(
939 &mut rng,
940 subject,
941 &cert,
942 &Sequential,
943 ));
944 let pairs = [(subject, &cert)];
945 assert!(as_verifier.verify_certificates::<_, Sha256Digest, _>(
946 &mut rng,
947 non_empty![@pairs.iter().copied()],
948 &Sequential,
949 ));
950 assert_eq!(
951 <Scoped<Ed25519Scheme> as Verifier>::is_batchable(),
952 <Ed25519Scheme as Verifier>::is_batchable(),
953 );
954 assert_eq!(
955 as_verifier.certificate_codec_config(),
956 schemes[0].certificate_codec_config(),
957 );
958 let _ = <Scoped<Ed25519Scheme> as Verifier>::certificate_codec_config_unbounded();
959
960 assert!(as_verifier.into_scheme().is_none());
962 assert!(as_scheme.into_scheme().is_some());
963
964 let provider = ConstantProvider::<_, ()>::new(schemes[0].clone());
965 assert!(provider.scoped(()).is_some());
966 assert!(provider.scheme(()).is_some());
967 }
968
969 #[cfg(feature = "arbitrary")]
970 mod conformance {
971 use super::{ed25519_fixture::Scheme, *};
972 use commonware_codec::conformance::CodecConformance;
973
974 commonware_conformance::conformance_tests! {
975 CodecConformance<Signers>,
976 CodecConformance<Attestation<Scheme>>,
977 }
978 }
979}