1#[cfg(feature = "mocks")]
12pub mod mocks;
13
14use crate::{
15 bls12381::primitives::{
16 group::Share,
17 ops::{
18 aggregate_signatures, aggregate_verify_multiple_messages, partial_sign_message,
19 partial_verify_multiple_public_keys, threshold_signature_recover, verify_message,
20 },
21 sharing::Sharing,
22 variant::{PartialSignature, Variant},
23 },
24 certificate::{Attestation, Scheme, Subject, Verification},
25 Digest, PublicKey,
26};
27#[cfg(not(feature = "std"))]
28use alloc::{collections::BTreeSet, vec::Vec};
29use commonware_utils::ordered::Set;
30use core::fmt::Debug;
31use rand::{CryptoRng, Rng};
32#[cfg(feature = "std")]
33use std::collections::BTreeSet;
34
35#[derive(Clone, Debug)]
45pub enum Generic<P: PublicKey, V: Variant> {
46 Signer {
47 participants: Set<P>,
49 polynomial: Sharing<V>,
51 share: Share,
53 },
54 Verifier {
55 participants: Set<P>,
57 polynomial: Sharing<V>,
59 },
60 CertificateVerifier {
61 identity: V::Public,
63 },
64}
65
66impl<P: PublicKey, V: Variant> Generic<P, V> {
67 pub fn signer(participants: Set<P>, polynomial: Sharing<V>, share: Share) -> Option<Self> {
79 assert_eq!(
80 polynomial.total().get() as usize,
81 participants.len(),
82 "polynomial total must equal participant len"
83 );
84 #[cfg(feature = "std")]
85 polynomial.precompute_partial_publics();
86 let partial_public = polynomial
87 .partial_public(share.index)
88 .expect("share index must match participant indices");
89 if partial_public == share.public::<V>() {
90 Some(Self::Signer {
91 participants,
92 polynomial,
93 share,
94 })
95 } else {
96 None
97 }
98 }
99
100 pub fn verifier(participants: Set<P>, polynomial: Sharing<V>) -> Self {
109 assert_eq!(
110 polynomial.total().get() as usize,
111 participants.len(),
112 "polynomial total must equal participant len"
113 );
114 #[cfg(feature = "std")]
115 polynomial.precompute_partial_publics();
116
117 Self::Verifier {
118 participants,
119 polynomial,
120 }
121 }
122
123 pub const fn certificate_verifier(identity: V::Public) -> Self {
130 Self::CertificateVerifier { identity }
131 }
132
133 pub fn participants(&self) -> &Set<P> {
135 match self {
136 Self::Signer { participants, .. } => participants,
137 Self::Verifier { participants, .. } => participants,
138 _ => panic!("can only be called for signer and verifier"),
139 }
140 }
141
142 pub fn identity(&self) -> &V::Public {
144 match self {
145 Self::Signer { polynomial, .. } => polynomial.public(),
146 Self::Verifier { polynomial, .. } => polynomial.public(),
147 Self::CertificateVerifier { identity, .. } => identity,
148 }
149 }
150
151 pub const fn share(&self) -> Option<&Share> {
153 match self {
154 Self::Signer { share, .. } => Some(share),
155 _ => None,
156 }
157 }
158
159 fn polynomial(&self) -> &Sharing<V> {
161 match self {
162 Self::Signer { polynomial, .. } => polynomial,
163 Self::Verifier { polynomial, .. } => polynomial,
164 _ => panic!("can only be called for signer and verifier"),
165 }
166 }
167
168 pub const fn me(&self) -> Option<u32> {
170 match self {
171 Self::Signer { share, .. } => Some(share.index),
172 _ => None,
173 }
174 }
175
176 pub fn sign<S, D>(&self, namespace: &[u8], subject: S::Subject<'_, D>) -> Option<Attestation<S>>
178 where
179 S: Scheme<Signature = V::Signature>,
180 D: Digest,
181 {
182 let share = self.share()?;
183
184 let (namespace, message) = subject.namespace_and_message(namespace);
185 let signature =
186 partial_sign_message::<V>(share, Some(namespace.as_ref()), message.as_ref()).value;
187
188 Some(Attestation {
189 signer: share.index,
190 signature,
191 })
192 }
193
194 pub fn verify_attestation<S, D>(
196 &self,
197 namespace: &[u8],
198 subject: S::Subject<'_, D>,
199 attestation: &Attestation<S>,
200 ) -> bool
201 where
202 S: Scheme<Signature = V::Signature>,
203 D: Digest,
204 {
205 let Ok(evaluated) = self.polynomial().partial_public(attestation.signer) else {
206 return false;
207 };
208
209 let (namespace, message) = subject.namespace_and_message(namespace);
210 verify_message::<V>(
211 &evaluated,
212 Some(namespace.as_ref()),
213 message.as_ref(),
214 &attestation.signature,
215 )
216 .is_ok()
217 }
218
219 pub fn verify_attestations<S, R, D, I>(
221 &self,
222 _rng: &mut R,
223 namespace: &[u8],
224 subject: S::Subject<'_, D>,
225 attestations: I,
226 ) -> Verification<S>
227 where
228 S: Scheme<Signature = V::Signature>,
229 R: Rng + CryptoRng,
230 D: Digest,
231 I: IntoIterator<Item = Attestation<S>>,
232 {
233 let mut invalid = BTreeSet::new();
234 let partials: Vec<_> = attestations
235 .into_iter()
236 .map(|attestation| PartialSignature::<V> {
237 index: attestation.signer,
238 value: attestation.signature,
239 })
240 .collect();
241
242 let polynomial = self.polynomial();
243 let (namespace, message) = subject.namespace_and_message(namespace);
244 if let Err(errs) = partial_verify_multiple_public_keys::<V, _>(
245 polynomial,
246 Some(namespace.as_ref()),
247 message.as_ref(),
248 partials.iter(),
249 ) {
250 for partial in errs {
251 invalid.insert(partial.index);
252 }
253 }
254
255 let verified = partials
256 .into_iter()
257 .filter(|partial| !invalid.contains(&partial.index))
258 .map(|partial| Attestation {
259 signer: partial.index,
260 signature: partial.value,
261 })
262 .collect();
263
264 Verification::new(verified, invalid.into_iter().collect())
265 }
266
267 pub fn assemble<S, I>(&self, attestations: I) -> Option<V::Signature>
269 where
270 S: Scheme<Signature = V::Signature>,
271 I: IntoIterator<Item = Attestation<S>>,
272 {
273 let partials: Vec<_> = attestations
274 .into_iter()
275 .map(|attestation| PartialSignature::<V> {
276 index: attestation.signer,
277 value: attestation.signature,
278 })
279 .collect();
280
281 let quorum = self.polynomial();
282 if partials.len() < quorum.required() as usize {
283 return None;
284 }
285
286 threshold_signature_recover::<V, _>(quorum, partials.iter()).ok()
287 }
288
289 pub fn verify_certificate<S, R, D>(
291 &self,
292 _rng: &mut R,
293 namespace: &[u8],
294 subject: S::Subject<'_, D>,
295 certificate: &V::Signature,
296 ) -> bool
297 where
298 S: Scheme,
299 R: Rng + CryptoRng,
300 D: Digest,
301 {
302 let identity = self.identity();
303 let (namespace, message) = subject.namespace_and_message(namespace);
304 verify_message::<V>(
305 identity,
306 Some(namespace.as_ref()),
307 message.as_ref(),
308 certificate,
309 )
310 .is_ok()
311 }
312
313 pub fn verify_certificates<'a, S, R, D, I>(
315 &self,
316 _rng: &mut R,
317 namespace: &[u8],
318 certificates: I,
319 ) -> bool
320 where
321 S: Scheme,
322 R: Rng + CryptoRng,
323 D: Digest,
324 I: Iterator<Item = (S::Subject<'a, D>, &'a V::Signature)>,
325 {
326 let identity = self.identity();
327
328 let mut messages = Vec::new();
329 let mut signatures = Vec::new();
330
331 for (subject, certificate) in certificates {
332 let (namespace, message) = subject.namespace_and_message(namespace);
333 messages.push((Some(namespace), message));
334 signatures.push(*certificate);
335 }
336
337 if messages.is_empty() {
338 return true;
339 }
340
341 let signature = aggregate_signatures::<V, _>(signatures.iter());
342 aggregate_verify_multiple_messages::<V, _>(
343 identity,
344 &messages
345 .iter()
346 .map(|(namespace, message)| (namespace.as_deref(), message.as_ref()))
347 .collect::<Vec<_>>(),
348 &signature,
349 1,
350 )
351 .is_ok()
352 }
353
354 pub const fn is_attributable(&self) -> bool {
355 false
356 }
357
358 pub const fn certificate_codec_config(&self) {}
359
360 pub const fn certificate_codec_config_unbounded() {}
361}
362
363mod macros {
364 #[macro_export]
375 macro_rules! impl_certificate_bls12381_threshold {
376 ($subject:ty) => {
377 #[cfg(feature = "mocks")]
382 #[allow(dead_code)]
383 pub fn fixture<V, R>(
384 rng: &mut R,
385 n: u32,
386 ) -> $crate::certificate::mocks::Fixture<Scheme<$crate::ed25519::PublicKey, V>>
387 where
388 V: $crate::bls12381::primitives::variant::Variant,
389 R: rand::RngCore + rand::CryptoRng,
390 {
391 $crate::bls12381::certificate::threshold::mocks::fixture::<_, V, _>(
392 rng,
393 n,
394 Scheme::signer,
395 Scheme::verifier,
396 )
397 }
398
399 #[derive(Clone, Debug)]
401 pub struct Scheme<
402 P: $crate::PublicKey,
403 V: $crate::bls12381::primitives::variant::Variant,
404 > {
405 generic: $crate::bls12381::certificate::threshold::Generic<P, V>,
406 }
407
408 impl<
409 P: $crate::PublicKey,
410 V: $crate::bls12381::primitives::variant::Variant,
411 > Scheme<P, V> {
412 pub fn signer(
414 participants: commonware_utils::ordered::Set<P>,
415 polynomial: $crate::bls12381::primitives::sharing::Sharing<V>,
416 share: $crate::bls12381::primitives::group::Share,
417 ) -> Option<Self> {
418 Some(Self {
419 generic: $crate::bls12381::certificate::threshold::Generic::signer(
420 participants,
421 polynomial,
422 share,
423 )?,
424 })
425 }
426
427 pub fn verifier(
429 participants: commonware_utils::ordered::Set<P>,
430 polynomial: $crate::bls12381::primitives::sharing::Sharing<V>,
431 ) -> Self {
432 Self {
433 generic: $crate::bls12381::certificate::threshold::Generic::verifier(
434 participants,
435 polynomial,
436 ),
437 }
438 }
439
440 pub const fn certificate_verifier(identity: V::Public) -> Self {
442 Self {
443 generic: $crate::bls12381::certificate::threshold::Generic::certificate_verifier(
444 identity,
445 ),
446 }
447 }
448
449 pub fn identity(&self) -> &V::Public {
451 self.generic.identity()
452 }
453
454 pub const fn share(&self) -> Option<&$crate::bls12381::primitives::group::Share> {
456 self.generic.share()
457 }
458 }
459
460 impl<
461 P: $crate::PublicKey,
462 V: $crate::bls12381::primitives::variant::Variant + Send + Sync,
463 > $crate::certificate::Scheme for Scheme<P, V> {
464 type Subject<'a, D: $crate::Digest> = $subject;
465 type PublicKey = P;
466 type Signature = V::Signature;
467 type Certificate = V::Signature;
468
469 fn me(&self) -> Option<u32> {
470 self.generic.me()
471 }
472
473 fn participants(&self) -> &commonware_utils::ordered::Set<Self::PublicKey> {
474 self.generic.participants()
475 }
476
477 fn sign<D: $crate::Digest>(
478 &self,
479 namespace: &[u8],
480 subject: Self::Subject<'_, D>,
481 ) -> Option<$crate::certificate::Attestation<Self>> {
482 self.generic.sign::<_, D>(namespace, subject)
483 }
484
485 fn verify_attestation<D: $crate::Digest>(
486 &self,
487 namespace: &[u8],
488 subject: Self::Subject<'_, D>,
489 attestation: &$crate::certificate::Attestation<Self>,
490 ) -> bool {
491 self.generic.verify_attestation::<_, D>(namespace, subject, attestation)
492 }
493
494 fn verify_attestations<R, D, I>(
495 &self,
496 rng: &mut R,
497 namespace: &[u8],
498 subject: Self::Subject<'_, D>,
499 attestations: I,
500 ) -> $crate::certificate::Verification<Self>
501 where
502 R: rand::Rng + rand::CryptoRng,
503 D: $crate::Digest,
504 I: IntoIterator<Item = $crate::certificate::Attestation<Self>>,
505 {
506 self.generic.verify_attestations::<_, _, D, _>(rng, namespace, subject, attestations)
507 }
508
509 fn assemble<I>(&self, attestations: I) -> Option<Self::Certificate>
510 where
511 I: IntoIterator<Item = $crate::certificate::Attestation<Self>>,
512 {
513 self.generic.assemble(attestations)
514 }
515
516 fn verify_certificate<
517 R: rand::Rng + rand::CryptoRng,
518 D: $crate::Digest,
519 >(
520 &self,
521 rng: &mut R,
522 namespace: &[u8],
523 subject: Self::Subject<'_, D>,
524 certificate: &Self::Certificate,
525 ) -> bool {
526 self.generic.verify_certificate::<Self, _, D>(rng, namespace, subject, certificate)
527 }
528
529 fn verify_certificates<'a, R, D, I>(
530 &self,
531 rng: &mut R,
532 namespace: &[u8],
533 certificates: I,
534 ) -> bool
535 where
536 R: rand::Rng + rand::CryptoRng,
537 D: $crate::Digest,
538 I: Iterator<Item = (Self::Subject<'a, D>, &'a Self::Certificate)>,
539 {
540 self.generic.verify_certificates::<Self, _, D, _>(rng, namespace, certificates)
541 }
542
543 fn is_attributable(&self) -> bool {
544 self.generic.is_attributable()
545 }
546
547 fn certificate_codec_config(
548 &self,
549 ) -> <Self::Certificate as commonware_codec::Read>::Cfg {
550 self.generic.certificate_codec_config()
551 }
552
553 fn certificate_codec_config_unbounded(
554 ) -> <Self::Certificate as commonware_codec::Read>::Cfg {
555 $crate::bls12381::certificate::threshold::Generic::<P, V>::certificate_codec_config_unbounded()
556 }
557 }
558 };
559 }
560}
561
562#[cfg(test)]
563mod tests {
564 use super::*;
565 use crate::{
566 bls12381::{
567 dkg,
568 primitives::{
569 ops::partial_sign_message,
570 variant::{MinPk, MinSig, Variant},
571 },
572 },
573 certificate::Scheme as _,
574 ed25519::{self, PrivateKey as Ed25519PrivateKey},
575 impl_certificate_bls12381_threshold,
576 sha256::Digest as Sha256Digest,
577 Signer as _,
578 };
579 use bytes::Bytes;
580 use commonware_codec::{DecodeExt, Encode};
581 use commonware_math::algebra::{Additive, Random};
582 use commonware_utils::{ordered::Set, quorum, TryCollect, NZU32};
583 use rand::{rngs::StdRng, thread_rng, SeedableRng};
584
585 const NAMESPACE: &[u8] = b"test-bls12381-threshold";
586 const MESSAGE: &[u8] = b"test message";
587
588 #[derive(Clone, Debug)]
590 pub struct TestSubject<'a> {
591 pub message: &'a [u8],
592 }
593
594 impl<'a> Subject for TestSubject<'a> {
595 fn namespace_and_message(&self, namespace: &[u8]) -> (Bytes, Bytes) {
596 (namespace.to_vec().into(), self.message.to_vec().into())
597 }
598 }
599
600 impl_certificate_bls12381_threshold!(TestSubject<'a>);
602
603 #[allow(clippy::type_complexity)]
604 fn setup_signers<V: Variant>(
605 n: u32,
606 seed: u64,
607 ) -> (
608 Vec<Scheme<ed25519::PublicKey, V>>,
609 Scheme<ed25519::PublicKey, V>,
610 Sharing<V>,
611 ) {
612 let mut rng = StdRng::seed_from_u64(seed);
613
614 let identity_keys: Vec<_> = (0..n)
616 .map(|_| Ed25519PrivateKey::random(&mut rng))
617 .collect();
618 let participants: Set<ed25519::PublicKey> = identity_keys
619 .iter()
620 .map(|sk| sk.public_key())
621 .try_collect()
622 .unwrap();
623
624 let (polynomial, shares) =
626 dkg::deal_anonymous::<V>(&mut rng, Default::default(), NZU32!(n));
627
628 let signers = shares
629 .into_iter()
630 .map(|share| Scheme::signer(participants.clone(), polynomial.clone(), share).unwrap())
631 .collect();
632
633 let verifier = Scheme::verifier(participants, polynomial.clone());
634
635 (signers, verifier, polynomial)
636 }
637
638 fn test_sign_vote_roundtrip<V: Variant + Send + Sync>() {
639 let (schemes, _, _) = setup_signers::<V>(4, 42);
640 let scheme = &schemes[0];
641
642 let attestation = scheme
643 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
644 .unwrap();
645 assert!(scheme.verify_attestation::<Sha256Digest>(
646 NAMESPACE,
647 TestSubject { message: MESSAGE },
648 &attestation
649 ));
650 }
651
652 #[test]
653 fn test_sign_vote_roundtrip_variants() {
654 test_sign_vote_roundtrip::<MinPk>();
655 test_sign_vote_roundtrip::<MinSig>();
656 }
657
658 fn test_verifier_cannot_sign<V: Variant + Send + Sync>() {
659 let (_, verifier, _) = setup_signers::<V>(4, 43);
660 assert!(verifier
661 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
662 .is_none());
663 }
664
665 #[test]
666 fn test_verifier_cannot_sign_variants() {
667 test_verifier_cannot_sign::<MinPk>();
668 test_verifier_cannot_sign::<MinSig>();
669 }
670
671 fn test_verify_attestations_filters_invalid<V: Variant + Send + Sync>() {
672 let (schemes, _, _) = setup_signers::<V>(5, 44);
673 let quorum = quorum(schemes.len() as u32) as usize;
674
675 let attestations: Vec<_> = schemes
676 .iter()
677 .take(quorum)
678 .map(|s| {
679 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
680 .unwrap()
681 })
682 .collect();
683
684 let mut rng = StdRng::seed_from_u64(45);
685 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
686 &mut rng,
687 NAMESPACE,
688 TestSubject { message: MESSAGE },
689 attestations.clone(),
690 );
691 assert!(result.invalid.is_empty());
692 assert_eq!(result.verified.len(), quorum);
693
694 let mut attestations_corrupted = attestations.clone();
696 attestations_corrupted[0].signer = 999;
697 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
698 &mut rng,
699 NAMESPACE,
700 TestSubject { message: MESSAGE },
701 attestations_corrupted,
702 );
703 assert_eq!(result.invalid, vec![999]);
704 assert_eq!(result.verified.len(), quorum - 1);
705
706 let mut attestations_corrupted = attestations;
708 attestations_corrupted[0].signature = attestations_corrupted[1].signature;
709 let result = schemes[0].verify_attestations::<_, Sha256Digest, _>(
710 &mut rng,
711 NAMESPACE,
712 TestSubject { message: MESSAGE },
713 attestations_corrupted,
714 );
715 assert_eq!(result.invalid.len(), 1);
716 assert_eq!(result.verified.len(), quorum - 1);
717 }
718
719 #[test]
720 fn test_verify_attestations_filters_invalid_variants() {
721 test_verify_attestations_filters_invalid::<MinPk>();
722 test_verify_attestations_filters_invalid::<MinSig>();
723 }
724
725 fn test_assemble_certificate<V: Variant + Send + Sync>() {
726 let (schemes, verifier, _) = setup_signers::<V>(4, 46);
727 let quorum = quorum(schemes.len() as u32) as usize;
728
729 let attestations: Vec<_> = schemes
730 .iter()
731 .take(quorum)
732 .map(|s| {
733 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
734 .unwrap()
735 })
736 .collect();
737
738 let certificate = schemes[0].assemble(attestations).unwrap();
739
740 assert!(verifier.verify_certificate::<_, Sha256Digest>(
742 &mut thread_rng(),
743 NAMESPACE,
744 TestSubject { message: MESSAGE },
745 &certificate
746 ));
747 }
748
749 #[test]
750 fn test_assemble_certificate_variants() {
751 test_assemble_certificate::<MinPk>();
752 test_assemble_certificate::<MinSig>();
753 }
754
755 fn test_verify_certificate<V: Variant + Send + Sync>() {
756 let (schemes, verifier, _) = setup_signers::<V>(4, 48);
757 let quorum = quorum(schemes.len() as u32) as usize;
758
759 let attestations: Vec<_> = schemes
760 .iter()
761 .take(quorum)
762 .map(|s| {
763 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
764 .unwrap()
765 })
766 .collect();
767
768 let certificate = schemes[0].assemble(attestations).unwrap();
769
770 let mut rng = StdRng::seed_from_u64(49);
771 assert!(verifier.verify_certificate::<_, Sha256Digest>(
772 &mut rng,
773 NAMESPACE,
774 TestSubject { message: MESSAGE },
775 &certificate
776 ));
777 }
778
779 #[test]
780 fn test_verify_certificate_variants() {
781 test_verify_certificate::<MinPk>();
782 test_verify_certificate::<MinSig>();
783 }
784
785 fn test_verify_certificate_detects_corruption<V: Variant + Send + Sync>() {
786 let (schemes, verifier, _) = setup_signers::<V>(4, 50);
787 let quorum = quorum(schemes.len() as u32) as usize;
788
789 let attestations: Vec<_> = schemes
790 .iter()
791 .take(quorum)
792 .map(|s| {
793 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
794 .unwrap()
795 })
796 .collect();
797
798 let certificate = schemes[0].assemble(attestations).unwrap();
799
800 assert!(verifier.verify_certificate::<_, Sha256Digest>(
802 &mut thread_rng(),
803 NAMESPACE,
804 TestSubject { message: MESSAGE },
805 &certificate
806 ));
807
808 let corrupted = V::Signature::zero();
810 assert!(!verifier.verify_certificate::<_, Sha256Digest>(
811 &mut thread_rng(),
812 NAMESPACE,
813 TestSubject { message: MESSAGE },
814 &corrupted
815 ));
816 }
817
818 #[test]
819 fn test_verify_certificate_detects_corruption_variants() {
820 test_verify_certificate_detects_corruption::<MinPk>();
821 test_verify_certificate_detects_corruption::<MinSig>();
822 }
823
824 fn test_certificate_codec_roundtrip<V: Variant + Send + Sync>() {
825 let (schemes, _, _) = setup_signers::<V>(4, 51);
826 let quorum = quorum(schemes.len() as u32) as usize;
827
828 let attestations: Vec<_> = schemes
829 .iter()
830 .take(quorum)
831 .map(|s| {
832 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
833 .unwrap()
834 })
835 .collect();
836
837 let certificate = schemes[0].assemble(attestations).unwrap();
838 let encoded = certificate.encode();
839 let decoded = V::Signature::decode(encoded).expect("decode certificate");
840 assert_eq!(decoded, certificate);
841 }
842
843 #[test]
844 fn test_certificate_codec_roundtrip_variants() {
845 test_certificate_codec_roundtrip::<MinPk>();
846 test_certificate_codec_roundtrip::<MinSig>();
847 }
848
849 fn test_certificate_rejects_sub_quorum<V: Variant + Send + Sync>() {
850 let (schemes, _, _) = setup_signers::<V>(4, 52);
851 let sub_quorum = 2; let attestations: Vec<_> = schemes
854 .iter()
855 .take(sub_quorum)
856 .map(|s| {
857 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
858 .unwrap()
859 })
860 .collect();
861
862 assert!(schemes[0].assemble(attestations).is_none());
863 }
864
865 #[test]
866 fn test_certificate_rejects_sub_quorum_variants() {
867 test_certificate_rejects_sub_quorum::<MinPk>();
868 test_certificate_rejects_sub_quorum::<MinSig>();
869 }
870
871 fn test_verify_certificates_batch<V: Variant + Send + Sync>() {
872 let (schemes, verifier, _) = setup_signers::<V>(4, 56);
873 let quorum = quorum(schemes.len() as u32) as usize;
874
875 let messages = [b"msg1".as_slice(), b"msg2".as_slice(), b"msg3".as_slice()];
876 let mut certificates = Vec::new();
877
878 for msg in &messages {
879 let attestations: Vec<_> = schemes
880 .iter()
881 .take(quorum)
882 .map(|s| {
883 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: msg })
884 .unwrap()
885 })
886 .collect();
887 certificates.push(schemes[0].assemble(attestations).unwrap());
888 }
889
890 let certs_iter = messages
891 .iter()
892 .zip(&certificates)
893 .map(|(msg, cert)| (TestSubject { message: msg }, cert));
894
895 let mut rng = StdRng::seed_from_u64(57);
896 assert!(verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, NAMESPACE, certs_iter));
897 }
898
899 #[test]
900 fn test_verify_certificates_batch_variants() {
901 test_verify_certificates_batch::<MinPk>();
902 test_verify_certificates_batch::<MinSig>();
903 }
904
905 fn test_verify_certificates_batch_detects_failure<V: Variant + Send + Sync>() {
906 let (schemes, verifier, _) = setup_signers::<V>(4, 58);
907 let quorum = quorum(schemes.len() as u32) as usize;
908
909 let messages = [b"msg1".as_slice(), b"msg2".as_slice()];
910 let mut certificates = Vec::new();
911
912 for msg in &messages {
913 let attestations: Vec<_> = schemes
914 .iter()
915 .take(quorum)
916 .map(|s| {
917 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: msg })
918 .unwrap()
919 })
920 .collect();
921 certificates.push(schemes[0].assemble(attestations).unwrap());
922 }
923
924 certificates[1] = V::Signature::zero();
926
927 let certs_iter = messages
928 .iter()
929 .zip(&certificates)
930 .map(|(msg, cert)| (TestSubject { message: msg }, cert));
931
932 let mut rng = StdRng::seed_from_u64(59);
933 assert!(
934 !verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, NAMESPACE, certs_iter)
935 );
936 }
937
938 #[test]
939 fn test_verify_certificates_batch_detects_failure_variants() {
940 test_verify_certificates_batch_detects_failure::<MinPk>();
941 test_verify_certificates_batch_detects_failure::<MinSig>();
942 }
943
944 fn test_certificate_verifier<V: Variant + Send + Sync>() {
945 let (schemes, _, polynomial) = setup_signers::<V>(4, 60);
946 let quorum = quorum(schemes.len() as u32) as usize;
947
948 let attestations: Vec<_> = schemes
949 .iter()
950 .take(quorum)
951 .map(|s| {
952 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
953 .unwrap()
954 })
955 .collect();
956
957 let certificate = schemes[0].assemble(attestations).unwrap();
958
959 let identity = polynomial.public();
961 let cert_verifier = Scheme::<ed25519::PublicKey, V>::certificate_verifier(*identity);
962
963 assert!(cert_verifier.verify_certificate::<_, Sha256Digest>(
965 &mut thread_rng(),
966 NAMESPACE,
967 TestSubject { message: MESSAGE },
968 &certificate
969 ));
970
971 assert!(cert_verifier
973 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
974 .is_none());
975 }
976
977 #[test]
978 fn test_certificate_verifier_variants() {
979 test_certificate_verifier::<MinPk>();
980 test_certificate_verifier::<MinSig>();
981 }
982
983 fn test_is_not_attributable<V: Variant + Send + Sync>() {
984 let (schemes, verifier, _) = setup_signers::<V>(4, 61);
985
986 assert!(!schemes[0].is_attributable());
988 assert!(!verifier.is_attributable());
989 }
990
991 #[test]
992 fn test_is_not_attributable_variants() {
993 test_is_not_attributable::<MinPk>();
994 test_is_not_attributable::<MinSig>();
995 }
996
997 fn test_verifier_accepts_votes<V: Variant + Send + Sync>() {
998 let (schemes, verifier, _) = setup_signers::<V>(4, 62);
999
1000 let vote = schemes[1]
1001 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
1002 .unwrap();
1003 assert!(verifier.verify_attestation::<Sha256Digest>(
1004 NAMESPACE,
1005 TestSubject { message: MESSAGE },
1006 &vote
1007 ));
1008 }
1009
1010 #[test]
1011 fn test_verifier_accepts_votes_variants() {
1012 test_verifier_accepts_votes::<MinPk>();
1013 test_verifier_accepts_votes::<MinSig>();
1014 }
1015
1016 fn test_scheme_clone_and_verifier<V: Variant + Send + Sync>() {
1017 let (schemes, verifier, _) = setup_signers::<V>(4, 63);
1018
1019 let signer = schemes[0].clone();
1021 assert!(
1022 signer
1023 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
1024 .is_some(),
1025 "signer should produce votes"
1026 );
1027
1028 assert!(
1030 verifier
1031 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
1032 .is_none(),
1033 "verifier should not produce votes"
1034 );
1035 }
1036
1037 #[test]
1038 fn test_scheme_clone_and_verifier_variants() {
1039 test_scheme_clone_and_verifier::<MinPk>();
1040 test_scheme_clone_and_verifier::<MinSig>();
1041 }
1042
1043 fn certificate_verifier_panics_on_vote<V: Variant + Send + Sync>() {
1044 let (schemes, _, _) = setup_signers::<V>(4, 37);
1045 let certificate_verifier =
1046 Scheme::<ed25519::PublicKey, V>::certificate_verifier(*schemes[0].identity());
1047
1048 let vote = schemes[1]
1049 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
1050 .unwrap();
1051
1052 certificate_verifier.verify_attestation::<Sha256Digest>(
1054 NAMESPACE,
1055 TestSubject { message: MESSAGE },
1056 &vote,
1057 );
1058 }
1059
1060 #[test]
1061 #[should_panic(expected = "can only be called for signer and verifier")]
1062 fn test_certificate_verifier_panics_on_vote_min_pk() {
1063 certificate_verifier_panics_on_vote::<MinPk>();
1064 }
1065
1066 #[test]
1067 #[should_panic(expected = "can only be called for signer and verifier")]
1068 fn test_certificate_verifier_panics_on_vote_min_sig() {
1069 certificate_verifier_panics_on_vote::<MinSig>();
1070 }
1071
1072 fn signer_shares_must_match_participant_indices<V: Variant + Send + Sync>() {
1073 let mut rng = StdRng::seed_from_u64(64);
1074
1075 let identity_keys: Vec<_> = (0..4)
1077 .map(|_| Ed25519PrivateKey::random(&mut rng))
1078 .collect();
1079 let participants: Set<ed25519::PublicKey> = identity_keys
1080 .iter()
1081 .map(|sk| sk.public_key())
1082 .try_collect()
1083 .unwrap();
1084
1085 let (polynomial, mut shares) =
1086 dkg::deal_anonymous::<V>(&mut rng, Default::default(), NZU32!(4));
1087 shares[0].index = 999;
1088 Scheme::<ed25519::PublicKey, V>::signer(participants, polynomial, shares[0].clone());
1089 }
1090
1091 #[test]
1092 #[should_panic(expected = "share index must match participant indices")]
1093 fn test_signer_shares_must_match_participant_indices_min_pk() {
1094 signer_shares_must_match_participant_indices::<MinPk>();
1095 }
1096
1097 #[test]
1098 #[should_panic(expected = "share index must match participant indices")]
1099 fn test_signer_shares_must_match_participant_indices_min_sig() {
1100 signer_shares_must_match_participant_indices::<MinSig>();
1101 }
1102
1103 fn make_participants<R: rand::RngCore + rand::CryptoRng + Clone>(
1104 rng: &mut R,
1105 n: u32,
1106 ) -> Set<ed25519::PublicKey> {
1107 (0..n)
1108 .map(|_| Ed25519PrivateKey::random(&mut *rng).public_key())
1109 .try_collect()
1110 .expect("participants are unique")
1111 }
1112
1113 fn signer_polynomial_threshold_must_equal_quorum<V: Variant>() {
1114 let mut rng = StdRng::seed_from_u64(7);
1115 let participants = make_participants(&mut rng, 5);
1116 let (polynomial, shares) =
1120 dkg::deal_anonymous::<V>(&mut rng, Default::default(), NZU32!(2));
1121 Scheme::<ed25519::PublicKey, V>::signer(participants, polynomial, shares[0].clone());
1122 }
1123
1124 #[test]
1125 #[should_panic(expected = "polynomial total must equal participant len")]
1126 fn test_signer_polynomial_threshold_must_equal_quorum_min_pk() {
1127 signer_polynomial_threshold_must_equal_quorum::<MinPk>();
1128 }
1129
1130 #[test]
1131 #[should_panic(expected = "polynomial total must equal participant len")]
1132 fn test_signer_polynomial_threshold_must_equal_quorum_min_sig() {
1133 signer_polynomial_threshold_must_equal_quorum::<MinSig>();
1134 }
1135
1136 fn verifier_polynomial_threshold_must_equal_quorum<V: Variant>() {
1137 let mut rng = StdRng::seed_from_u64(7);
1138 let participants = make_participants(&mut rng, 5);
1139 let (polynomial, _) = dkg::deal_anonymous::<V>(&mut rng, Default::default(), NZU32!(2));
1142 Scheme::<ed25519::PublicKey, V>::verifier(participants, polynomial);
1143 }
1144
1145 #[test]
1146 #[should_panic(expected = "polynomial total must equal participant len")]
1147 fn test_verifier_polynomial_threshold_must_equal_quorum_min_pk() {
1148 verifier_polynomial_threshold_must_equal_quorum::<MinPk>();
1149 }
1150
1151 #[test]
1152 #[should_panic(expected = "polynomial total must equal participant len")]
1153 fn test_verifier_polynomial_threshold_must_equal_quorum_min_sig() {
1154 verifier_polynomial_threshold_must_equal_quorum::<MinSig>();
1155 }
1156
1157 fn certificate_decode_rejects_length_mismatch<V: Variant + Send + Sync>() {
1158 let (schemes, _, _) = setup_signers::<V>(4, 65);
1159 let quorum = quorum(schemes.len() as u32) as usize;
1160
1161 let attestations: Vec<_> = schemes
1162 .iter()
1163 .take(quorum)
1164 .map(|s| {
1165 s.sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
1166 .unwrap()
1167 })
1168 .collect();
1169
1170 let certificate = schemes[0].assemble(attestations).unwrap();
1171 let mut encoded = certificate.encode();
1172 encoded.truncate(encoded.len() - 1);
1173 assert!(V::Signature::decode(encoded).is_err());
1174 }
1175
1176 #[test]
1177 fn test_certificate_decode_rejects_length_mismatch_variants() {
1178 certificate_decode_rejects_length_mismatch::<MinPk>();
1179 certificate_decode_rejects_length_mismatch::<MinSig>();
1180 }
1181
1182 fn sign_vote_partial_matches_share<V: Variant + Send + Sync>() {
1183 let (schemes, _, _) = setup_signers::<V>(4, 66);
1184 let scheme = &schemes[0];
1185
1186 let signature = scheme
1187 .sign::<Sha256Digest>(NAMESPACE, TestSubject { message: MESSAGE })
1188 .unwrap();
1189
1190 let share = scheme.share().expect("expected signer");
1192
1193 let expected = partial_sign_message::<V>(share, Some(NAMESPACE), MESSAGE);
1194
1195 assert_eq!(signature.signer, share.index);
1196 assert_eq!(signature.signature, expected.value);
1197 }
1198
1199 #[test]
1200 fn test_sign_vote_partial_matches_share_variants() {
1201 sign_vote_partial_matches_share::<MinPk>();
1202 sign_vote_partial_matches_share::<MinSig>();
1203 }
1204}