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
548#[cfg(test)]
549mod tests {
550 use super::*;
551 use crate::{ed25519::PrivateKey, sha256::Digest as Sha256Digest, Signer as _};
552 use commonware_codec::{Decode, Encode};
553 use commonware_math::algebra::Random;
554 use commonware_parallel::Sequential;
555 use commonware_utils::{ordered::Set, test_rng, N3f1, TryCollect};
556 use ed25519_fixture::{Scheme as Ed25519Scheme, TestSubject};
557
558 #[test]
559 fn test_from_signers() {
560 let signers = Signers::from(6, [0, 3, 5].map(Participant::new));
561 let collected: Vec<_> = signers.iter().collect();
562 assert_eq!(
563 collected,
564 vec![0, 3, 5]
565 .into_iter()
566 .map(Participant::new)
567 .collect::<Vec<_>>()
568 );
569 assert_eq!(signers.count(), 3);
570 }
571
572 #[test]
573 #[should_panic(expected = "bit 4 out of bounds (len: 4)")]
574 fn test_from_out_of_bounds() {
575 Signers::from(4, [0, 4].map(Participant::new));
576 }
577
578 #[test]
579 #[should_panic(expected = "duplicate signer index: 0")]
580 fn test_from_duplicate() {
581 Signers::from(4, [0, 0, 1].map(Participant::new));
582 }
583
584 #[test]
585 fn test_from_not_increasing() {
586 Signers::from(4, [2, 1].map(Participant::new));
587 }
588
589 #[test]
590 fn test_codec_round_trip() {
591 let signers = Signers::from(9, [1, 6].map(Participant::new));
592 let encoded = signers.encode();
593 let decoded = Signers::decode_cfg(encoded, &9).unwrap();
594 assert_eq!(decoded, signers);
595 }
596
597 #[test]
598 fn test_decode_respects_participant_limit() {
599 let signers = Signers::from(8, [0, 3, 7].map(Participant::new));
600 let encoded = signers.encode();
601 assert!(Signers::decode_cfg(encoded.clone(), &2).is_err());
603 assert!(Signers::decode_cfg(encoded.clone(), &8).is_ok());
605 assert!(Signers::decode_cfg(encoded, &10).is_ok());
607 }
608
609 mod ed25519_fixture {
610 use crate::{certificate::Subject, impl_certificate_ed25519};
611
612 #[derive(Copy, Clone, Debug)]
614 pub struct TestSubject {
615 pub message: &'static [u8],
616 }
617
618 impl Subject for TestSubject {
619 type Namespace = Vec<u8>;
620
621 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8] {
622 derived
623 }
624
625 fn message(&self) -> bytes::Bytes {
626 bytes::Bytes::from_static(self.message)
627 }
628 }
629
630 impl_certificate_ed25519!(TestSubject, Vec<u8>);
632 }
633
634 const NAMESPACE: &[u8] = b"test-bisect";
635 const MESSAGE: &[u8] = b"good message";
636 const BAD_MESSAGE: &[u8] = b"bad message";
637
638 fn make_certificate(
639 schemes: &[Ed25519Scheme],
640 message: &'static [u8],
641 ) -> <Ed25519Scheme as Scheme>::Certificate {
642 let attestations: Vec<_> = schemes
643 .iter()
644 .filter_map(|s| s.sign::<Sha256Digest>(TestSubject { message }))
645 .collect();
646 schemes[0]
647 .assemble::<_, N3f1>(attestations, &Sequential)
648 .expect("assembly failed")
649 }
650
651 fn setup_ed25519(n: u32) -> (Vec<Ed25519Scheme>, Ed25519Scheme) {
652 let mut rng = test_rng();
653 let private_keys: Vec<_> = (0..n).map(|_| PrivateKey::random(&mut rng)).collect();
654 let participants: Set<crate::ed25519::PublicKey> = private_keys
655 .iter()
656 .map(|sk| sk.public_key())
657 .try_collect()
658 .unwrap();
659 let signers: Vec<_> = private_keys
660 .into_iter()
661 .map(|sk| Ed25519Scheme::signer(NAMESPACE, participants.clone(), sk).unwrap())
662 .collect();
663 let verifier = Ed25519Scheme::verifier(NAMESPACE, participants);
664 (signers, verifier)
665 }
666
667 #[test]
668 fn test_bisect_empty() {
669 let mut rng = test_rng();
670 let (_, verifier) = setup_ed25519(4);
671 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
672 &mut rng,
673 &[],
674 &Sequential,
675 );
676 assert!(result.is_empty());
677 }
678
679 #[test]
680 fn test_bisect_all_valid() {
681 let mut rng = test_rng();
682 let (schemes, verifier) = setup_ed25519(4);
683 let cert = make_certificate(&schemes, MESSAGE);
684 let good = TestSubject { message: MESSAGE };
685 let pairs: Vec<_> = (0..5).map(|_| (good, &cert)).collect();
686 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
687 &mut rng,
688 &pairs,
689 &Sequential,
690 );
691 assert_eq!(result, vec![true; 5]);
692 }
693
694 #[test]
695 fn test_bisect_mixed() {
696 let mut rng = test_rng();
697 let (schemes, verifier) = setup_ed25519(4);
698 let cert = make_certificate(&schemes, MESSAGE);
699 let good = TestSubject { message: MESSAGE };
700 let bad = TestSubject {
701 message: BAD_MESSAGE,
702 };
703 let pairs = vec![
704 (good, &cert),
705 (bad, &cert),
706 (good, &cert),
707 (bad, &cert),
708 (good, &cert),
709 (good, &cert),
710 (bad, &cert),
711 (bad, &cert),
712 ];
713 let expected = vec![true, false, true, false, true, true, false, false];
714 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
715 &mut rng,
716 &pairs,
717 &Sequential,
718 );
719 assert_eq!(result, expected);
720 }
721
722 #[test]
723 fn test_bisect_all_invalid() {
724 let mut rng = test_rng();
725 let (schemes, verifier) = setup_ed25519(4);
726 let cert = make_certificate(&schemes, MESSAGE);
727 let bad = TestSubject {
728 message: BAD_MESSAGE,
729 };
730 let pairs: Vec<_> = (0..4).map(|_| (bad, &cert)).collect();
731 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
732 &mut rng,
733 &pairs,
734 &Sequential,
735 );
736 assert_eq!(result, vec![false; 4]);
737 }
738
739 #[test]
740 fn test_bisect_single_valid() {
741 let mut rng = test_rng();
742 let (schemes, verifier) = setup_ed25519(4);
743 let cert = make_certificate(&schemes, MESSAGE);
744 let pairs = vec![(TestSubject { message: MESSAGE }, &cert)];
745 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
746 &mut rng,
747 &pairs,
748 &Sequential,
749 );
750 assert_eq!(result, vec![true]);
751 }
752
753 #[test]
754 fn test_bisect_single_invalid() {
755 let mut rng = test_rng();
756 let (schemes, verifier) = setup_ed25519(4);
757 let cert = make_certificate(&schemes, MESSAGE);
758 let pairs = vec![(
759 TestSubject {
760 message: BAD_MESSAGE,
761 },
762 &cert,
763 )];
764 let result = verifier.verify_certificates_bisect::<_, Sha256Digest, N3f1>(
765 &mut rng,
766 &pairs,
767 &Sequential,
768 );
769 assert_eq!(result, vec![false]);
770 }
771
772 #[cfg(feature = "arbitrary")]
773 mod conformance {
774 use super::{ed25519_fixture::Scheme, *};
775 use commonware_codec::conformance::CodecConformance;
776
777 commonware_conformance::conformance_tests! {
778 CodecConformance<Signers>,
779 CodecConformance<Attestation<Scheme>>,
780 }
781 }
782}