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