#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(feature = "std")]
use std::vec::Vec;
#[cfg(feature = "std")]
use std::cmp::Ordering;
#[cfg(not(feature = "std"))]
use core::cmp::Ordering;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE;
use curve25519_dalek::ristretto::CompressedRistretto;
use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::Identity;
use rand::rngs::OsRng;
use zeroize::Zeroize;
use crate::nizk::NizkOfSecretKey;
use crate::parameters::Parameters;
#[derive(Zeroize)]
#[zeroize(drop)]
pub struct Coefficients(pub(crate) Vec<Scalar>);
#[derive(Clone, Debug)]
pub struct VerifiableSecretSharingCommitment(pub(crate) Vec<RistrettoPoint>);
#[derive(Clone, Debug)]
pub struct DealtParticipant {
pub(crate) secret_share: SecretShare,
pub(crate) public_key: IndividualPublicKey,
pub(crate) group_key: RistrettoPoint,
}
#[derive(Clone, Debug)]
pub struct Participant {
pub index: u32,
pub commitments: Vec<RistrettoPoint>,
pub proof_of_secret_key: NizkOfSecretKey,
}
impl Participant {
pub fn dealer(parameters: &Parameters) -> (Vec<DealtParticipant>, VerifiableSecretSharingCommitment) {
let mut rng: OsRng = OsRng;
let secret = Scalar::random(&mut rng);
generate_shares(parameters, secret, rng)
}
pub fn new(parameters: &Parameters, index: u32) -> (Self, Coefficients) {
let t: usize = parameters.t as usize;
let mut rng: OsRng = OsRng;
let mut coefficients: Vec<Scalar> = Vec::with_capacity(t);
let mut commitments: Vec<RistrettoPoint> = Vec::with_capacity(t);
for _ in 0..t {
coefficients.push(Scalar::random(&mut rng));
}
let coefficients = Coefficients(coefficients);
for j in 0..t {
commitments.push(&coefficients.0[j] * &RISTRETTO_BASEPOINT_TABLE);
}
let proof: NizkOfSecretKey = NizkOfSecretKey::prove(&index, &coefficients.0[0], &commitments[0], rng);
(Participant { index, commitments, proof_of_secret_key: proof }, coefficients)
}
pub fn public_key(&self) -> Option<&RistrettoPoint> {
if !self.commitments.is_empty() {
return Some(&self.commitments[0]);
}
None
}
}
fn generate_shares(parameters: &Parameters, secret: Scalar, mut rng: OsRng) -> (Vec<DealtParticipant>, VerifiableSecretSharingCommitment) {
let mut participants: Vec<DealtParticipant> = Vec::with_capacity(parameters.n as usize);
let t: usize = parameters.t as usize;
let mut coefficients: Vec<Scalar> = Vec::with_capacity(t as usize);
let mut commitment = VerifiableSecretSharingCommitment(Vec::with_capacity(t as usize));
coefficients.push(secret);
for _ in 0..t-1 {
coefficients.push(Scalar::random(&mut rng));
}
let coefficients = Coefficients(coefficients);
for j in 0..t {
commitment.0.push(&coefficients.0[j] * &RISTRETTO_BASEPOINT_TABLE);
}
let group_key = &RISTRETTO_BASEPOINT_TABLE * &coefficients.0[0];
for i in 1..parameters.n + 1 {
let secret_share = SecretShare::evaluate_polynomial(&i, &coefficients);
let public_key = IndividualPublicKey {
index: i,
share: &RISTRETTO_BASEPOINT_TABLE * &secret_share.polynomial_evaluation,
};
participants.push(DealtParticipant { secret_share, public_key, group_key });
}
(participants, commitment)
}
impl PartialOrd for Participant {
fn partial_cmp(&self, other: &Participant) -> Option<Ordering> {
match self.index.cmp(&other.index) {
Ordering::Less => Some(Ordering::Less),
Ordering::Equal => None, Ordering::Greater => Some(Ordering::Greater),
}
}
}
impl PartialEq for Participant {
fn eq(&self, other: &Participant) -> bool {
self.index == other.index
}
}
mod private {
pub trait Sealed {}
impl Sealed for super::RoundOne {}
impl Sealed for super::RoundTwo {}
}
#[derive(Clone, Debug)]
pub struct DistributedKeyGeneration<S: DkgState> {
state: Box<ActualState>,
data: S,
}
#[derive(Clone, Debug)]
struct ActualState {
parameters: Parameters,
their_commitments: Vec<(u32, VerifiableSecretSharingCommitment)>,
my_secret_share: SecretShare,
their_secret_shares: Option<Vec<SecretShare>>,
my_secret_shares: Option<Vec<SecretShare>>,
}
pub trait DkgState: private::Sealed {}
impl DkgState for RoundOne {}
impl DkgState for RoundTwo {}
pub trait Round1: private::Sealed {}
pub trait Round2: private::Sealed {}
impl Round1 for RoundOne {}
impl Round2 for RoundTwo {}
#[derive(Clone, Debug)]
pub struct RoundOne {}
impl DistributedKeyGeneration<RoundOne> {
pub fn new(
parameters: &Parameters,
my_index: &u32,
my_coefficients: &Coefficients,
other_participants: &mut Vec<Participant>,
) -> Result<Self, Vec<u32>>
{
let mut their_commitments: Vec<(u32, VerifiableSecretSharingCommitment)> = Vec::with_capacity(parameters.t as usize);
let mut misbehaving_participants: Vec<u32> = Vec::new();
if other_participants.len() != parameters.n as usize - 1 {
return Err(misbehaving_participants);
}
for p in other_participants.iter() {
let public_key = match p.commitments.get(0) {
Some(key) => key,
None => {
misbehaving_participants.push(p.index);
continue;
}
};
match p.proof_of_secret_key.verify(&p.index, &public_key) {
Ok(_) => their_commitments.push((p.index, VerifiableSecretSharingCommitment(p.commitments.clone()))),
Err(_) => misbehaving_participants.push(p.index),
}
}
if !misbehaving_participants.is_empty() {
return Err(misbehaving_participants);
}
let mut their_secret_shares: Vec<SecretShare> = Vec::with_capacity(parameters.n as usize - 1);
for p in other_participants.iter() {
their_secret_shares.push(SecretShare::evaluate_polynomial(&p.index, my_coefficients));
}
let my_secret_share = SecretShare::evaluate_polynomial(my_index, my_coefficients);
let state = ActualState {
parameters: *parameters,
their_commitments,
my_secret_share,
their_secret_shares: Some(their_secret_shares),
my_secret_shares: None,
};
Ok(DistributedKeyGeneration::<RoundOne> {
state: Box::new(state),
data: RoundOne {},
})
}
pub fn their_secret_shares(&self) -> Result<&Vec<SecretShare>, ()> {
self.state.their_secret_shares.as_ref().ok_or(())
}
#[allow(clippy::wrong_self_convention)]
pub fn to_round_two(
mut self,
my_secret_shares: Vec<SecretShare>,
) -> Result<DistributedKeyGeneration<RoundTwo>, ()>
{
if self.state.their_secret_shares.is_some() {
self.state.their_secret_shares.unwrap().zeroize();
self.state.their_secret_shares = None;
}
if my_secret_shares.len() != self.state.parameters.n as usize - 1 {
return Err(());
}
for share in my_secret_shares.iter() {
for (index, commitment) in self.state.their_commitments.iter() {
if index == &share.index {
share.verify(commitment)?;
}
}
}
self.state.my_secret_shares = Some(my_secret_shares);
Ok(DistributedKeyGeneration::<RoundTwo> {
state: self.state,
data: RoundTwo {},
})
}
}
#[derive(Clone, Debug, Zeroize)]
#[zeroize(drop)]
pub struct SecretShare {
pub index: u32,
pub(crate) polynomial_evaluation: Scalar,
}
impl SecretShare {
pub(crate) fn evaluate_polynomial(index: &u32, coefficients: &Coefficients) -> SecretShare {
let term: Scalar = (*index).into();
let mut sum: Scalar = Scalar::zero();
for (index, coefficient) in coefficients.0.iter().rev().enumerate() {
sum += coefficient;
if index != (coefficients.0.len() - 1) {
sum *= term;
}
}
SecretShare { index: *index, polynomial_evaluation: sum }
}
pub(crate) fn verify(&self, commitment: &VerifiableSecretSharingCommitment) -> Result<(), ()> {
let lhs = &RISTRETTO_BASEPOINT_TABLE * &self.polynomial_evaluation;
let term: Scalar = self.index.into();
let mut rhs: RistrettoPoint = RistrettoPoint::identity();
for (index, com) in commitment.0.iter().rev().enumerate() {
rhs += com;
if index != (commitment.0.len() - 1) {
rhs *= term;
}
}
match lhs.compress() == rhs.compress() {
true => Ok(()),
false => Err(()),
}
}
}
#[derive(Clone, Debug)]
pub struct RoundTwo {}
impl DistributedKeyGeneration<RoundTwo> {
pub fn finish(mut self, my_commitment: &RistrettoPoint) -> Result<(GroupKey, SecretKey), ()> {
let secret_key = self.calculate_signing_key()?;
let group_key = self.calculate_group_key(my_commitment)?;
self.state.my_secret_share.zeroize();
self.state.my_secret_shares.zeroize();
Ok((group_key, secret_key))
}
pub(crate) fn calculate_signing_key(&self) -> Result<SecretKey, ()> {
let my_secret_shares = self.state.my_secret_shares.as_ref().ok_or(())?;
let mut key = my_secret_shares.iter().map(|x| x.polynomial_evaluation).sum();
key += self.state.my_secret_share.polynomial_evaluation;
Ok(SecretKey { index: self.state.my_secret_share.index, key })
}
pub(crate) fn calculate_group_key(&self, my_commitment: &RistrettoPoint) -> Result<GroupKey, ()> {
let mut keys: Vec<RistrettoPoint> = Vec::with_capacity(self.state.parameters.n as usize);
for commitment in self.state.their_commitments.iter() {
match commitment.1.0.get(0) {
Some(key) => keys.push(*key),
None => return Err(()),
}
}
keys.push(*my_commitment);
Ok(GroupKey(keys.iter().sum()))
}
}
#[derive(Clone, Debug)]
pub struct IndividualPublicKey {
pub index: u32,
pub share: RistrettoPoint,
}
impl IndividualPublicKey {
#[allow(unused)]
pub fn verify(
&self,
parameters: &Parameters,
commitments: &[RistrettoPoint],
) -> Result<(), ()>
{
let rhs = RistrettoPoint::identity();
for j in 1..parameters.n {
for k in 0..parameters.t {
}
}
unimplemented!()
}
}
#[derive(Debug, Zeroize)]
#[zeroize(drop)]
pub struct SecretKey {
pub(crate) index: u32,
pub(crate) key: Scalar,
}
impl SecretKey {
pub fn to_public(&self) -> IndividualPublicKey {
let share = &RISTRETTO_BASEPOINT_TABLE * &self.key;
IndividualPublicKey {
index: self.index,
share,
}
}
}
impl From<&SecretKey> for IndividualPublicKey {
fn from(source: &SecretKey) -> IndividualPublicKey {
source.to_public()
}
}
#[derive(Clone, Copy, Debug, Eq)]
pub struct GroupKey(pub(crate) RistrettoPoint);
impl PartialEq for GroupKey {
fn eq(&self, other: &Self) -> bool {
self.0.compress() == other.0.compress()
}
}
impl GroupKey {
pub fn to_bytes(&self) -> [u8; 32] {
self.0.compress().to_bytes()
}
pub fn from_bytes(bytes: [u8; 32]) -> Result<GroupKey, ()> {
let point = CompressedRistretto(bytes).decompress().ok_or(())?;
Ok(GroupKey(point))
}
}
#[cfg(test)]
mod test {
use super::*;
#[cfg(feature = "std")]
use crate::precomputation::generate_commitment_share_lists;
#[cfg(feature = "std")]
use crate::signature::{calculate_lagrange_coefficients, compute_message_hash};
#[cfg(feature = "std")]
use crate::signature::SignatureAggregator;
#[cfg(feature = "std")]
fn reconstruct_secret(participants: &Vec<&DealtParticipant>) -> Result<Scalar, &'static str> {
let all_participant_indices: Vec<u32> = participants.iter().map(|p| p.public_key.index).collect();
let mut secret = Scalar::zero();
for this_participant in participants {
let my_coeff = calculate_lagrange_coefficients(&this_participant.public_key.index,
&all_participant_indices)?;
secret += my_coeff * this_participant.secret_share.polynomial_evaluation;
}
Ok(secret)
}
#[test]
fn nizk_of_secret_key() {
let params = Parameters { n: 3, t: 2 };
let (p, _) = Participant::new(¶ms, 0);
let result = p.proof_of_secret_key.verify(&p.index, &p.commitments[0]);
assert!(result.is_ok());
}
#[cfg(feature = "std")]
#[test]
fn verify_secret_sharing_from_dealer() {
let params = Parameters { n: 3, t: 2 };
let mut rng: OsRng = OsRng;
let secret = Scalar::random(&mut rng);
let (participants, _commitment) = generate_shares(¶ms, secret, rng);
let mut subset_participants = Vec::new();
for i in 0..params.t{
subset_participants.push(&participants[i as usize]);
}
let supposed_secret = reconstruct_secret(&subset_participants);
assert!(secret == supposed_secret.unwrap());
}
#[test]
fn dkg_with_dealer() {
let params = Parameters { t: 1, n: 2 };
let (participants, commitment) = Participant::dealer(¶ms);
let (_, commitment2) = Participant::dealer(¶ms);
for p in participants.iter() {
let result = p.secret_share.verify(&commitment);
assert!(result.is_ok(), "participant {} failed to receive a valid secret share", p.public_key.index);
let result = p.secret_share.verify(&commitment2);
assert!(!result.is_ok(), "Should not validate with invalid commitment");
}
}
#[cfg(feature = "std")]
#[test]
fn dkg_with_dealer_and_signing() {
let params = Parameters { t: 1, n: 2 };
let (participants, commitment) = Participant::dealer(¶ms);
for p in participants.iter() {
let result = p.secret_share.verify(&commitment);
assert!(result.is_ok(), "participant {} failed to receive a valid secret share", p.public_key.index);
}
let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
let message = b"This is a test of the tsunami alert system. This is only a test.";
let (p1_public_comshares, mut p1_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 1, 1);
let (p2_public_comshares, mut p2_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 2, 1);
let p1_sk = SecretKey {
index: participants[0].secret_share.index,
key: participants[0].secret_share.polynomial_evaluation,
};
let p2_sk = SecretKey {
index: participants[1].secret_share.index,
key: participants[1].secret_share.polynomial_evaluation,
};
let group_key = GroupKey(participants[0].group_key);
let mut aggregator = SignatureAggregator::new(params, group_key, &context[..], &message[..]);
aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
aggregator.include_signer(2, p2_public_comshares.commitments[0], (&p2_sk).into());
let signers = aggregator.get_signers();
let message_hash = compute_message_hash(&context[..], &message[..]);
let p1_partial = p1_sk.sign(&message_hash, &group_key, &mut p1_secret_comshares, 0, signers).unwrap();
let p2_partial = p2_sk.sign(&message_hash, &group_key, &mut p2_secret_comshares, 0, signers).unwrap();
aggregator.include_partial_signature(p1_partial);
aggregator.include_partial_signature(p2_partial);
let aggregator = aggregator.finalize().unwrap();
let signing_result = aggregator.aggregate();
assert!(signing_result.is_ok());
let threshold_signature = signing_result.unwrap();
let verification_result = threshold_signature.verify(&group_key, &message_hash);
println!("{:?}", verification_result);
assert!(verification_result.is_ok());
}
#[test]
fn secret_share_from_one_coefficients() {
let mut coeffs: Vec<Scalar> = Vec::new();
for _ in 0..5 {
coeffs.push(Scalar::one());
}
let coefficients = Coefficients(coeffs);
let share = SecretShare::evaluate_polynomial(&1, &coefficients);
assert!(share.polynomial_evaluation == Scalar::from(5u8));
let mut commitments = VerifiableSecretSharingCommitment(Vec::new());
for i in 0..5 {
commitments.0.push(&RISTRETTO_BASEPOINT_TABLE * &coefficients.0[i]);
}
assert!(share.verify(&commitments).is_ok());
}
#[test]
fn secret_share_participant_index_zero() {
let mut coeffs: Vec<Scalar> = Vec::new();
for _ in 0..5 {
coeffs.push(Scalar::one());
}
let coefficients = Coefficients(coeffs);
let share = SecretShare::evaluate_polynomial(&0, &coefficients);
assert!(share.polynomial_evaluation == Scalar::one());
let mut commitments = VerifiableSecretSharingCommitment(Vec::new());
for i in 0..5 {
commitments.0.push(&RISTRETTO_BASEPOINT_TABLE * &coefficients.0[i]);
}
assert!(share.verify(&commitments).is_ok());
}
#[test]
fn single_party_keygen() {
let params = Parameters { n: 1, t: 1 };
let (p1, p1coeffs) = Participant::new(¶ms, 1);
p1.proof_of_secret_key.verify(&p1.index, &p1.commitments[0]).unwrap();
let mut p1_other_participants: Vec<Participant> = Vec::new();
let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p1.index,
&p1coeffs,
&mut p1_other_participants).unwrap();
let p1_my_secret_shares = Vec::new();
let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
let result = p1_state.finish(p1.public_key().unwrap());
assert!(result.is_ok());
let (p1_group_key, p1_secret_key) = result.unwrap();
assert!(p1_group_key.0.compress() == (&p1_secret_key.key * &RISTRETTO_BASEPOINT_TABLE).compress());
}
#[test]
fn keygen_3_out_of_5() {
let params = Parameters { n: 5, t: 3 };
let (p1, p1coeffs) = Participant::new(¶ms, 1);
let (p2, p2coeffs) = Participant::new(¶ms, 2);
let (p3, p3coeffs) = Participant::new(¶ms, 3);
let (p4, p4coeffs) = Participant::new(¶ms, 4);
let (p5, p5coeffs) = Participant::new(¶ms, 5);
p1.proof_of_secret_key.verify(&p1.index, &p1.public_key().unwrap()).unwrap();
p2.proof_of_secret_key.verify(&p2.index, &p2.public_key().unwrap()).unwrap();
p3.proof_of_secret_key.verify(&p3.index, &p3.public_key().unwrap()).unwrap();
p4.proof_of_secret_key.verify(&p4.index, &p4.public_key().unwrap()).unwrap();
p5.proof_of_secret_key.verify(&p5.index, &p5.public_key().unwrap()).unwrap();
let mut p1_other_participants: Vec<Participant> = vec!(p2.clone(), p3.clone(), p4.clone(), p5.clone());
let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p1.index,
&p1coeffs,
&mut p1_other_participants).unwrap();
let p1_their_secret_shares = p1_state.their_secret_shares().unwrap();
let mut p2_other_participants: Vec<Participant> = vec!(p1.clone(), p3.clone(), p4.clone(), p5.clone());
let p2_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p2.index,
&p2coeffs,
&mut p2_other_participants).unwrap();
let p2_their_secret_shares = p2_state.their_secret_shares().unwrap();
let mut p3_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p4.clone(), p5.clone());
let p3_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p3.index,
&p3coeffs,
&mut p3_other_participants).unwrap();
let p3_their_secret_shares = p3_state.their_secret_shares().unwrap();
let mut p4_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p3.clone(), p5.clone());
let p4_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p4.index,
&p4coeffs,
&mut p4_other_participants).unwrap();
let p4_their_secret_shares = p4_state.their_secret_shares().unwrap();
let mut p5_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p3.clone(), p4.clone());
let p5_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p5.index,
&p5coeffs,
&mut p5_other_participants).unwrap();
let p5_their_secret_shares = p5_state.their_secret_shares().unwrap();
let p1_my_secret_shares = vec!(p2_their_secret_shares[0].clone(), p3_their_secret_shares[0].clone(),
p4_their_secret_shares[0].clone(),
p5_their_secret_shares[0].clone());
let p2_my_secret_shares = vec!(p1_their_secret_shares[0].clone(),
p3_their_secret_shares[1].clone(),
p4_their_secret_shares[1].clone(),
p5_their_secret_shares[1].clone());
let p3_my_secret_shares = vec!(p1_their_secret_shares[1].clone(),
p2_their_secret_shares[1].clone(),
p4_their_secret_shares[2].clone(),
p5_their_secret_shares[2].clone());
let p4_my_secret_shares = vec!(p1_their_secret_shares[2].clone(),
p2_their_secret_shares[2].clone(),
p3_their_secret_shares[2].clone(),
p5_their_secret_shares[3].clone());
let p5_my_secret_shares = vec!(p1_their_secret_shares[3].clone(),
p2_their_secret_shares[3].clone(),
p3_their_secret_shares[3].clone(),
p4_their_secret_shares[3].clone());
let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
let p2_state = p2_state.to_round_two(p2_my_secret_shares).unwrap();
let p3_state = p3_state.to_round_two(p3_my_secret_shares).unwrap();
let p4_state = p4_state.to_round_two(p4_my_secret_shares).unwrap();
let p5_state = p5_state.to_round_two(p5_my_secret_shares).unwrap();
let (p1_group_key, _p1_secret_key) = p1_state.finish(p1.public_key().unwrap()).unwrap();
let (p2_group_key, _p2_secret_key) = p2_state.finish(p2.public_key().unwrap()).unwrap();
let (p3_group_key, _p3_secret_key) = p3_state.finish(p3.public_key().unwrap()).unwrap();
let (p4_group_key, _p4_secret_key) = p4_state.finish(p4.public_key().unwrap()).unwrap();
let (p5_group_key, _p5_secret_key) = p5_state.finish(p5.public_key().unwrap()).unwrap();
assert!(p1_group_key.0.compress() == p2_group_key.0.compress());
assert!(p2_group_key.0.compress() == p3_group_key.0.compress());
assert!(p3_group_key.0.compress() == p4_group_key.0.compress());
assert!(p4_group_key.0.compress() == p5_group_key.0.compress());
assert!(p5_group_key.0.compress() ==
(p1.public_key().unwrap() +
p2.public_key().unwrap() +
p3.public_key().unwrap() +
p4.public_key().unwrap() +
p5.public_key().unwrap()).compress());
}
#[test]
fn keygen_2_out_of_3() {
fn do_test() -> Result<(), ()> {
let params = Parameters { n: 3, t: 2 };
let (p1, p1coeffs) = Participant::new(¶ms, 1);
let (p2, p2coeffs) = Participant::new(¶ms, 2);
let (p3, p3coeffs) = Participant::new(¶ms, 3);
p1.proof_of_secret_key.verify(&p1.index, &p1.public_key().unwrap())?;
p2.proof_of_secret_key.verify(&p2.index, &p2.public_key().unwrap())?;
p3.proof_of_secret_key.verify(&p3.index, &p3.public_key().unwrap())?;
let mut p1_other_participants: Vec<Participant> = vec!(p2.clone(), p3.clone());
let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p1.index,
&p1coeffs,
&mut p1_other_participants).or(Err(()))?;
let p1_their_secret_shares = p1_state.their_secret_shares()?;
let mut p2_other_participants: Vec<Participant> = vec!(p1.clone(), p3.clone());
let p2_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p2.index,
&p2coeffs,
&mut p2_other_participants).or(Err(()))?;
let p2_their_secret_shares = p2_state.their_secret_shares()?;
let mut p3_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone());
let p3_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
&p3.index,
&p3coeffs,
&mut p3_other_participants).or(Err(()))?;
let p3_their_secret_shares = p3_state.their_secret_shares()?;
let p1_my_secret_shares = vec!(p2_their_secret_shares[0].clone(), p3_their_secret_shares[0].clone());
let p2_my_secret_shares = vec!(p1_their_secret_shares[0].clone(),
p3_their_secret_shares[1].clone());
let p3_my_secret_shares = vec!(p1_their_secret_shares[1].clone(),
p2_their_secret_shares[1].clone());
let p1_state = p1_state.to_round_two(p1_my_secret_shares)?;
let p2_state = p2_state.to_round_two(p2_my_secret_shares)?;
let p3_state = p3_state.to_round_two(p3_my_secret_shares)?;
let (p1_group_key, _p1_secret_key) = p1_state.finish(p1.public_key().unwrap())?;
let (p2_group_key, _p2_secret_key) = p2_state.finish(p2.public_key().unwrap())?;
let (p3_group_key, _p3_secret_key) = p3_state.finish(p3.public_key().unwrap())?;
assert!(p1_group_key.0.compress() == p2_group_key.0.compress());
assert!(p2_group_key.0.compress() == p3_group_key.0.compress());
Ok(())
}
assert!(do_test().is_ok());
}
}