Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion frost-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Entries are listed in reverse chronological order.

## Unreleases
## Unreleased

### Breaking Changes

Expand All @@ -12,6 +12,13 @@ Entries are listed in reverse chronological order.
the default behaviour is now as if `cheater-detection` was enabled. If you
explicitly *did not enable* it, you can avoid cheater detection by calling
`aggregate_custom()` with `CheaterDetection::Disabled`.
* The `std` and `nightly` features were removed from all crates
* Renamed `frost_core::keys::refresh::refresh_dkg_part_1` to `refresh_dkg_part1`.
* Fixed the crate-specific versions of the `refresh` module to be non-generic.

### Additional changes

* Added DKG refresh functions to the crate-specific `refresh` modules.

## 2.2.0

Expand Down
37 changes: 35 additions & 2 deletions frost-core/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,11 @@ where
pub(crate) fn coefficients(&self) -> &[CoefficientCommitment<C>] {
&self.0
}

/// Return the threshold associated with this commitment.
pub(crate) fn min_signers(&self) -> u16 {
self.0.len() as u16
}
}

/// A secret share generated by performing a (t-out-of-n) secret sharing scheme,
Expand Down Expand Up @@ -563,6 +568,7 @@ pub fn split<C: Ciphersuite, R: RngCore + CryptoRng>(
header: Header::default(),
verifying_shares,
verifying_key,
min_signers: Some(min_signers),
};

// Apply post-processing
Expand Down Expand Up @@ -706,7 +712,7 @@ where
signing_share: secret_share.signing_share,
verifying_share,
verifying_key,
min_signers: secret_share.commitment.0.len() as u16,
min_signers: secret_share.commitment.min_signers(),
})
}
}
Expand All @@ -716,7 +722,7 @@ where
///
/// Used for verification purposes before publishing a signature.
#[derive(Clone, Debug, PartialEq, Eq, Getters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct PublicKeyPackage<C: Ciphersuite> {
Expand All @@ -728,6 +734,12 @@ pub struct PublicKeyPackage<C: Ciphersuite> {
pub(crate) verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
/// The joint public key for the entire group.
pub(crate) verifying_key: VerifyingKey<C>,
/// The minimum number of signers (threshold) required for the group.
/// This can be None in packages created with `frost_core` prior to 3.0.0.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(feature = "serde", serde(default))]
#[getter(copy)]
pub(crate) min_signers: Option<u16>,
}

impl<C> PublicKeyPackage<C>
Expand All @@ -738,11 +750,26 @@ where
pub fn new(
verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
verifying_key: VerifyingKey<C>,
min_signers: u16,
) -> Self {
Self::new_internal(verifying_shares, verifying_key, Some(min_signers))
}

/// Create a new [`PublicKeyPackage`] instance, allowing not specifying the
/// number of signers. This is used internally, in particular for testing
/// old [`PublicKeyPackage`]s that do not encode the `min_signers`.
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new_internal(
verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
verifying_key: VerifyingKey<C>,
min_signers: Option<u16>,
) -> Self {
Self {
header: Header::default(),
verifying_shares,
verifying_key,
min_signers,
}
}

Expand All @@ -761,6 +788,7 @@ where
Ok(PublicKeyPackage::new(
verifying_keys,
VerifyingKey::from_commitment(commitment)?,
commitment.min_signers(),
))
}

Expand All @@ -777,6 +805,11 @@ where
let group_commitment = sum_commitments(&commitments)?;
Self::from_commitment(&identifiers, &group_commitment)
}

/// Return the maximum number of signers.
pub fn max_signers(&self) -> u16 {
self.verifying_shares.len() as u16
}
}

#[cfg(feature = "serialization")]
Expand Down
2 changes: 1 addition & 1 deletion frost-core/src/keys/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ pub fn part2<C: Ciphersuite>(
}

for package in round1_packages.values() {
if package.commitment.0.len() != secret_package.min_signers as usize {
if package.commitment.min_signers() != secret_package.min_signers {
return Err(Error::IncorrectNumberOfCommitments);
}
}
Expand Down
14 changes: 12 additions & 2 deletions frost-core/src/keys/refresh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//!
//! For the DKG approach, the flow is very similar to [DKG
//! itself](`https://frost.zfnd.org/tutorial/dkg.html`). Each participant calls
//! [`refresh_dkg_part_1()`], keeps the returned secret package and sends the
//! [`refresh_dkg_part1()`], keeps the returned secret package and sends the
//! returned package to other participants. Then each participants calls
//! [`refresh_dkg_part2()`] and sends the returned packages to the other
//! participants. Finally each participant calls [`refresh_dkg_shares()`].
Expand Down Expand Up @@ -61,6 +61,14 @@ pub fn compute_refreshing_shares<C: Ciphersuite, R: RngCore + CryptoRng>(
identifiers: &[Identifier<C>],
rng: &mut R,
) -> Result<(Vec<SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
// Validate min_signers. It's OK if the min_signers is missing, because
// we validate it again in `refresh_share()`.
if let Some(package_min_signers) = pub_key_package.min_signers {
if min_signers != package_min_signers {
return Err(Error::InvalidMinSigners);
}
}

// Validate inputs
if identifiers.len() != max_signers as usize {
return Err(Error::IncorrectNumberOfIdentifiers);
Expand Down Expand Up @@ -110,6 +118,7 @@ pub fn compute_refreshing_shares<C: Ciphersuite, R: RngCore + CryptoRng>(
header: pub_key_package.header,
verifying_shares: refreshed_verifying_shares,
verifying_key: pub_key_package.verifying_key,
min_signers: Some(pub_key_package.min_signers.unwrap_or(min_signers)),
};

Ok((refreshing_shares_minus_identity, refreshed_pub_key_package))
Expand Down Expand Up @@ -168,7 +177,7 @@ pub fn refresh_share<C: Ciphersuite>(
/// It returns the [`round1::SecretPackage`] that must be kept in memory
/// by the participant for the other steps, and the [`round1::Package`] that
/// must be sent to each other participant in the refresh run.
pub fn refresh_dkg_part_1<C: Ciphersuite, R: RngCore + CryptoRng>(
pub fn refresh_dkg_part1<C: Ciphersuite, R: RngCore + CryptoRng>(
identifier: Identifier<C>,
max_signers: u16,
min_signers: u16,
Expand Down Expand Up @@ -460,6 +469,7 @@ pub fn refresh_dkg_shares<C: Ciphersuite>(
header: old_pub_key_package.header,
verifying_shares: new_verifying_shares,
verifying_key: old_pub_key_package.verifying_key,
min_signers: Some(round2_secret_package.min_signers),
};

let key_package = KeyPackage {
Expand Down
10 changes: 9 additions & 1 deletion frost-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,15 @@ pub fn verify_signature_share<C: Ciphersuite>(
// In order to reuse `pre_aggregate()`, we need to create some "dummy" containers
let signature_shares = BTreeMap::from([(identifier, *signature_share)]);
let verifying_shares = BTreeMap::from([(identifier, *verifying_share)]);
let public_key_package = PublicKeyPackage::new(verifying_shares, *verifying_key);
let public_key_package = PublicKeyPackage {
verifying_shares,
verifying_key: *verifying_key,
// Use None since we don't have the min_signers value here. This
// can only cause problems if the `pre_aggregate` function relies on it.
// This has been documented in `pre_aggregate()`.
min_signers: None,
header: Header::default(),
};

let (signing_package, signature_shares, pubkeys) =
<C>::pre_aggregate(signing_package, &signature_shares, &public_key_package)?;
Expand Down
Loading
Loading