Simplify rerandomized FROST (#437)

* refactor Lagrange coefficient computation

* simplified rerandomized FROST

* switch to a Randomize trait, remove unaccurate comment

* remove manual rerandomization test

* improve comments

* removed unneeded alpha_share

* Apply suggestions from code review

Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>

* frost-rerandomized: add serde feature

* add Randomizer type

* revert DuplicatedIdentifiers back to DuplicatedIdentifier

---------

Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
This commit is contained in:
Conrado Gouvea 2023-08-14 13:15:22 -03:00 committed by GitHub
parent 4bf92b7a2c
commit ba8086db5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 316 additions and 221 deletions

View File

@ -24,8 +24,8 @@ pub enum Error<C: Ciphersuite> {
#[error("Malformed identifier is unserializable.")]
MalformedIdentifier,
/// This identifier is duplicated.
#[error("Duplicated identifiers.")]
DuplicatedIdentifiers,
#[error("Duplicated identifier.")]
DuplicatedIdentifier,
/// This identifier does not belong to a participant in the signing process.
#[error("Unknown identifier.")]
UnknownIdentifier,
@ -140,7 +140,7 @@ where
| Error::DKGNotSupported
| Error::FieldError(_)
| Error::GroupError(_)
| Error::DuplicatedIdentifiers
| Error::DuplicatedIdentifier
| Error::InvalidCoefficient
| Error::UnknownIdentifier
| Error::IncorrectNumberOfIdentifiers

View File

@ -192,8 +192,10 @@ fn compute_lagrange_coefficient<C: Ciphersuite>(
return Err(Error::UnknownIdentifier);
}
Ok(num
* <<C::Group as Group>::Field>::invert(&den).map_err(|_| Error::DuplicatedIdentifiers)?)
Ok(
num * <<C::Group as Group>::Field>::invert(&den)
.map_err(|_| Error::DuplicatedIdentifier)?,
)
}
/// Generates the lagrange coefficient for the i'th participant (for `signer_id`).

View File

@ -56,6 +56,18 @@ impl<C> SigningShare<C>
where
C: Ciphersuite,
{
/// Create a new [`SigningShare`] from a scalar.
#[cfg(feature = "internals")]
pub fn new(scalar: Scalar<C>) -> Self {
Self(scalar)
}
/// Get the inner scalar.
#[cfg(feature = "internals")]
pub fn to_scalar(&self) -> Scalar<C> {
self.0
}
/// Deserialize from bytes
pub fn deserialize(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
@ -143,6 +155,18 @@ impl<C> VerifyingShare<C>
where
C: Ciphersuite,
{
/// Create a new [`VerifyingShare`] from a element.
#[cfg(feature = "internals")]
pub fn new(element: Element<C>) -> Self {
Self(element)
}
/// Get the inner element.
#[cfg(feature = "internals")]
pub fn to_element(&self) -> Element<C> {
self.0
}
/// Deserialize from bytes
pub fn deserialize(bytes: <C::Group as Group>::Serialization) -> Result<Self, Error<C>> {
<C::Group as Group>::deserialize(&bytes)
@ -718,7 +742,7 @@ pub(crate) fn generate_secret_shares<C: Ciphersuite>(
let identifiers_set: HashSet<_> = identifiers.iter().collect();
if identifiers_set.len() != identifiers.len() {
return Err(Error::DuplicatedIdentifiers);
return Err(Error::DuplicatedIdentifier);
}
for id in identifiers {
@ -763,7 +787,7 @@ pub fn reconstruct<C: Ciphersuite>(
.collect();
if identifiers.len() != secret_shares.len() {
return Err(Error::DuplicatedIdentifiers);
return Err(Error::DuplicatedIdentifier);
}
// Compute the Lagrange coefficients

View File

@ -31,7 +31,7 @@ pub fn repair_share_step_1<C: Ciphersuite, R: RngCore + CryptoRng>(
}
let xset: BTreeSet<_> = helpers.iter().cloned().collect();
if xset.len() != helpers.len() {
return Err(Error::DuplicatedIdentifiers);
return Err(Error::DuplicatedIdentifier);
}
let rand_val: Vec<Scalar<C>> = generate_coefficients::<C, R>(helpers.len() - 1, rng);

View File

@ -96,8 +96,10 @@ pub trait Field: Copy + Clone {
pub type Scalar<C> = <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar;
#[cfg(feature = "serde")]
#[cfg_attr(feature = "internals", visibility::make(pub))]
/// Helper struct to serialize a Scalar.
pub(crate) struct ScalarSerialization<C: Ciphersuite>(
<<<C as Ciphersuite>::Group as Group>::Field as Field>::Serialization,
pub <<<C as Ciphersuite>::Group as Group>::Field as Field>::Serialization,
);
#[cfg(feature = "serde")]

View File

@ -51,6 +51,20 @@ where
Signature { R, z }
}
/// Creates a SigningKey from a scalar.
#[cfg(feature = "internals")]
pub fn from_scalar(
scalar: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
) -> Self {
Self { scalar }
}
/// Return the underlying scalar.
#[cfg(feature = "internals")]
pub fn to_scalar(self) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
self.scalar
}
}
impl<C> std::fmt::Debug for SigningKey<C>

View File

@ -55,7 +55,7 @@ pub fn check_share_generation<C: Ciphersuite, R: RngCore + CryptoRng>(mut rng: R
assert_eq!(
frost::keys::reconstruct::<C>(&secret_shares).unwrap_err(),
Error::DuplicatedIdentifiers
Error::DuplicatedIdentifier
);
}
@ -89,7 +89,8 @@ pub fn check_sign_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
check_sign(min_signers, key_packages, rng, pubkeys)
}
fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
/// Test FROST signing with the given shares.
pub fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
min_signers: u16,
key_packages: HashMap<frost::Identifier<C>, frost::keys::KeyPackage<C>>,
mut rng: R,
@ -372,7 +373,7 @@ pub fn check_sign_with_dealer_and_identifiers<C: Ciphersuite, R: RngCore + Crypt
&mut rng,
)
.unwrap_err();
assert_eq!(err, Error::DuplicatedIdentifiers);
assert_eq!(err, Error::DuplicatedIdentifier);
// Check correct case

View File

@ -29,6 +29,7 @@ sha2 = "0.10.2"
[dev-dependencies]
criterion = "0.5"
frost-rerandomized = { path = "../frost-rerandomized", version = "0.6.0", features = ["test-impl"] }
ed25519-dalek = "1.0.1"
hex = "0.4.3"
lazy_static = "1.4"

View File

@ -0,0 +1,10 @@
use frost_ed25519::Ed25519Sha512;
use rand::thread_rng;
#[test]
fn check_randomized_sign_with_dealer() {
let rng = thread_rng();
let (_msg, _group_signature, _group_pubkey) =
frost_rerandomized::tests::check_randomized_sign_with_dealer::<Ed25519Sha512, _>(rng);
}

View File

@ -28,6 +28,7 @@ sha3 = "0.10.6"
[dev-dependencies]
criterion = "0.5"
frost-rerandomized = { path = "../frost-rerandomized", version = "0.6.0", features = ["test-impl"] }
lazy_static = "1.4"
hex = "0.4.3"
proptest = "1.0"

View File

@ -0,0 +1,10 @@
use frost_ed448::Ed448Shake256;
use rand::thread_rng;
#[test]
fn check_randomized_sign_with_dealer() {
let rng = thread_rng();
let (_msg, _group_signature, _group_pubkey) =
frost_rerandomized::tests::check_randomized_sign_with_dealer::<Ed448Shake256, _>(rng);
}

View File

@ -29,6 +29,7 @@ sha2 = "0.10.2"
[dev-dependencies]
criterion = "0.5"
frost-rerandomized = { path = "../frost-rerandomized", version = "0.6.0", features = ["test-impl"] }
hex = "0.4.3"
lazy_static = "1.4"
proptest = "1.0"

View File

@ -0,0 +1,10 @@
use frost_p256::P256Sha256;
use rand::thread_rng;
#[test]
fn check_randomized_sign_with_dealer() {
let rng = thread_rng();
let (_msg, _group_signature, _group_pubkey) =
frost_rerandomized::tests::check_randomized_sign_with_dealer::<P256Sha256, _>(rng);
}

View File

@ -19,6 +19,7 @@ description = "Types and traits to support implementing a re-randomized variant
features = ["nightly"]
[dependencies]
derive-getters = "0.3.0"
frost-core = { path = "../frost-core", version = "0.6.0", features = ["internals"] }
rand_core = "0.6"

View File

@ -1,5 +1,14 @@
//! Randomized FROST support.
//! FROST implementation supporting re-randomizable keys.
//!
//! To sign with re-randomized FROST:
//!
//! - Do Round 1 the same way as regular FROST;
//! - The Coordinator should generate a [`RandomizedParams`] and send
//! the [`RandomizedParams::randomizer`] to all participants, using a
//! confidential channel, along with the regular [`SigningPackage`];
//! - Each participant should call [`sign`] and send the resulting
//! [`SignatureShare`] back to the Coordinator;
//! - The Coordinator should then call [`aggregate`].
#![allow(non_snake_case)]
#[cfg(any(test, feature = "test-impl"))]
@ -7,91 +16,119 @@ pub mod tests;
use std::collections::HashMap;
use derive_getters::Getters;
pub use frost_core;
use frost_core::{
frost::{self, keys::PublicKeyPackage},
frost::{
self,
keys::{KeyPackage, PublicKeyPackage, SigningShare, VerifyingShare},
},
Ciphersuite, Error, Field, Group, Scalar, VerifyingKey,
};
#[cfg(feature = "serde")]
use frost_core::serde;
#[cfg(feature = "serde")]
use frost_core::ScalarSerialization;
// When pulled into `reddsa`, that has its own sibling `rand_core` import.
// For the time being, we do not re-export this `rand_core`.
use rand_core::{CryptoRng, RngCore};
/// Performed once by each participant selected for the signing operation.
/// Randomize the given key type for usage in a FROST signing with re-randomized keys,
/// using the given [`RandomizedParams`].
trait Randomize<C> {
fn randomize(&self, params: &RandomizedParams<C>) -> Result<Self, Error<C>>
where
Self: Sized,
C: Ciphersuite;
}
impl<C: Ciphersuite> Randomize<C> for KeyPackage<C> {
/// Randomize the given [`KeyPackage`] for usage in a re-randomized FROST signing,
/// using the given [`RandomizedParams`].
///
/// It's recommended to use [`sign`] directly which already handles
/// the key package randomization.
///
/// You MUST NOT reuse the randomized key package for more than one signing.
fn randomize(&self, randomized_params: &RandomizedParams<C>) -> Result<Self, Error<C>>
where
Self: Sized,
C: Ciphersuite,
{
let verifying_share = self.public();
let randomized_verifying_share = VerifyingShare::<C>::new(
verifying_share.to_element() + randomized_params.randomizer_element,
);
let signing_share = self.secret_share();
let randomized_signing_share =
SigningShare::new(signing_share.to_scalar() + randomized_params.randomizer.0);
let randomized_key_package = KeyPackage::new(
*self.identifier(),
randomized_signing_share,
randomized_verifying_share,
randomized_params.randomized_verifying_key,
);
Ok(randomized_key_package)
}
}
impl<C: Ciphersuite> Randomize<C> for PublicKeyPackage<C> {
/// Randomized the given [`PublicKeyPackage`] for usage in a re-randomized FROST
/// aggregation, using the given [`RandomizedParams`].
///
/// It's recommended to use [`aggregate`] directly which already handles
/// the public key package randomization.
fn randomize(&self, randomized_params: &RandomizedParams<C>) -> Result<Self, Error<C>>
where
Self: Sized,
C: Ciphersuite,
{
let verifying_shares = self.signer_pubkeys().clone();
let randomized_verifying_shares = verifying_shares
.iter()
.map(|(identifier, verifying_share)| {
(
*identifier,
VerifyingShare::<C>::new(
verifying_share.to_element() + randomized_params.randomizer_element,
),
)
})
.collect();
Ok(PublicKeyPackage::new(
randomized_verifying_shares,
randomized_params.randomized_verifying_key,
))
}
}
/// Re-randomized FROST signing using the given `randomizer`, which should
/// be sent from the Coordinator using a confidential channel.
///
/// Implements [`sign`] from the spec.
///
/// Receives the message to be signed and a set of signing commitments and a set
/// of randomizing commitments to be used in that signing operation, including
/// that for this participant.
///
/// Assumes the participant has already determined which nonce corresponds with
/// the commitment that was assigned by the coordinator in the SigningPackage.
///
/// [`sign`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#name-round-two-signature-share-g
/// See [`frost::round2::sign`] for documentation on the other parameters.
pub fn sign<C: Ciphersuite>(
signing_package: &frost::SigningPackage<C>,
signer_nonces: &frost::round1::SigningNonces<C>,
key_package: &frost::keys::KeyPackage<C>,
randomizer_point: &<C::Group as Group>::Element,
randomizer: Randomizer<C>,
) -> Result<frost::round2::SignatureShare<C>, Error<C>> {
let public_key = key_package.group_public().to_element() + *randomizer_point;
// Encodes the signing commitment list produced in round one as part of generating [`Rho`], the
// binding factor.
let binding_factor_list = frost::compute_binding_factor_list(
signing_package,
key_package.group_public(),
<C::Group as Group>::serialize(randomizer_point).as_ref(),
);
let rho: frost::BindingFactor<C> = binding_factor_list[*key_package.identifier()].clone();
// Compute the group commitment from signing commitments produced in round one.
let group_commitment = frost::compute_group_commitment(signing_package, &binding_factor_list)?;
// Compute Lagrange coefficient.
let lambda_i = frost::derive_interpolating_value(key_package.identifier(), signing_package)?;
// Compute the per-message challenge.
let challenge = frost_core::challenge::<C>(
&group_commitment.to_element(),
&public_key,
signing_package.message().as_slice(),
);
// Compute the Schnorr signature share.
let signature_share = frost::round2::compute_signature_share(
signer_nonces,
rho,
lambda_i,
key_package,
challenge,
);
Ok(signature_share)
let randomized_params =
RandomizedParams::from_randomizer(key_package.group_public(), randomizer);
let randomized_key_package = key_package.randomize(&randomized_params)?;
frost::round2::sign(signing_package, signer_nonces, &randomized_key_package)
}
/// Aggregates the shares into a verified signature to publish.
/// Re-randomized FROST signature share aggregation with the given [`RandomizedParams`],
/// which can be computed from the previously generated randomizer using
/// [`RandomizedParams::from_randomizer`].
///
/// 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
/// (who is trusted to not perform denial of service attacks, but does not learn
/// any secret information). Note that because the coordinator is trusted to
/// report misbehaving parties in order to avoid publishing an invalid
/// signature, if the coordinator themselves is a signer and misbehaves, they
/// can avoid that step. However, at worst, this results in a denial of
/// service attack due to publishing an invalid signature.
/// See [`frost::aggregate`] for documentation on the other parameters.
pub fn aggregate<C>(
signing_package: &frost::SigningPackage<C>,
signature_shares: &HashMap<frost::Identifier<C>, frost::round2::SignatureShare<C>>,
@ -101,151 +138,113 @@ pub fn aggregate<C>(
where
C: Ciphersuite,
{
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.
let binding_factor_list = frost::compute_binding_factor_list(
let randomized_public_key_package = pubkeys.randomize(randomized_params)?;
frost::aggregate(
signing_package,
pubkeys.group_public(),
<C::Group as Group>::serialize(randomized_params.randomizer_point()).as_ref(),
);
// Compute the group commitment from signing commitments produced in round one.
let group_commitment = frost::compute_group_commitment(signing_package, &binding_factor_list)?;
// Compute the per-message challenge.
let challenge = frost_core::challenge::<C>(
&group_commitment.clone().to_element(),
&public_key.to_element(),
signing_package.message().as_slice(),
);
// 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-12.html#section-5.3
let mut z = <<C::Group as Group>::Field as Field>::zero();
for signature_share in signature_shares.values() {
z = z + *signature_share.share();
}
z = z + challenge.clone().to_scalar() * randomized_params.randomizer;
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_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)
.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(
*signature_share_identifier,
&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)
signature_shares,
&randomized_public_key_package,
)
}
/// Randomized params for a signing instance of randomized FROST.
/// A randomizer. A random scalar which is used to randomize the key.
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "ScalarSerialization<C>"))]
#[cfg_attr(feature = "serde", serde(into = "ScalarSerialization<C>"))]
#[cfg_attr(feature = "serde", serde(crate = "self::serde"))]
pub struct Randomizer<C: Ciphersuite>(Scalar<C>);
impl<C> Randomizer<C>
where
C: Ciphersuite,
{
/// Create a new random Randomizer.
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> Self {
let randomizer = <<C::Group as Group>::Field as Field>::random(&mut rng);
Self(randomizer)
}
/// Create a new Randomizer from the given scalar. It MUST be randomly generated.
pub fn from_scalar(scalar: Scalar<C>) -> Self {
Self(scalar)
}
/// Serialize the identifier using the ciphersuite encoding.
pub fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field>::serialize(&self.0)
}
/// Deserialize an Identifier from a serialized buffer.
/// Returns an error if it attempts to deserialize zero.
pub fn deserialize(
buf: &<<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error<C>> {
let scalar = <<C::Group as Group>::Field>::deserialize(buf)?;
Ok(Self(scalar))
}
}
#[cfg(feature = "serde")]
impl<C> TryFrom<ScalarSerialization<C>> for Randomizer<C>
where
C: Ciphersuite,
{
type Error = Error<C>;
fn try_from(value: ScalarSerialization<C>) -> Result<Self, Self::Error> {
Self::deserialize(&value.0)
}
}
#[cfg(feature = "serde")]
impl<C> From<Randomizer<C>> for ScalarSerialization<C>
where
C: Ciphersuite,
{
fn from(value: Randomizer<C>) -> Self {
Self(value.serialize())
}
}
/// Randomized parameters for a signing instance of randomized FROST.
#[derive(Clone, PartialEq, Eq, Getters)]
pub struct RandomizedParams<C: Ciphersuite> {
/// The randomizer, also called `alpha`
randomizer: frost_core::Scalar<C>,
/// The randomizer, also called α
randomizer: Randomizer<C>,
/// The generator multiplied by the randomizer.
randomizer_point: <C::Group as Group>::Element,
/// The randomized group public key. The group public key added to the randomizer point.
randomized_group_public_key: frost_core::VerifyingKey<C>,
randomizer_element: <C::Group as Group>::Element,
/// The randomized group public key. The group public key added to the randomizer element.
randomized_verifying_key: frost_core::VerifyingKey<C>,
}
impl<C> RandomizedParams<C>
where
C: Ciphersuite,
{
/// Create a new RandomizedParams for the given [`PublicKeyPackage`]
pub fn new<R: RngCore + CryptoRng>(
public_key_package: &PublicKeyPackage<C>,
mut rng: R,
) -> Self {
let randomizer = <<C::Group as Group>::Field as Field>::random(&mut rng);
Self::from_randomizer(public_key_package, randomizer)
/// Create a new [`RandomizedParams`] for the given [`VerifyingKey`] and
/// the given `participants`.
pub fn new<R: RngCore + CryptoRng>(group_verifying_key: &VerifyingKey<C>, rng: R) -> Self {
Self::from_randomizer(group_verifying_key, Randomizer::new(rng))
}
/// Create a new RandomizedParams for the given [`PublicKeyPackage`]
/// with the given `randomizer`. The `randomizer` MUST be generated uniformly
/// at random! Use [`RandomizedParams::new()`] which generates a fresh
/// randomizer, unless your application requires generating a randomizer
/// outside.
/// Create a new [`RandomizedParams`] for the given [`VerifyingKey`] and the
/// given `participants` for the given `randomizer`. The `randomizer` MUST
/// be generated uniformly at random! Use [`RandomizedParams::new()`] which
/// generates a fresh randomizer, unless your application requires generating
/// a randomizer outside.
pub fn from_randomizer(
public_key_package: &PublicKeyPackage<C>,
randomizer: Scalar<C>,
group_verifying_key: &VerifyingKey<C>,
randomizer: Randomizer<C>,
) -> Self {
let randomizer_point = <C::Group as Group>::generator() * randomizer;
let group_public_point = public_key_package.group_public().to_element();
let randomized_group_public_point = group_public_point + randomizer_point;
let randomized_group_public_key = VerifyingKey::new(randomized_group_public_point);
let randomizer_element = <C::Group as Group>::generator() * randomizer.0;
let group_public_element = group_verifying_key.to_element();
let randomized_group_public_element = group_public_element + randomizer_element;
let randomized_verifying_key = VerifyingKey::<C>::new(randomized_group_public_element);
Self {
randomizer,
randomizer_point,
randomized_group_public_key,
randomizer_element,
randomized_verifying_key,
}
}
/// Return the randomizer.
///
/// It can be useful to the coordinator, e.g. to generate the ZK proof
/// in Zcash. It MUST NOT be sent to other parties.
pub fn randomizer(&self) -> &frost_core::Scalar<C> {
&self.randomizer
}
/// Return the randomizer point.
///
/// It must be sent by the coordinator to each participant when signing.
pub fn randomizer_point(&self) -> &<C::Group as Group>::Element {
&self.randomizer_point
}
/// Return the randomized group public key.
///
/// It can be used to verify the final signature.
pub fn randomized_group_public_key(&self) -> &frost_core::VerifyingKey<C> {
&self.randomized_group_public_key
}
}

View File

@ -2,8 +2,8 @@
use std::collections::{BTreeMap, HashMap};
use crate::{frost_core::frost, frost_core::Ciphersuite, RandomizedParams};
use frost_core::{Field, Group, Signature, VerifyingKey};
use crate::{frost_core::frost, frost_core::Ciphersuite, RandomizedParams, Randomizer};
use frost_core::{Signature, VerifyingKey};
use rand_core::{CryptoRng, RngCore};
/// Test re-randomized FROST signing with trusted dealer with a Ciphersuite.
@ -39,7 +39,8 @@ pub fn check_randomized_sign_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>
BTreeMap::new();
check_from_randomizer(&pubkeys, &mut rng);
let randomizer_params = RandomizedParams::new(&pubkeys, &mut rng);
let randomizer_params = RandomizedParams::new(pubkeys.group_public(), &mut rng);
let randomizer = randomizer_params.randomizer();
////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
@ -78,13 +79,8 @@ pub fn check_randomized_sign_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>
let nonces_to_use = &nonces.get(participant_identifier).unwrap();
// Each participant generates their signature share.
let signature_share = crate::sign(
&signing_package,
nonces_to_use,
key_package,
randomizer_params.randomizer_point(),
)
.unwrap();
let signature_share =
crate::sign(&signing_package, nonces_to_use, key_package, *randomizer).unwrap();
signature_shares.insert(*participant_identifier, signature_share);
}
@ -108,7 +104,7 @@ pub fn check_randomized_sign_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>
// Check that the threshold signature can be verified by the randomized group public
// key (the verification key).
assert!(randomizer_params
.randomized_group_public_key()
.randomized_verifying_key()
.verify(message, &group_signature)
.is_ok());
@ -118,17 +114,17 @@ pub fn check_randomized_sign_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>
(
message.to_owned(),
group_signature,
*randomizer_params.randomized_group_public_key(),
*randomizer_params.randomized_verifying_key(),
)
}
fn check_from_randomizer<C: Ciphersuite, R: RngCore + CryptoRng>(
pubkeys: &frost::keys::PublicKeyPackage<C>,
mut rng: &mut R,
rng: &mut R,
) {
let randomizer = <<C::Group as Group>::Field as Field>::random(&mut rng);
let randomizer = Randomizer::new(rng);
let randomizer_params = RandomizedParams::from_randomizer(pubkeys, randomizer);
let randomizer_params = RandomizedParams::from_randomizer(pubkeys.group_public(), randomizer);
assert!(*randomizer_params.randomizer() == randomizer);
}

View File

@ -25,6 +25,7 @@ sha2 = "0.10.2"
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
frost-rerandomized = { path = "../frost-rerandomized", version = "0.6.0", features = ["test-impl"] }
hex = "0.4.3"
lazy_static = "1.4"
proptest = "1.0"

View File

@ -0,0 +1,10 @@
use frost_ristretto255::Ristretto255Sha512;
use rand::thread_rng;
#[test]
fn check_randomized_sign_with_dealer() {
let rng = thread_rng();
let (_msg, _group_signature, _group_pubkey) =
frost_rerandomized::tests::check_randomized_sign_with_dealer::<Ristretto255Sha512, _>(rng);
}

View File

@ -28,6 +28,7 @@ sha2 = "0.10.2"
[dev-dependencies]
criterion = "0.5"
frost-rerandomized = { path = "../frost-rerandomized", version = "0.6.0", features = ["test-impl"] }
hex = "0.4.3"
lazy_static = "1.4"
proptest = "1.0"

View File

@ -0,0 +1,10 @@
use frost_secp256k1::Secp256K1Sha256;
use rand::thread_rng;
#[test]
fn check_randomized_sign_with_dealer() {
let rng = thread_rng();
let (_msg, _group_signature, _group_pubkey) =
frost_rerandomized::tests::check_randomized_sign_with_dealer::<Secp256K1Sha256, _>(rng);
}

View File

@ -324,6 +324,7 @@ fn main() -> ExitCode {
"tests/common_traits_tests.rs",
"tests/integration_tests.rs",
"tests/recreation_tests.rs",
"tests/rerandomized_tests.rs",
"tests/serde_tests.rs",
"tests/helpers/samples.rs",
] {