1#[cfg(feature = "mocks")]
7pub mod mocks;
8
9use crate::{
10 certificate::{Attestation, Namespace, Scheme, Signers, Subject, Verification},
11 secp256r1::standard::{PrivateKey, PublicKey, Signature as Secp256r1Signature},
12 Digest, Signer as _, Verifier as _,
13};
14#[cfg(not(feature = "std"))]
15use alloc::{collections::BTreeSet, vec::Vec};
16use bytes::{Buf, BufMut};
17use commonware_codec::{types::lazy::Lazy, EncodeSize, Error, Read, ReadRangeExt, Write};
18use commonware_utils::{
19 ordered::{BiMap, Quorum, Set},
20 Faults, Participant,
21};
22use rand_core::{CryptoRng, Rng};
23#[cfg(feature = "std")]
24use std::collections::BTreeSet;
25
26#[derive(Clone, Debug)]
32pub struct Generic<P: crate::PublicKey, N: Namespace> {
33 pub participants: BiMap<P, PublicKey>,
35 pub signer: Option<(Participant, PrivateKey)>,
37 pub namespace: N,
39}
40
41impl<P: crate::PublicKey, N: Namespace> Generic<P, N> {
42 pub fn signer(
51 namespace: &[u8],
52 participants: BiMap<P, PublicKey>,
53 private_key: PrivateKey,
54 ) -> Option<Self> {
55 let public_key = private_key.public_key();
56 let signer = participants
57 .values()
58 .iter()
59 .position(|p| p == &public_key)
60 .map(|index| (Participant::from_usize(index), private_key))?;
61
62 Some(Self {
63 participants,
64 signer: Some(signer),
65 namespace: N::derive(namespace),
66 })
67 }
68
69 pub fn verifier(namespace: &[u8], participants: BiMap<P, PublicKey>) -> Self {
75 Self {
76 participants,
77 signer: None,
78 namespace: N::derive(namespace),
79 }
80 }
81
82 pub const fn participants(&self) -> &Set<P> {
84 self.participants.keys()
85 }
86
87 pub fn me(&self) -> Option<Participant> {
89 self.signer.as_ref().map(|(index, _)| *index)
90 }
91
92 pub fn sign<'a, S, D>(&self, subject: S::Subject<'a, D>) -> Option<Attestation<S>>
94 where
95 S: Scheme<Signature = Secp256r1Signature>,
96 S::Subject<'a, D>: Subject<Namespace = N>,
97 D: Digest,
98 {
99 let (index, private_key) = self.signer.as_ref()?;
100
101 let signature = private_key.sign(subject.namespace(&self.namespace), &subject.message());
102
103 Some(Attestation {
104 signer: *index,
105 signature: signature.into(),
106 })
107 }
108
109 pub fn verify_attestation<'a, S, D>(
111 &self,
112 subject: S::Subject<'a, D>,
113 attestation: &Attestation<S>,
114 ) -> bool
115 where
116 S: Scheme<Signature = Secp256r1Signature>,
117 S::Subject<'a, D>: Subject<Namespace = N>,
118 D: Digest,
119 {
120 let Some(public_key) = self.participants.value(attestation.signer.into()) else {
121 return false;
122 };
123 let Some(signature) = attestation.signature.get() else {
124 return false;
125 };
126
127 public_key.verify(
128 subject.namespace(&self.namespace),
129 &subject.message(),
130 signature,
131 )
132 }
133
134 pub fn verify_attestations<'a, S, R, D, I>(
136 &self,
137 _rng: &mut R,
138 subject: S::Subject<'a, D>,
139 attestations: I,
140 ) -> Verification<S>
141 where
142 S: Scheme<Signature = Secp256r1Signature>,
143 S::Subject<'a, D>: Subject<Namespace = N>,
144 R: Rng + CryptoRng,
145 D: Digest,
146 I: IntoIterator<Item = Attestation<S>>,
147 {
148 let namespace = subject.namespace(&self.namespace);
149 let message = subject.message();
150
151 let mut invalid = BTreeSet::new();
152 let mut verified = Vec::new();
153
154 for attestation in attestations.into_iter() {
155 let Some(public_key) = self.participants.value(attestation.signer.into()) else {
156 invalid.insert(attestation.signer);
157 continue;
158 };
159 let Some(signature) = attestation.signature.get() else {
160 invalid.insert(attestation.signer);
161 continue;
162 };
163
164 if public_key.verify(namespace, &message, signature) {
165 verified.push(attestation);
166 } else {
167 invalid.insert(attestation.signer);
168 }
169 }
170
171 Verification::new(verified, invalid.into_iter().collect())
172 }
173
174 pub fn assemble<S, I, M>(&self, attestations: I) -> Option<Certificate>
176 where
177 S: Scheme<Signature = Secp256r1Signature>,
178 I: IntoIterator<Item = Attestation<S>>,
179 M: Faults,
180 {
181 let mut entries = Vec::new();
183 for Attestation { signer, signature } in attestations {
184 if usize::from(signer) >= self.participants.len() {
185 return None;
186 }
187 let signature = signature.get().cloned()?;
188 entries.push((signer, signature));
189 }
190 if entries.len() < self.participants.quorum::<M>() as usize {
191 return None;
192 }
193
194 entries.sort_by_key(|(signer, _)| *signer);
196 let (signer, signatures): (Vec<Participant>, Vec<_>) = entries.into_iter().unzip();
197 let signers = Signers::from(self.participants.len(), signer);
198 let signatures = signatures.into_iter().map(Lazy::from).collect();
199
200 Some(Certificate {
201 signers,
202 signatures,
203 })
204 }
205
206 pub fn verify_certificate<'a, S, R, D, M>(
208 &self,
209 _rng: &mut R,
210 subject: S::Subject<'a, D>,
211 certificate: &Certificate,
212 ) -> bool
213 where
214 S: Scheme,
215 S::Subject<'a, D>: Subject<Namespace = N>,
216 R: Rng + CryptoRng,
217 D: Digest,
218 M: Faults,
219 {
220 if certificate.signers.len() != self.participants.len() {
222 return false;
223 }
224
225 if certificate.signers.count() != certificate.signatures.len() {
227 return false;
228 }
229
230 if certificate.signers.count() < self.participants.quorum::<M>() as usize {
232 return false;
233 }
234
235 let namespace = subject.namespace(&self.namespace);
236 let message = subject.message();
237 for (signer, signature) in certificate.signers.iter().zip(&certificate.signatures) {
238 let Some(public_key) = self.participants.value(signer.into()) else {
239 return false;
240 };
241 let Some(signature) = signature.get() else {
242 return false;
243 };
244 if !public_key.verify(namespace, &message, signature) {
245 return false;
246 }
247 }
248
249 true
250 }
251
252 pub const fn is_attributable() -> bool {
253 true
254 }
255
256 pub const fn is_batchable() -> bool {
257 false
258 }
259
260 pub const fn certificate_codec_config(&self) -> <Certificate as commonware_codec::Read>::Cfg {
261 self.participants.len()
262 }
263
264 pub const fn certificate_codec_config_unbounded() -> <Certificate as commonware_codec::Read>::Cfg
265 {
266 u32::MAX as usize
267 }
268}
269
270#[derive(Clone, Debug, PartialEq, Eq, Hash)]
271pub struct Certificate {
272 pub signers: Signers,
274 pub signatures: Vec<Lazy<Secp256r1Signature>>,
276}
277
278#[cfg(feature = "arbitrary")]
279impl arbitrary::Arbitrary<'_> for Certificate {
280 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
281 let signers = Signers::arbitrary(u)?;
282 let signatures = (0..signers.count())
283 .map(|_| u.arbitrary::<Secp256r1Signature>().map(Lazy::from))
284 .collect::<arbitrary::Result<Vec<_>>>()?;
285 Ok(Self {
286 signers,
287 signatures,
288 })
289 }
290}
291
292impl Write for Certificate {
293 fn write(&self, writer: &mut impl BufMut) {
294 self.signers.write(writer);
295 self.signatures.write(writer);
296 }
297}
298
299impl EncodeSize for Certificate {
300 fn encode_size(&self) -> usize {
301 self.signers.encode_size() + self.signatures.encode_size()
302 }
303}
304
305impl Read for Certificate {
306 type Cfg = usize;
307
308 fn read_cfg(reader: &mut impl Buf, participants: &usize) -> Result<Self, Error> {
309 let signers = Signers::read_cfg(reader, participants)?;
310 if signers.count() == 0 {
311 return Err(Error::Invalid(
312 "cryptography::secp256r1::certificate::Certificate",
313 "Certificate contains no signers",
314 ));
315 }
316
317 let signatures = Vec::<Lazy<Secp256r1Signature>>::read_range(reader, ..=*participants)?;
318 if signers.count() != signatures.len() {
319 return Err(Error::Invalid(
320 "cryptography::secp256r1::certificate::Certificate",
321 "Signers and signatures counts differ",
322 ));
323 }
324
325 Ok(Self {
326 signers,
327 signatures,
328 })
329 }
330}
331
332#[macro_export]
343macro_rules! impl_certificate_secp256r1 {
344 ($subject:ty, $namespace:ty) => {
345 #[cfg(feature = "mocks")]
350 #[allow(dead_code)]
351 pub fn fixture<R>(
352 rng: &mut R,
353 namespace: &[u8],
354 n: u32,
355 ) -> $crate::certificate::mocks::Fixture<Scheme<$crate::ed25519::PublicKey>>
356 where
357 R: rand_core::CryptoRng,
358 {
359 $crate::secp256r1::certificate::mocks::fixture(
360 rng,
361 namespace,
362 n,
363 Scheme::signer,
364 Scheme::verifier,
365 )
366 }
367
368 #[derive(Clone, Debug)]
370 pub struct Scheme<P: $crate::PublicKey> {
371 generic: $crate::secp256r1::certificate::Generic<P, $namespace>,
372 }
373
374 impl<P: $crate::PublicKey> Scheme<P> {
375 pub fn signer(
377 namespace: &[u8],
378 participants: commonware_utils::ordered::BiMap<P, $crate::secp256r1::standard::PublicKey>,
379 private_key: $crate::secp256r1::standard::PrivateKey,
380 ) -> Option<Self> {
381 Some(Self {
382 generic: $crate::secp256r1::certificate::Generic::signer(
383 namespace,
384 participants,
385 private_key,
386 )?,
387 })
388 }
389
390 pub fn verifier(
392 namespace: &[u8],
393 participants: commonware_utils::ordered::BiMap<P, $crate::secp256r1::standard::PublicKey>,
394 ) -> Self {
395 Self {
396 generic: $crate::secp256r1::certificate::Generic::verifier(
397 namespace,
398 participants,
399 ),
400 }
401 }
402 }
403
404 impl<P: $crate::PublicKey> $crate::certificate::Verifier for Scheme<P> {
405 type Subject<'a, D: $crate::Digest> = $subject;
406 type PublicKey = P;
407 type Certificate = $crate::secp256r1::certificate::Certificate;
408
409 fn verify_certificate<R, D, M>(
410 &self,
411 rng: &mut R,
412 subject: Self::Subject<'_, D>,
413 certificate: &Self::Certificate,
414 _strategy: &impl commonware_parallel::Strategy,
415 ) -> bool
416 where
417 R: rand_core::CryptoRng,
418 D: $crate::Digest,
419 M: commonware_utils::Faults,
420 {
421 self.generic.verify_certificate::<Self, _, D, M>(
422 rng,
423 subject,
424 certificate,
425 )
426 }
427
428 fn verify_certificates<'a, R, D, I, M>(
429 &self,
430 rng: &mut R,
431 certificates: I,
432 _strategy: &impl commonware_parallel::Strategy,
433 ) -> bool
434 where
435 R: rand_core::CryptoRng,
436 D: $crate::Digest,
437 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
438 M: commonware_utils::Faults,
439 {
440 for (subject, certificate) in certificates {
441 if !self.generic.verify_certificate::<Self, _, D, M>(rng, subject, certificate) {
442 return false;
443 }
444 }
445 true
446 }
447
448 fn is_batchable() -> bool {
449 $crate::secp256r1::certificate::Generic::<P, $namespace>::is_batchable()
450 }
451
452 fn certificate_codec_config(
453 &self,
454 ) -> <Self::Certificate as commonware_codec::Read>::Cfg {
455 self.generic.certificate_codec_config()
456 }
457
458 fn certificate_codec_config_unbounded() -> <Self::Certificate as commonware_codec::Read>::Cfg {
459 $crate::secp256r1::certificate::Generic::<P, $namespace>::certificate_codec_config_unbounded()
460 }
461 }
462
463 impl<P: $crate::PublicKey> $crate::certificate::Scheme for Scheme<P> {
464 type Signature = $crate::secp256r1::standard::Signature;
465
466 fn me(&self) -> Option<commonware_utils::Participant> {
467 self.generic.me()
468 }
469
470 fn participants(&self) -> &commonware_utils::ordered::Set<Self::PublicKey> {
471 self.generic.participants()
472 }
473
474 fn sign<D: $crate::Digest>(
475 &self,
476 subject: Self::Subject<'_, D>,
477 ) -> Option<$crate::certificate::Attestation<Self>> {
478 self.generic.sign::<_, D>(subject)
479 }
480
481 fn verify_attestation<R, D>(
482 &self,
483 _rng: &mut R,
484 subject: Self::Subject<'_, D>,
485 attestation: &$crate::certificate::Attestation<Self>,
486 _strategy: &impl commonware_parallel::Strategy,
487 ) -> bool
488 where
489 R: rand_core::CryptoRng,
490 D: $crate::Digest,
491 {
492 self.generic
493 .verify_attestation::<_, D>(subject, attestation)
494 }
495
496 fn verify_attestations<R, D, I>(
497 &self,
498 rng: &mut R,
499 subject: Self::Subject<'_, D>,
500 attestations: I,
501 _strategy: &impl commonware_parallel::Strategy,
502 ) -> $crate::certificate::Verification<Self>
503 where
504 R: rand_core::CryptoRng,
505 D: $crate::Digest,
506 I: IntoIterator<Item = $crate::certificate::Attestation<Self>>,
507 {
508 self.generic.verify_attestations::<_, _, D, _>(
509 rng,
510 subject,
511 attestations,
512 )
513 }
514
515 fn assemble<I, M>(
516 &self,
517 attestations: I,
518 _strategy: &impl commonware_parallel::Strategy,
519 ) -> Option<Self::Certificate>
520 where
521 I: IntoIterator<Item = $crate::certificate::Attestation<Self>>,
522 M: commonware_utils::Faults,
523 {
524 self.generic.assemble::<Self, _, M>(attestations)
525 }
526
527 fn is_attributable() -> bool {
528 $crate::secp256r1::certificate::Generic::<P, $namespace>::is_attributable()
529 }
530 }
531 };
532}
533
534#[cfg(test)]
535mod tests {
536 use super::*;
537 use crate::{
538 certificate::{Scheme as _, Verifier as _},
539 sha256::Digest as Sha256Digest,
540 };
541 use bytes::Bytes;
542 use commonware_codec::{Decode, Encode};
543 use commonware_math::algebra::Random;
544 use commonware_parallel::Sequential;
545 use commonware_utils::{ordered::BiMap, test_rng, Faults, N3f1, TryCollect};
546 use rand_core::CryptoRng;
547
548 const NAMESPACE: &[u8] = b"test-secp256r1";
549 const MESSAGE: &[u8] = b"test message";
550
551 #[derive(Clone, Debug)]
553 pub struct TestSubject {
554 pub message: Bytes,
555 }
556
557 impl Subject for TestSubject {
558 type Namespace = Vec<u8>;
559
560 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8] {
561 derived.as_ref()
562 }
563
564 fn message(&self) -> Bytes {
565 self.message.clone()
566 }
567 }
568
569 impl_certificate_secp256r1!(TestSubject, Vec<u8>);
571
572 fn setup_signers(
573 rng: &mut impl CryptoRng,
574 n: u32,
575 ) -> (Vec<Scheme<PublicKey>>, Scheme<PublicKey>) {
576 let private_keys: Vec<_> = (0..n).map(|_| PrivateKey::random(&mut *rng)).collect();
577
578 let participants: BiMap<PublicKey, PublicKey> = private_keys
580 .iter()
581 .map(|sk| {
582 let pk = sk.public_key();
583 (pk.clone(), pk)
584 })
585 .try_collect()
586 .unwrap();
587
588 let signers = private_keys
589 .into_iter()
590 .map(|sk| Scheme::signer(NAMESPACE, participants.clone(), sk).unwrap())
591 .collect();
592
593 let verifier = Scheme::verifier(NAMESPACE, participants);
594
595 (signers, verifier)
596 }
597
598 #[test]
599 fn test_is_attributable() {
600 assert!(Generic::<PublicKey, Vec<u8>>::is_attributable());
601 assert!(Scheme::<PublicKey>::is_attributable());
602 }
603
604 #[test]
605 fn test_is_not_batchable() {
606 assert!(!Generic::<PublicKey, Vec<u8>>::is_batchable());
607 assert!(!Scheme::<PublicKey>::is_batchable());
608 }
609
610 #[test]
611 fn test_sign_vote_roundtrip() {
612 let mut rng = test_rng();
613 let (schemes, _) = setup_signers(&mut rng, 4);
614 let scheme = &schemes[0];
615
616 let attestation = scheme
617 .sign::<Sha256Digest>(TestSubject {
618 message: Bytes::from_static(MESSAGE),
619 })
620 .unwrap();
621 assert!(scheme.verify_attestation::<_, Sha256Digest>(
622 &mut rng,
623 TestSubject {
624 message: Bytes::from_static(MESSAGE),
625 },
626 &attestation,
627 &Sequential,
628 ));
629 }
630
631 #[test]
632 fn test_verifier_cannot_sign() {
633 let mut rng = test_rng();
634 let (_, verifier) = setup_signers(&mut rng, 4);
635 assert!(verifier
636 .sign::<Sha256Digest>(TestSubject {
637 message: Bytes::from_static(MESSAGE),
638 })
639 .is_none());
640 }
641
642 #[test]
643 fn test_verify_attestations_filters_invalid() {
644 let mut rng = test_rng();
645 let (schemes, _) = setup_signers(&mut rng, 5);
646 let quorum = N3f1::quorum(schemes.len()) as usize;
647
648 let attestations: Vec<_> = schemes
649 .iter()
650 .take(quorum)
651 .map(|s| {
652 s.sign::<Sha256Digest>(TestSubject {
653 message: Bytes::from_static(MESSAGE),
654 })
655 .unwrap()
656 })
657 .collect();
658
659 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
660 &mut rng,
661 TestSubject {
662 message: Bytes::from_static(MESSAGE),
663 },
664 attestations.clone(),
665 &Sequential,
666 );
667 assert!(result.invalid.is_empty());
668 assert_eq!(result.verified.len(), quorum);
669
670 let mut attestations_corrupted = attestations.clone();
672 attestations_corrupted[0].signer = Participant::new(999);
673 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
674 &mut rng,
675 TestSubject {
676 message: Bytes::from_static(MESSAGE),
677 },
678 attestations_corrupted,
679 &Sequential,
680 );
681 assert_eq!(result.invalid, vec![Participant::new(999)]);
682 assert_eq!(result.verified.len(), quorum - 1);
683
684 let mut attestations_corrupted = attestations;
686 let first_signer = attestations_corrupted[0].signer;
687 attestations_corrupted[0].signature = attestations_corrupted[1].signature.clone();
688 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
689 &mut rng,
690 TestSubject {
691 message: Bytes::from_static(MESSAGE),
692 },
693 attestations_corrupted,
694 &Sequential,
695 );
696 assert_eq!(result.invalid, vec![first_signer]);
698 assert_eq!(result.verified.len(), quorum - 1);
699 }
700
701 #[test]
702 fn test_assemble_certificate() {
703 let mut rng = test_rng();
704 let (schemes, _) = setup_signers(&mut rng, 4);
705 let quorum = N3f1::quorum(schemes.len()) as usize;
706
707 let attestations: Vec<_> = schemes
708 .iter()
709 .take(quorum)
710 .map(|s| {
711 s.sign::<Sha256Digest>(TestSubject {
712 message: Bytes::from_static(MESSAGE),
713 })
714 .unwrap()
715 })
716 .collect();
717
718 let certificate = schemes[0]
719 .assemble::<_, N3f1>(attestations, &Sequential)
720 .unwrap();
721
722 assert_eq!(certificate.signers.count(), quorum);
724 assert_eq!(certificate.signatures.len(), quorum);
725 }
726
727 #[test]
728 fn test_assemble_certificate_sorts_signers() {
729 let mut rng = test_rng();
730 let (schemes, _) = setup_signers(&mut rng, 4);
731
732 let mut indexed: Vec<_> = (0..3).map(|i| (schemes[i].me().unwrap(), i)).collect();
734 indexed.sort_by_key(|(idx, _)| *idx);
735
736 let attestations = vec![
738 schemes[indexed[2].1]
739 .sign::<Sha256Digest>(TestSubject {
740 message: Bytes::from_static(MESSAGE),
741 })
742 .unwrap(),
743 schemes[indexed[1].1]
744 .sign::<Sha256Digest>(TestSubject {
745 message: Bytes::from_static(MESSAGE),
746 })
747 .unwrap(),
748 schemes[indexed[0].1]
749 .sign::<Sha256Digest>(TestSubject {
750 message: Bytes::from_static(MESSAGE),
751 })
752 .unwrap(),
753 ];
754
755 let certificate = schemes[0]
756 .assemble::<_, N3f1>(attestations, &Sequential)
757 .unwrap();
758
759 let expected: Vec<_> = indexed.iter().map(|(idx, _)| *idx).collect();
761 assert_eq!(certificate.signers.iter().collect::<Vec<_>>(), expected);
762 }
763
764 #[test]
765 fn test_verify_certificate() {
766 let mut rng = test_rng();
767 let (schemes, verifier) = setup_signers(&mut rng, 4);
768 let quorum = N3f1::quorum(schemes.len()) as usize;
769
770 let attestations: Vec<_> = schemes
771 .iter()
772 .take(quorum)
773 .map(|s| {
774 s.sign::<Sha256Digest>(TestSubject {
775 message: Bytes::from_static(MESSAGE),
776 })
777 .unwrap()
778 })
779 .collect();
780
781 let certificate = schemes[0]
782 .assemble::<_, N3f1>(attestations, &Sequential)
783 .unwrap();
784
785 assert!(verifier.verify_certificate::<_, Sha256Digest, N3f1>(
786 &mut rng,
787 TestSubject {
788 message: Bytes::from_static(MESSAGE),
789 },
790 &certificate,
791 &Sequential,
792 ));
793 }
794
795 #[test]
796 fn test_verify_certificate_detects_corruption() {
797 let mut rng = test_rng();
798 let (schemes, verifier) = setup_signers(&mut rng, 4);
799 let quorum = N3f1::quorum(schemes.len()) as usize;
800
801 let attestations: Vec<_> = schemes
802 .iter()
803 .take(quorum)
804 .map(|s| {
805 s.sign::<Sha256Digest>(TestSubject {
806 message: Bytes::from_static(MESSAGE),
807 })
808 .unwrap()
809 })
810 .collect();
811
812 let certificate = schemes[0]
813 .assemble::<_, N3f1>(attestations, &Sequential)
814 .unwrap();
815
816 assert!(verifier.verify_certificate::<_, Sha256Digest, N3f1>(
818 &mut rng,
819 TestSubject {
820 message: Bytes::from_static(MESSAGE),
821 },
822 &certificate,
823 &Sequential,
824 ));
825
826 let mut corrupted = certificate;
828 corrupted.signatures[0] = corrupted.signatures[1].clone();
829 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
830 &mut rng,
831 TestSubject {
832 message: Bytes::from_static(MESSAGE),
833 },
834 &corrupted,
835 &Sequential,
836 ));
837 }
838
839 #[test]
840 fn test_certificate_codec_roundtrip() {
841 let mut rng = test_rng();
842 let (schemes, _) = setup_signers(&mut rng, 4);
843 let quorum = N3f1::quorum(schemes.len()) as usize;
844
845 let attestations: Vec<_> = schemes
846 .iter()
847 .take(quorum)
848 .map(|s| {
849 s.sign::<Sha256Digest>(TestSubject {
850 message: Bytes::from_static(MESSAGE),
851 })
852 .unwrap()
853 })
854 .collect();
855
856 let certificate = schemes[0]
857 .assemble::<_, N3f1>(attestations, &Sequential)
858 .unwrap();
859 let encoded = certificate.encode();
860 let decoded = Certificate::decode_cfg(encoded, &schemes.len()).expect("decode certificate");
861 assert_eq!(decoded, certificate);
862 }
863
864 #[test]
865 fn test_certificate_rejects_sub_quorum() {
866 let mut rng = test_rng();
867 let (schemes, _) = setup_signers(&mut rng, 4);
868 let sub_quorum = 2; let attestations: Vec<_> = schemes
871 .iter()
872 .take(sub_quorum)
873 .map(|s| {
874 s.sign::<Sha256Digest>(TestSubject {
875 message: Bytes::from_static(MESSAGE),
876 })
877 .unwrap()
878 })
879 .collect();
880
881 assert!(schemes[0]
882 .assemble::<_, N3f1>(attestations, &Sequential)
883 .is_none());
884 }
885
886 #[test]
887 fn test_certificate_rejects_invalid_signer() {
888 let mut rng = test_rng();
889 let (schemes, _) = setup_signers(&mut rng, 4);
890 let quorum = N3f1::quorum(schemes.len()) as usize;
891
892 let mut attestations: Vec<_> = schemes
893 .iter()
894 .take(quorum)
895 .map(|s| {
896 s.sign::<Sha256Digest>(TestSubject {
897 message: Bytes::from_static(MESSAGE),
898 })
899 .unwrap()
900 })
901 .collect();
902
903 attestations[0].signer = Participant::new(999);
905
906 assert!(schemes[0]
907 .assemble::<_, N3f1>(attestations, &Sequential)
908 .is_none());
909 }
910
911 #[test]
912 fn test_verify_certificate_rejects_sub_quorum() {
913 let mut rng = test_rng();
914 let (schemes, verifier) = setup_signers(&mut rng, 4);
915 let participants_len = schemes.len();
916
917 let attestations: Vec<_> = schemes
918 .iter()
919 .take(3)
920 .map(|s| {
921 s.sign::<Sha256Digest>(TestSubject {
922 message: Bytes::from_static(MESSAGE),
923 })
924 .unwrap()
925 })
926 .collect();
927
928 let mut certificate = schemes[0]
929 .assemble::<_, N3f1>(attestations, &Sequential)
930 .unwrap();
931
932 let mut signers: Vec<Participant> = certificate.signers.iter().collect();
934 signers.pop();
935 certificate.signers = Signers::from(participants_len, signers);
936 certificate.signatures.pop();
937
938 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
939 &mut rng,
940 TestSubject {
941 message: Bytes::from_static(MESSAGE),
942 },
943 &certificate,
944 &Sequential,
945 ));
946 }
947
948 #[test]
949 fn test_verify_certificate_rejects_mismatched_signature_count() {
950 let mut rng = test_rng();
951 let (schemes, verifier) = setup_signers(&mut rng, 4);
952
953 let attestations: Vec<_> = schemes
954 .iter()
955 .take(3)
956 .map(|s| {
957 s.sign::<Sha256Digest>(TestSubject {
958 message: Bytes::from_static(MESSAGE),
959 })
960 .unwrap()
961 })
962 .collect();
963
964 let mut certificate = schemes[0]
965 .assemble::<_, N3f1>(attestations, &Sequential)
966 .unwrap();
967
968 certificate.signatures.pop();
970
971 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
972 &mut rng,
973 TestSubject {
974 message: Bytes::from_static(MESSAGE),
975 },
976 &certificate,
977 &Sequential,
978 ));
979 }
980
981 #[test]
982 fn test_verify_certificates_batch() {
983 let mut rng = test_rng();
984 let (schemes, verifier) = setup_signers(&mut rng, 4);
985 let quorum = N3f1::quorum(schemes.len()) as usize;
986
987 let messages: Vec<Bytes> = [b"msg1".as_slice(), b"msg2".as_slice(), b"msg3".as_slice()]
988 .into_iter()
989 .map(Bytes::copy_from_slice)
990 .collect();
991 let mut certificates = Vec::new();
992
993 for msg in &messages {
994 let attestations: Vec<_> = schemes
995 .iter()
996 .take(quorum)
997 .map(|s| {
998 s.sign::<Sha256Digest>(TestSubject {
999 message: msg.clone(),
1000 })
1001 .unwrap()
1002 })
1003 .collect();
1004 certificates.push(
1005 schemes[0]
1006 .assemble::<_, N3f1>(attestations, &Sequential)
1007 .unwrap(),
1008 );
1009 }
1010
1011 let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| {
1012 (
1013 TestSubject {
1014 message: msg.clone(),
1015 },
1016 cert,
1017 )
1018 });
1019
1020 assert!(verifier.verify_certificates::<_, Sha256Digest, _, N3f1>(
1021 &mut rng,
1022 certs_iter,
1023 &Sequential
1024 ));
1025 }
1026
1027 #[test]
1028 fn test_verify_certificates_batch_detects_failure() {
1029 let mut rng = test_rng();
1030 let (schemes, verifier) = setup_signers(&mut rng, 4);
1031 let quorum = N3f1::quorum(schemes.len()) as usize;
1032
1033 let messages: Vec<Bytes> = [b"msg1".as_slice(), b"msg2".as_slice()]
1034 .into_iter()
1035 .map(Bytes::copy_from_slice)
1036 .collect();
1037 let mut certificates = Vec::new();
1038
1039 for msg in &messages {
1040 let attestations: Vec<_> = schemes
1041 .iter()
1042 .take(quorum)
1043 .map(|s| {
1044 s.sign::<Sha256Digest>(TestSubject {
1045 message: msg.clone(),
1046 })
1047 .unwrap()
1048 })
1049 .collect();
1050 certificates.push(
1051 schemes[0]
1052 .assemble::<_, N3f1>(attestations, &Sequential)
1053 .unwrap(),
1054 );
1055 }
1056
1057 certificates[1].signatures[0] = certificates[1].signatures[1].clone();
1059
1060 let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| {
1061 (
1062 TestSubject {
1063 message: msg.clone(),
1064 },
1065 cert,
1066 )
1067 });
1068
1069 assert!(!verifier.verify_certificates::<_, Sha256Digest, _, N3f1>(
1070 &mut rng,
1071 certs_iter,
1072 &Sequential
1073 ));
1074 }
1075
1076 #[test]
1077 #[should_panic(expected = "duplicate signer index")]
1078 fn test_assemble_certificate_rejects_duplicate_signers() {
1079 let mut rng = test_rng();
1080 let (schemes, _) = setup_signers(&mut rng, 4);
1081
1082 let mut attestations: Vec<_> = schemes
1083 .iter()
1084 .take(3)
1085 .map(|s| {
1086 s.sign::<Sha256Digest>(TestSubject {
1087 message: Bytes::from_static(MESSAGE),
1088 })
1089 .unwrap()
1090 })
1091 .collect();
1092
1093 attestations.push(attestations.last().unwrap().clone());
1095
1096 schemes[0].assemble::<_, N3f1>(attestations, &Sequential);
1098 }
1099
1100 #[test]
1101 fn test_scheme_clone_and_verifier() {
1102 let mut rng = test_rng();
1103 let (schemes, _) = setup_signers(&mut rng, 4);
1104 let participants = schemes[0].generic.participants.clone();
1105
1106 let signer = schemes[0].clone();
1108 assert!(
1109 signer
1110 .sign::<Sha256Digest>(TestSubject {
1111 message: Bytes::from_static(MESSAGE),
1112 })
1113 .is_some(),
1114 "signer should produce votes"
1115 );
1116
1117 let verifier = Scheme::verifier(NAMESPACE, participants);
1119 assert!(
1120 verifier
1121 .sign::<Sha256Digest>(TestSubject {
1122 message: Bytes::from_static(MESSAGE),
1123 })
1124 .is_none(),
1125 "verifier should not produce votes"
1126 );
1127 }
1128
1129 #[test]
1130 fn test_certificate_decode_validation() {
1131 let mut rng = test_rng();
1132 let (schemes, _) = setup_signers(&mut rng, 4);
1133 let participants_len = schemes.len();
1134
1135 let attestations: Vec<_> = schemes
1136 .iter()
1137 .take(3)
1138 .map(|s| {
1139 s.sign::<Sha256Digest>(TestSubject {
1140 message: Bytes::from_static(MESSAGE),
1141 })
1142 .unwrap()
1143 })
1144 .collect();
1145
1146 let certificate = schemes[0]
1147 .assemble::<_, N3f1>(attestations, &Sequential)
1148 .unwrap();
1149
1150 let encoded = certificate.encode();
1152 let decoded =
1153 Certificate::decode_cfg(encoded, &participants_len).expect("decode certificate");
1154 assert_eq!(decoded, certificate);
1155
1156 let empty = Certificate {
1158 signers: Signers::from(participants_len, std::iter::empty::<Participant>()),
1159 signatures: Vec::new(),
1160 };
1161 assert!(Certificate::decode_cfg(empty.encode(), &participants_len).is_err());
1162
1163 let mismatched = Certificate {
1165 signers: Signers::from(participants_len, [Participant::new(0), Participant::new(1)]),
1166 signatures: vec![certificate.signatures[0].clone()],
1167 };
1168 assert!(Certificate::decode_cfg(mismatched.encode(), &participants_len).is_err());
1169
1170 let mut signers = certificate.signers.iter().collect::<Vec<_>>();
1172 signers.push(Participant::from_usize(participants_len));
1173 let mut sigs = certificate.signatures.clone();
1174 sigs.push(certificate.signatures[0].clone());
1175 let extended = Certificate {
1176 signers: Signers::from(participants_len + 1, signers),
1177 signatures: sigs,
1178 };
1179 assert!(Certificate::decode_cfg(extended.encode(), &participants_len).is_err());
1180 }
1181
1182 #[test]
1183 fn test_verify_certificate_rejects_unknown_signer() {
1184 let mut rng = test_rng();
1185 let (schemes, verifier) = setup_signers(&mut rng, 4);
1186 let participants_len = schemes.len();
1187
1188 let attestations: Vec<_> = schemes
1189 .iter()
1190 .take(3)
1191 .map(|s| {
1192 s.sign::<Sha256Digest>(TestSubject {
1193 message: Bytes::from_static(MESSAGE),
1194 })
1195 .unwrap()
1196 })
1197 .collect();
1198
1199 let mut certificate = schemes[0]
1200 .assemble::<_, N3f1>(attestations, &Sequential)
1201 .unwrap();
1202
1203 let mut signers: Vec<Participant> = certificate.signers.iter().collect();
1205 signers.push(Participant::from_usize(participants_len));
1206 certificate.signers = Signers::from(participants_len + 1, signers);
1207 certificate
1208 .signatures
1209 .push(certificate.signatures[0].clone());
1210
1211 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1212 &mut rng,
1213 TestSubject {
1214 message: Bytes::from_static(MESSAGE),
1215 },
1216 &certificate,
1217 &Sequential,
1218 ));
1219 }
1220
1221 #[test]
1222 fn test_verify_certificate_rejects_invalid_certificate_signers_size() {
1223 let mut rng = test_rng();
1224 let (schemes, verifier) = setup_signers(&mut rng, 4);
1225 let participants_len = schemes.len();
1226
1227 let attestations: Vec<_> = schemes
1228 .iter()
1229 .take(3)
1230 .map(|s| {
1231 s.sign::<Sha256Digest>(TestSubject {
1232 message: Bytes::from_static(MESSAGE),
1233 })
1234 .unwrap()
1235 })
1236 .collect();
1237
1238 let mut certificate = schemes[0]
1239 .assemble::<_, N3f1>(attestations, &Sequential)
1240 .unwrap();
1241
1242 assert!(verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1244 &mut rng,
1245 TestSubject {
1246 message: Bytes::from_static(MESSAGE),
1247 },
1248 &certificate,
1249 &Sequential,
1250 ));
1251
1252 let signers: Vec<Participant> = certificate.signers.iter().collect();
1254 certificate.signers = Signers::from(participants_len + 1, signers);
1255
1256 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1258 &mut rng,
1259 TestSubject {
1260 message: Bytes::from_static(MESSAGE),
1261 },
1262 &certificate,
1263 &Sequential,
1264 ));
1265 }
1266
1267 #[test]
1268 fn test_verify_certificate_rejects_signers_size_mismatch() {
1269 let mut rng = test_rng();
1270 let (schemes, verifier) = setup_signers(&mut rng, 4);
1271 let participants_len = schemes.len();
1272
1273 let attestations: Vec<_> = schemes
1274 .iter()
1275 .take(3)
1276 .map(|s| {
1277 s.sign::<Sha256Digest>(TestSubject {
1278 message: Bytes::from_static(MESSAGE),
1279 })
1280 .unwrap()
1281 })
1282 .collect();
1283
1284 let mut certificate = schemes[0]
1285 .assemble::<_, N3f1>(attestations, &Sequential)
1286 .unwrap();
1287
1288 let signers: Vec<Participant> = certificate.signers.iter().collect();
1290 certificate.signers = Signers::from(participants_len + 1, signers);
1291 certificate
1292 .signatures
1293 .push(certificate.signatures[0].clone());
1294
1295 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1296 &mut rng,
1297 TestSubject {
1298 message: Bytes::from_static(MESSAGE),
1299 },
1300 &certificate,
1301 &Sequential,
1302 ));
1303 }
1304
1305 #[cfg(feature = "arbitrary")]
1306 mod conformance {
1307 use super::*;
1308 use commonware_codec::conformance::CodecConformance;
1309
1310 commonware_conformance::conformance_tests! {
1311 CodecConformance<Certificate> => 1024,
1312 }
1313 }
1314}