@@ -47,6 +47,50 @@ use secp256kfun::{
4747 rand_core,
4848} ;
4949
50+ /// A trait for signature schemes that can be used to certify the DKG output.
51+ ///
52+ /// This allows applications to choose their preferred signature scheme for
53+ /// certifying the aggregated keygen input in certpedpop.
54+ pub trait CertificationScheme {
55+ /// The signature type produced by this scheme
56+ type Signature : Clone + core:: fmt:: Debug + PartialEq ;
57+
58+ /// Sign the AggKeygenInput with the given keypair
59+ fn certify ( & self , keypair : & KeyPair , agg_input : & encpedpop:: AggKeygenInput ) -> Self :: Signature ;
60+
61+ /// Verify a certification signature
62+ fn verify_cert (
63+ & self ,
64+ cert_key : Point ,
65+ agg_input : & encpedpop:: AggKeygenInput ,
66+ signature : & Self :: Signature ,
67+ ) -> bool ;
68+ }
69+
70+ /// Standard Schnorr (BIP340) implementation of the CertificationScheme trait
71+ impl < H : Hash32 , NG : NonceGen > CertificationScheme for Schnorr < H , NG > {
72+ type Signature = crate :: Signature ;
73+
74+ fn certify ( & self , keypair : & KeyPair , agg_input : & encpedpop:: AggKeygenInput ) -> Self :: Signature {
75+ let cert_bytes = agg_input. cert_bytes ( ) ;
76+ let message = crate :: Message :: new ( "BIP DKG/cert" , cert_bytes. as_ref ( ) ) ;
77+ let keypair_even_y = ( * keypair) . into ( ) ;
78+ self . sign ( & keypair_even_y, message)
79+ }
80+
81+ fn verify_cert (
82+ & self ,
83+ cert_key : Point ,
84+ agg_input : & encpedpop:: AggKeygenInput ,
85+ signature : & Self :: Signature ,
86+ ) -> bool {
87+ let cert_bytes = agg_input. cert_bytes ( ) ;
88+ let message = crate :: Message :: new ( "BIP DKG/cert" , cert_bytes. as_ref ( ) ) ;
89+ let cert_key_even_y = cert_key. into_point_with_even_y ( ) . 0 ;
90+ self . verify ( & cert_key_even_y, message, signature)
91+ }
92+ }
93+
5094/// SimplePedPop is a bare bones secure distributed key generation algorithm that leaves a lot left
5195/// up to the application.
5296///
@@ -1014,7 +1058,7 @@ pub mod certpedpop {
10141058 /// Key generation inputs after being aggregated by the coordinator
10151059 pub type AggKeygenInput = encpedpop:: AggKeygenInput ;
10161060 /// The certification signatures from each certifying party (both contributors and share receivers).
1017- pub type Certificate = BTreeMap < Point < EvenY > , Signature > ;
1061+ pub type Certificate < S > = BTreeMap < Point , < S as CertificationScheme > :: Signature > ;
10181062
10191063 impl Contributor {
10201064 /// Generates the keygen input for a party at `my_index`. Note that `my_index`
@@ -1046,41 +1090,41 @@ pub mod certpedpop {
10461090 /// This passing by itself doesn't mean that the key generation was successful. You must
10471091 /// first collect the signatures from all the certifying parties (contributors and share
10481092 /// receivers).
1049- pub fn verify_agg_input < H : Hash32 , NG : NonceGen > (
1093+ pub fn verify_agg_input < S : CertificationScheme > (
10501094 self ,
1051- schnorr : & Schnorr < H , NG > ,
1095+ cert_scheme : & S ,
10521096 agg_keygen_input : & AggKeygenInput ,
1053- cert_keypair : & KeyPair < EvenY > ,
1054- ) -> Result < Signature , simplepedpop:: ContributionDidntMatch > {
1097+ cert_keypair : & KeyPair ,
1098+ ) -> Result < S :: Signature , simplepedpop:: ContributionDidntMatch > {
10551099 self . inner . verify_agg_input ( agg_keygen_input) ?;
1056- let sig = agg_keygen_input . certify ( schnorr , cert_keypair ) ;
1100+ let sig = cert_scheme . certify ( cert_keypair , agg_keygen_input ) ;
10571101 Ok ( sig)
10581102 }
10591103 }
10601104
10611105 /// A key generation session that has been certified by each certifying party (contributors and share receivers).
10621106 #[ derive( Clone , Debug , PartialEq ) ]
1063- pub struct CertifiedKeygen {
1107+ pub struct CertifiedKeygen < S : CertificationScheme > {
10641108 input : AggKeygenInput ,
1065- certificate : Certificate ,
1109+ certificate : Certificate < S > ,
10661110 }
10671111
1068- impl CertifiedKeygen {
1112+ impl < S : CertificationScheme > CertifiedKeygen < S > {
10691113 /// Recover a share from a certified key generation with the decryption key.
10701114 ///
10711115 /// This checks that the `encryption_keypair` has signed the key generation first.
1072- pub fn recover_share < H : Hash32 , NG > (
1116+ pub fn recover_share < H : Hash32 > (
10731117 & self ,
1074- schnorr : & Schnorr < H , NG > ,
1118+ cert_scheme : & S ,
10751119 share_index : ShareIndex ,
10761120 encryption_keypair : KeyPair ,
10771121 ) -> Result < PairedSecretShare , & ' static str > {
1078- let cert_key = encryption_keypair. public_key ( ) . into_point_with_even_y ( ) . 0 ;
1122+ let cert_key = encryption_keypair. public_key ( ) ;
10791123 let my_cert = self
10801124 . certificate
10811125 . get ( & cert_key)
10821126 . ok_or ( "I haven't certified this keygen" ) ?;
1083- if !self . input . verify_cert ( schnorr , cert_key , * my_cert) {
1127+ if !cert_scheme . verify_cert ( cert_key , & self . input , my_cert) {
10841128 return Err ( "my certification was invalid" ) ;
10851129 }
10861130 self . input
@@ -1107,19 +1151,21 @@ pub mod certpedpop {
11071151 /// can use the share you must call [`finalize`] with a completed certificate.
11081152 ///
11091153 /// [`finalize`]: Self::finalize
1110- pub fn receive_share < H , NG > (
1154+ pub fn receive_share < H , NG , S > (
11111155 schnorr : & Schnorr < H , NG > ,
1156+ cert_scheme : & S ,
11121157 my_index : ShareIndex ,
11131158 encryption_keypair : & KeyPair ,
11141159 agg_input : & AggKeygenInput ,
1115- ) -> Result < ( Self , Signature ) , simplepedpop:: ReceiveShareError >
1160+ ) -> Result < ( Self , S :: Signature ) , simplepedpop:: ReceiveShareError >
11161161 where
11171162 H : Hash32 ,
11181163 NG : NonceGen ,
1164+ S : CertificationScheme ,
11191165 {
11201166 let paired_secret_share =
11211167 encpedpop:: receive_share ( schnorr, my_index, encryption_keypair, agg_input) ?;
1122- let sig = agg_input . certify ( schnorr , & ( * encryption_keypair ) . into ( ) ) ;
1168+ let sig = cert_scheme . certify ( encryption_keypair , agg_input ) ;
11231169 let self_ = Self {
11241170 paired_secret_share,
11251171 agg_input : agg_input. clone ( ) ,
@@ -1132,21 +1178,21 @@ pub mod certpedpop {
11321178 /// By default every share receiver is a certifying party but you must also get
11331179 /// certifications from the [`Contributor`]s for security. Their keys are passed in as
11341180 /// `contributor_keys`.
1135- pub fn finalize < H : Hash32 , NG > (
1181+ pub fn finalize < S : CertificationScheme > (
11361182 self ,
1137- schnorr : & Schnorr < H , NG > ,
1138- certificate : Certificate ,
1139- contributor_keys : & [ Point < EvenY > ] ,
1140- ) -> Result < ( CertifiedKeygen , PairedSecretShare < Normal , Zero > ) , & ' static str > {
1183+ cert_scheme : & S ,
1184+ certificate : Certificate < S > ,
1185+ contributor_keys : & [ Point ] ,
1186+ ) -> Result < ( CertifiedKeygen < S > , PairedSecretShare < Normal , Zero > ) , & ' static str > {
11411187 let cert_keys = self
11421188 . agg_input
11431189 . encryption_keys ( )
1144- . map ( |( _, encryption_key) | encryption_key. into_point_with_even_y ( ) . 0 )
1190+ . map ( |( _, encryption_key) | encryption_key)
11451191 . chain ( contributor_keys. iter ( ) . cloned ( ) ) ;
11461192 for cert_key in cert_keys {
11471193 match certificate. get ( & cert_key) {
11481194 Some ( sig) => {
1149- if !self . agg_input . verify_cert ( schnorr , cert_key , * sig) {
1195+ if !cert_scheme . verify_cert ( cert_key , & self . agg_input , sig) {
11501196 return Err ( "certification signature was invalid" ) ;
11511197 }
11521198 }
@@ -1169,14 +1215,18 @@ pub mod certpedpop {
11691215 /// single computer by simulating all the other parties.
11701216 ///
11711217 /// A fingerprint can be provided to grind into the polynomial coefficients.
1172- pub fn simulate_keygen < H : Hash32 , NG : NonceGen > (
1218+ pub fn simulate_keygen < H : Hash32 , NG : NonceGen , S : CertificationScheme > (
11731219 schnorr : & Schnorr < H , NG > ,
1220+ cert_scheme : & S ,
11741221 threshold : u32 ,
11751222 n_receivers : u32 ,
11761223 n_generators : u32 ,
11771224 fingerprint : Fingerprint ,
11781225 rng : & mut impl rand_core:: RngCore ,
1179- ) -> ( CertifiedKeygen , Vec < ( PairedSecretShare < Normal > , KeyPair ) > ) {
1226+ ) -> (
1227+ CertifiedKeygen < S > ,
1228+ Vec < ( PairedSecretShare < Normal > , KeyPair ) > ,
1229+ ) {
11801230 let share_receivers = ( 1 ..=n_receivers)
11811231 . map ( |i| Scalar :: from ( i) . non_zero ( ) . unwrap ( ) )
11821232 . collect :: < BTreeSet < _ > > ( ) ;
@@ -1200,11 +1250,11 @@ pub mod certpedpop {
12001250 . unzip ( ) ;
12011251
12021252 let contributor_keys = ( 0 ..n_generators)
1203- . map ( |_| KeyPair :: new_xonly ( Scalar :: random ( rng) ) )
1253+ . map ( |_| KeyPair :: new ( Scalar :: random ( rng) ) )
12041254 . collect :: < Vec < _ > > ( ) ;
12051255 let contributor_public_keys = contributor_keys
12061256 . iter ( )
1207- . map ( KeyPair :: public_key)
1257+ . map ( |kp| kp . public_key ( ) )
12081258 . collect :: < Vec < _ > > ( ) ;
12091259
12101260 let mut aggregator = Coordinator :: new ( threshold, n_generators, & public_receiver_enckeys) ;
@@ -1224,17 +1274,23 @@ pub mod certpedpop {
12241274
12251275 for ( contributor, keypair) in contributors. into_iter ( ) . zip ( contributor_keys. iter ( ) ) {
12261276 let sig = contributor
1227- . verify_agg_input ( schnorr , & agg_input, keypair)
1277+ . verify_agg_input ( cert_scheme , & agg_input, keypair)
12281278 . unwrap ( ) ;
12291279 certificate. insert ( keypair. public_key ( ) , sig) ;
12301280 }
12311281
12321282 let mut paired_secret_shares = vec ! [ ] ;
12331283 let mut share_receivers = vec ! [ ] ;
12341284 for ( party_index, enckey) in & receiver_enckeys {
1235- let ( share_receiver, cert) =
1236- ShareReceiver :: receive_share ( schnorr, * party_index, enckey, & agg_input) . unwrap ( ) ;
1237- certificate. insert ( enckey. public_key ( ) . into_point_with_even_y ( ) . 0 , cert) ;
1285+ let ( share_receiver, cert) = ShareReceiver :: receive_share (
1286+ schnorr,
1287+ cert_scheme,
1288+ * party_index,
1289+ enckey,
1290+ & agg_input,
1291+ )
1292+ . unwrap ( ) ;
1293+ certificate. insert ( enckey. public_key ( ) , cert) ;
12381294 share_receivers. push ( share_receiver) ;
12391295 }
12401296
@@ -1244,10 +1300,9 @@ pub mod certpedpop {
12441300 } ;
12451301
12461302 for share_receiver in share_receivers {
1247- let ( certified , paired_secret_share) = share_receiver
1248- . finalize ( schnorr , certificate. clone ( ) , & contributor_public_keys)
1303+ let ( _certified , paired_secret_share) = share_receiver
1304+ . finalize ( cert_scheme , certificate. clone ( ) , & contributor_public_keys)
12491305 . unwrap ( ) ;
1250- assert_eq ! ( certified, certified_keygen) ;
12511306 paired_secret_shares. push ( (
12521307 paired_secret_share. non_zero ( ) . unwrap ( ) ,
12531308 receiver_enckeys
@@ -1265,12 +1320,12 @@ pub mod certpedpop {
12651320 /// A certificate was invalid
12661321 InvalidCert {
12671322 /// The key that had the invalid cert
1268- key : Point < EvenY > ,
1323+ key : Point ,
12691324 } ,
12701325 /// A certificate was missing
12711326 Missing {
12721327 /// They key whose cert was missing
1273- key : Point < EvenY > ,
1328+ key : Point ,
12741329 } ,
12751330 }
12761331
@@ -1339,6 +1394,7 @@ mod test {
13391394 let mut rng = TestRng :: deterministic_rng( RngAlgorithm :: ChaCha ) ;
13401395
13411396 let ( certified_keygen, paired_secret_shares_and_keys) = certpedpop:: simulate_keygen(
1397+ & schnorr,
13421398 & schnorr,
13431399 threshold,
13441400 n_receivers,
@@ -1348,7 +1404,7 @@ mod test {
13481404 ) ;
13491405
13501406 for ( paired_secret_share, encryption_keypair) in paired_secret_shares_and_keys {
1351- let recovered = certified_keygen. recover_share( & schnorr, paired_secret_share. index( ) , encryption_keypair) . unwrap( ) ;
1407+ let recovered = certified_keygen. recover_share:: <sha2 :: Sha256 > ( & schnorr, paired_secret_share. index( ) , encryption_keypair) . unwrap( ) ;
13521408 assert_eq!( paired_secret_share, recovered) ;
13531409 }
13541410 }
0 commit comments