frost-rerandomized: add aggregate optimization (#214)
* frost-rerandomized: add aggregate optimization * Update frost-rerandomized/src/lib.rs Co-authored-by: Marek <mail@marek.onl> * Updated docs around aggregate() * rustfmt --------- Co-authored-by: Marek <mail@marek.onl> Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
This commit is contained in:
parent
984f421d47
commit
09f3f36aab
|
@ -68,12 +68,16 @@ pub fn sign<C: Ciphersuite>(
|
|||
Ok(signature_share)
|
||||
}
|
||||
|
||||
/// Verifies each participant's signature share, and if all are valid,
|
||||
/// aggregates the shares into a signature to publish.
|
||||
/// Aggregates the shares into a verified signature to publish.
|
||||
///
|
||||
/// Resulting signature is compatible with verification of a plain SpendAuth
|
||||
/// signature.
|
||||
///
|
||||
/// If the aggegated signature does not verify, each participant's signature share
|
||||
/// is validated, to find the cheater(s). This approach is more efficient and secure
|
||||
/// as we don't need to verify all shares if the aggregate signature is verifiable
|
||||
/// under the public group key and message (which should be the common case).
|
||||
///
|
||||
/// 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
|
||||
|
@ -92,7 +96,7 @@ pub fn aggregate<C>(
|
|||
where
|
||||
C: Ciphersuite,
|
||||
{
|
||||
let public_key = pubkeys.group_public.to_element() + *randomized_params.randomizer_point();
|
||||
let public_key = randomized_params.randomized_group_public_key();
|
||||
|
||||
// Encodes the signing commitment list produced in round one as part of generating [`Rho`], the
|
||||
// binding factor.
|
||||
|
@ -107,49 +111,62 @@ where
|
|||
// Compute the per-message challenge.
|
||||
let challenge = frost_core::challenge::<C>(
|
||||
&group_commitment.clone().to_element(),
|
||||
&public_key,
|
||||
&public_key.to_element(),
|
||||
signing_package.message().as_slice(),
|
||||
);
|
||||
|
||||
// Verify the signature shares.
|
||||
for 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)
|
||||
.unwrap();
|
||||
|
||||
// Compute Lagrange coefficient.
|
||||
let lambda_i =
|
||||
frost::derive_interpolating_value(&signature_share.identifier, signing_package)?;
|
||||
|
||||
let rho = binding_factor_list[signature_share.identifier].clone();
|
||||
|
||||
// Compute the commitment share.
|
||||
let R_share = signing_package
|
||||
.signing_commitment(&signature_share.identifier)
|
||||
.to_group_commitment_share(&rho);
|
||||
|
||||
// Compute relation values to verify this signature share.
|
||||
signature_share.verify(&R_share, signer_pubkey, lambda_i, &challenge)?;
|
||||
}
|
||||
|
||||
// The aggregation of the signature shares by summing them up, resulting in
|
||||
// a plain Schnorr signature.
|
||||
//
|
||||
// Implements [`aggregate`] from the spec.
|
||||
//
|
||||
// [`aggregate`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#section-5.3
|
||||
// [`aggregate`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html#section-5.3
|
||||
let mut z = <<C::Group as Group>::Field as Field>::zero();
|
||||
|
||||
for signature_share in signature_shares {
|
||||
z = z + signature_share.signature.z_share;
|
||||
}
|
||||
|
||||
z = z + challenge.to_scalar() * randomized_params.randomizer;
|
||||
z = z + challenge.clone().to_scalar() * randomized_params.randomizer;
|
||||
|
||||
Ok(frost_core::Signature::new(group_commitment.to_element(), z))
|
||||
let signature = frost_core::Signature::new(group_commitment.to_element(), z);
|
||||
|
||||
// Verify the aggregate signature
|
||||
let verification_result = public_key.verify(signing_package.message(), &signature);
|
||||
|
||||
// Only if the verification of the aggregate signature failed; verify each share to find the cheater.
|
||||
// This approach is more efficient since we don't need to verify all shares
|
||||
// if the aggregate signature is valid (which should be the common case).
|
||||
if let Err(err) = verification_result {
|
||||
// Verify the signature shares.
|
||||
for 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)
|
||||
.unwrap();
|
||||
|
||||
// Compute Lagrange coefficient.
|
||||
let lambda_i =
|
||||
frost::derive_interpolating_value(&signature_share.identifier, signing_package)?;
|
||||
|
||||
let binding_factor = binding_factor_list[signature_share.identifier].clone();
|
||||
|
||||
// Compute the commitment share.
|
||||
let R_share = signing_package
|
||||
.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)?;
|
||||
}
|
||||
|
||||
// We should never reach here; but we return the verification error to be safe.
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
/// Randomized params for a signing instance of randomized FROST.
|
||||
|
|
Loading…
Reference in New Issue