Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
Add test case for resharing from outside of FROST (#36)
Browse files Browse the repository at this point in the history
* Add test case for resharing from outside of FROST

* Add signing check

* Fix clippy warning and remove a clone on the signers set during `finalize()` (#37)

* Fix clippy warning and remove a clone

* Update comment

* Fix doc

* Rename constants

---------

Co-authored-by: David <[email protected]>
  • Loading branch information
Nashtare and dvdplm authored Apr 3, 2024
1 parent 562b64e commit ed205b6
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 5 deletions.
5 changes: 3 additions & 2 deletions src/dkg/key_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,8 +666,9 @@ impl<C: CipherSuite> DistributedKeyGeneration<RoundOne, C> {
///
/// # Inputs
///
/// * The protocol new instance [`ThresholdParameters`]. These parameters can
/// be different from the previous ICE-FROST session using the same group key.
/// * The protocol old instance [`ThresholdParameters`]. These parameters can
/// be different from the current ICE-FROST session which will be having the
/// same group key.
/// * This participant's [`DiffieHellmanPrivateKey`].
/// * This participant's `index`.
/// * The list of `dealers`. These are the participants of the previous ICE-FROST
Expand Down
10 changes: 9 additions & 1 deletion src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,15 @@ impl<C: CipherSuite> Drop for IndividualSigningKey<C> {
}

impl<C: CipherSuite> IndividualSigningKey<C> {
/// Derive the corresponding public key for this secret key.
/// Outputs an [`IndividualSigningKey`] from an isolated secret key.
/// This can be useful for single parties owning a public key for
/// Schnorr signatures outside of an ICE-FROST context and who would
/// like to reshare its corresponding secret key to a set of participants.
pub fn from_single_key(key: <C::G as Group>::ScalarField) -> Self {
Self { index: 1, key }
}

/// Derives the corresponding public key for this secret key.
pub fn to_public(&self) -> IndividualVerifyingKey<C> {
let share = C::G::generator() * self.key;

Expand Down
2 changes: 2 additions & 0 deletions src/sign/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,8 @@ impl<C: CipherSuite> SignatureAggregator<C, Initial<'_>> {
}

/// Get the list of partipating signers.
/// It will internally sort the signers by indices, remove any duplicate,
/// and then return a reference to the updated internal list.
///
/// # Returns
///
Expand Down
146 changes: 144 additions & 2 deletions tests/ice_frost.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
//! Integration tests for ICE-FROST.

use ark_ec::Group;
use ark_ff::UniformRand;
use ice_frost::keys::{DiffieHellmanPrivateKey, GroupVerifyingKey, IndividualSigningKey};
use rand::rngs::OsRng;

use ice_frost::CipherSuite;

use ice_frost::dkg::{DistributedKeyGeneration, Participant};
use ice_frost::dkg::{DistributedKeyGeneration, EncryptedSecretShare, Participant, RoundOne};
use ice_frost::parameters::ThresholdParameters;
use ice_frost::sign::generate_commitment_share_lists;
use ice_frost::sign::{
generate_commitment_share_lists, PublicCommitmentShareList, SecretCommitmentShareList,
};

use ice_frost::sign::SignatureAggregator;

Expand All @@ -15,6 +20,9 @@ use ice_frost::testing::Secp256k1Sha256;
type ParticipantDKG = Participant<Secp256k1Sha256>;
type Dkg<T> = DistributedKeyGeneration<T, Secp256k1Sha256>;

type PublicCommShareList = PublicCommitmentShareList<Secp256k1Sha256>;
type SecretCommShareList = SecretCommitmentShareList<Secp256k1Sha256>;

#[test]
fn signing_and_verification_3_out_of_5() {
let params = ThresholdParameters::new(5, 3);
Expand Down Expand Up @@ -272,3 +280,137 @@ fn signing_and_verification_3_out_of_5() {
assert!(verification_result1.is_ok());
assert!(verification_result2.is_ok());
}

#[test]
fn resharing_from_non_frost_key() {
type SchnorrSecretKey = <<Secp256k1Sha256 as CipherSuite>::G as Group>::ScalarField;
type SchnorrPublicKey = <Secp256k1Sha256 as CipherSuite>::G;

// A single party outside of any ICE-FROST scenario, who owns a keypair to perform
// Schnorr signatures.
let mut rng = OsRng;
let single_party_sk: SchnorrSecretKey = SchnorrSecretKey::rand(&mut rng);
let single_party_pk: SchnorrPublicKey =
<<Secp256k1Sha256 as CipherSuite>::G>::generator() * single_party_sk;

// Converts this party's keys into ICE-FROST format, simulating a 1-out-of-1 setup.
let simulated_parameters = ThresholdParameters::new(1, 1);
let frost_sk = IndividualSigningKey::from_single_key(single_party_sk);
let frost_pk = GroupVerifyingKey::new(single_party_pk);

// Start a resharing phase from this single party to a set of new participants.
const NUMBER_OF_PARTICIPANTS: u32 = 5;
const THRESHOLD_OF_PARTICIPANTS: u32 = 3;

let threshold_parameters =
ThresholdParameters::new(NUMBER_OF_PARTICIPANTS, THRESHOLD_OF_PARTICIPANTS);

let mut signers = Vec::<Participant<Secp256k1Sha256>>::new();
let mut signers_dh_secret_keys = Vec::<DiffieHellmanPrivateKey<Secp256k1Sha256>>::new();

for i in 1..=NUMBER_OF_PARTICIPANTS {
let (p, dh_sk) =
Participant::<Secp256k1Sha256>::new_signer(threshold_parameters, i, rng).unwrap();

signers.push(p);
signers_dh_secret_keys.push(dh_sk);
}

let mut signers_encrypted_secret_shares: Vec<Vec<EncryptedSecretShare<Secp256k1Sha256>>> =
(0..NUMBER_OF_PARTICIPANTS).map(|_| Vec::new()).collect();

let mut signers_states_1 = Vec::<Dkg<_>>::new();
let mut signers_states_2 = Vec::<Dkg<_>>::new();

let (single_dealer, dealer_encrypted_shares_for_signers, _participant_lists) =
Participant::reshare(threshold_parameters, &frost_sk, &signers, rng).unwrap();

for i in 0..NUMBER_OF_PARTICIPANTS as usize {
let (signer_state, _participant_lists) =
DistributedKeyGeneration::<RoundOne, Secp256k1Sha256>::new(
simulated_parameters,
&signers_dh_secret_keys[i],
signers[i].index,
&[single_dealer.clone()],
rng,
)
.unwrap();
signers_states_1.push(signer_state);
}

for (i, shares) in signers_encrypted_secret_shares.iter_mut().enumerate() {
let share_for_signer = dealer_encrypted_shares_for_signers
.get(&(i as u32 + 1))
.unwrap()
.clone();
*shares = vec![share_for_signer];
}

for i in 0..NUMBER_OF_PARTICIPANTS as usize {
let (si_state, complaints) = signers_states_1[i]
.clone()
.to_round_two(&signers_encrypted_secret_shares[i], rng)
.unwrap();
assert!(complaints.is_empty());

signers_states_2.push(si_state);
}

let mut signers_secret_keys = Vec::<IndividualSigningKey<Secp256k1Sha256>>::new();

for signers_state in &signers_states_2 {
let (si_group_key, si_sk) = signers_state.clone().finish().unwrap();
signers_secret_keys.push(si_sk);

// Assert that each signer's individual group key matches the converted
// single's party public key.
assert!(si_group_key == frost_pk);
}

let message = b"This is a test of the tsunami alert system. This is only a test.";

let mut signers_public_comshares =
Vec::<PublicCommShareList>::with_capacity(NUMBER_OF_PARTICIPANTS as usize);
let mut signers_secret_comshares =
Vec::<SecretCommShareList>::with_capacity(NUMBER_OF_PARTICIPANTS as usize);

for i in 0..THRESHOLD_OF_PARTICIPANTS {
let (pi_public_comshares, pi_secret_comshares) =
generate_commitment_share_lists(&mut OsRng, &signers_secret_keys[i as usize], 1)
.unwrap();
signers_public_comshares.push(pi_public_comshares);
signers_secret_comshares.push(pi_secret_comshares);
}

let mut aggregator = SignatureAggregator::new(threshold_parameters, frost_pk, &message[..]);

for i in 0..THRESHOLD_OF_PARTICIPANTS {
aggregator.include_signer(
signers[i as usize].index,
signers_public_comshares[i as usize].commitments[0],
&signers_secret_keys[i as usize].to_public(),
);
}

let participating_signers = aggregator.get_signers().clone();
let message_hash = Secp256k1Sha256::h4(&message[..]);

for i in 0..THRESHOLD_OF_PARTICIPANTS {
let pi_partial_signature = signers_secret_keys[i as usize]
.sign(
&message_hash,
&frost_pk,
&mut signers_secret_comshares[i as usize],
0,
&participating_signers,
)
.unwrap();
aggregator.include_partial_signature(&pi_partial_signature);
}

let aggregator = aggregator.finalize().unwrap();

let threshold_signature = aggregator.aggregate().unwrap();

assert!(threshold_signature.verify(&frost_pk, &message_hash).is_ok());
}

0 comments on commit ed205b6

Please sign in to comment.