33//! To sign with re-randomized FROST:
44//!
55//! - Do Round 1 the same way as regular FROST;
6- //! - The Coordinator should call [`RandomizedParams::new()`] and send
7- //! the [`RandomizedParams::randomizer`] to all participants, using a
8- //! confidential channel, along with the regular [`frost::SigningPackage`];
9- //! - Each participant should call [`sign`] and send the resulting
6+ //! - The Coordinator should call [`RandomizedParams::new_from_commitments()`]
7+ //! and send the generate randomizer seed (the second returned value) to all
8+ //! participants, using a confidential channel, along with the regular
9+ //! [`frost::SigningPackage`];
10+ //! - Each participant should regenerate the RandomizerParams by calling
11+ //! [`RandomizedParams::regenerate_from_seed_and_commitments()`], which they
12+ //! should pass to [`sign_with_randomizer_seed()`] and send the resulting
1013//! [`frost::round2::SignatureShare`] back to the Coordinator;
1114//! - The Coordinator should then call [`aggregate`].
1215#![ no_std]
@@ -27,16 +30,17 @@ use frost_core::SigningPackage;
2730use frost_core:: {
2831 self as frost,
2932 keys:: { KeyPackage , PublicKeyPackage , SigningShare , VerifyingShare } ,
33+ round1:: encode_group_commitments,
34+ round1:: SigningCommitments ,
3035 serialization:: SerializableScalar ,
31- Ciphersuite , Error , Field , Group , Scalar , VerifyingKey ,
36+ Ciphersuite , Error , Field , Group , Identifier , Scalar , VerifyingKey ,
3237} ;
3338
3439#[ cfg( feature = "serde" ) ]
3540use frost_core:: serde;
3641
3742// When pulled into `reddsa`, that has its own sibling `rand_core` import.
3843// For the time being, we do not re-export this `rand_core`.
39- #[ cfg( feature = "serialization" ) ]
4044use rand_core:: { CryptoRng , RngCore } ;
4145
4246/// Randomize the given key type for usage in a FROST signing with re-randomized keys,
@@ -123,6 +127,9 @@ impl<C: Ciphersuite> Randomize<C> for PublicKeyPackage<C> {
123127/// be sent from the Coordinator using a confidential channel.
124128///
125129/// See [`frost::round2::sign`] for documentation on the other parameters.
130+ #[ deprecated(
131+ note = "switch to sign_with_randomizer_seed(), passing a seed generated with RandomizedParams::new_from_commitments()"
132+ ) ]
126133pub fn sign < C : RandomizedCiphersuite > (
127134 signing_package : & frost:: SigningPackage < C > ,
128135 signer_nonces : & frost:: round1:: SigningNonces < C > ,
@@ -135,6 +142,25 @@ pub fn sign<C: RandomizedCiphersuite>(
135142 frost:: round2:: sign ( signing_package, signer_nonces, & randomized_key_package)
136143}
137144
145+ /// Re-randomized FROST signing using the given `randomizer_seed`, which should
146+ /// be sent from the Coordinator using a confidential channel.
147+ ///
148+ /// See [`frost::round2::sign`] for documentation on the other parameters.
149+ pub fn sign_with_randomizer_seed < C : RandomizedCiphersuite > (
150+ signing_package : & frost:: SigningPackage < C > ,
151+ signer_nonces : & frost:: round1:: SigningNonces < C > ,
152+ key_package : & frost:: keys:: KeyPackage < C > ,
153+ randomizer_seed : & [ u8 ] ,
154+ ) -> Result < frost:: round2:: SignatureShare < C > , Error < C > > {
155+ let randomized_params = RandomizedParams :: regenerate_from_seed_and_commitments (
156+ key_package. verifying_key ( ) ,
157+ randomizer_seed,
158+ signing_package. signing_commitments ( ) ,
159+ ) ?;
160+ let randomized_key_package = key_package. randomize ( & randomized_params) ?;
161+ frost:: round2:: sign ( signing_package, signer_nonces, & randomized_key_package)
162+ }
163+
138164/// Re-randomized FROST signature share aggregation with the given [`RandomizedParams`],
139165/// which can be computed from the previously generated randomizer using
140166/// [`RandomizedParams::from_randomizer`].
@@ -178,12 +204,15 @@ impl<C> Randomizer<C>
178204where
179205 C : RandomizedCiphersuite ,
180206{
181- /// Create a new random Randomizer.
207+ /// Create a new random Randomizer using a SigningPackage for randomness .
182208 ///
183209 /// The [`SigningPackage`] must be the signing package being used in the
184210 /// current FROST signing run. It is hashed into the randomizer calculation,
185211 /// which binds it to that specific package.
186212 #[ cfg( feature = "serialization" ) ]
213+ #[ deprecated(
214+ note = "switch to new_from_commitments(), passing the commitments from SigningPackage"
215+ ) ]
187216 pub fn new < R : RngCore + CryptoRng > (
188217 mut rng : R ,
189218 signing_package : & SigningPackage < C > ,
@@ -212,6 +241,65 @@ where
212241 . ok_or ( Error :: SerializationError ) ?;
213242 Ok ( Self ( SerializableScalar ( randomizer) ) )
214243 }
244+
245+ /// Create a new random Randomizer using SigningCommitments for randomness.
246+ ///
247+ /// The [`SigningCommitments`] map must be the one being used in the current
248+ /// FROST signing run (built by the Coordinator after receiving from
249+ /// Participants). It is hashed into the randomizer calculation, which binds
250+ /// it to that specific commitments.
251+ ///
252+ /// Returns the Randomizer and the generate randomizer seed. Both can be
253+ /// used to regenerate the Randomizer with
254+ /// [`Self::regenerate_from_seed_and_commitments()`].
255+ pub fn new_from_commitments < R : RngCore + CryptoRng > (
256+ mut rng : R ,
257+ signing_commitments : & BTreeMap < Identifier < C > , SigningCommitments < C > > ,
258+ ) -> Result < ( Self , Vec < u8 > ) , Error < C > > {
259+ // Generate a dummy scalar to get its encoded size
260+ let zero = <<C :: Group as Group >:: Field as Field >:: zero ( ) ;
261+ let ns = <<C :: Group as Group >:: Field as Field >:: serialize ( & zero)
262+ . as_ref ( )
263+ . len ( ) ;
264+ let mut randomizer_seed = alloc:: vec![ 0 ; ns] ;
265+ rng. fill_bytes ( & mut randomizer_seed) ;
266+ Ok ( (
267+ Self :: regenerate_from_seed_and_commitments ( & randomizer_seed, signing_commitments) ?,
268+ randomizer_seed,
269+ ) )
270+ }
271+
272+ /// Regenerates a Randomizer generated with
273+ /// [`Self::new_from_commitments()`]. This can be used by Participants after
274+ /// receiving the randomizer seed and commitments in Round 2. This is better
275+ /// than the Coordinator simply generating a Randomizer and sending it to
276+ /// Participants, because in this approach the participants don't need to
277+ /// fully trust the Coordinator's random number generator (i.e. even if the
278+ /// randomizer seed was not randomly generated the randomizer will still
279+ /// be).
280+ ///
281+ /// This should be used exclusively with the output of
282+ /// [`Self::new_from_commitments()`]; it is strongly suggested to not
283+ /// attempt generating the randomizer seed yourself (even if the point of
284+ /// this approach is to hedge against issues in the randomizer seed
285+ /// generation).
286+ pub fn regenerate_from_seed_and_commitments (
287+ randomizer_seed : & [ u8 ] ,
288+ signing_commitments : & BTreeMap < Identifier < C > , SigningCommitments < C > > ,
289+ ) -> Result < Randomizer < C > , Error < C > >
290+ where
291+ C : RandomizedCiphersuite ,
292+ {
293+ let randomizer = C :: hash_randomizer (
294+ & [
295+ randomizer_seed,
296+ & encode_group_commitments ( signing_commitments) ?,
297+ ]
298+ . concat ( ) ,
299+ )
300+ . ok_or ( Error :: SerializationError ) ?;
301+ Ok ( Self ( SerializableScalar ( randomizer) ) )
302+ }
215303}
216304
217305impl < C > Randomizer < C >
@@ -267,18 +355,76 @@ where
267355 C : RandomizedCiphersuite ,
268356{
269357 /// Create a new [`RandomizedParams`] for the given [`VerifyingKey`] and
270- /// the given `participants` .
358+ /// the given [`SigningPackage`] .
271359 #[ cfg( feature = "serialization" ) ]
360+ #[ deprecated(
361+ note = "switch to new_from_commitments(), passing the commitments from SigningPackage"
362+ ) ]
272363 pub fn new < R : RngCore + CryptoRng > (
273364 group_verifying_key : & VerifyingKey < C > ,
274365 signing_package : & SigningPackage < C > ,
275366 rng : R ,
276367 ) -> Result < Self , Error < C > > {
368+ #[ allow( deprecated) ]
277369 Ok ( Self :: from_randomizer (
278370 group_verifying_key,
279371 Randomizer :: new ( rng, signing_package) ?,
280372 ) )
281373 }
374+
375+ /// Create a new [`RandomizedParams`] for the given [`VerifyingKey`] and the
376+ /// given signing commitments.
377+ ///
378+ /// The [`SigningCommitments`] map must be the one being used in the current
379+ /// FROST signing run (built by the Coordinator after receiving from
380+ /// Participants). It is hashed into the randomizer calculation, which binds
381+ /// it to that specific commitments.
382+ ///
383+ /// Returns the generated [`RandomizedParams`] and a randomizer seed. Both
384+ /// can be used to regenerate the [`RandomizedParams`] with
385+ /// [`Self::regenerate_from_seed_and_commitments()`].
386+ pub fn new_from_commitments < R : RngCore + CryptoRng > (
387+ group_verifying_key : & VerifyingKey < C > ,
388+ signing_commitments : & BTreeMap < Identifier < C > , SigningCommitments < C > > ,
389+ rng : R ,
390+ ) -> Result < ( Self , Vec < u8 > ) , Error < C > > {
391+ let ( randomizer, randomizer_seed) =
392+ Randomizer :: new_from_commitments ( rng, signing_commitments) ?;
393+ Ok ( (
394+ Self :: from_randomizer ( group_verifying_key, randomizer) ,
395+ randomizer_seed,
396+ ) )
397+ }
398+
399+ /// Regenerate a [`RandomizedParams`] with the given [`VerifyingKey`] from
400+ /// the given given signing commitments.
401+ ///
402+ /// Returns the generated [`RandomizedParams`] and a randomizer seed, which
403+ /// can be used to regenerate the [`RandomizedParams`].
404+ ///
405+ /// Regenerates a [`RandomizedParams`] generated with
406+ /// [`Self::new_from_commitments()`]. This can be used by Participants after
407+ /// receiving the randomizer seed and commitments in Round 2. This is better
408+ /// than the Coordinator simply generating a [`Randomizer`] and sending it
409+ /// to Participants, because in this approach the participants don't need to
410+ /// fully trust the Coordinator's random number generator (i.e. even if the
411+ /// randomizer seed was not randomly generated the randomizer will still
412+ /// be).
413+ ///
414+ /// This should be used exclusively with the output of
415+ /// [`Self::new_from_commitments()`]; it is strongly suggested to not
416+ /// attempt generating the randomizer seed yourself (even if the point of
417+ /// this approach is to hedge against issues in the randomizer seed
418+ /// generation).
419+ pub fn regenerate_from_seed_and_commitments (
420+ group_verifying_key : & VerifyingKey < C > ,
421+ randomizer_seed : & [ u8 ] ,
422+ signing_commitments : & BTreeMap < Identifier < C > , SigningCommitments < C > > ,
423+ ) -> Result < Self , Error < C > > {
424+ let randomizer =
425+ Randomizer :: regenerate_from_seed_and_commitments ( randomizer_seed, signing_commitments) ?;
426+ Ok ( Self :: from_randomizer ( group_verifying_key, randomizer) )
427+ }
282428}
283429
284430impl < C > RandomizedParams < C >
0 commit comments