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::{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::RngCore + rand::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::Scheme for Scheme<P> {
405 type Subject<'a, D: $crate::Digest> = $subject;
406 type PublicKey = P;
407 type Signature = $crate::secp256r1::standard::Signature;
408 type Certificate = $crate::secp256r1::certificate::Certificate;
409
410 fn me(&self) -> Option<commonware_utils::Participant> {
411 self.generic.me()
412 }
413
414 fn participants(&self) -> &commonware_utils::ordered::Set<Self::PublicKey> {
415 self.generic.participants()
416 }
417
418 fn sign<D: $crate::Digest>(
419 &self,
420 subject: Self::Subject<'_, D>,
421 ) -> Option<$crate::certificate::Attestation<Self>> {
422 self.generic.sign::<_, D>(subject)
423 }
424
425 fn verify_attestation<R, D>(
426 &self,
427 _rng: &mut R,
428 subject: Self::Subject<'_, D>,
429 attestation: &$crate::certificate::Attestation<Self>,
430 _strategy: &impl commonware_parallel::Strategy,
431 ) -> bool
432 where
433 R: rand_core::CryptoRngCore,
434 D: $crate::Digest,
435 {
436 self.generic
437 .verify_attestation::<_, D>(subject, attestation)
438 }
439
440 fn verify_attestations<R, D, I>(
441 &self,
442 rng: &mut R,
443 subject: Self::Subject<'_, D>,
444 attestations: I,
445 _strategy: &impl commonware_parallel::Strategy,
446 ) -> $crate::certificate::Verification<Self>
447 where
448 R: rand_core::CryptoRngCore,
449 D: $crate::Digest,
450 I: IntoIterator<Item = $crate::certificate::Attestation<Self>>,
451 {
452 self.generic.verify_attestations::<_, _, D, _>(
453 rng,
454 subject,
455 attestations,
456 )
457 }
458
459 fn assemble<I, M>(
460 &self,
461 attestations: I,
462 _strategy: &impl commonware_parallel::Strategy,
463 ) -> Option<Self::Certificate>
464 where
465 I: IntoIterator<Item = $crate::certificate::Attestation<Self>>,
466 M: commonware_utils::Faults,
467 {
468 self.generic.assemble::<Self, _, M>(attestations)
469 }
470
471 fn verify_certificate<R, D, M>(
472 &self,
473 rng: &mut R,
474 subject: Self::Subject<'_, D>,
475 certificate: &Self::Certificate,
476 _strategy: &impl commonware_parallel::Strategy,
477 ) -> bool
478 where
479 R: rand_core::CryptoRngCore,
480 D: $crate::Digest,
481 M: commonware_utils::Faults,
482 {
483 self.generic.verify_certificate::<Self, _, D, M>(
484 rng,
485 subject,
486 certificate,
487 )
488 }
489
490 fn verify_certificates<'a, R, D, I, M>(
491 &self,
492 rng: &mut R,
493 certificates: I,
494 _strategy: &impl commonware_parallel::Strategy,
495 ) -> bool
496 where
497 R: rand_core::CryptoRngCore,
498 D: $crate::Digest,
499 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
500 M: commonware_utils::Faults,
501 {
502 for (subject, certificate) in certificates {
503 if !self.generic.verify_certificate::<Self, _, D, M>(rng, subject, certificate) {
504 return false;
505 }
506 }
507 true
508 }
509
510 fn is_attributable() -> bool {
511 $crate::secp256r1::certificate::Generic::<P, $namespace>::is_attributable()
512 }
513
514 fn is_batchable() -> bool {
515 $crate::secp256r1::certificate::Generic::<P, $namespace>::is_batchable()
516 }
517
518 fn certificate_codec_config(
519 &self,
520 ) -> <Self::Certificate as commonware_codec::Read>::Cfg {
521 self.generic.certificate_codec_config()
522 }
523
524 fn certificate_codec_config_unbounded() -> <Self::Certificate as commonware_codec::Read>::Cfg {
525 $crate::secp256r1::certificate::Generic::<P, $namespace>::certificate_codec_config_unbounded()
526 }
527 }
528 };
529}
530
531#[cfg(test)]
532mod tests {
533 use super::*;
534 use crate::{certificate::Scheme as _, sha256::Digest as Sha256Digest};
535 use bytes::Bytes;
536 use commonware_codec::{Decode, Encode};
537 use commonware_math::algebra::Random;
538 use commonware_parallel::Sequential;
539 use commonware_utils::{ordered::BiMap, test_rng, Faults, N3f1, TryCollect};
540 use rand_core::CryptoRngCore;
541
542 const NAMESPACE: &[u8] = b"test-secp256r1";
543 const MESSAGE: &[u8] = b"test message";
544
545 #[derive(Clone, Debug)]
547 pub struct TestSubject {
548 pub message: Bytes,
549 }
550
551 impl Subject for TestSubject {
552 type Namespace = Vec<u8>;
553
554 fn namespace<'a>(&self, derived: &'a Self::Namespace) -> &'a [u8] {
555 derived.as_ref()
556 }
557
558 fn message(&self) -> Bytes {
559 self.message.clone()
560 }
561 }
562
563 impl_certificate_secp256r1!(TestSubject, Vec<u8>);
565
566 fn setup_signers(
567 rng: &mut impl CryptoRngCore,
568 n: u32,
569 ) -> (Vec<Scheme<PublicKey>>, Scheme<PublicKey>) {
570 let private_keys: Vec<_> = (0..n).map(|_| PrivateKey::random(&mut *rng)).collect();
571
572 let participants: BiMap<PublicKey, PublicKey> = private_keys
574 .iter()
575 .map(|sk| {
576 let pk = sk.public_key();
577 (pk.clone(), pk)
578 })
579 .try_collect()
580 .unwrap();
581
582 let signers = private_keys
583 .into_iter()
584 .map(|sk| Scheme::signer(NAMESPACE, participants.clone(), sk).unwrap())
585 .collect();
586
587 let verifier = Scheme::verifier(NAMESPACE, participants);
588
589 (signers, verifier)
590 }
591
592 #[test]
593 fn test_is_attributable() {
594 assert!(Generic::<PublicKey, Vec<u8>>::is_attributable());
595 assert!(Scheme::<PublicKey>::is_attributable());
596 }
597
598 #[test]
599 fn test_is_not_batchable() {
600 assert!(!Generic::<PublicKey, Vec<u8>>::is_batchable());
601 assert!(!Scheme::<PublicKey>::is_batchable());
602 }
603
604 #[test]
605 fn test_sign_vote_roundtrip() {
606 let mut rng = test_rng();
607 let (schemes, _) = setup_signers(&mut rng, 4);
608 let scheme = &schemes[0];
609
610 let attestation = scheme
611 .sign::<Sha256Digest>(TestSubject {
612 message: Bytes::from_static(MESSAGE),
613 })
614 .unwrap();
615 assert!(scheme.verify_attestation::<_, Sha256Digest>(
616 &mut rng,
617 TestSubject {
618 message: Bytes::from_static(MESSAGE),
619 },
620 &attestation,
621 &Sequential,
622 ));
623 }
624
625 #[test]
626 fn test_verifier_cannot_sign() {
627 let mut rng = test_rng();
628 let (_, verifier) = setup_signers(&mut rng, 4);
629 assert!(verifier
630 .sign::<Sha256Digest>(TestSubject {
631 message: Bytes::from_static(MESSAGE),
632 })
633 .is_none());
634 }
635
636 #[test]
637 fn test_verify_attestations_filters_invalid() {
638 let mut rng = test_rng();
639 let (schemes, _) = setup_signers(&mut rng, 5);
640 let quorum = N3f1::quorum(schemes.len()) as usize;
641
642 let attestations: Vec<_> = schemes
643 .iter()
644 .take(quorum)
645 .map(|s| {
646 s.sign::<Sha256Digest>(TestSubject {
647 message: Bytes::from_static(MESSAGE),
648 })
649 .unwrap()
650 })
651 .collect();
652
653 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
654 &mut rng,
655 TestSubject {
656 message: Bytes::from_static(MESSAGE),
657 },
658 attestations.clone(),
659 &Sequential,
660 );
661 assert!(result.invalid.is_empty());
662 assert_eq!(result.verified.len(), quorum);
663
664 let mut attestations_corrupted = attestations.clone();
666 attestations_corrupted[0].signer = Participant::new(999);
667 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
668 &mut rng,
669 TestSubject {
670 message: Bytes::from_static(MESSAGE),
671 },
672 attestations_corrupted,
673 &Sequential,
674 );
675 assert_eq!(result.invalid, vec![Participant::new(999)]);
676 assert_eq!(result.verified.len(), quorum - 1);
677
678 let mut attestations_corrupted = attestations;
680 let first_signer = attestations_corrupted[0].signer;
681 attestations_corrupted[0].signature = attestations_corrupted[1].signature.clone();
682 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
683 &mut rng,
684 TestSubject {
685 message: Bytes::from_static(MESSAGE),
686 },
687 attestations_corrupted,
688 &Sequential,
689 );
690 assert_eq!(result.invalid, vec![first_signer]);
692 assert_eq!(result.verified.len(), quorum - 1);
693 }
694
695 #[test]
696 fn test_assemble_certificate() {
697 let mut rng = test_rng();
698 let (schemes, _) = setup_signers(&mut rng, 4);
699 let quorum = N3f1::quorum(schemes.len()) as usize;
700
701 let attestations: Vec<_> = schemes
702 .iter()
703 .take(quorum)
704 .map(|s| {
705 s.sign::<Sha256Digest>(TestSubject {
706 message: Bytes::from_static(MESSAGE),
707 })
708 .unwrap()
709 })
710 .collect();
711
712 let certificate = schemes[0]
713 .assemble::<_, N3f1>(attestations, &Sequential)
714 .unwrap();
715
716 assert_eq!(certificate.signers.count(), quorum);
718 assert_eq!(certificate.signatures.len(), quorum);
719 }
720
721 #[test]
722 fn test_assemble_certificate_sorts_signers() {
723 let mut rng = test_rng();
724 let (schemes, _) = setup_signers(&mut rng, 4);
725
726 let mut indexed: Vec<_> = (0..3).map(|i| (schemes[i].me().unwrap(), i)).collect();
728 indexed.sort_by_key(|(idx, _)| *idx);
729
730 let attestations = vec![
732 schemes[indexed[2].1]
733 .sign::<Sha256Digest>(TestSubject {
734 message: Bytes::from_static(MESSAGE),
735 })
736 .unwrap(),
737 schemes[indexed[1].1]
738 .sign::<Sha256Digest>(TestSubject {
739 message: Bytes::from_static(MESSAGE),
740 })
741 .unwrap(),
742 schemes[indexed[0].1]
743 .sign::<Sha256Digest>(TestSubject {
744 message: Bytes::from_static(MESSAGE),
745 })
746 .unwrap(),
747 ];
748
749 let certificate = schemes[0]
750 .assemble::<_, N3f1>(attestations, &Sequential)
751 .unwrap();
752
753 let expected: Vec<_> = indexed.iter().map(|(idx, _)| *idx).collect();
755 assert_eq!(certificate.signers.iter().collect::<Vec<_>>(), expected);
756 }
757
758 #[test]
759 fn test_verify_certificate() {
760 let mut rng = test_rng();
761 let (schemes, verifier) = setup_signers(&mut rng, 4);
762 let quorum = N3f1::quorum(schemes.len()) as usize;
763
764 let attestations: Vec<_> = schemes
765 .iter()
766 .take(quorum)
767 .map(|s| {
768 s.sign::<Sha256Digest>(TestSubject {
769 message: Bytes::from_static(MESSAGE),
770 })
771 .unwrap()
772 })
773 .collect();
774
775 let certificate = schemes[0]
776 .assemble::<_, N3f1>(attestations, &Sequential)
777 .unwrap();
778
779 assert!(verifier.verify_certificate::<_, Sha256Digest, N3f1>(
780 &mut rng,
781 TestSubject {
782 message: Bytes::from_static(MESSAGE),
783 },
784 &certificate,
785 &Sequential,
786 ));
787 }
788
789 #[test]
790 fn test_verify_certificate_detects_corruption() {
791 let mut rng = test_rng();
792 let (schemes, verifier) = setup_signers(&mut rng, 4);
793 let quorum = N3f1::quorum(schemes.len()) as usize;
794
795 let attestations: Vec<_> = schemes
796 .iter()
797 .take(quorum)
798 .map(|s| {
799 s.sign::<Sha256Digest>(TestSubject {
800 message: Bytes::from_static(MESSAGE),
801 })
802 .unwrap()
803 })
804 .collect();
805
806 let certificate = schemes[0]
807 .assemble::<_, N3f1>(attestations, &Sequential)
808 .unwrap();
809
810 assert!(verifier.verify_certificate::<_, Sha256Digest, N3f1>(
812 &mut rng,
813 TestSubject {
814 message: Bytes::from_static(MESSAGE),
815 },
816 &certificate,
817 &Sequential,
818 ));
819
820 let mut corrupted = certificate;
822 corrupted.signatures[0] = corrupted.signatures[1].clone();
823 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
824 &mut rng,
825 TestSubject {
826 message: Bytes::from_static(MESSAGE),
827 },
828 &corrupted,
829 &Sequential,
830 ));
831 }
832
833 #[test]
834 fn test_certificate_codec_roundtrip() {
835 let mut rng = test_rng();
836 let (schemes, _) = setup_signers(&mut rng, 4);
837 let quorum = N3f1::quorum(schemes.len()) as usize;
838
839 let attestations: Vec<_> = schemes
840 .iter()
841 .take(quorum)
842 .map(|s| {
843 s.sign::<Sha256Digest>(TestSubject {
844 message: Bytes::from_static(MESSAGE),
845 })
846 .unwrap()
847 })
848 .collect();
849
850 let certificate = schemes[0]
851 .assemble::<_, N3f1>(attestations, &Sequential)
852 .unwrap();
853 let encoded = certificate.encode();
854 let decoded = Certificate::decode_cfg(encoded, &schemes.len()).expect("decode certificate");
855 assert_eq!(decoded, certificate);
856 }
857
858 #[test]
859 fn test_certificate_rejects_sub_quorum() {
860 let mut rng = test_rng();
861 let (schemes, _) = setup_signers(&mut rng, 4);
862 let sub_quorum = 2; let attestations: Vec<_> = schemes
865 .iter()
866 .take(sub_quorum)
867 .map(|s| {
868 s.sign::<Sha256Digest>(TestSubject {
869 message: Bytes::from_static(MESSAGE),
870 })
871 .unwrap()
872 })
873 .collect();
874
875 assert!(schemes[0]
876 .assemble::<_, N3f1>(attestations, &Sequential)
877 .is_none());
878 }
879
880 #[test]
881 fn test_certificate_rejects_invalid_signer() {
882 let mut rng = test_rng();
883 let (schemes, _) = setup_signers(&mut rng, 4);
884 let quorum = N3f1::quorum(schemes.len()) as usize;
885
886 let mut attestations: Vec<_> = schemes
887 .iter()
888 .take(quorum)
889 .map(|s| {
890 s.sign::<Sha256Digest>(TestSubject {
891 message: Bytes::from_static(MESSAGE),
892 })
893 .unwrap()
894 })
895 .collect();
896
897 attestations[0].signer = Participant::new(999);
899
900 assert!(schemes[0]
901 .assemble::<_, N3f1>(attestations, &Sequential)
902 .is_none());
903 }
904
905 #[test]
906 fn test_verify_certificate_rejects_sub_quorum() {
907 let mut rng = test_rng();
908 let (schemes, verifier) = setup_signers(&mut rng, 4);
909 let participants_len = schemes.len();
910
911 let attestations: Vec<_> = schemes
912 .iter()
913 .take(3)
914 .map(|s| {
915 s.sign::<Sha256Digest>(TestSubject {
916 message: Bytes::from_static(MESSAGE),
917 })
918 .unwrap()
919 })
920 .collect();
921
922 let mut certificate = schemes[0]
923 .assemble::<_, N3f1>(attestations, &Sequential)
924 .unwrap();
925
926 let mut signers: Vec<Participant> = certificate.signers.iter().collect();
928 signers.pop();
929 certificate.signers = Signers::from(participants_len, signers);
930 certificate.signatures.pop();
931
932 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
933 &mut rng,
934 TestSubject {
935 message: Bytes::from_static(MESSAGE),
936 },
937 &certificate,
938 &Sequential,
939 ));
940 }
941
942 #[test]
943 fn test_verify_certificate_rejects_mismatched_signature_count() {
944 let mut rng = test_rng();
945 let (schemes, verifier) = setup_signers(&mut rng, 4);
946
947 let attestations: Vec<_> = schemes
948 .iter()
949 .take(3)
950 .map(|s| {
951 s.sign::<Sha256Digest>(TestSubject {
952 message: Bytes::from_static(MESSAGE),
953 })
954 .unwrap()
955 })
956 .collect();
957
958 let mut certificate = schemes[0]
959 .assemble::<_, N3f1>(attestations, &Sequential)
960 .unwrap();
961
962 certificate.signatures.pop();
964
965 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
966 &mut rng,
967 TestSubject {
968 message: Bytes::from_static(MESSAGE),
969 },
970 &certificate,
971 &Sequential,
972 ));
973 }
974
975 #[test]
976 fn test_verify_certificates_batch() {
977 let mut rng = test_rng();
978 let (schemes, verifier) = setup_signers(&mut rng, 4);
979 let quorum = N3f1::quorum(schemes.len()) as usize;
980
981 let messages: Vec<Bytes> = [b"msg1".as_slice(), b"msg2".as_slice(), b"msg3".as_slice()]
982 .into_iter()
983 .map(Bytes::copy_from_slice)
984 .collect();
985 let mut certificates = Vec::new();
986
987 for msg in &messages {
988 let attestations: Vec<_> = schemes
989 .iter()
990 .take(quorum)
991 .map(|s| {
992 s.sign::<Sha256Digest>(TestSubject {
993 message: msg.clone(),
994 })
995 .unwrap()
996 })
997 .collect();
998 certificates.push(
999 schemes[0]
1000 .assemble::<_, N3f1>(attestations, &Sequential)
1001 .unwrap(),
1002 );
1003 }
1004
1005 let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| {
1006 (
1007 TestSubject {
1008 message: msg.clone(),
1009 },
1010 cert,
1011 )
1012 });
1013
1014 assert!(verifier.verify_certificates::<_, Sha256Digest, _, N3f1>(
1015 &mut rng,
1016 certs_iter,
1017 &Sequential
1018 ));
1019 }
1020
1021 #[test]
1022 fn test_verify_certificates_batch_detects_failure() {
1023 let mut rng = test_rng();
1024 let (schemes, verifier) = setup_signers(&mut rng, 4);
1025 let quorum = N3f1::quorum(schemes.len()) as usize;
1026
1027 let messages: Vec<Bytes> = [b"msg1".as_slice(), b"msg2".as_slice()]
1028 .into_iter()
1029 .map(Bytes::copy_from_slice)
1030 .collect();
1031 let mut certificates = Vec::new();
1032
1033 for msg in &messages {
1034 let attestations: Vec<_> = schemes
1035 .iter()
1036 .take(quorum)
1037 .map(|s| {
1038 s.sign::<Sha256Digest>(TestSubject {
1039 message: msg.clone(),
1040 })
1041 .unwrap()
1042 })
1043 .collect();
1044 certificates.push(
1045 schemes[0]
1046 .assemble::<_, N3f1>(attestations, &Sequential)
1047 .unwrap(),
1048 );
1049 }
1050
1051 certificates[1].signatures[0] = certificates[1].signatures[1].clone();
1053
1054 let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| {
1055 (
1056 TestSubject {
1057 message: msg.clone(),
1058 },
1059 cert,
1060 )
1061 });
1062
1063 assert!(!verifier.verify_certificates::<_, Sha256Digest, _, N3f1>(
1064 &mut rng,
1065 certs_iter,
1066 &Sequential
1067 ));
1068 }
1069
1070 #[test]
1071 #[should_panic(expected = "duplicate signer index")]
1072 fn test_assemble_certificate_rejects_duplicate_signers() {
1073 let mut rng = test_rng();
1074 let (schemes, _) = setup_signers(&mut rng, 4);
1075
1076 let mut attestations: Vec<_> = schemes
1077 .iter()
1078 .take(3)
1079 .map(|s| {
1080 s.sign::<Sha256Digest>(TestSubject {
1081 message: Bytes::from_static(MESSAGE),
1082 })
1083 .unwrap()
1084 })
1085 .collect();
1086
1087 attestations.push(attestations.last().unwrap().clone());
1089
1090 schemes[0].assemble::<_, N3f1>(attestations, &Sequential);
1092 }
1093
1094 #[test]
1095 fn test_scheme_clone_and_verifier() {
1096 let mut rng = test_rng();
1097 let (schemes, _) = setup_signers(&mut rng, 4);
1098 let participants = schemes[0].generic.participants.clone();
1099
1100 let signer = schemes[0].clone();
1102 assert!(
1103 signer
1104 .sign::<Sha256Digest>(TestSubject {
1105 message: Bytes::from_static(MESSAGE),
1106 })
1107 .is_some(),
1108 "signer should produce votes"
1109 );
1110
1111 let verifier = Scheme::verifier(NAMESPACE, participants);
1113 assert!(
1114 verifier
1115 .sign::<Sha256Digest>(TestSubject {
1116 message: Bytes::from_static(MESSAGE),
1117 })
1118 .is_none(),
1119 "verifier should not produce votes"
1120 );
1121 }
1122
1123 #[test]
1124 fn test_certificate_decode_validation() {
1125 let mut rng = test_rng();
1126 let (schemes, _) = setup_signers(&mut rng, 4);
1127 let participants_len = schemes.len();
1128
1129 let attestations: Vec<_> = schemes
1130 .iter()
1131 .take(3)
1132 .map(|s| {
1133 s.sign::<Sha256Digest>(TestSubject {
1134 message: Bytes::from_static(MESSAGE),
1135 })
1136 .unwrap()
1137 })
1138 .collect();
1139
1140 let certificate = schemes[0]
1141 .assemble::<_, N3f1>(attestations, &Sequential)
1142 .unwrap();
1143
1144 let encoded = certificate.encode();
1146 let decoded =
1147 Certificate::decode_cfg(encoded, &participants_len).expect("decode certificate");
1148 assert_eq!(decoded, certificate);
1149
1150 let empty = Certificate {
1152 signers: Signers::from(participants_len, std::iter::empty::<Participant>()),
1153 signatures: Vec::new(),
1154 };
1155 assert!(Certificate::decode_cfg(empty.encode(), &participants_len).is_err());
1156
1157 let mismatched = Certificate {
1159 signers: Signers::from(participants_len, [Participant::new(0), Participant::new(1)]),
1160 signatures: vec![certificate.signatures[0].clone()],
1161 };
1162 assert!(Certificate::decode_cfg(mismatched.encode(), &participants_len).is_err());
1163
1164 let mut signers = certificate.signers.iter().collect::<Vec<_>>();
1166 signers.push(Participant::from_usize(participants_len));
1167 let mut sigs = certificate.signatures.clone();
1168 sigs.push(certificate.signatures[0].clone());
1169 let extended = Certificate {
1170 signers: Signers::from(participants_len + 1, signers),
1171 signatures: sigs,
1172 };
1173 assert!(Certificate::decode_cfg(extended.encode(), &participants_len).is_err());
1174 }
1175
1176 #[test]
1177 fn test_verify_certificate_rejects_unknown_signer() {
1178 let mut rng = test_rng();
1179 let (schemes, verifier) = setup_signers(&mut rng, 4);
1180 let participants_len = schemes.len();
1181
1182 let attestations: Vec<_> = schemes
1183 .iter()
1184 .take(3)
1185 .map(|s| {
1186 s.sign::<Sha256Digest>(TestSubject {
1187 message: Bytes::from_static(MESSAGE),
1188 })
1189 .unwrap()
1190 })
1191 .collect();
1192
1193 let mut certificate = schemes[0]
1194 .assemble::<_, N3f1>(attestations, &Sequential)
1195 .unwrap();
1196
1197 let mut signers: Vec<Participant> = certificate.signers.iter().collect();
1199 signers.push(Participant::from_usize(participants_len));
1200 certificate.signers = Signers::from(participants_len + 1, signers);
1201 certificate
1202 .signatures
1203 .push(certificate.signatures[0].clone());
1204
1205 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1206 &mut rng,
1207 TestSubject {
1208 message: Bytes::from_static(MESSAGE),
1209 },
1210 &certificate,
1211 &Sequential,
1212 ));
1213 }
1214
1215 #[test]
1216 fn test_verify_certificate_rejects_invalid_certificate_signers_size() {
1217 let mut rng = test_rng();
1218 let (schemes, verifier) = setup_signers(&mut rng, 4);
1219 let participants_len = schemes.len();
1220
1221 let attestations: Vec<_> = schemes
1222 .iter()
1223 .take(3)
1224 .map(|s| {
1225 s.sign::<Sha256Digest>(TestSubject {
1226 message: Bytes::from_static(MESSAGE),
1227 })
1228 .unwrap()
1229 })
1230 .collect();
1231
1232 let mut certificate = schemes[0]
1233 .assemble::<_, N3f1>(attestations, &Sequential)
1234 .unwrap();
1235
1236 assert!(verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1238 &mut rng,
1239 TestSubject {
1240 message: Bytes::from_static(MESSAGE),
1241 },
1242 &certificate,
1243 &Sequential,
1244 ));
1245
1246 let signers: Vec<Participant> = certificate.signers.iter().collect();
1248 certificate.signers = Signers::from(participants_len + 1, signers);
1249
1250 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1252 &mut rng,
1253 TestSubject {
1254 message: Bytes::from_static(MESSAGE),
1255 },
1256 &certificate,
1257 &Sequential,
1258 ));
1259 }
1260
1261 #[test]
1262 fn test_verify_certificate_rejects_signers_size_mismatch() {
1263 let mut rng = test_rng();
1264 let (schemes, verifier) = setup_signers(&mut rng, 4);
1265 let participants_len = schemes.len();
1266
1267 let attestations: Vec<_> = schemes
1268 .iter()
1269 .take(3)
1270 .map(|s| {
1271 s.sign::<Sha256Digest>(TestSubject {
1272 message: Bytes::from_static(MESSAGE),
1273 })
1274 .unwrap()
1275 })
1276 .collect();
1277
1278 let mut certificate = schemes[0]
1279 .assemble::<_, N3f1>(attestations, &Sequential)
1280 .unwrap();
1281
1282 let signers: Vec<Participant> = certificate.signers.iter().collect();
1284 certificate.signers = Signers::from(participants_len + 1, signers);
1285 certificate
1286 .signatures
1287 .push(certificate.signatures[0].clone());
1288
1289 assert!(!verifier.verify_certificate::<_, Sha256Digest, N3f1>(
1290 &mut rng,
1291 TestSubject {
1292 message: Bytes::from_static(MESSAGE),
1293 },
1294 &certificate,
1295 &Sequential,
1296 ));
1297 }
1298
1299 #[cfg(feature = "arbitrary")]
1300 mod conformance {
1301 use super::*;
1302 use commonware_codec::conformance::CodecConformance;
1303
1304 commonware_conformance::conformance_tests! {
1305 CodecConformance<Certificate> => 1024,
1306 }
1307 }
1308}