1#[commonware_macros::stability(ALPHA)]
61pub use crate::secp256r1::certificate as secp256r1;
62pub use crate::{
63 bls12381::certificate::{multisig as bls12381_multisig, threshold as bls12381_threshold},
64 ed25519::certificate as ed25519,
65};
66use crate::{Digest, PublicKey};
67#[cfg(not(feature = "std"))]
68use alloc::{collections::BTreeSet, sync::Arc, vec, vec::Vec};
69use bytes::{Buf, BufMut, Bytes};
70use commonware_codec::{
71 types::lazy::Lazy, Codec, CodecFixed, EncodeSize, Error, Read, ReadExt, Write,
72};
73use commonware_parallel::Strategy;
74use commonware_utils::{bitmap::BitMap, ordered::Set, Faults, Participant};
75use core::{fmt::Debug, hash::Hash};
76use rand_core::CryptoRng;
77#[cfg(feature = "std")]
78use std::{collections::BTreeSet, sync::Arc, vec::Vec};
79
80#[derive(Clone, Debug)]
82pub struct Attestation<S: Scheme> {
83 pub signer: Participant,
85 pub signature: Lazy<S::Signature>,
87}
88
89impl<S: Scheme> PartialEq for Attestation<S> {
90 fn eq(&self, other: &Self) -> bool {
91 self.signer == other.signer && self.signature == other.signature
92 }
93}
94
95impl<S: Scheme> Eq for Attestation<S> {}
96
97impl<S: Scheme> Hash for Attestation<S> {
98 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
99 self.signer.hash(state);
100 self.signature.hash(state);
101 }
102}
103
104impl<S: Scheme> Write for Attestation<S> {
105 fn write(&self, writer: &mut impl BufMut) {
106 self.signer.write(writer);
107 self.signature.write(writer);
108 }
109}
110
111impl<S: Scheme> EncodeSize for Attestation<S> {
112 fn encode_size(&self) -> usize {
113 self.signer.encode_size() + self.signature.encode_size()
114 }
115}
116
117impl<S: Scheme> Read for Attestation<S> {
118 type Cfg = ();
119
120 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
121 let signer = Participant::read(reader)?;
122 let signature = ReadExt::read(reader)?;
123
124 Ok(Self { signer, signature })
125 }
126}
127
128#[cfg(feature = "arbitrary")]
129impl<S: Scheme> arbitrary::Arbitrary<'_> for Attestation<S>
130where
131 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
132{
133 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
134 let signer = Participant::arbitrary(u)?;
135 let signature = S::Signature::arbitrary(u)?;
136 Ok(Self {
137 signer,
138 signature: signature.into(),
139 })
140 }
141}
142
143pub struct Verification<S: Scheme> {
145 pub verified: Vec<Attestation<S>>,
147 pub invalid: Vec<Participant>,
149}
150
151impl<S: Scheme> Verification<S> {
152 pub const fn new(verified: Vec<Attestation<S>>, invalid: Vec<Participant>) -> Self {
154 Self { verified, invalid }
155 }
156}
157
158pub trait Namespace: Clone + Send + Sync {
163 fn derive(namespace: &[u8]) -> Self;
165}
166
167impl Namespace for Vec<u8> {
168 fn derive(namespace: &[u8]) -> Self {
169 namespace.to_vec()
170 }
171}
172
173pub trait Subject: Clone + Debug + Send + Sync {
175 type Namespace: Namespace;
177
178 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8];
180
181 fn message(&self) -> Bytes;
183}
184
185pub trait Verifier: Clone + Debug + Send + Sync + 'static {
190 type Subject<'a, D: Digest>: Subject;
192
193 type PublicKey: PublicKey;
195 type Certificate: Clone + Debug + PartialEq + Eq + Hash + Send + Sync + Codec;
197
198 fn verify_certificate<R, D, M>(
200 &self,
201 rng: &mut R,
202 subject: Self::Subject<'_, D>,
203 certificate: &Self::Certificate,
204 strategy: &impl Strategy,
205 ) -> bool
206 where
207 R: CryptoRng,
208 D: Digest,
209 M: Faults;
210
211 fn verify_certificates<'a, R, D, I, M>(
213 &self,
214 rng: &mut R,
215 certificates: I,
216 strategy: &impl Strategy,
217 ) -> bool
218 where
219 R: CryptoRng,
220 D: Digest,
221 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
222 M: Faults,
223 {
224 for (subject, certificate) in certificates {
225 if !self.verify_certificate::<_, _, M>(rng, subject, certificate, strategy) {
226 return false;
227 }
228 }
229
230 true
231 }
232
233 fn verify_certificates_bisect<'a, R, D, M>(
239 &self,
240 rng: &mut R,
241 certificates: &[(Self::Subject<'a, D>, &'a Self::Certificate)],
242 strategy: &impl Strategy,
243 ) -> Vec<bool>
244 where
245 R: CryptoRng,
246 D: Digest,
247 Self::Subject<'a, D>: Copy,
248 Self::Certificate: 'a,
249 M: Faults,
250 {
251 let len = certificates.len();
252 let mut verified = vec![false; len];
253 if len == 0 {
254 return verified;
255 }
256
257 if !Self::is_batchable() {
260 for (i, (subject, certificate)) in certificates.iter().enumerate() {
261 verified[i] =
262 self.verify_certificate::<_, _, M>(rng, *subject, certificate, strategy);
263 }
264 return verified;
265 }
266
267 let mut stack = vec![(0, len)];
279 while let Some((start, end)) = stack.pop() {
280 if self.verify_certificates::<_, D, _, M>(
281 rng,
282 certificates[start..end].iter().copied(),
283 strategy,
284 ) {
285 verified[start..end].fill(true);
286 } else if end - start > 1 {
287 let mid = start + (end - start) / 2;
288 stack.push((mid, end));
289 stack.push((start, mid));
290 }
291 }
292
293 verified
294 }
295
296 fn is_batchable() -> bool;
305
306 fn certificate_codec_config(&self) -> <Self::Certificate as Read>::Cfg;
308
309 fn certificate_codec_config_unbounded() -> <Self::Certificate as Read>::Cfg;
314}
315
316pub trait Scheme: Verifier {
322 type Signature: Clone + Debug + PartialEq + Eq + Hash + Send + Sync + CodecFixed<Cfg = ()>;
324
325 fn me(&self) -> Option<Participant>;
328
329 fn participants(&self) -> &Set<Self::PublicKey>;
331
332 fn sign<D: Digest>(&self, subject: Self::Subject<'_, D>) -> Option<Attestation<Self>>;
335
336 fn verify_attestation<R, D>(
338 &self,
339 rng: &mut R,
340 subject: Self::Subject<'_, D>,
341 attestation: &Attestation<Self>,
342 strategy: &impl Strategy,
343 ) -> bool
344 where
345 R: CryptoRng,
346 D: Digest;
347
348 fn verify_attestations<R, D, I>(
354 &self,
355 rng: &mut R,
356 subject: Self::Subject<'_, D>,
357 attestations: I,
358 strategy: &impl Strategy,
359 ) -> Verification<Self>
360 where
361 R: CryptoRng,
362 D: Digest,
363 I: IntoIterator<Item = Attestation<Self>>,
364 I::IntoIter: Send,
365 {
366 let mut invalid = BTreeSet::new();
367
368 let verified = attestations.into_iter().filter_map(|attestation| {
369 if self.verify_attestation(&mut *rng, subject.clone(), &attestation, strategy) {
370 Some(attestation)
371 } else {
372 invalid.insert(attestation.signer);
373 None
374 }
375 });
376
377 Verification::new(verified.collect(), invalid.into_iter().collect())
378 }
379
380 fn assemble<I, M>(
385 &self,
386 attestations: I,
387 strategy: &impl Strategy,
388 ) -> Option<Self::Certificate>
389 where
390 I: IntoIterator<Item = Attestation<Self>>,
391 I::IntoIter: Send,
392 M: Faults;
393
394 fn is_attributable() -> bool;
399}
400
401#[derive(Clone, Debug)]
407pub struct Scoped<S: Scheme> {
408 scheme: Arc<S>,
409 can_sign: bool,
410}
411
412impl<S: Scheme> Scoped<S> {
413 pub const fn verifier(scheme: Arc<S>) -> Self {
415 Self {
416 scheme,
417 can_sign: false,
418 }
419 }
420
421 pub const fn scheme(scheme: Arc<S>) -> Self {
423 Self {
424 scheme,
425 can_sign: true,
426 }
427 }
428
429 pub fn into_scheme(self) -> Option<Arc<S>> {
431 self.can_sign.then_some(self.scheme)
432 }
433}
434
435impl<S: Scheme> Verifier for Scoped<S> {
436 type Subject<'a, D: Digest> = S::Subject<'a, D>;
437 type PublicKey = S::PublicKey;
438 type Certificate = S::Certificate;
439
440 fn verify_certificate<R, D, M>(
441 &self,
442 rng: &mut R,
443 subject: Self::Subject<'_, D>,
444 certificate: &Self::Certificate,
445 strategy: &impl Strategy,
446 ) -> bool
447 where
448 R: CryptoRng,
449 D: Digest,
450 M: Faults,
451 {
452 self.scheme
453 .verify_certificate::<_, D, M>(rng, subject, certificate, strategy)
454 }
455
456 fn verify_certificates<'a, R, D, I, M>(
457 &self,
458 rng: &mut R,
459 certificates: I,
460 strategy: &impl Strategy,
461 ) -> bool
462 where
463 R: CryptoRng,
464 D: Digest,
465 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
466 M: Faults,
467 {
468 self.scheme
469 .verify_certificates::<_, D, _, M>(rng, certificates, strategy)
470 }
471
472 fn is_batchable() -> bool {
473 S::is_batchable()
474 }
475
476 fn certificate_codec_config(&self) -> <Self::Certificate as Read>::Cfg {
477 self.scheme.certificate_codec_config()
478 }
479
480 fn certificate_codec_config_unbounded() -> <Self::Certificate as Read>::Cfg {
481 S::certificate_codec_config_unbounded()
482 }
483}
484
485pub trait Provider: Clone + Send + Sync + 'static {
490 type Scope: Clone + Send + Sync + 'static;
492 type Scheme: Scheme;
494
495 fn scoped(&self, scope: Self::Scope) -> Option<Scoped<Self::Scheme>>;
502
503 fn scheme(&self, scope: Self::Scope) -> Option<Arc<Self::Scheme>> {
509 self.scoped(scope).and_then(Scoped::into_scheme)
510 }
511}
512
513#[derive(Clone, Debug, PartialEq, Eq, Hash)]
517pub struct Signers {
518 bitmap: BitMap<1>,
519}
520
521impl Signers {
522 pub fn from(participants: usize, signers: impl IntoIterator<Item = Participant>) -> Self {
529 let mut bitmap = BitMap::zeroes(participants as u64);
530 for signer in signers.into_iter() {
531 assert!(
532 !bitmap.get(signer.get() as u64),
533 "duplicate signer index: {signer}",
534 );
535 bitmap.set(signer.get() as u64, true);
540 }
541
542 Self { bitmap }
543 }
544
545 #[allow(clippy::len_without_is_empty)]
547 pub const fn len(&self) -> usize {
548 self.bitmap.len() as usize
549 }
550
551 pub fn count(&self) -> usize {
553 self.bitmap.count_ones() as usize
554 }
555
556 pub fn iter(&self) -> impl Iterator<Item = Participant> + '_ {
558 self.bitmap
559 .iter()
560 .enumerate()
561 .filter_map(|(index, bit)| bit.then_some(Participant::from_usize(index)))
562 }
563}
564
565impl Write for Signers {
566 fn write(&self, writer: &mut impl BufMut) {
567 self.bitmap.write(writer);
568 }
569}
570
571impl EncodeSize for Signers {
572 fn encode_size(&self) -> usize {
573 self.bitmap.encode_size()
574 }
575}
576
577impl Read for Signers {
578 type Cfg = usize;
579
580 fn read_cfg(reader: &mut impl Buf, max_participants: &usize) -> Result<Self, Error> {
581 let bitmap = BitMap::read_cfg(reader, &(*max_participants as u64))?;
582 Ok(Self { bitmap })
589 }
590}
591
592#[cfg(feature = "arbitrary")]
593impl arbitrary::Arbitrary<'_> for Signers {
594 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
595 let participants = u.arbitrary_len::<u8>()? % 10;
596 let signer_count = u.arbitrary_len::<u8>()?.min(participants);
597 let signers = (0..signer_count as u32)
598 .map(Participant::new)
599 .collect::<Vec<_>>();
600 Ok(Self::from(participants, signers))
601 }
602}
603
604#[derive(Clone, Debug)]
606pub struct ConstantProvider<S: Scheme, Sc = ()> {
607 scheme: Arc<S>,
608 _scope: core::marker::PhantomData<Sc>,
609}
610
611impl<S: Scheme, Sc> ConstantProvider<S, Sc> {
612 pub fn new(scheme: S) -> Self {
614 Self {
615 scheme: Arc::new(scheme),
616 _scope: core::marker::PhantomData,
617 }
618 }
619}
620
621impl<S: Scheme, Sc: Clone + Send + Sync + 'static> crate::certificate::Provider
622 for ConstantProvider<S, Sc>
623{
624 type Scope = Sc;
625 type Scheme = S;
626
627 fn scoped(&self, _: Sc) -> Option<Scoped<S>> {
628 Some(Scoped::scheme(self.scheme.clone()))
629 }
630}
631
632#[cfg(feature = "mocks")]
633pub mod mocks;
634
635#[cfg(test)]
636mod tests {
637 use super::*;
638 use crate::{ed25519::PrivateKey, sha256::Digest as Sha256Digest, Signer as _};
639 use commonware_codec::{Decode, Encode};
640 use commonware_math::algebra::Random;
641 use commonware_parallel::Sequential;
642 use commonware_utils::{ordered::Set, test_rng, N3f1, TryCollect};
643 use ed25519_fixture::{Scheme as Ed25519Scheme, TestSubject};
644
645 #[test]
646 fn test_from_signers() {
647 let signers = Signers::from(6, [0, 3, 5].map(Participant::new));
648 let collected: Vec<_> = signers.iter().collect();
649 assert_eq!(
650 collected,
651 vec![0, 3, 5]
652 .into_iter()
653 .map(Participant::new)
654 .collect::<Vec<_>>()
655 );
656 assert_eq!(signers.count(), 3);
657 }
658
659 #[test]
660 #[should_panic(expected = "bit 4 out of bounds (len: 4)")]
661 fn test_from_out_of_bounds() {
662 Signers::from(4, [0, 4].map(Participant::new));
663 }
664
665 #[test]
666 #[should_panic(expected = "duplicate signer index: 0")]
667 fn test_from_duplicate() {
668 Signers::from(4, [0, 0, 1].map(Participant::new));
669 }
670
671 #[test]
672 fn test_from_not_increasing() {
673 Signers::from(4, [2, 1].map(Participant::new));
674 }
675
676 #[test]
677 fn test_codec_round_trip() {
678 let signers = Signers::from(9, [1, 6].map(Participant::new));
679 let encoded = signers.encode();
680 let decoded = Signers::decode_cfg(encoded, &9).unwrap();
681 assert_eq!(decoded, signers);
682 }
683
684 #[test]
685 fn test_decode_respects_participant_limit() {
686 let signers = Signers::from(8, [0, 3, 7].map(Participant::new));
687 let encoded = signers.encode();
688 assert!(Signers::decode_cfg(encoded.clone(), &2).is_err());
690 assert!(Signers::decode_cfg(encoded.clone(), &8).is_ok());
692 assert!(Signers::decode_cfg(encoded, &10).is_ok());
694 }
695
696 mod ed25519_fixture {
697 use crate::{certificate::Subject, impl_certificate_ed25519};
698
699 #[derive(Copy, Clone, Debug)]
701 pub struct TestSubject {
702 pub message: &'static [u8],
703 }
704
705 impl Subject for TestSubject {
706 type Namespace = Vec<u8>;
707
708 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8] {
709 derived
710 }
711
712 fn message(&self) -> bytes::Bytes {
713 bytes::Bytes::from_static(self.message)
714 }
715 }
716
717 impl_certificate_ed25519!(TestSubject, Vec<u8>);
719 }
720
721 const NAMESPACE: &[u8] = b"test-bisect";
722 const MESSAGE: &[u8] = b"good message";
723 const BAD_MESSAGE: &[u8] = b"bad message";
724
725 fn make_certificate(
726 schemes: &[Ed25519Scheme],
727 message: &'static [u8],
728 ) -> <Ed25519Scheme as Verifier>::Certificate {
729 let attestations: Vec<_> = schemes
730 .iter()
731 .filter_map(|s| s.sign::<Sha256Digest>(TestSubject { message }))
732 .collect();
733 schemes[0]
734 .assemble::<_, N3f1>(attestations, &Sequential)
735 .expect("assembly failed")
736 }
737
738 fn setup_ed25519(n: u32) -> (Vec<Ed25519Scheme>, Ed25519Scheme) {
739 let mut rng = test_rng();
740 let private_keys: Vec<_> = (0..n).map(|_| PrivateKey::random(&mut rng)).collect();
741 let participants: Set<crate::ed25519::PublicKey> = private_keys
742 .iter()
743 .map(|sk| sk.public_key())
744 .try_collect()
745 .unwrap();
746 let signers: Vec<_> = private_keys
747 .into_iter()
748 .map(|sk| Ed25519Scheme::signer(NAMESPACE, participants.clone(), sk).unwrap())
749 .collect();
750 let verifier = Ed25519Scheme::verifier(NAMESPACE, participants);
751 (signers, verifier)
752 }
753
754 #[test]
755 fn test_bisect_empty() {
756 let mut rng = test_rng();
757 let (_, verifier) = setup_ed25519(4);
758 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
759 &mut rng,
760 &[],
761 &Sequential,
762 );
763 assert!(result.is_empty());
764 }
765
766 #[test]
767 fn test_bisect_all_valid() {
768 let mut rng = test_rng();
769 let (schemes, verifier) = setup_ed25519(4);
770 let cert = make_certificate(&schemes, MESSAGE);
771 let good = TestSubject { message: MESSAGE };
772 let pairs: Vec<_> = (0..5).map(|_| (good, &cert)).collect();
773 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
774 &mut rng,
775 &pairs,
776 &Sequential,
777 );
778 assert_eq!(result, vec![true; 5]);
779 }
780
781 #[test]
782 fn test_bisect_mixed() {
783 let mut rng = test_rng();
784 let (schemes, verifier) = setup_ed25519(4);
785 let cert = make_certificate(&schemes, MESSAGE);
786 let good = TestSubject { message: MESSAGE };
787 let bad = TestSubject {
788 message: BAD_MESSAGE,
789 };
790 let pairs = vec![
791 (good, &cert),
792 (bad, &cert),
793 (good, &cert),
794 (bad, &cert),
795 (good, &cert),
796 (good, &cert),
797 (bad, &cert),
798 (bad, &cert),
799 ];
800 let expected = vec![true, false, true, false, true, true, false, false];
801 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
802 &mut rng,
803 &pairs,
804 &Sequential,
805 );
806 assert_eq!(result, expected);
807 }
808
809 #[test]
810 fn test_bisect_all_invalid() {
811 let mut rng = test_rng();
812 let (schemes, verifier) = setup_ed25519(4);
813 let cert = make_certificate(&schemes, MESSAGE);
814 let bad = TestSubject {
815 message: BAD_MESSAGE,
816 };
817 let pairs: Vec<_> = (0..4).map(|_| (bad, &cert)).collect();
818 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
819 &mut rng,
820 &pairs,
821 &Sequential,
822 );
823 assert_eq!(result, vec![false; 4]);
824 }
825
826 #[test]
827 fn test_bisect_single_valid() {
828 let mut rng = test_rng();
829 let (schemes, verifier) = setup_ed25519(4);
830 let cert = make_certificate(&schemes, MESSAGE);
831 let pairs = vec![(TestSubject { message: MESSAGE }, &cert)];
832 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
833 &mut rng,
834 &pairs,
835 &Sequential,
836 );
837 assert_eq!(result, vec![true]);
838 }
839
840 #[test]
841 fn test_bisect_single_invalid() {
842 let mut rng = test_rng();
843 let (schemes, verifier) = setup_ed25519(4);
844 let cert = make_certificate(&schemes, MESSAGE);
845 let pairs = vec![(
846 TestSubject {
847 message: BAD_MESSAGE,
848 },
849 &cert,
850 )];
851 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
852 &mut rng,
853 &pairs,
854 &Sequential,
855 );
856 assert_eq!(result, vec![false]);
857 }
858
859 #[test]
860 fn test_scoped_verifies_and_into_scheme() {
861 let mut rng = test_rng();
862 let (schemes, verifier) = setup_ed25519(4);
863 let cert = make_certificate(&schemes, MESSAGE);
864 let subject = TestSubject { message: MESSAGE };
865
866 let as_verifier = Scoped::verifier(Arc::new(verifier));
867 let as_scheme = Scoped::scheme(Arc::new(schemes[0].clone()));
868
869 assert!(as_verifier.verify_certificate::<_, Sha256Digest, N3f1>(
871 &mut rng,
872 subject,
873 &cert,
874 &Sequential,
875 ));
876 assert!(as_scheme.verify_certificate::<_, Sha256Digest, N3f1>(
877 &mut rng,
878 subject,
879 &cert,
880 &Sequential,
881 ));
882 let pairs = [(subject, &cert)];
883 assert!(as_verifier.verify_certificates::<_, Sha256Digest, _, N3f1>(
884 &mut rng,
885 pairs.iter().copied(),
886 &Sequential,
887 ));
888 assert_eq!(
889 <Scoped<Ed25519Scheme> as Verifier>::is_batchable(),
890 <Ed25519Scheme as Verifier>::is_batchable(),
891 );
892 assert_eq!(
893 as_verifier.certificate_codec_config(),
894 schemes[0].certificate_codec_config(),
895 );
896 let _ = <Scoped<Ed25519Scheme> as Verifier>::certificate_codec_config_unbounded();
897
898 assert!(as_verifier.into_scheme().is_none());
900 assert!(as_scheme.into_scheme().is_some());
901
902 let provider = ConstantProvider::<_, ()>::new(schemes[0].clone());
903 assert!(provider.scoped(()).is_some());
904 assert!(provider.scheme(()).is_some());
905 }
906
907 #[cfg(feature = "arbitrary")]
908 mod conformance {
909 use super::{ed25519_fixture::Scheme, *};
910 use commonware_codec::conformance::CodecConformance;
911
912 commonware_conformance::conformance_tests! {
913 CodecConformance<Signers>,
914 CodecConformance<Attestation<Scheme>>,
915 }
916 }
917}