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::CryptoRngCore;
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 Scheme: Clone + Debug + Send + Sync + 'static {
191 type Subject<'a, D: Digest>: Subject;
193
194 type PublicKey: PublicKey;
196 type Signature: Clone + Debug + PartialEq + Eq + Hash + Send + Sync + CodecFixed<Cfg = ()>;
198 type Certificate: Clone + Debug + PartialEq + Eq + Hash + Send + Sync + Codec;
200
201 fn me(&self) -> Option<Participant>;
204
205 fn participants(&self) -> &Set<Self::PublicKey>;
207
208 fn sign<D: Digest>(&self, subject: Self::Subject<'_, D>) -> Option<Attestation<Self>>;
211
212 fn verify_attestation<R, D>(
214 &self,
215 rng: &mut R,
216 subject: Self::Subject<'_, D>,
217 attestation: &Attestation<Self>,
218 strategy: &impl Strategy,
219 ) -> bool
220 where
221 R: CryptoRngCore,
222 D: Digest;
223
224 fn verify_attestations<R, D, I>(
230 &self,
231 rng: &mut R,
232 subject: Self::Subject<'_, D>,
233 attestations: I,
234 strategy: &impl Strategy,
235 ) -> Verification<Self>
236 where
237 R: CryptoRngCore,
238 D: Digest,
239 I: IntoIterator<Item = Attestation<Self>>,
240 I::IntoIter: Send,
241 {
242 let mut invalid = BTreeSet::new();
243
244 let verified = attestations.into_iter().filter_map(|attestation| {
245 if self.verify_attestation(&mut *rng, subject.clone(), &attestation, strategy) {
246 Some(attestation)
247 } else {
248 invalid.insert(attestation.signer);
249 None
250 }
251 });
252
253 Verification::new(verified.collect(), invalid.into_iter().collect())
254 }
255
256 fn assemble<I, M>(
261 &self,
262 attestations: I,
263 strategy: &impl Strategy,
264 ) -> Option<Self::Certificate>
265 where
266 I: IntoIterator<Item = Attestation<Self>>,
267 I::IntoIter: Send,
268 M: Faults;
269
270 fn verify_certificate<R, D, M>(
272 &self,
273 rng: &mut R,
274 subject: Self::Subject<'_, D>,
275 certificate: &Self::Certificate,
276 strategy: &impl Strategy,
277 ) -> bool
278 where
279 R: CryptoRngCore,
280 D: Digest,
281 M: Faults;
282
283 fn verify_certificates<'a, R, D, I, M>(
285 &self,
286 rng: &mut R,
287 certificates: I,
288 strategy: &impl Strategy,
289 ) -> bool
290 where
291 R: CryptoRngCore,
292 D: Digest,
293 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
294 M: Faults,
295 {
296 for (subject, certificate) in certificates {
297 if !self.verify_certificate::<_, _, M>(rng, subject, certificate, strategy) {
298 return false;
299 }
300 }
301
302 true
303 }
304
305 fn verify_certificates_bisect<'a, R, D, M>(
311 &self,
312 rng: &mut R,
313 certificates: &[(Self::Subject<'a, D>, &'a Self::Certificate)],
314 strategy: &impl Strategy,
315 ) -> Vec<bool>
316 where
317 R: CryptoRngCore,
318 D: Digest,
319 Self::Subject<'a, D>: Copy,
320 Self::Certificate: 'a,
321 M: Faults,
322 {
323 let len = certificates.len();
324 let mut verified = vec![false; len];
325 if len == 0 {
326 return verified;
327 }
328
329 if !Self::is_batchable() {
332 for (i, (subject, certificate)) in certificates.iter().enumerate() {
333 verified[i] =
334 self.verify_certificate::<_, _, M>(rng, *subject, certificate, strategy);
335 }
336 return verified;
337 }
338
339 let mut stack = vec![(0, len)];
351 while let Some((start, end)) = stack.pop() {
352 if self.verify_certificates::<_, D, _, M>(
353 rng,
354 certificates[start..end].iter().copied(),
355 strategy,
356 ) {
357 verified[start..end].fill(true);
358 } else if end - start > 1 {
359 let mid = start + (end - start) / 2;
360 stack.push((mid, end));
361 stack.push((start, mid));
362 }
363 }
364
365 verified
366 }
367
368 fn is_attributable() -> bool;
373
374 fn is_batchable() -> bool;
383
384 fn certificate_codec_config(&self) -> <Self::Certificate as Read>::Cfg;
386
387 fn certificate_codec_config_unbounded() -> <Self::Certificate as Read>::Cfg;
392}
393
394pub trait Provider: Clone + Send + Sync + 'static {
399 type Scope: Clone + Send + Sync + 'static;
401 type Scheme: Scheme;
403
404 fn scoped(&self, scope: Self::Scope) -> Option<Arc<Self::Scheme>>;
406
407 fn all(&self) -> Option<Arc<Self::Scheme>> {
418 None
419 }
420}
421
422#[derive(Clone, Debug, PartialEq, Eq, Hash)]
426pub struct Signers {
427 bitmap: BitMap<1>,
428}
429
430impl Signers {
431 pub fn from(participants: usize, signers: impl IntoIterator<Item = Participant>) -> Self {
438 let mut bitmap = BitMap::zeroes(participants as u64);
439 for signer in signers.into_iter() {
440 assert!(
441 !bitmap.get(signer.get() as u64),
442 "duplicate signer index: {signer}",
443 );
444 bitmap.set(signer.get() as u64, true);
449 }
450
451 Self { bitmap }
452 }
453
454 #[allow(clippy::len_without_is_empty)]
456 pub const fn len(&self) -> usize {
457 self.bitmap.len() as usize
458 }
459
460 pub fn count(&self) -> usize {
462 self.bitmap.count_ones() as usize
463 }
464
465 pub fn iter(&self) -> impl Iterator<Item = Participant> + '_ {
467 self.bitmap
468 .iter()
469 .enumerate()
470 .filter_map(|(index, bit)| bit.then_some(Participant::from_usize(index)))
471 }
472}
473
474impl Write for Signers {
475 fn write(&self, writer: &mut impl BufMut) {
476 self.bitmap.write(writer);
477 }
478}
479
480impl EncodeSize for Signers {
481 fn encode_size(&self) -> usize {
482 self.bitmap.encode_size()
483 }
484}
485
486impl Read for Signers {
487 type Cfg = usize;
488
489 fn read_cfg(reader: &mut impl Buf, max_participants: &usize) -> Result<Self, Error> {
490 let bitmap = BitMap::read_cfg(reader, &(*max_participants as u64))?;
491 Ok(Self { bitmap })
498 }
499}
500
501#[cfg(feature = "arbitrary")]
502impl arbitrary::Arbitrary<'_> for Signers {
503 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
504 let participants = u.arbitrary_len::<u8>()? % 10;
505 let signer_count = u.arbitrary_len::<u8>()?.min(participants);
506 let signers = (0..signer_count as u32)
507 .map(Participant::new)
508 .collect::<Vec<_>>();
509 Ok(Self::from(participants, signers))
510 }
511}
512
513#[derive(Clone, Debug)]
515pub struct ConstantProvider<S: Scheme, Sc = ()> {
516 scheme: Arc<S>,
517 _scope: core::marker::PhantomData<Sc>,
518}
519
520impl<S: Scheme, Sc> ConstantProvider<S, Sc> {
521 pub fn new(scheme: S) -> Self {
523 Self {
524 scheme: Arc::new(scheme),
525 _scope: core::marker::PhantomData,
526 }
527 }
528}
529
530impl<S: Scheme, Sc: Clone + Send + Sync + 'static> crate::certificate::Provider
531 for ConstantProvider<S, Sc>
532{
533 type Scope = Sc;
534 type Scheme = S;
535
536 fn scoped(&self, _: Sc) -> Option<Arc<S>> {
537 Some(self.scheme.clone())
538 }
539
540 fn all(&self) -> Option<Arc<Self::Scheme>> {
541 Some(self.scheme.clone())
542 }
543}
544
545#[cfg(feature = "mocks")]
546pub mod mocks {
547 #[derive(Clone, Debug)]
552 pub struct Fixture<S> {
553 pub participants: Vec<crate::ed25519::PublicKey>,
555 pub private_keys: Vec<crate::ed25519::PrivateKey>,
557 pub schemes: Vec<S>,
559 pub verifier: S,
561 }
562}
563
564#[cfg(test)]
565mod tests {
566 use super::*;
567 use crate::{ed25519::PrivateKey, sha256::Digest as Sha256Digest, Signer as _};
568 use commonware_codec::{Decode, Encode};
569 use commonware_math::algebra::Random;
570 use commonware_parallel::Sequential;
571 use commonware_utils::{ordered::Set, test_rng, N3f1, TryCollect};
572 use ed25519_fixture::{Scheme as Ed25519Scheme, TestSubject};
573
574 #[test]
575 fn test_from_signers() {
576 let signers = Signers::from(6, [0, 3, 5].map(Participant::new));
577 let collected: Vec<_> = signers.iter().collect();
578 assert_eq!(
579 collected,
580 vec![0, 3, 5]
581 .into_iter()
582 .map(Participant::new)
583 .collect::<Vec<_>>()
584 );
585 assert_eq!(signers.count(), 3);
586 }
587
588 #[test]
589 #[should_panic(expected = "bit 4 out of bounds (len: 4)")]
590 fn test_from_out_of_bounds() {
591 Signers::from(4, [0, 4].map(Participant::new));
592 }
593
594 #[test]
595 #[should_panic(expected = "duplicate signer index: 0")]
596 fn test_from_duplicate() {
597 Signers::from(4, [0, 0, 1].map(Participant::new));
598 }
599
600 #[test]
601 fn test_from_not_increasing() {
602 Signers::from(4, [2, 1].map(Participant::new));
603 }
604
605 #[test]
606 fn test_codec_round_trip() {
607 let signers = Signers::from(9, [1, 6].map(Participant::new));
608 let encoded = signers.encode();
609 let decoded = Signers::decode_cfg(encoded, &9).unwrap();
610 assert_eq!(decoded, signers);
611 }
612
613 #[test]
614 fn test_decode_respects_participant_limit() {
615 let signers = Signers::from(8, [0, 3, 7].map(Participant::new));
616 let encoded = signers.encode();
617 assert!(Signers::decode_cfg(encoded.clone(), &2).is_err());
619 assert!(Signers::decode_cfg(encoded.clone(), &8).is_ok());
621 assert!(Signers::decode_cfg(encoded, &10).is_ok());
623 }
624
625 mod ed25519_fixture {
626 use crate::{certificate::Subject, impl_certificate_ed25519};
627
628 #[derive(Copy, Clone, Debug)]
630 pub struct TestSubject {
631 pub message: &'static [u8],
632 }
633
634 impl Subject for TestSubject {
635 type Namespace = Vec<u8>;
636
637 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8] {
638 derived
639 }
640
641 fn message(&self) -> bytes::Bytes {
642 bytes::Bytes::from_static(self.message)
643 }
644 }
645
646 impl_certificate_ed25519!(TestSubject, Vec<u8>);
648 }
649
650 const NAMESPACE: &[u8] = b"test-bisect";
651 const MESSAGE: &[u8] = b"good message";
652 const BAD_MESSAGE: &[u8] = b"bad message";
653
654 fn make_certificate(
655 schemes: &[Ed25519Scheme],
656 message: &'static [u8],
657 ) -> <Ed25519Scheme as Scheme>::Certificate {
658 let attestations: Vec<_> = schemes
659 .iter()
660 .filter_map(|s| s.sign::<Sha256Digest>(TestSubject { message }))
661 .collect();
662 schemes[0]
663 .assemble::<_, N3f1>(attestations, &Sequential)
664 .expect("assembly failed")
665 }
666
667 fn setup_ed25519(n: u32) -> (Vec<Ed25519Scheme>, Ed25519Scheme) {
668 let mut rng = test_rng();
669 let private_keys: Vec<_> = (0..n).map(|_| PrivateKey::random(&mut rng)).collect();
670 let participants: Set<crate::ed25519::PublicKey> = private_keys
671 .iter()
672 .map(|sk| sk.public_key())
673 .try_collect()
674 .unwrap();
675 let signers: Vec<_> = private_keys
676 .into_iter()
677 .map(|sk| Ed25519Scheme::signer(NAMESPACE, participants.clone(), sk).unwrap())
678 .collect();
679 let verifier = Ed25519Scheme::verifier(NAMESPACE, participants);
680 (signers, verifier)
681 }
682
683 #[test]
684 fn test_bisect_empty() {
685 let mut rng = test_rng();
686 let (_, verifier) = setup_ed25519(4);
687 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
688 &mut rng,
689 &[],
690 &Sequential,
691 );
692 assert!(result.is_empty());
693 }
694
695 #[test]
696 fn test_bisect_all_valid() {
697 let mut rng = test_rng();
698 let (schemes, verifier) = setup_ed25519(4);
699 let cert = make_certificate(&schemes, MESSAGE);
700 let good = TestSubject { message: MESSAGE };
701 let pairs: Vec<_> = (0..5).map(|_| (good, &cert)).collect();
702 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
703 &mut rng,
704 &pairs,
705 &Sequential,
706 );
707 assert_eq!(result, vec![true; 5]);
708 }
709
710 #[test]
711 fn test_bisect_mixed() {
712 let mut rng = test_rng();
713 let (schemes, verifier) = setup_ed25519(4);
714 let cert = make_certificate(&schemes, MESSAGE);
715 let good = TestSubject { message: MESSAGE };
716 let bad = TestSubject {
717 message: BAD_MESSAGE,
718 };
719 let pairs = vec![
720 (good, &cert),
721 (bad, &cert),
722 (good, &cert),
723 (bad, &cert),
724 (good, &cert),
725 (good, &cert),
726 (bad, &cert),
727 (bad, &cert),
728 ];
729 let expected = vec![true, false, true, false, true, true, false, false];
730 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
731 &mut rng,
732 &pairs,
733 &Sequential,
734 );
735 assert_eq!(result, expected);
736 }
737
738 #[test]
739 fn test_bisect_all_invalid() {
740 let mut rng = test_rng();
741 let (schemes, verifier) = setup_ed25519(4);
742 let cert = make_certificate(&schemes, MESSAGE);
743 let bad = TestSubject {
744 message: BAD_MESSAGE,
745 };
746 let pairs: Vec<_> = (0..4).map(|_| (bad, &cert)).collect();
747 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
748 &mut rng,
749 &pairs,
750 &Sequential,
751 );
752 assert_eq!(result, vec![false; 4]);
753 }
754
755 #[test]
756 fn test_bisect_single_valid() {
757 let mut rng = test_rng();
758 let (schemes, verifier) = setup_ed25519(4);
759 let cert = make_certificate(&schemes, MESSAGE);
760 let pairs = vec![(TestSubject { message: MESSAGE }, &cert)];
761 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
762 &mut rng,
763 &pairs,
764 &Sequential,
765 );
766 assert_eq!(result, vec![true]);
767 }
768
769 #[test]
770 fn test_bisect_single_invalid() {
771 let mut rng = test_rng();
772 let (schemes, verifier) = setup_ed25519(4);
773 let cert = make_certificate(&schemes, MESSAGE);
774 let pairs = vec![(
775 TestSubject {
776 message: BAD_MESSAGE,
777 },
778 &cert,
779 )];
780 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
781 &mut rng,
782 &pairs,
783 &Sequential,
784 );
785 assert_eq!(result, vec![false]);
786 }
787
788 #[cfg(feature = "arbitrary")]
789 mod conformance {
790 use super::{ed25519_fixture::Scheme, *};
791 use commonware_codec::conformance::CodecConformance;
792
793 commonware_conformance::conformance_tests! {
794 CodecConformance<Signers>,
795 CodecConformance<Attestation<Scheme>>,
796 }
797 }
798}