Skip to content

Commit

Permalink
removed identifier from SignatureShare
Browse files Browse the repository at this point in the history
  • Loading branch information
conradoplg committed Jun 29, 2023
1 parent ba187f2 commit 2d939ed
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 68 deletions.
6 changes: 3 additions & 3 deletions frost-core/src/benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,21 +162,21 @@ pub fn bench_sign<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(
},
);

let mut signature_shares = Vec::new();
let mut signature_shares = HashMap::new();
for participant_identifier in nonces.keys() {
let key_package = key_packages.get(participant_identifier).unwrap();
let nonces_to_use = &nonces.get(participant_identifier).unwrap();
let signature_share =
frost::round2::sign(&signing_package, nonces_to_use, key_package).unwrap();
signature_shares.push(signature_share);
signature_shares.insert(*key_package.identifier(), signature_share);
}

group.bench_with_input(
BenchmarkId::new("Aggregate", min_signers),
&(signing_package.clone(), signature_shares.clone(), pubkeys),
|b, (signing_package, signature_shares, pubkeys)| {
b.iter(|| {
frost::aggregate(signing_package, &signature_shares[..], pubkeys).unwrap();
frost::aggregate(signing_package, &signature_shares, pubkeys).unwrap();
})
},
);
Expand Down
30 changes: 21 additions & 9 deletions frost-core/src/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! Sharing, where shares are generated using Shamir Secret Sharing.

use std::{
collections::BTreeMap,
collections::{BTreeMap, HashMap},
fmt::{self, Debug},
ops::Index,
};
Expand Down Expand Up @@ -354,6 +354,12 @@ where
/// Aggregates the signature shares to produce a final signature that
/// can be verified with the group public key.
///
/// `signature_shares` maps the identifier of each participant to the
/// [`round2::SignatureShare`] 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::SignatureShare`] came from
/// the participant with that identifier.
///
/// This operation is performed by a coordinator that can communicate with all
/// the signing participants before publishing the final signature. The
/// coordinator can be one of the participants or a semi-trusted third party
Expand All @@ -365,7 +371,7 @@ where
/// service attack due to publishing an invalid signature.
pub fn aggregate<C>(
signing_package: &SigningPackage<C>,
signature_shares: &[round2::SignatureShare<C>],
signature_shares: &HashMap<Identifier<C>, round2::SignatureShare<C>>,
pubkeys: &keys::PublicKeyPackage<C>,
) -> Result<Signature<C>, Error<C>>
where
Expand All @@ -387,7 +393,7 @@ where
// [`aggregate`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-5.3
let mut z = <<C::Group as Group>::Field>::zero();

for signature_share in signature_shares {
for signature_share in signature_shares.values() {
z = z + signature_share.signature.z_share;
}

Expand All @@ -413,27 +419,33 @@ where
);

// Verify the signature shares.
for signature_share in signature_shares {
for (signature_share_identifier, signature_share) in signature_shares {
// Look up the public key for this signer, where `signer_pubkey` = _G.ScalarBaseMult(s[i])_,
// and where s[i] is a secret share of the constant term of _f_, the secret polynomial.
let signer_pubkey = pubkeys
.signer_pubkeys
.get(&signature_share.identifier)
.get(&signature_share_identifier)
.unwrap();

// Compute Lagrange coefficient.
let lambda_i =
derive_interpolating_value(&signature_share.identifier, signing_package)?;
derive_interpolating_value(&signature_share_identifier, signing_package)?;

let binding_factor = binding_factor_list[signature_share.identifier].clone();
let binding_factor = binding_factor_list[*signature_share_identifier].clone();

// Compute the commitment share.
let R_share = signing_package
.signing_commitment(&signature_share.identifier)
.signing_commitment(&signature_share_identifier)
.to_group_commitment_share(&binding_factor);

// Compute relation values to verify this signature share.
signature_share.verify(&R_share, signer_pubkey, lambda_i, &challenge)?;
signature_share.verify(
*signature_share_identifier,
&R_share,
signer_pubkey,
lambda_i,
&challenge,
)?;
}

// We should never reach here; but we return the verification error to be safe.
Expand Down
14 changes: 4 additions & 10 deletions frost-core/src/frost/round2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ where
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SignatureShare<C: Ciphersuite> {
/// Represents the participant identifier.
pub(crate) identifier: Identifier<C>,
/// This participant's signature over the message.
pub(crate) signature: SignatureResponse<C>,
/// Ciphersuite ID for serialization
Expand All @@ -112,9 +110,8 @@ where
C: Ciphersuite,
{
/// Create a new [`SignatureShare`].
pub fn new(identifier: Identifier<C>, signature: SignatureResponse<C>) -> Self {
pub fn new(signature: SignatureResponse<C>) -> Self {
Self {
identifier,
signature,
ciphersuite: (),
}
Expand All @@ -126,8 +123,9 @@ where
/// This is the final step of [`verify_signature_share`] from the spec.
///
/// [`verify_signature_share`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-signature-share-verificatio
pub fn verify(
pub(crate) fn verify(
&self,
identifier: Identifier<C>,
group_commitment_share: &round1::GroupCommitmentShare<C>,
public_key: &frost::keys::VerifyingShare<C>,
lambda_i: Scalar<C>,
Expand All @@ -136,9 +134,7 @@ where
if (<C::Group>::generator() * self.signature.z_share)
!= (group_commitment_share.0 + (public_key.0 * challenge.0 * lambda_i))
{
return Err(Error::InvalidSignatureShare {
signer: self.identifier,
});
return Err(Error::InvalidSignatureShare { signer: identifier });
}

Ok(())
Expand All @@ -151,7 +147,6 @@ where
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SignatureShare")
.field("identifier", &self.identifier)
.field("signature", &self.signature)
.finish()
}
Expand All @@ -171,7 +166,6 @@ fn compute_signature_share<C: Ciphersuite>(
+ (lambda_i * key_package.secret_share.0 * challenge.0);

SignatureShare::<C> {
identifier: *key_package.identifier(),
signature: SignatureResponse::<C> { z_share },
ciphersuite: (),
}
Expand Down
6 changes: 3 additions & 3 deletions frost-core/src/tests/ciphersuite_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
// This is what the signature aggregator / coordinator needs to do:
// - decide what message to sign
// - take one (unused) commitment per signing participant
let mut signature_shares = Vec::new();
let mut signature_shares = HashMap::new();
let message = "message to sign".as_bytes();
let signing_package = frost::SigningPackage::new(commitments_map, message);

Expand All @@ -129,7 +129,7 @@ fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
// Each participant generates their signature share.
let signature_share =
frost::round2::sign(&signing_package, nonces_to_use, key_package).unwrap();
signature_shares.push(signature_share);
signature_shares.insert(*participant_identifier, signature_share);
}

////////////////////////////////////////////////////////////////////////////
Expand All @@ -139,7 +139,7 @@ fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(

// Aggregate (also verifies the signature shares)
let group_signature =
frost::aggregate(&signing_package, &signature_shares[..], &pubkey_package).unwrap();
frost::aggregate(&signing_package, &signature_shares, &pubkey_package).unwrap();

// Check that the threshold signature can be verified by the group public
// key (the verification key).
Expand Down
27 changes: 8 additions & 19 deletions frost-core/src/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,9 @@ pub fn parse_test_vectors<C: Ciphersuite>(json_vectors: &Value) -> TestVectors<C
)
.debugless_unwrap();

let signature_share = SignatureShare::<C>::new(
u16::from_str(i).unwrap().try_into().unwrap(),
SignatureResponse {
z_share: <<C::Group as Group>::Field>::deserialize(&sig_share).unwrap(),
},
);
let signature_share = SignatureShare::<C>::new(SignatureResponse {
z_share: <<C::Group as Group>::Field>::deserialize(&sig_share).unwrap(),
});

signature_shares.insert(
u16::from_str(i).unwrap().try_into().unwrap(),
Expand Down Expand Up @@ -285,7 +282,7 @@ pub fn check_sign_with_test_vectors<C: Ciphersuite>(json_vectors: &Value) {
assert_eq!(*binding_factor, binding_factors[identifier]);
}

let mut our_signature_shares: Vec<frost::round2::SignatureShare<C>> = Vec::new();
let mut our_signature_shares = HashMap::new();

// Each participant generates their signature share
for identifier in signer_nonces.keys() {
Expand All @@ -295,12 +292,10 @@ pub fn check_sign_with_test_vectors<C: Ciphersuite>(json_vectors: &Value) {
// Each participant generates their signature share.
let signature_share = frost::round2::sign(&signing_package, nonces, key_package).unwrap();

our_signature_shares.push(signature_share);
our_signature_shares.insert(*identifier, signature_share);
}

for sig_share in our_signature_shares.clone() {
assert_eq!(sig_share, signature_shares[sig_share.identifier()]);
}
assert_eq!(our_signature_shares, signature_shares);

let signer_pubkeys = key_packages
.into_iter()
Expand All @@ -315,14 +310,8 @@ pub fn check_sign_with_test_vectors<C: Ciphersuite>(json_vectors: &Value) {
////////////////////////////////////////////////////////////////////////////

// Aggregate the FROST signature from test vector sig shares
let group_signature_result = frost::aggregate(
&signing_package,
&signature_shares
.values()
.cloned()
.collect::<Vec<frost::round2::SignatureShare<C>>>(),
&pubkey_package,
);
let group_signature_result =
frost::aggregate(&signing_package, &signature_shares, &pubkey_package);

// Check that the aggregation passed signature share verification and generation
assert!(group_signature_result.is_ok());
Expand Down
6 changes: 3 additions & 3 deletions frost-ristretto255/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ for participant_index in 1..(min_signers as u16 + 1) {
// This is what the signature aggregator / coordinator needs to do:
// - decide what message to sign
// - take one (unused) commitment per signing participant
let mut signature_shares = Vec::new();
let mut signature_shares = HashMap::new();
# // ANCHOR: round2_package
let message = "message to sign".as_bytes();
# // In practice, the SigningPackage must be sent to all participants
Expand All @@ -88,7 +88,7 @@ for participant_identifier in nonces_map.keys() {

// In practice, the signature share must be sent to the Coordinator
// using an authenticated channel.
signature_shares.push(signature_share);
signature_shares.insert(*participant_identifier, signature_share);
}

////////////////////////////////////////////////////////////////////////////
Expand All @@ -98,7 +98,7 @@ for participant_identifier in nonces_map.keys() {

// Aggregate (also verifies the signature shares)
# // ANCHOR: aggregate
let group_signature = frost::aggregate(&signing_package, &signature_shares[..], &pubkey_package)?;
let group_signature = frost::aggregate(&signing_package, &signature_shares, &pubkey_package)?;
# // ANCHOR_END: aggregate


Expand Down
9 changes: 4 additions & 5 deletions frost-ristretto255/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]

use std::collections::HashMap;

use curve25519_dalek::{
constants::RISTRETTO_BASEPOINT_POINT,
ristretto::{CompressedRistretto, RistrettoPoint},
Expand Down Expand Up @@ -316,10 +318,7 @@ pub mod round1 {
///
/// Generates the signing nonces and commitments to be used in the signing
/// operation.
pub fn commit<RNG>(
secret: &SigningShare,
rng: &mut RNG,
) -> (SigningNonces, SigningCommitments)
pub fn commit<RNG>(secret: &SigningShare, rng: &mut RNG) -> (SigningNonces, SigningCommitments)
where
RNG: CryptoRng + RngCore,
{
Expand Down Expand Up @@ -379,7 +378,7 @@ pub type Signature = frost_core::Signature<R>;
/// service attack due to publishing an invalid signature.
pub fn aggregate(
signing_package: &SigningPackage,
signature_shares: &[round2::SignatureShare],
signature_shares: &HashMap<Identifier, round2::SignatureShare>,
pubkeys: &keys::PublicKeyPackage,
) -> Result<Signature, Error> {
frost::aggregate(signing_package, signature_shares, pubkeys)
Expand Down
3 changes: 1 addition & 2 deletions frost-ristretto255/tests/helpers/samples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,10 @@ pub fn signing_package() -> SigningPackage {

/// Generate a sample SignatureShare.
pub fn signature_share() -> SignatureShare {
let identifier = 42u16.try_into().unwrap();
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let signature_response = SignatureResponse::from_bytes(serialized_scalar).unwrap();

SignatureShare::new(identifier, signature_response)
SignatureShare::new(signature_response)
}

/// Generate a sample SecretShare.
Expand Down
3 changes: 1 addition & 2 deletions frost-ristretto255/tests/recreation_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ fn check_signing_package_recreation() {
fn check_signature_share_recreation() {
let signature_share = samples::signature_share();

let identifier = signature_share.identifier();
let signature_response = signature_share.signature();

let new_signature_share = SignatureShare::new(*identifier, *signature_response);
let new_signature_share = SignatureShare::new(*signature_response);
assert!(signature_share == new_signature_share);
}

Expand Down
12 changes: 0 additions & 12 deletions frost-ristretto255/tests/serde_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ fn check_signature_share_serialization() {
assert!(signature_share == decoded_signature_share);

let json = r#"{
"identifier": "2a00000000000000000000000000000000000000000000000000000000000000",
"signature": "498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a",
"ciphersuite": "FROST(ristretto255, SHA-512)"
}"#;
Expand All @@ -179,32 +178,21 @@ fn check_signature_share_serialization() {
let invalid_json = "{}";
assert!(serde_json::from_str::<SignatureShare>(invalid_json).is_err());

// Invalid identifier
let invalid_json = r#"{
"identifier": "0000000000000000000000000000000000000000000000000000000000000000",
"signature": "498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a",
"ciphersuite": "FROST(ristretto255, SHA-512)"
}"#;
assert!(serde_json::from_str::<SignatureShare>(invalid_json).is_err());

// Invalid field
let invalid_json = r#"{
"identifier": "2a00000000000000000000000000000000000000000000000000000000000000",
"foo": "498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a",
"ciphersuite": "FROST(ristretto255, SHA-512)"
}"#;
assert!(serde_json::from_str::<SignatureShare>(invalid_json).is_err());

// Missing field
let invalid_json = r#"{
"identifier": "2a00000000000000000000000000000000000000000000000000000000000000",,
"ciphersuite": "FROST(ristretto255, SHA-512)"
}"#;
assert!(serde_json::from_str::<SignatureShare>(invalid_json).is_err());

// Extra field
let invalid_json = r#"{
"identifier": "2a00000000000000000000000000000000000000000000000000000000000000",
"signature": "498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a",
"extra": 1,
"ciphersuite": "FROST(ristretto255, SHA-512)"
Expand Down

0 comments on commit 2d939ed

Please sign in to comment.