Skip to content

Commit 720c10f

Browse files
authored
Merge of #730
2 parents 958fde3 + 59d1da2 commit 720c10f

File tree

61 files changed

+4060
-125
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+4060
-125
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ members = [
77
"frost-p256",
88
"frost-ristretto255",
99
"frost-secp256k1",
10+
"frost-secp256k1-tr",
1011
"frost-rerandomized",
1112
"gencode"
1213
]

frost-core/src/batch.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,14 @@ where
3333
where
3434
M: AsRef<[u8]>,
3535
{
36-
// Compute c now to avoid dependency on the msg lifetime.
37-
let c = crate::challenge(&sig.R, &vk, msg.as_ref())?;
38-
39-
Ok(Self { vk, sig, c })
36+
let (msg, sig, vk) = <C>::pre_verify(msg.as_ref(), &sig, &vk)?;
37+
let c = <C>::challenge(&sig.R, &vk, &msg)?;
38+
39+
Ok(Self {
40+
vk: *vk,
41+
sig: *sig,
42+
c,
43+
})
4044
}
4145
}
4246

frost-core/src/keys/dkg.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,7 @@ pub(crate) fn compute_proof_of_knowledge<C: Ciphersuite, R: RngCore + CryptoRng>
355355
// > a_{i0} by calculating σ_i = (R_i, μ_i), such that k ← Z_q, R_i = g^k,
356356
// > c_i = H(i, Φ, g^{a_{i0}} , R_i), μ_i = k + a_{i0} · c_i, with Φ being
357357
// > a context string to prevent replay attacks.
358-
let k = <<C::Group as Group>::Field>::random(&mut rng);
359-
let R_i = <C::Group>::generator() * k;
358+
let (k, R_i) = <C>::generate_nonce(&mut rng);
360359
let c_i = challenge::<C>(identifier, &commitment.verifying_key()?, &R_i)?;
361360
let a_i0 = *coefficients
362361
.first()
@@ -570,5 +569,5 @@ pub fn part3<C: Ciphersuite>(
570569
min_signers: round2_secret_package.min_signers,
571570
};
572571

573-
Ok((key_package, public_key_package))
572+
C::post_dkg(key_package, public_key_package)
574573
}

frost-core/src/lib.rs

+55-26
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use alloc::{
2525
use derive_getters::Getters;
2626
#[cfg(any(test, feature = "test-impl"))]
2727
use hex::FromHex;
28+
use keys::PublicKeyPackage;
2829
use rand_core::{CryptoRng, RngCore};
2930
use serialization::SerializableScalar;
3031
use zeroize::Zeroize;
@@ -64,11 +65,7 @@ pub use verifying_key::VerifyingKey;
6465
///
6566
/// [challenge]: https://datatracker.ietf.org/doc/html/rfc9591#name-signature-challenge-computa
6667
#[derive(Copy, Clone)]
67-
#[cfg_attr(feature = "internals", visibility::make(pub))]
68-
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
69-
pub(crate) struct Challenge<C: Ciphersuite>(
70-
pub(crate) <<C::Group as Group>::Field as Field>::Scalar,
71-
);
68+
pub struct Challenge<C: Ciphersuite>(pub(crate) <<C::Group as Group>::Field as Field>::Scalar);
7269

7370
impl<C> Challenge<C>
7471
where
@@ -138,6 +135,8 @@ where
138135
/// Generates a random nonzero scalar.
139136
///
140137
/// It assumes that the Scalar Eq/PartialEq implementation is constant-time.
138+
#[cfg_attr(feature = "internals", visibility::make(pub))]
139+
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
141140
pub(crate) fn random_nonzero<C: Ciphersuite, R: RngCore + CryptoRng>(rng: &mut R) -> Scalar<C> {
142141
loop {
143142
let scalar = <<C::Group as Group>::Field>::random(rng);
@@ -192,9 +191,7 @@ where
192191
///
193192
/// <https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md>
194193
#[derive(Clone, PartialEq, Eq)]
195-
#[cfg_attr(feature = "internals", visibility::make(pub))]
196-
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
197-
pub(crate) struct BindingFactor<C: Ciphersuite>(Scalar<C>);
194+
pub struct BindingFactor<C: Ciphersuite>(Scalar<C>);
198195

199196
impl<C> BindingFactor<C>
200197
where
@@ -469,9 +466,7 @@ where
469466
/// The product of all signers' individual commitments, published as part of the
470467
/// final signature.
471468
#[derive(Clone, PartialEq, Eq)]
472-
#[cfg_attr(feature = "internals", visibility::make(pub))]
473-
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
474-
pub(crate) struct GroupCommitment<C: Ciphersuite>(pub(crate) Element<C>);
469+
pub struct GroupCommitment<C: Ciphersuite>(pub(crate) Element<C>);
475470

476471
impl<C> GroupCommitment<C>
477472
where
@@ -483,6 +478,12 @@ where
483478
pub(crate) fn to_element(self) -> <C::Group as Group>::Element {
484479
self.0
485480
}
481+
482+
/// Return the underlying element.
483+
#[cfg(feature = "internals")]
484+
pub fn from_element(element: Element<C>) -> Self {
485+
Self(element)
486+
}
486487
}
487488

488489
/// Generates the group commitment which is published as part of the joint
@@ -584,12 +585,15 @@ where
584585
return Err(Error::UnknownIdentifier);
585586
}
586587

588+
let (signing_package, signature_shares, pubkeys) =
589+
<C>::pre_aggregate(signing_package, signature_shares, pubkeys)?;
590+
587591
// Encodes the signing commitment list produced in round one as part of generating [`BindingFactor`], the
588592
// binding factor.
589593
let binding_factor_list: BindingFactorList<C> =
590-
compute_binding_factor_list(signing_package, &pubkeys.verifying_key, &[])?;
594+
compute_binding_factor_list(&signing_package, &pubkeys.verifying_key, &[])?;
591595
// Compute the group commitment from signing commitments produced in round one.
592-
let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?;
596+
let group_commitment = compute_group_commitment(&signing_package, &binding_factor_list)?;
593597

594598
// The aggregation of the signature shares by summing them up, resulting in
595599
// a plain Schnorr signature.
@@ -619,10 +623,10 @@ where
619623
#[cfg(feature = "cheater-detection")]
620624
if verification_result.is_err() {
621625
detect_cheater(
622-
group_commitment,
623-
pubkeys,
624-
signing_package,
625-
signature_shares,
626+
&group_commitment,
627+
&pubkeys,
628+
&signing_package,
629+
&signature_shares,
626630
&binding_factor_list,
627631
)?;
628632
}
@@ -637,17 +641,17 @@ where
637641
/// Each share is verified to find the cheater
638642
#[cfg(feature = "cheater-detection")]
639643
fn detect_cheater<C: Ciphersuite>(
640-
group_commitment: GroupCommitment<C>,
644+
group_commitment: &GroupCommitment<C>,
641645
pubkeys: &keys::PublicKeyPackage<C>,
642646
signing_package: &SigningPackage<C>,
643647
signature_shares: &BTreeMap<Identifier<C>, round2::SignatureShare<C>>,
644648
binding_factor_list: &BindingFactorList<C>,
645649
) -> Result<(), Error<C>> {
646650
// Compute the per-message challenge.
647-
let challenge = crate::challenge::<C>(
651+
let challenge = <C>::challenge(
648652
&group_commitment.0,
649653
&pubkeys.verifying_key,
650-
signing_package.message().as_slice(),
654+
signing_package.message(),
651655
)?;
652656

653657
// Verify the signature shares.
@@ -663,6 +667,7 @@ fn detect_cheater<C: Ciphersuite>(
663667
*identifier,
664668
signing_package,
665669
binding_factor_list,
670+
group_commitment,
666671
signature_share,
667672
verifying_share,
668673
challenge,
@@ -688,24 +693,44 @@ pub fn verify_signature_share<C: Ciphersuite>(
688693
signing_package: &SigningPackage<C>,
689694
verifying_key: &VerifyingKey<C>,
690695
) -> Result<(), Error<C>> {
696+
// In order to reuse `pre_aggregate()`, we need to create some "dummy" containers
697+
let signature_shares = BTreeMap::from([(identifier, *signature_share)]);
698+
let verifying_shares = BTreeMap::from([(identifier, *verifying_share)]);
699+
let public_key_package = PublicKeyPackage::new(verifying_shares, *verifying_key);
700+
701+
let (signing_package, signature_shares, pubkeys) =
702+
<C>::pre_aggregate(signing_package, &signature_shares, &public_key_package)?;
703+
704+
// Extract the processed values back from the "dummy" containers
705+
let verifying_share = pubkeys
706+
.verifying_shares()
707+
.get(&identifier)
708+
.expect("pre_aggregate() must keep the identifiers");
709+
let verifying_key = pubkeys.verifying_key();
710+
let signature_share = signature_shares
711+
.get(&identifier)
712+
.expect("pre_aggregate() must keep the identifiers");
713+
691714
// Encodes the signing commitment list produced in round one as part of generating [`BindingFactor`], the
692715
// binding factor.
693716
let binding_factor_list: BindingFactorList<C> =
694-
compute_binding_factor_list(signing_package, verifying_key, &[])?;
717+
compute_binding_factor_list(&signing_package, verifying_key, &[])?;
718+
695719
// Compute the group commitment from signing commitments produced in round one.
696-
let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?;
720+
let group_commitment = compute_group_commitment(&signing_package, &binding_factor_list)?;
697721

698722
// Compute the per-message challenge.
699-
let challenge = crate::challenge::<C>(
700-
&group_commitment.to_element(),
723+
let challenge = <C>::challenge(
724+
&group_commitment.clone().to_element(),
701725
verifying_key,
702726
signing_package.message().as_slice(),
703727
)?;
704728

705729
verify_signature_share_precomputed(
706730
identifier,
707-
signing_package,
731+
&signing_package,
708732
&binding_factor_list,
733+
&group_commitment,
709734
signature_share,
710735
verifying_share,
711736
challenge,
@@ -720,6 +745,7 @@ fn verify_signature_share_precomputed<C: Ciphersuite>(
720745
signature_share_identifier: Identifier<C>,
721746
signing_package: &SigningPackage<C>,
722747
binding_factor_list: &BindingFactorList<C>,
748+
group_commitment: &GroupCommitment<C>,
723749
signature_share: &round2::SignatureShare<C>,
724750
verifying_share: &keys::VerifyingShare<C>,
725751
challenge: Challenge<C>,
@@ -735,7 +761,10 @@ fn verify_signature_share_precomputed<C: Ciphersuite>(
735761
.ok_or(Error::UnknownIdentifier)?
736762
.to_group_commitment_share(binding_factor);
737763

738-
signature_share.verify(
764+
// Compute relation values to verify this signature share.
765+
<C>::verify_share(
766+
group_commitment,
767+
signature_share,
739768
signature_share_identifier,
740769
&R_share,
741770
verifying_share,

frost-core/src/round1.rs

+20
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,16 @@ where
5454
Self::nonce_generate_from_random_bytes(secret, random_bytes)
5555
}
5656

57+
/// Create a nonce from a scalar.
58+
#[cfg_attr(feature = "internals", visibility::make(pub))]
59+
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
5760
fn from_scalar(scalar: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar) -> Self {
5861
Self(SerializableScalar(scalar))
5962
}
6063

64+
/// Convert a nonce into a scalar.
65+
#[cfg_attr(feature = "internals", visibility::make(pub))]
66+
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
6167
pub(crate) fn to_scalar(
6268
self,
6369
) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
@@ -358,6 +364,20 @@ where
358364
#[derive(Clone, Copy, PartialEq)]
359365
pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) Element<C>);
360366

367+
impl<C: Ciphersuite> GroupCommitmentShare<C> {
368+
/// Create from an element.
369+
#[cfg_attr(feature = "internals", visibility::make(pub))]
370+
pub(crate) fn from_element(element: Element<C>) -> Self {
371+
Self(element)
372+
}
373+
374+
/// Return the underlying element.
375+
#[cfg_attr(feature = "internals", visibility::make(pub))]
376+
pub(crate) fn to_element(self) -> Element<C> {
377+
self.0
378+
}
379+
}
380+
361381
/// Encode the list of group signing commitments.
362382
///
363383
/// Implements [`encode_group_commitment_list()`] from the spec.

frost-core/src/round2.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::fmt::{self, Debug};
44

55
use crate as frost;
66
use crate::{
7-
challenge, Challenge, Ciphersuite, Error, Field, Group, {round1, *},
7+
Challenge, Ciphersuite, Error, Field, Group, {round1, *},
88
};
99

1010
/// A participant's signature share, which the coordinator will aggregate with all other signer's
@@ -71,7 +71,8 @@ where
7171
challenge: &Challenge<C>,
7272
) -> Result<(), Error<C>> {
7373
if (<C::Group>::generator() * self.to_scalar())
74-
!= (group_commitment_share.0 + (verifying_share.to_element() * challenge.0 * lambda_i))
74+
!= (group_commitment_share.to_element()
75+
+ (verifying_share.to_element() * challenge.0 * lambda_i))
7576
{
7677
return Err(Error::InvalidSignatureShare {
7778
culprit: identifier,
@@ -96,7 +97,7 @@ where
9697
/// Compute the signature share for a signing operation.
9798
#[cfg_attr(feature = "internals", visibility::make(pub))]
9899
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
99-
fn compute_signature_share<C: Ciphersuite>(
100+
pub(super) fn compute_signature_share<C: Ciphersuite>(
100101
signer_nonces: &round1::SigningNonces<C>,
101102
binding_factor: BindingFactor<C>,
102103
lambda_i: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
@@ -142,34 +143,38 @@ pub fn sign<C: Ciphersuite>(
142143
return Err(Error::IncorrectCommitment);
143144
}
144145

146+
let (signing_package, signer_nonces, key_package) =
147+
<C>::pre_sign(signing_package, signer_nonces, key_package)?;
148+
145149
// Encodes the signing commitment list produced in round one as part of generating [`BindingFactor`], the
146150
// binding factor.
147151
let binding_factor_list: BindingFactorList<C> =
148-
compute_binding_factor_list(signing_package, &key_package.verifying_key, &[])?;
152+
compute_binding_factor_list(&signing_package, &key_package.verifying_key, &[])?;
149153
let binding_factor: frost::BindingFactor<C> = binding_factor_list
150154
.get(&key_package.identifier)
151155
.ok_or(Error::UnknownIdentifier)?
152156
.clone();
153157

154158
// Compute the group commitment from signing commitments produced in round one.
155-
let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?;
159+
let group_commitment = compute_group_commitment(&signing_package, &binding_factor_list)?;
156160

157161
// Compute Lagrange coefficient.
158-
let lambda_i = frost::derive_interpolating_value(key_package.identifier(), signing_package)?;
162+
let lambda_i = frost::derive_interpolating_value(key_package.identifier(), &signing_package)?;
159163

160164
// Compute the per-message challenge.
161-
let challenge = challenge::<C>(
165+
let challenge = <C>::challenge(
162166
&group_commitment.0,
163167
&key_package.verifying_key,
164-
signing_package.message.as_slice(),
168+
signing_package.message(),
165169
)?;
166170

167171
// Compute the Schnorr signature share.
168-
let signature_share = compute_signature_share(
169-
signer_nonces,
172+
let signature_share = <C>::compute_signature_share(
173+
&group_commitment,
174+
&signer_nonces,
170175
binding_factor,
171176
lambda_i,
172-
key_package,
177+
&key_package,
173178
challenge,
174179
);
175180

0 commit comments

Comments
 (0)