Skip to content

Commit

Permalink
remove identifiers from DKG packages
Browse files Browse the repository at this point in the history
  • Loading branch information
conradoplg committed Jun 29, 2023
1 parent 2d939ed commit 4cdb6cd
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 116 deletions.
4 changes: 3 additions & 1 deletion frost-core/src/frost/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ where
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Identifier")
.field(&<<C::Group as Group>::Field>::serialize(&self.0).as_ref())
.field(&hex::encode(
<<C::Group as Group>::Field>::serialize(&self.0).as_ref(),
))
.finish()
}
}
Expand Down
110 changes: 55 additions & 55 deletions frost-core/src/frost/keys/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ pub mod round1 {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct Package<C: Ciphersuite> {
/// The identifier of the participant who is sending the package (i).
pub(crate) sender_identifier: Identifier<C>,
/// The public commitment from the participant (C_i)
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
/// The proof of knowledge of the temporary secret (σ_i = (R_i, μ_i))
Expand All @@ -82,12 +80,10 @@ pub mod round1 {
{
/// Create a new [`Package`] instance.
pub fn new(
sender_identifier: Identifier<C>,
commitment: VerifiableSecretSharingCommitment<C>,
proof_of_knowledge: Signature<C>,
) -> Self {
Self {
sender_identifier,
commitment,
proof_of_knowledge,
ciphersuite: (),
Expand Down Expand Up @@ -132,10 +128,6 @@ pub mod round2 {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct Package<C: Ciphersuite> {
/// The identifier of the participant that generated the package (i).
pub(crate) sender_identifier: Identifier<C>,
/// The identifier of the participant what will receive the package (ℓ).
pub(crate) receiver_identifier: Identifier<C>,
/// The secret share being sent.
pub(crate) secret_share: SigningShare<C>,
/// Ciphersuite ID for serialization
Expand All @@ -156,14 +148,8 @@ pub mod round2 {
C: Ciphersuite,
{
/// Create a new [`Package`] instance.
pub fn new(
sender_identifier: Identifier<C>,
receiver_identifier: Identifier<C>,
secret_share: SigningShare<C>,
) -> Self {
pub fn new(secret_share: SigningShare<C>) -> Self {
Self {
sender_identifier,
receiver_identifier,
secret_share,
ciphersuite: (),
}
Expand Down Expand Up @@ -233,7 +219,6 @@ pub fn part1<C: Ciphersuite, R: RngCore + CryptoRng>(
max_signers,
};
let package = round1::Package {
sender_identifier: identifier,
commitment,
proof_of_knowledge: Signature { R: R_i, z: mu_i },
ciphersuite: (),
Expand Down Expand Up @@ -264,21 +249,33 @@ where
/// for the participant holding the given [`round1::SecretPackage`],
/// given the received [`round1::Package`]s received from the other participants.
///
/// `round1_packages` maps the identifier of each participant to the
/// [`round1::Package`] they sent. These identifiers must come from whatever mapping
/// the coordinator has between communication channels and participants, i.e.
/// they must have assurance that the [`round1::Package`] came from
/// the participant with that identifier.
///
/// It returns the [`round2::SecretPackage`] that must be kept in memory
/// by the participant for the final step, and the [`round2::Package`]s that
/// must be sent to other participants.
/// by the participant for the final step, and the a map of [`round2::Package`]s that
/// must be sent to each participant who has the given identifier in the map key.
pub fn part2<C: Ciphersuite>(
secret_package: round1::SecretPackage<C>,
round1_packages: &[round1::Package<C>],
) -> Result<(round2::SecretPackage<C>, Vec<round2::Package<C>>), Error<C>> {
round1_packages: &HashMap<Identifier<C>, round1::Package<C>>,
) -> Result<
(
round2::SecretPackage<C>,
HashMap<Identifier<C>, round2::Package<C>>,
),
Error<C>,
> {
if round1_packages.len() != (secret_package.max_signers - 1) as usize {
return Err(Error::IncorrectNumberOfPackages);
}

let mut round2_packages = Vec::new();
let mut round2_packages = HashMap::new();

for round1_package in round1_packages {
let ell = round1_package.sender_identifier;
for (sender_identifier, round1_package) in round1_packages {
let ell = *sender_identifier;
// Round 1, Step 5
//
// > Upon receiving C⃗_ℓ, σ_ℓ from participants 1 ≤ ℓ ≤ n, ℓ ≠ i, participant
Expand All @@ -300,12 +297,13 @@ pub fn part2<C: Ciphersuite>(
// > which they keep for themselves.
let value = evaluate_polynomial(ell, &secret_package.coefficients);

round2_packages.push(round2::Package {
sender_identifier: secret_package.identifier,
receiver_identifier: ell,
secret_share: SigningShare(value),
ciphersuite: (),
});
round2_packages.insert(
ell,
round2::Package {
secret_share: SigningShare(value),
ciphersuite: (),
},
);
}
let fii = evaluate_polynomial(secret_package.identifier, &secret_package.coefficients);
Ok((
Expand All @@ -322,8 +320,7 @@ pub fn part2<C: Ciphersuite>(
/// Computes the verifying keys of the other participants for the third step
/// of the DKG protocol.
fn compute_verifying_keys<C: Ciphersuite>(
round2_packages: &[round2::Package<C>],
round1_packages_map: HashMap<Identifier<C>, &round1::Package<C>>,
round1_packages: &HashMap<Identifier<C>, round1::Package<C>>,
round2_secret_package: &round2::SecretPackage<C>,
) -> Result<HashMap<Identifier<C>, VerifyingShare<C>>, Error<C>> {
// Round 2, Step 4
Expand All @@ -334,26 +331,26 @@ fn compute_verifying_keys<C: Ciphersuite>(

// Note that in this loop, "i" refers to the other participant whose public verification share
// we are computing, and not the current participant.
for i in round2_packages.iter().map(|p| p.sender_identifier) {
for i in round1_packages.keys().cloned() {
let mut y_i = <C::Group>::identity();

// We need to iterate through all commitment vectors, including our own,
// so chain it manually
for commitments in round2_packages
.iter()
.map(|p| {
for commitment in round1_packages
.keys()
.map(|k| {
// Get the commitment vector for this participant
Ok::<&VerifiableSecretSharingCommitment<C>, Error<C>>(
&round1_packages_map
.get(&p.sender_identifier)
&round1_packages
.get(k)
.ok_or(Error::PackageNotFound)?
.commitment,
)
})
// Chain our own commitment vector
.chain(iter::once(Ok(&round2_secret_package.commitment)))
{
y_i = y_i + evaluate_vss(commitments?, i);
y_i = y_i + evaluate_vss(commitment?, i);
}
let y_i = VerifyingShare(y_i);
others_verifying_keys.insert(i, y_i);
Expand All @@ -366,45 +363,49 @@ fn compute_verifying_keys<C: Ciphersuite>(
/// given the received [`round1::Package`]s and [`round2::Package`]s received from
/// the other participants.
///
/// `round1_packages` must be the same used in [`part2()`].
///
/// `round2_packages` maps the identifier of each participant to the
/// [`round2::Package`] they sent. These identifiers must come from whatever mapping
/// the coordinator has between communication channels and participants, i.e.
/// they must have assurance that the [`round2::Package`] came from
/// the participant with that identifier.
///
/// It returns the [`KeyPackage`] that has the long-lived key share for the
/// participant, and the [`PublicKeyPackage`]s that has public information
/// about all participants; both of which are required to compute FROST
/// signatures.
pub fn part3<C: Ciphersuite>(
round2_secret_package: &round2::SecretPackage<C>,
round1_packages: &[round1::Package<C>],
round2_packages: &[round2::Package<C>],
round1_packages: &HashMap<Identifier<C>, round1::Package<C>>,
round2_packages: &HashMap<Identifier<C>, round2::Package<C>>,
) -> Result<(KeyPackage<C>, PublicKeyPackage<C>), Error<C>> {
if round1_packages.len() != (round2_secret_package.max_signers - 1) as usize {
return Err(Error::IncorrectNumberOfPackages);
}
if round1_packages.len() != round2_packages.len() {
return Err(Error::IncorrectNumberOfPackages);
}
if round1_packages
.keys()
.any(|id| !round2_packages.contains_key(id))
{
return Err(Error::IncorrectPackage);
}

let mut signing_share = <<C::Group as Group>::Field>::zero();
let mut group_public = <C::Group>::identity();

let round1_packages_map: HashMap<Identifier<C>, &round1::Package<C>> = round1_packages
.iter()
.map(|package| (package.sender_identifier, package))
.collect();

for round2_package in round2_packages {
// Sanity check; was the package really meant to us?
if round2_package.receiver_identifier != round2_secret_package.identifier {
return Err(Error::IncorrectPackage);
}

for (sender_identifier, round2_package) in round2_packages {
// Round 2, Step 2
//
// > Each P_i verifies their shares by calculating:
// > g^{f_ℓ(i)} ≟ ∏^{t−1}_{k=0} φ^{i^k mod q}_{ℓk}, aborting if the
// > check fails.
let ell = round2_package.sender_identifier;
let ell = *sender_identifier;
let f_ell_i = round2_package.secret_share;

let commitment = &round1_packages_map
let commitment = &round1_packages
.get(&ell)
.ok_or(Error::PackageNotFound)?
.commitment;
Expand Down Expand Up @@ -450,8 +451,7 @@ pub fn part3<C: Ciphersuite>(
//
// > Any participant can compute the public verification share of any other participant
// > by calculating Y_i = ∏_{j=1}^n ∏_{k=0}^{t−1} φ_{jk}^{i^k mod q}.
let mut all_verifying_keys =
compute_verifying_keys(round2_packages, round1_packages_map, round2_secret_package)?;
let mut all_verifying_keys = compute_verifying_keys(round1_packages, round2_secret_package)?;

// Add the participant's own public verification share for consistency
all_verifying_keys.insert(round2_secret_package.identifier, verifying_key);
Expand Down
14 changes: 7 additions & 7 deletions frost-core/src/tests/ciphersuite_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ where
// will be sent through some communication channel.
let mut received_round1_packages: HashMap<
frost::Identifier<C>,
Vec<frost::keys::dkg::round1::Package<C>>,
HashMap<frost::Identifier<C>, frost::keys::dkg::round1::Package<C>>,
> = HashMap::new();

// For each participant, perform the first part of the DKG protocol.
Expand All @@ -221,8 +221,8 @@ where
.expect("should be nonzero");
received_round1_packages
.entry(receiver_participant_identifier)
.or_insert_with(Vec::new)
.push(round1_package.clone());
.or_insert_with(HashMap::new)
.insert(participant_identifier, round1_package.clone());
}
}

Expand Down Expand Up @@ -260,11 +260,11 @@ where
// sent through some communication channel.
// Note that, in contrast to the previous part, here each other participant
// gets its own specific package.
for round2_package in round2_packages {
for (receiver_identifier, round2_package) in round2_packages {
received_round2_packages
.entry(round2_package.receiver_identifier)
.or_insert_with(Vec::new)
.push(round2_package);
.entry(receiver_identifier)
.or_insert_with(HashMap::new)
.insert(participant_identifier, round2_package);
}
}

Expand Down
12 changes: 6 additions & 6 deletions frost-ristretto255/dkg.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ for participant_index in 1..=max_signers {
.expect("should be nonzero");
received_round1_packages
.entry(receiver_participant_identifier)
.or_insert_with(Vec::new)
.push(round1_package.clone());
.or_insert_with(HashMap::new)
.insert(participant_identifier, round1_package.clone());
}
}

Expand Down Expand Up @@ -121,11 +121,11 @@ for participant_index in 1..=max_signers {
// sent through some communication channel.
// Note that, in contrast to the previous part, here each other participant
// gets its own specific package.
for round2_package in round2_packages {
for (receiver_identifier, round2_package) in round2_packages {
received_round2_packages
.entry(*round2_package.receiver_identifier())
.or_insert_with(Vec::new)
.push(round2_package);
.entry(receiver_identifier)
.or_insert_with(HashMap::new)
.insert(participant_identifier, round2_package);
}
}

Expand Down
8 changes: 4 additions & 4 deletions frost-ristretto255/src/keys/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ pub fn part1<R: RngCore + CryptoRng>(
/// must be sent to other participants.
pub fn part2(
secret_package: round1::SecretPackage,
round1_packages: &[round1::Package],
) -> Result<(round2::SecretPackage, Vec<round2::Package>), Error> {
round1_packages: &HashMap<Identifier, round1::Package>,
) -> Result<(round2::SecretPackage, HashMap<Identifier, round2::Package>), Error> {
frost::keys::dkg::part2(secret_package, round1_packages)
}

Expand All @@ -80,8 +80,8 @@ pub fn part2(
/// signatures.
pub fn part3(
round2_secret_package: &round2::SecretPackage,
round1_packages: &[round1::Package],
round2_packages: &[round2::Package],
round1_packages: &HashMap<Identifier, round1::Package>,
round2_packages: &HashMap<Identifier, round2::Package>,
) -> Result<(KeyPackage, PublicKeyPackage), Error> {
frost::keys::dkg::part3(round2_secret_package, round1_packages, round2_packages)
}
6 changes: 2 additions & 4 deletions frost-ristretto255/tests/helpers/samples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ pub fn public_key_package() -> PublicKeyPackage {

/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let identifier = 42u16.try_into().unwrap();
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
let serialized_signature = serialized_element
Expand All @@ -113,14 +112,13 @@ pub fn round1_package() -> round1::Package {
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let signature = Signature::from_bytes(serialized_signature).unwrap();

round1::Package::new(identifier, vss_commitment, signature)
round1::Package::new(vss_commitment, signature)
}

/// Generate a sample round2::Package.
pub fn round2_package() -> round2::Package {
let identifier = 42u16.try_into().unwrap();
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();

round2::Package::new(identifier, identifier, signing_share)
round2::Package::new(signing_share)
}
8 changes: 2 additions & 6 deletions frost-ristretto255/tests/recreation_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,10 @@ fn check_public_key_package_recreation() {
fn check_round1_package_recreation() {
let round1_package = samples::round1_package();

let identifier = round1_package.sender_identifier();
let vss_commitment = round1_package.commitment();
let signature = round1_package.proof_of_knowledge();

let new_round1_package = round1::Package::new(*identifier, vss_commitment.clone(), *signature);
let new_round1_package = round1::Package::new(vss_commitment.clone(), *signature);

assert!(round1_package == new_round1_package);
}
Expand All @@ -114,12 +113,9 @@ fn check_round1_package_recreation() {
fn check_round2_package_recreation() {
let round2_package = samples::round2_package();

let sender_identifier = round2_package.sender_identifier();
let receiver_identifier = round2_package.receiver_identifier();
let signing_share = round2_package.secret_share();

let new_round2_package =
round2::Package::new(*sender_identifier, *receiver_identifier, *signing_share);
let new_round2_package = round2::Package::new(*signing_share);

assert!(round2_package == new_round2_package);
}
Loading

0 comments on commit 4cdb6cd

Please sign in to comment.