@@ -8,14 +8,18 @@ use alloc::collections::BTreeMap;
88use alloc:: vec:: Vec ;
99
1010use crate :: {
11+ keys:: dkg:: { compute_proof_of_knowledge, round1, round2} ,
1112 keys:: {
12- generate_coefficients, generate_secret_shares, validate_num_of_signers,
13- CoefficientCommitment , PublicKeyPackage , SigningKey , SigningShare , VerifyingShare ,
13+ evaluate_polynomial, generate_coefficients, generate_secret_polynomial,
14+ generate_secret_shares, validate_num_of_signers, CoefficientCommitment , PublicKeyPackage ,
15+ SigningKey , SigningShare , VerifyingShare ,
1416 } ,
15- Ciphersuite , CryptoRng , Error , Field , Group , Identifier , RngCore ,
17+ Ciphersuite , CryptoRng , Error , Field , Group , Header , Identifier , RngCore ,
1618} ;
1719
18- use super :: { KeyPackage , SecretShare , VerifiableSecretSharingCommitment } ;
20+ use core:: iter;
21+
22+ use super :: { dkg:: round1:: Package , KeyPackage , SecretShare , VerifiableSecretSharingCommitment } ;
1923
2024/// Generates new zero key shares and a public key package using a trusted
2125/// dealer Building a new public key package is done by taking the verifying
@@ -114,3 +118,260 @@ pub fn refresh_share<C: Ciphersuite>(
114118
115119 Ok ( new_key_package)
116120}
121+
122+ /// Part 1 of refresh share with DKG. A refreshing_key is generated and a new package and secret_package are generated.
123+ /// The identity commitment is removed from the packages.
124+ pub fn refresh_dkg_part_1 < C : Ciphersuite , R : RngCore + CryptoRng > (
125+ identifier : Identifier < C > ,
126+ max_signers : u16 ,
127+ min_signers : u16 ,
128+ mut rng : R ,
129+ ) -> Result < ( round1:: SecretPackage < C > , round1:: Package < C > ) , Error < C > > {
130+ validate_num_of_signers :: < C > ( min_signers, max_signers) ?;
131+
132+ // Build refreshing shares
133+ let refreshing_key = SigningKey {
134+ scalar : <<C :: Group as Group >:: Field >:: zero ( ) ,
135+ } ;
136+
137+ // Round 1, Step 1
138+ let coefficients = generate_coefficients :: < C , R > ( min_signers as usize - 1 , & mut rng) ;
139+
140+ let ( coefficients, commitment) =
141+ generate_secret_polynomial ( & refreshing_key, max_signers, min_signers, coefficients) ?;
142+
143+ // Remove identity element from coefficients
144+ let mut coeff_comms = commitment. 0 ;
145+ coeff_comms. remove ( 0 ) ;
146+ let commitment = VerifiableSecretSharingCommitment :: new ( coeff_comms. clone ( ) ) ;
147+
148+ let proof_of_knowledge =
149+ compute_proof_of_knowledge ( identifier, & coefficients, & commitment, & mut rng) ?;
150+
151+ let secret_package = round1:: SecretPackage {
152+ identifier,
153+ coefficients : coefficients. clone ( ) ,
154+ commitment : commitment. clone ( ) ,
155+ min_signers,
156+ max_signers,
157+ } ;
158+ let package = round1:: Package {
159+ header : Header :: default ( ) ,
160+ commitment,
161+ proof_of_knowledge,
162+ } ;
163+
164+ Ok ( ( secret_package, package) )
165+ }
166+
167+ /// Part 2 of refresh share with DKG. The identity commitment needs to be added back into the secret package.
168+ pub fn refresh_dkg_part2 < C : Ciphersuite > (
169+ mut secret_package : round1:: SecretPackage < C > ,
170+ round1_packages : & BTreeMap < Identifier < C > , round1:: Package < C > > ,
171+ ) -> Result <
172+ (
173+ round2:: SecretPackage < C > ,
174+ BTreeMap < Identifier < C > , round2:: Package < C > > ,
175+ ) ,
176+ Error < C > ,
177+ > {
178+ if round1_packages. len ( ) != ( secret_package. max_signers - 1 ) as usize {
179+ return Err ( Error :: IncorrectNumberOfPackages ) ;
180+ }
181+
182+ // The identity commitment needs to be added to the VSS commitment for secret package
183+ let identity_commitment: Vec < CoefficientCommitment < C > > =
184+ vec ! [ CoefficientCommitment :: new( C :: Group :: identity( ) ) ] ;
185+
186+ let refreshing_secret_share_commitments: Vec < CoefficientCommitment < C > > = identity_commitment
187+ . into_iter ( )
188+ . chain ( secret_package. commitment . 0 . clone ( ) )
189+ . collect ( ) ;
190+
191+ secret_package. commitment =
192+ VerifiableSecretSharingCommitment :: < C > :: new ( refreshing_secret_share_commitments) ;
193+
194+ let mut round2_packages = BTreeMap :: new ( ) ;
195+
196+ for ( sender_identifier, round1_package) in round1_packages {
197+ // The identity commitment needs to be added to the VSS commitment for every round 1 package
198+ let identity_commitment: Vec < CoefficientCommitment < C > > =
199+ vec ! [ CoefficientCommitment :: new( C :: Group :: identity( ) ) ] ;
200+
201+ let refreshing_share_commitments: Vec < CoefficientCommitment < C > > = identity_commitment
202+ . into_iter ( )
203+ . chain ( round1_package. commitment . 0 . clone ( ) )
204+ . collect ( ) ;
205+
206+ if refreshing_share_commitments. clone ( ) . len ( ) != secret_package. min_signers as usize {
207+ return Err ( Error :: IncorrectNumberOfCommitments ) ;
208+ }
209+
210+ let ell = * sender_identifier;
211+
212+ // Round 1, Step 5
213+ // We don't need to verify the proof of knowledge
214+
215+ // Round 2, Step 1
216+ //
217+ // > Each P_i securely sends to each other participant P_ℓ a secret share (ℓ, f_i(ℓ)),
218+ // > deleting f_i and each share afterward except for (i, f_i(i)),
219+ // > which they keep for themselves.
220+ let signing_share = SigningShare :: from_coefficients ( & secret_package. coefficients , ell) ;
221+
222+ round2_packages. insert (
223+ ell,
224+ round2:: Package {
225+ header : Header :: default ( ) ,
226+ signing_share,
227+ } ,
228+ ) ;
229+ }
230+ let fii = evaluate_polynomial ( secret_package. identifier , & secret_package. coefficients ) ;
231+
232+ Ok ( (
233+ round2:: SecretPackage {
234+ identifier : secret_package. identifier ,
235+ commitment : secret_package. commitment ,
236+ secret_share : fii,
237+ min_signers : secret_package. min_signers ,
238+ max_signers : secret_package. max_signers ,
239+ } ,
240+ round2_packages,
241+ ) )
242+ }
243+
244+ /// This is the step that actually refreshes the shares. New public key packages
245+ /// and key packages are created.
246+ pub fn refresh_dkg_shares < C : Ciphersuite > (
247+ round2_secret_package : & round2:: SecretPackage < C > ,
248+ round1_packages : & BTreeMap < Identifier < C > , round1:: Package < C > > ,
249+ round2_packages : & BTreeMap < Identifier < C > , round2:: Package < C > > ,
250+ old_pub_key_package : PublicKeyPackage < C > ,
251+ old_key_package : KeyPackage < C > ,
252+ ) -> Result < ( KeyPackage < C > , PublicKeyPackage < C > ) , Error < C > > {
253+ // Add identity commitment back into round1_packages
254+ let mut new_round_1_packages = BTreeMap :: new ( ) ;
255+ for ( sender_identifier, round1_package) in round1_packages {
256+ // The identity commitment needs to be added to the VSS commitment for every round 1 package
257+ let identity_commitment: Vec < CoefficientCommitment < C > > =
258+ vec ! [ CoefficientCommitment :: new( C :: Group :: identity( ) ) ] ;
259+
260+ let refreshing_share_commitments: Vec < CoefficientCommitment < C > > = identity_commitment
261+ . into_iter ( )
262+ . chain ( round1_package. commitment . 0 . clone ( ) )
263+ . collect ( ) ;
264+
265+ let new_commitments =
266+ VerifiableSecretSharingCommitment :: < C > :: new ( refreshing_share_commitments) ;
267+
268+ let new_round_1_package = Package {
269+ header : round1_package. header ,
270+ commitment : new_commitments,
271+ proof_of_knowledge : round1_package. proof_of_knowledge ,
272+ } ;
273+
274+ new_round_1_packages. insert ( * sender_identifier, new_round_1_package) ;
275+ }
276+
277+ if new_round_1_packages. len ( ) != ( round2_secret_package. max_signers - 1 ) as usize {
278+ return Err ( Error :: IncorrectNumberOfPackages ) ;
279+ }
280+ if new_round_1_packages. len ( ) != round2_packages. len ( ) {
281+ return Err ( Error :: IncorrectNumberOfPackages ) ;
282+ }
283+ if new_round_1_packages
284+ . keys ( )
285+ . any ( |id| !round2_packages. contains_key ( id) )
286+ {
287+ return Err ( Error :: IncorrectPackage ) ;
288+ }
289+
290+ let mut signing_share = <<C :: Group as Group >:: Field >:: zero ( ) ;
291+
292+ for ( sender_identifier, round2_package) in round2_packages {
293+ // Round 2, Step 2
294+ //
295+ // > Each P_i verifies their shares by calculating:
296+ // > g^{f_ℓ(i)} ≟ ∏^{t−1}_{k=0} φ^{i^k mod q}_{ℓk}, aborting if the
297+ // > check fails.
298+ let ell = * sender_identifier;
299+ let f_ell_i = round2_package. signing_share ;
300+
301+ let commitment = & new_round_1_packages
302+ . get ( & ell)
303+ . ok_or ( Error :: PackageNotFound ) ?
304+ . commitment ;
305+
306+ // The verification is exactly the same as the regular SecretShare verification;
307+ // however the required components are in different places.
308+ // Build a temporary SecretShare so what we can call verify().
309+ let secret_share = SecretShare {
310+ header : Header :: default ( ) ,
311+ identifier : round2_secret_package. identifier ,
312+ signing_share : f_ell_i,
313+ commitment : commitment. clone ( ) ,
314+ } ;
315+
316+ // Verify the share. We don't need the result.
317+ let _ = secret_share. verify ( ) ?;
318+
319+ // Round 2, Step 3
320+ //
321+ // > Each P_i calculates their long-lived private signing share by computing
322+ // > s_i = ∑^n_{ℓ=1} f_ℓ(i), stores s_i securely, and deletes each f_ℓ(i).
323+ signing_share = signing_share + f_ell_i. to_scalar ( ) ;
324+ }
325+
326+ signing_share = signing_share + round2_secret_package. secret_share ;
327+
328+ // Build new signing share
329+ let old_signing_share = old_key_package. signing_share . to_scalar ( ) ;
330+ signing_share = signing_share + old_signing_share;
331+ let signing_share = SigningShare :: new ( signing_share) ;
332+
333+ // Round 2, Step 4
334+ //
335+ // > Each P_i calculates their public verification share Y_i = g^{s_i}.
336+ let verifying_share = signing_share. into ( ) ;
337+
338+ let commitments: BTreeMap < _ , _ > = new_round_1_packages
339+ . iter ( )
340+ . map ( |( id, package) | ( * id, & package. commitment ) )
341+ . chain ( iter:: once ( (
342+ round2_secret_package. identifier ,
343+ & round2_secret_package. commitment ,
344+ ) ) )
345+ . collect ( ) ;
346+
347+ let zero_shares_public_key_package = PublicKeyPackage :: from_dkg_commitments ( & commitments) ?;
348+
349+ let mut new_verifying_shares = BTreeMap :: new ( ) ;
350+
351+ for ( identifier, verifying_share) in zero_shares_public_key_package. verifying_shares {
352+ let new_verifying_share = verifying_share. to_element ( )
353+ + old_pub_key_package
354+ . verifying_shares
355+ . get ( & identifier)
356+ . ok_or ( Error :: UnknownIdentifier ) ?
357+ . to_element ( ) ;
358+ new_verifying_shares. insert ( identifier, VerifyingShare :: new ( new_verifying_share) ) ;
359+ }
360+
361+ let public_key_package = PublicKeyPackage {
362+ header : old_pub_key_package. header ,
363+ verifying_shares : new_verifying_shares,
364+ verifying_key : old_pub_key_package. verifying_key ,
365+ } ;
366+
367+ let key_package = KeyPackage {
368+ header : Header :: default ( ) ,
369+ identifier : round2_secret_package. identifier ,
370+ signing_share,
371+ verifying_share,
372+ verifying_key : public_key_package. verifying_key ,
373+ min_signers : round2_secret_package. min_signers ,
374+ } ;
375+
376+ Ok ( ( key_package, public_key_package) )
377+ }
0 commit comments