Skip to content

Commit

Permalink
all: make DKG SecretPackages serializable (#833)
Browse files Browse the repository at this point in the history
  • Loading branch information
conradoplg authored Jan 15, 2025
1 parent 3143a26 commit 80d53f2
Show file tree
Hide file tree
Showing 33 changed files with 816 additions and 37 deletions.
127 changes: 108 additions & 19 deletions frost-core/src/keys/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub mod round1 {

use super::*;

use crate::serialization::SerializableScalar;
#[cfg(feature = "serialization")]
use crate::serialization::{Deserialize, Serialize};

Expand Down Expand Up @@ -117,13 +118,16 @@ pub mod round1 {
///
/// This package MUST NOT be sent to other participants!
#[derive(Clone, PartialEq, Eq, Getters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SecretPackage<C: Ciphersuite> {
/// The identifier of the participant holding the secret.
pub(crate) identifier: Identifier<C>,
/// Coefficients of the temporary secret polynomial for the participant.
/// These are (a_{i0}, ..., a_{i(t−1)})) which define the polynomial f_i(x)
#[getter(skip)]
pub(crate) coefficients: Vec<Scalar<C>>,
pub(crate) coefficients: Vec<SerializableScalar<C>>,
/// The public commitment for the participant (C_i)
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
/// The minimum number of signers.
Expand All @@ -136,10 +140,45 @@ pub mod round1 {
where
C: Ciphersuite,
{
/// Create a new Secret Package. This should be called only if
/// custom serialization is required; run the DKG to create
/// a valid SecretPackage.
pub fn new(
identifier: Identifier<C>,
coefficients: Vec<Scalar<C>>,
commitment: VerifiableSecretSharingCommitment<C>,
min_signers: u16,
max_signers: u16,
) -> Self {
Self {
identifier,
coefficients: coefficients.into_iter().map(SerializableScalar).collect(),
commitment,
min_signers,
max_signers,
}
}

/// Returns the secret coefficients.
#[cfg(feature = "internals")]
pub fn coefficients(&self) -> &[Scalar<C>] {
&self.coefficients
pub fn coefficients(&self) -> Vec<Scalar<C>> {
self.coefficients.iter().map(|s| s.0).collect()
}
}

#[cfg(feature = "serialization")]
impl<C> SecretPackage<C>
where
C: Ciphersuite,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

Expand All @@ -164,7 +203,7 @@ pub mod round1 {
{
fn zeroize(&mut self) {
for c in self.coefficients.iter_mut() {
*c = <<C::Group as Group>::Field>::zero();
*c = SerializableScalar(<<C::Group as Group>::Field>::zero());
}
}
}
Expand All @@ -178,6 +217,8 @@ pub mod round2 {
#[cfg(feature = "serialization")]
use alloc::vec::Vec;

use crate::serialization::SerializableScalar;

use super::*;

/// A package that must be sent by each participant to some other participants
Expand Down Expand Up @@ -235,19 +276,67 @@ pub mod round2 {
///
/// This package MUST NOT be sent to other participants!
#[derive(Clone, PartialEq, Eq, Getters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SecretPackage<C: Ciphersuite> {
/// The identifier of the participant holding the secret.
pub(crate) identifier: Identifier<C>,
/// The public commitment from the participant (C_i)
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
/// The participant's own secret share (f_i(i)).
pub(crate) secret_share: Scalar<C>,
#[getter(skip)]
pub(crate) secret_share: SerializableScalar<C>,
/// The minimum number of signers.
pub(crate) min_signers: u16,
/// The total number of signers.
pub(crate) max_signers: u16,
}

impl<C> SecretPackage<C>
where
C: Ciphersuite,
{
/// Create a new SecretPackage. Use this only if custom serialization is
/// required; run the DKG to create a valid SecretPackage.
pub fn new(
identifier: Identifier<C>,
commitment: VerifiableSecretSharingCommitment<C>,
secret_share: Scalar<C>,
min_signers: u16,
max_signers: u16,
) -> Self {
Self {
identifier,
commitment,
secret_share: SerializableScalar(secret_share),
min_signers,
max_signers,
}
}

/// Return the SecretShare.
pub fn secret_share(&self) -> Scalar<C> {
self.secret_share.0
}
}

#[cfg(feature = "serialization")]
impl<C> SecretPackage<C>
where
C: Ciphersuite,
{
/// Serialize the struct into a Vec.
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}

/// Deserialize the struct from a slice of bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}

impl<C> core::fmt::Debug for SecretPackage<C>
where
C: Ciphersuite,
Expand All @@ -268,7 +357,7 @@ pub mod round2 {
C: Ciphersuite,
{
fn zeroize(&mut self) {
self.secret_share = <<C::Group as Group>::Field>::zero();
self.secret_share = SerializableScalar(<<C::Group as Group>::Field>::zero());
}
}
}
Expand Down Expand Up @@ -304,13 +393,13 @@ pub fn part1<C: Ciphersuite, R: RngCore + CryptoRng>(
let proof_of_knowledge =
compute_proof_of_knowledge(identifier, &coefficients, &commitment, &mut rng)?;

let secret_package = round1::SecretPackage {
let secret_package = round1::SecretPackage::new(
identifier,
coefficients,
commitment: commitment.clone(),
commitment.clone(),
min_signers,
max_signers,
};
);
let package = round1::Package {
header: Header::default(),
commitment,
Expand Down Expand Up @@ -439,7 +528,7 @@ pub fn part2<C: Ciphersuite>(
// > Each P_i securely sends to each other participant P_ℓ a secret share (ℓ, f_i(ℓ)),
// > deleting f_i and each share afterward except for (i, f_i(i)),
// > which they keep for themselves.
let signing_share = SigningShare::from_coefficients(&secret_package.coefficients, ell);
let signing_share = SigningShare::from_coefficients(&secret_package.coefficients(), ell);

round2_packages.insert(
ell,
Expand All @@ -449,15 +538,15 @@ pub fn part2<C: Ciphersuite>(
},
);
}
let fii = evaluate_polynomial(secret_package.identifier, &secret_package.coefficients);
let fii = evaluate_polynomial(secret_package.identifier, &secret_package.coefficients());
Ok((
round2::SecretPackage {
identifier: secret_package.identifier,
commitment: secret_package.commitment,
secret_share: fii,
min_signers: secret_package.min_signers,
max_signers: secret_package.max_signers,
},
round2::SecretPackage::new(
secret_package.identifier,
secret_package.commitment,
fii,
secret_package.min_signers,
secret_package.max_signers,
),
round2_packages,
))
}
Expand Down Expand Up @@ -542,7 +631,7 @@ pub fn part3<C: Ciphersuite>(
signing_share = signing_share + f_ell_i.to_scalar();
}

signing_share = signing_share + round2_secret_package.secret_share;
signing_share = signing_share + round2_secret_package.secret_share();
let signing_share = SigningShare::new(signing_share);

// Round 2, Step 4
Expand Down
28 changes: 14 additions & 14 deletions frost-core/src/keys/refresh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,13 @@ pub fn refresh_dkg_part_1<C: Ciphersuite, R: RngCore + CryptoRng>(
let proof_of_knowledge =
compute_proof_of_knowledge(identifier, &coefficients, &commitment, &mut rng)?;

let secret_package = round1::SecretPackage {
let secret_package = round1::SecretPackage::new(
identifier,
coefficients: coefficients.clone(),
commitment: commitment.clone(),
coefficients.clone(),
commitment.clone(),
min_signers,
max_signers,
};
);
let package = round1::Package {
header: Header::default(),
commitment,
Expand Down Expand Up @@ -217,7 +217,7 @@ pub fn refresh_dkg_part2<C: Ciphersuite>(
// > Each P_i securely sends to each other participant P_ℓ a secret share (ℓ, f_i(ℓ)),
// > deleting f_i and each share afterward except for (i, f_i(i)),
// > which they keep for themselves.
let signing_share = SigningShare::from_coefficients(&secret_package.coefficients, ell);
let signing_share = SigningShare::from_coefficients(&secret_package.coefficients(), ell);

round2_packages.insert(
ell,
Expand All @@ -227,16 +227,16 @@ pub fn refresh_dkg_part2<C: Ciphersuite>(
},
);
}
let fii = evaluate_polynomial(secret_package.identifier, &secret_package.coefficients);
let fii = evaluate_polynomial(secret_package.identifier, &secret_package.coefficients());

Ok((
round2::SecretPackage {
identifier: secret_package.identifier,
commitment: secret_package.commitment,
secret_share: fii,
min_signers: secret_package.min_signers,
max_signers: secret_package.max_signers,
},
round2::SecretPackage::new(
secret_package.identifier,
secret_package.commitment,
fii,
secret_package.min_signers,
secret_package.max_signers,
),
round2_packages,
))
}
Expand Down Expand Up @@ -323,7 +323,7 @@ pub fn refresh_dkg_shares<C: Ciphersuite>(
signing_share = signing_share + f_ell_i.to_scalar();
}

signing_share = signing_share + round2_secret_package.secret_share;
signing_share = signing_share + round2_secret_package.secret_share();

// Build new signing share
let old_signing_share = old_key_package.signing_share.to_scalar();
Expand Down
8 changes: 4 additions & 4 deletions frost-core/src/tests/vectors_dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,13 @@ pub fn check_dkg_keygen<C: Ciphersuite>(json_vectors: &Value) {
)
.unwrap();

let round1_secret_package = SecretPackage {
identifier: participant_id,
let round1_secret_package = SecretPackage::new(
participant_id,
coefficients,
commitment: commitment.clone(),
commitment.clone(),
min_signers,
max_signers,
};
);

let (round2_secret_package, _round2_packages_1) =
part2(round1_secret_package, &round1_packages).unwrap();
Expand Down
39 changes: 39 additions & 0 deletions frost-ed25519/tests/helpers/samples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ pub fn public_key_package() -> PublicKeyPackage {
PublicKeyPackage::new(verifying_shares, verifying_key)
}

/// Generate a sample round1::SecretPackage.
pub fn round1_secret_package() -> round1::SecretPackage {
let identifier = 42u16.try_into().unwrap();
let coefficients = vec![scalar1(), scalar1()];
let min_signers = 2;
let max_signers = 3;

let serialized_element = <C as Ciphersuite>::Group::serialize(&element1()).unwrap();
let commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();

round1::SecretPackage::new(
identifier,
coefficients,
commitment,
min_signers,
max_signers,
)
}

/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let serialized_signature = Signature::new(element1(), scalar1()).serialize().unwrap();
Expand All @@ -119,6 +139,25 @@ pub fn round1_package() -> round1::Package {
round1::Package::new(vss_commitment, signature)
}

/// Generate a sample round1::SecretPackage.
pub fn round2_secret_package() -> round2::SecretPackage {
let identifier = 42u16.try_into().unwrap();
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1()).unwrap();
let commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let secret_share = scalar1();
let min_signers = 2;
let max_signers = 3;

round2::SecretPackage::new(
identifier,
commitment,
secret_share,
min_signers,
max_signers,
)
}

/// Generate a sample round2::Package.
pub fn round2_package() -> round2::Package {
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
Expand Down
Loading

0 comments on commit 80d53f2

Please sign in to comment.