@@ -74,10 +74,11 @@ pub mod vrf_cert {
7474 use vrf_fun:: VrfProof ;
7575
7676 /// VRF certification scheme using SSWU VRF
77+ #[ derive( Clone , Debug , PartialEq ) ]
7778 pub struct VrfCertifier ;
7879
7980 /// The output from VRF verification containing the gamma point
80- #[ derive( Clone , Debug ) ]
81+ #[ derive( Clone , Debug , PartialEq ) ]
8182 pub struct VrfOutput {
8283 /// The VRF output point (gamma)
8384 pub gamma : Point ,
@@ -118,6 +119,7 @@ pub mod vrf_cert {
118119/// A party that generates secret input to the key generation. You need at least one of these
119120/// and if at least one of these parties is honest then the final secret key will not be known by an
120121/// attacker (unless they obtain `t` shares!).
122+ #[ derive( Clone , Debug , PartialEq ) ]
121123pub struct Contributor {
122124 inner : encpedpop:: Contributor ,
123125}
@@ -128,7 +130,13 @@ pub type KeygenInput = encpedpop::KeygenInput;
128130/// Key generation inputs after being aggregated by the coordinator
129131pub type AggKeygenInput = encpedpop:: AggKeygenInput ;
130132/// A certificate containing signatures or proofs from certifying parties
131- #[ derive( Clone , Debug ) ]
133+ #[ derive( Clone , Debug , PartialEq ) ]
134+ #[ cfg_attr( feature = "bincode" , derive( bincode:: Encode , bincode:: Decode ) ) ]
135+ #[ cfg_attr(
136+ feature = "serde" ,
137+ derive( crate :: fun:: serde:: Deserialize , crate :: fun:: serde:: Serialize ) ,
138+ serde( crate = "crate::fun::serde" )
139+ ) ]
132140pub struct Certificate < Sig > ( BTreeMap < Point , Sig > ) ;
133141
134142/// A certificate containing signatures or proofs from certifying parties
@@ -158,6 +166,17 @@ impl<Sig> Certificate<Sig> {
158166 pub fn iter ( & self ) -> impl Iterator < Item = ( & Point , & Sig ) > {
159167 self . 0 . iter ( )
160168 }
169+
170+ /// The number of certificates stored
171+ pub fn len ( & self ) -> usize {
172+ self . 0 . len ( )
173+ }
174+
175+ /// Have any certificates been collected
176+ pub fn is_empty ( & self ) -> bool {
177+ // clippy::len_without_is_empty wanted this method
178+ self . 0 . is_empty ( )
179+ }
161180}
162181
163182impl Contributor {
@@ -203,12 +222,14 @@ impl Contributor {
203222}
204223
205224/// A key generation session that has been certified by each certifying party (contributors and share receivers).
206- #[ derive( Clone , Debug ) ]
225+ #[ derive( Clone , Debug , PartialEq ) ]
207226pub struct CertifiedKeygen < S : CertificationScheme > {
208- input : AggKeygenInput ,
209- certificate : Certificate < S :: Signature > ,
227+ /// The aggregated inputs to keygen
228+ pub input : AggKeygenInput ,
229+ /// The collected certificates from each party
230+ pub certificate : Certificate < S :: Signature > ,
210231 /// The outputs from successful verification, indexed by certifying party's public key
211- outputs : BTreeMap < Point , S :: Output > ,
232+ pub outputs : BTreeMap < Point , S :: Output > ,
212233}
213234
214235impl < S : CertificationScheme > CertifiedKeygen < S > {
@@ -296,6 +317,7 @@ pub use encpedpop::Coordinator;
296317
297318/// Stores the state of share recipient who first receives their share and then waits to get
298319/// signatures from all the certifying parties on the keygeneration before accepting it.
320+ #[ derive( Debug , Clone , PartialEq ) ]
299321pub struct SecretShareReceiver {
300322 paired_secret_share : PairedSecretShare < Normal , Zero > ,
301323 agg_input : AggKeygenInput ,
@@ -344,7 +366,9 @@ impl SecretShareReceiver {
344366 . agg_input
345367 . encryption_keys ( )
346368 . map ( |( _, encryption_key) | encryption_key)
347- . chain ( contributor_keys. iter ( ) . cloned ( ) ) ;
369+ . chain ( contributor_keys. iter ( ) . cloned ( ) )
370+ . collect :: < BTreeSet < _ > > ( ) ; // dedupe as some contributers may have also be receivers
371+
348372 for cert_key in cert_keys {
349373 match certificate. get ( & cert_key) {
350374 Some ( sig) => match cert_scheme. verify_cert ( cert_key, & self . agg_input , sig) {
@@ -584,4 +608,104 @@ mod test {
584608 ( n_receivers + n_generators) as usize
585609 ) ;
586610 }
611+
612+ #[ test]
613+ fn contributors_are_receivers ( ) {
614+ use proptest:: test_runner:: { RngAlgorithm , TestRng } ;
615+ let schnorr = crate :: new_with_deterministic_nonces :: < sha2:: Sha256 > ( ) ;
616+ let mut rng = TestRng :: deterministic_rng ( RngAlgorithm :: ChaCha ) ;
617+
618+ let threshold = 3 ;
619+ let n_receivers = 5 ;
620+ let n_contributors = 2 ; // First 2 receivers will also be contributors
621+
622+ // Create receiver keypairs
623+ let share_receivers = ( 1 ..=n_receivers)
624+ . map ( |i| Scalar :: from ( i as u32 ) . non_zero ( ) . unwrap ( ) )
625+ . collect :: < BTreeSet < _ > > ( ) ;
626+
627+ let receiver_enckeys = share_receivers
628+ . iter ( )
629+ . cloned ( )
630+ . map ( |party_index| ( party_index, KeyPair :: new ( Scalar :: random ( & mut rng) ) ) )
631+ . collect :: < BTreeMap < _ , _ > > ( ) ;
632+
633+ let public_receiver_enckeys = receiver_enckeys
634+ . iter ( )
635+ . map ( |( party_index, enckeypair) | ( * party_index, enckeypair. public_key ( ) ) )
636+ . collect :: < BTreeMap < ShareIndex , Point > > ( ) ;
637+
638+ // Generate contributors
639+ let ( contributors, to_coordinator_messages) : ( Vec < Contributor > , Vec < KeygenInput > ) = ( 0
640+ ..n_contributors)
641+ . map ( |i| {
642+ Contributor :: gen_keygen_input (
643+ & schnorr,
644+ threshold,
645+ & public_receiver_enckeys,
646+ i,
647+ & mut rng,
648+ )
649+ } )
650+ . unzip ( ) ;
651+
652+ // Contributors use the first n_contributors receiver keypairs
653+ let contributor_keys: Vec < KeyPair > = receiver_enckeys
654+ . values ( )
655+ . take ( n_contributors as usize )
656+ . cloned ( )
657+ . collect ( ) ;
658+
659+ let contributor_public_keys = contributor_keys
660+ . iter ( )
661+ . map ( |kp| kp. public_key ( ) )
662+ . collect :: < Vec < _ > > ( ) ;
663+
664+ // Aggregate inputs
665+ let mut aggregator = Coordinator :: new ( threshold, n_contributors, & public_receiver_enckeys) ;
666+
667+ for ( i, to_coordinator_message) in to_coordinator_messages. into_iter ( ) . enumerate ( ) {
668+ aggregator
669+ . add_input ( & schnorr, i as u32 , to_coordinator_message)
670+ . unwrap ( ) ;
671+ }
672+
673+ let agg_input = aggregator. finish ( ) . unwrap ( ) ;
674+ let mut certificate = Certificate :: new ( ) ;
675+
676+ // Contributors certify
677+ for ( contributor, keypair) in contributors. into_iter ( ) . zip ( contributor_keys. iter ( ) ) {
678+ let sig = contributor
679+ . verify_agg_input ( & schnorr, & agg_input, keypair)
680+ . unwrap ( ) ;
681+ certificate. insert ( keypair. public_key ( ) , sig) ;
682+ }
683+
684+ // Receivers certify
685+ let mut paired_secret_shares = vec ! [ ] ;
686+ let mut share_receivers = vec ! [ ] ;
687+ for ( party_index, enckey) in & receiver_enckeys {
688+ let ( share_receiver, cert) = SecretShareReceiver :: receive_secret_share (
689+ & schnorr,
690+ & schnorr,
691+ * party_index,
692+ enckey,
693+ & agg_input,
694+ )
695+ . unwrap ( ) ;
696+ certificate. insert ( enckey. public_key ( ) , cert) ;
697+ share_receivers. push ( share_receiver) ;
698+ }
699+
700+ // Finalize
701+ for share_receiver in share_receivers {
702+ let ( _certified_keygen, paired_secret_share) = share_receiver
703+ . finalize ( & schnorr, certificate. clone ( ) , & contributor_public_keys)
704+ . unwrap ( ) ;
705+ paired_secret_shares. push ( paired_secret_share. non_zero ( ) . unwrap ( ) ) ;
706+ }
707+
708+ // Verify we have the expected number of unique shares
709+ assert_eq ! ( paired_secret_shares. len( ) , n_receivers as usize ) ;
710+ }
587711}
0 commit comments