frost_dalek/
keygen.rs

1// -*- mode: rust; -*-
2//
3// This file is part of dalek-frost.
4// Copyright (c) 2020 isis lovecruft
5// See LICENSE for licensing information.
6//
7// Authors:
8// - isis agora lovecruft <isis@patternsinthevoid.net>
9
10//! A variation of Pedersen's distributed key generation (DKG) protocol.
11//!
12//! This implementation uses the [typestate] design pattern (also called session
13//! types) behind the scenes to enforce that more programming errors are discoverable
14//! at compile-time.  Additionally, secrets generated for commitment openings, secret keys,
15//! nonces in zero-knowledge proofs, etc., are zeroed-out in memory when they are dropped
16//! out of scope.
17//!
18//! # Details
19//!
20//! ## Round One
21//!
22//! * Step #1: Every participant \\(P\_i\\) samples \\(t\\) random values \\((a\_{i0}, \\dots, a\_{i(t-1)})\\)
23//!            uniformly in \\(\mathbb{Z}\_q\\), and uses these values as coefficients to define a
24//!            polynomial \\(f\_i\(x\) = \sum\_{j=0}^{t-1} a\_{ij} x^{j}\\) of degree \\( t-1 \\) over
25//!            \\(\mathbb{Z}\_q\\).
26//!
27//! (Yes, I know the steps are out-of-order. These are the step numbers as given in the paper.  I do them
28//! out-of-order because it saves one scalar multiplication.)
29//!
30//! * Step #3: Every participant \\(P\_i\\) computes a public commitment
31//!            \\(C\_i = \[\phi\_{i0}, \\dots, \phi\_{i(t-1)}\]\\), where \\(\phi\_{ij} = g^{a\_{ij}}\\),
32//!            \\(0 \le j \le t-1\\).
33//!
34//! * Step #2: Every \\(P\_i\\) computes a proof of knowledge to the corresponding secret key
35//!            \\(a\_{i0}\\) by calculating a pseudo-Schnorr signature \\(\sigma\_i = \(s, r\)\\).  (In
36//!            the FROST paper: \\(\sigma\_i = \(\mu\_i, c\_i\)\\), but we stick with Schnorr's
37//!            original notation here.)
38//!
39//! * Step #4: Every participant \\(P\_i\\) broadcasts \\(\(C\_i\\), \\(\sigma\_i\)\\) to all other participants.
40//!
41//! * Step #5: Upon receiving \\((C\_l, \sigma\_l)\\) from participants \\(1 \le l \le n\\), \\(l \ne i\\),
42//!            participant \\(P\_i\\) verifies \\(\sigma\_l = (s\_l, r\_l)\\), by checking:
43//!            \\(s\_l \stackrel{?}{=} \mathcal{H}(l, \Phi, \phi\_{l0}, g^{r\_l} \cdot \phi\_{l0}^{-s\_i})\\).
44//!            If any participants' proofs cannot be verified, return their participant indices.
45//!
46//! ## Round Two
47//!
48//! * Step #1: Each \\(P\_i\\) securely sends to each other participant \\(P\_l\\) a secret share
49//!            \\((l, f\_i(l))\\) using their secret polynomial \\(f\_i(l)\\) and keeps \\((i, f\_i(i))\\)
50//!            for themselves.
51//!
52//! * Step #2: Each \\(P\_i\\) verifies their shares by calculating:
53//!            \\(g^{f\_l(i)} \stackrel{?}{=} \prod\_{k=0}^{n-1} \\)\\(\phi\_{lk}^{i^{k} \mod q}\\),
54//!            aborting if the check fails.
55//!
56//! * Step #3: Each \\(P\_i\\) calculates their secret signing key as the product of all the secret
57//!            polynomial evaluations (including their own):
58//!            \\(a\_i = g^{f\_i(i)} \cdot \prod\_{l=0}^{n-1} g^{f\_l(i)}\\), as well as calculating
59//!            the group public key in similar fashion from the commitments from round one:
60//!            \\(A = C\_i \cdot \prod\_{l=0}^{n-1} C_l\\).
61//!
62//! # Examples
63//!
64//! ```rust
65//! use frost_dalek::DistributedKeyGeneration;
66//! use frost_dalek::Parameters;
67//! use frost_dalek::Participant;
68//!
69//! # fn do_test() -> Result<(), ()> {
70//! // Set up key shares for a threshold signature scheme which needs at least
71//! // 2-out-of-3 signers.
72//! let params = Parameters { t: 2, n: 3 };
73//!
74//! // Alice, Bob, and Carol each generate their secret polynomial coefficients
75//! // and commitments to them, as well as a zero-knowledge proof of a secret key.
76//! let (alice, alice_coeffs) = Participant::new(&params, 1);
77//! let (bob, bob_coeffs) = Participant::new(&params, 2);
78//! let (carol, carol_coeffs) = Participant::new(&params, 3);
79//!
80//! // They send these values to each of the other participants (out of scope
81//! // for this library), or otherwise publish them somewhere.
82//! //
83//! // alice.send_to(bob);
84//! // alice.send_to(carol);
85//! // bob.send_to(alice);
86//! // bob.send_to(carol);
87//! // carol.send_to(alice);
88//! // carol.send_to(bob);
89//! //
90//! // NOTE: They should only send the `alice`, `bob`, and `carol` structs, *not*
91//! //       the `alice_coefficients`, etc.
92//! //
93//! // Bob and Carol verify Alice's zero-knowledge proof by doing:
94//!
95//! alice.proof_of_secret_key.verify(&alice.index, &alice.public_key().unwrap())?;
96//!
97//! // Similarly, Alice and Carol verify Bob's proof:
98//! bob.proof_of_secret_key.verify(&bob.index, &bob.public_key().unwrap())?;
99//!
100//! // And, again, Alice and Bob verify Carol's proof:
101//! carol.proof_of_secret_key.verify(&carol.index, &carol.public_key().unwrap())?;
102//!
103//! // Alice enters round one of the distributed key generation protocol.
104//! let mut alice_other_participants: Vec<Participant> = vec!(bob.clone(), carol.clone());
105//! let alice_state = DistributedKeyGeneration::<_>::new(&params, &alice.index, &alice_coeffs,
106//!                                                      &mut alice_other_participants).or(Err(()))?;
107//!
108//! // Alice then collects the secret shares which they send to the other participants:
109//! let alice_their_secret_shares = alice_state.their_secret_shares()?;
110//! // send_to_bob(alice_their_secret_shares[0]);
111//! // send_to_carol(alice_their_secret_shares[1]);
112//!
113//! // Bob enters round one of the distributed key generation protocol.
114//! let mut bob_other_participants: Vec<Participant> = vec!(alice.clone(), carol.clone());
115//! let bob_state = DistributedKeyGeneration::<_>::new(&params, &bob.index, &bob_coeffs,
116//!                                                    &mut bob_other_participants).or(Err(()))?;
117//!
118//! // Bob then collects the secret shares which they send to the other participants:
119//! let bob_their_secret_shares = bob_state.their_secret_shares()?;
120//! // send_to_alice(bob_their_secret_shares[0]);
121//! // send_to_carol(bob_their_secret_shares[1]);
122//!
123//! // Carol enters round one of the distributed key generation protocol.
124//! let mut carol_other_participants: Vec<Participant> = vec!(alice.clone(), bob.clone());
125//! let carol_state = DistributedKeyGeneration::<_>::new(&params, &carol.index, &carol_coeffs,
126//!                                                      &mut carol_other_participants).or(Err(()))?;
127//!
128//! // Carol then collects the secret shares which they send to the other participants:
129//! let carol_their_secret_shares = carol_state.their_secret_shares()?;
130//! // send_to_alice(carol_their_secret_shares[0]);
131//! // send_to_bob(carol_their_secret_shares[1]);
132//!
133//! // Each participant now has a vector of secret shares given to them by the other participants:
134//! let alice_my_secret_shares = vec!(bob_their_secret_shares[0].clone(),
135//!                                   carol_their_secret_shares[0].clone());
136//! let bob_my_secret_shares = vec!(alice_their_secret_shares[0].clone(),
137//!                                 carol_their_secret_shares[1].clone());
138//! let carol_my_secret_shares = vec!(alice_their_secret_shares[1].clone(),
139//!                                   bob_their_secret_shares[1].clone());
140//!
141//! // The participants then use these secret shares from the other participants to advance to
142//! // round two of the distributed key generation protocol.
143//! let alice_state = alice_state.to_round_two(alice_my_secret_shares)?;
144//! let bob_state = bob_state.to_round_two(bob_my_secret_shares)?;
145//! let carol_state = carol_state.to_round_two(carol_my_secret_shares)?;
146//!
147//! // Each participant can now derive their long-lived secret keys and the group's
148//! // public key.
149//! let (alice_group_key, alice_secret_key) = alice_state.finish(alice.public_key().unwrap())?;
150//! let (bob_group_key, bob_secret_key) = bob_state.finish(bob.public_key().unwrap())?;
151//! let (carol_group_key, carol_secret_key) = carol_state.finish(carol.public_key().unwrap())?;
152//!
153//! // They should all derive the same group public key.
154//! assert!(alice_group_key == bob_group_key);
155//! assert!(carol_group_key == bob_group_key);
156//!
157//! // Alice, Bob, and Carol can now create partial threshold signatures over an agreed upon
158//! // message with their respective secret keys, which they can then give to a
159//! // [`SignatureAggregator`] to create a 2-out-of-3 threshold signature.
160//! # Ok(())}
161//! # fn main() { assert!(do_test().is_ok()); }
162//! ```
163//!
164//! [typestate]: http://cliffle.com/blog/rust-typestate/
165
166#[cfg(feature = "std")]
167use std::boxed::Box;
168#[cfg(feature = "std")]
169use std::vec::Vec;
170
171#[cfg(feature = "std")]
172use std::cmp::Ordering;
173#[cfg(not(feature = "std"))]
174use core::cmp::Ordering;
175
176#[cfg(feature = "alloc")]
177use alloc::boxed::Box;
178#[cfg(feature = "alloc")]
179use alloc::vec::Vec;
180
181use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE;
182use curve25519_dalek::ristretto::CompressedRistretto;
183use curve25519_dalek::ristretto::RistrettoPoint;
184use curve25519_dalek::scalar::Scalar;
185use curve25519_dalek::traits::Identity;
186
187use rand::rngs::OsRng;
188
189use zeroize::Zeroize;
190
191use crate::nizk::NizkOfSecretKey;
192use crate::parameters::Parameters;
193
194/// A struct for holding a shard of the shared secret, in order to ensure that
195/// the shard is overwritten with zeroes when it falls out of scope.
196#[derive(Zeroize)]
197#[zeroize(drop)]
198pub struct Coefficients(pub(crate) Vec<Scalar>);
199
200/// A commitment to the dealer's secret polynomial coefficients for Feldman's
201/// verifiable secret sharing scheme.
202#[derive(Clone, Debug)]
203pub struct VerifiableSecretSharingCommitment(pub(crate) Vec<RistrettoPoint>);
204
205/// A participant created by a trusted dealer.
206///
207/// This can be used to create the participants' keys and secret shares without
208/// having to do secret sharing or zero-knowledge proofs.  It's mostly provided
209/// for testing and debugging purposes, but there is nothing wrong with using it
210/// if you have trust in the dealer to not forge rogue signatures.
211#[derive(Clone, Debug)]
212pub struct DealtParticipant {
213    pub(crate) secret_share: SecretShare,
214    pub(crate) public_key: IndividualPublicKey,
215    pub(crate) group_key: RistrettoPoint,
216}
217
218/// A participant in a threshold signing.
219#[derive(Clone, Debug)]
220pub struct Participant {
221    /// The index of this participant, to keep the participants in order.
222    pub index: u32,
223    /// A vector of Pedersen commitments to the coefficients of this
224    /// participant's private polynomial.
225    pub commitments: Vec<RistrettoPoint>,
226    /// The zero-knowledge proof of knowledge of the secret key (a.k.a. the
227    /// first coefficient in the private polynomial).  It is constructed as a
228    /// Schnorr signature using \\( a_{i0} \\) as the signing key.
229    pub proof_of_secret_key: NizkOfSecretKey,
230}
231
232impl Participant {
233    /// Have a trusted dealer generate all participants' key material and
234    /// associated commitments for distribution to the participants.
235    ///
236    /// # Warning
237    ///
238    /// Each participant MUST verify with all other n-1 participants that the
239    /// [`VerifiableSecretSharingCommitment`] given to them by the dealer is
240    /// identical.  Otherwise, the participants' secret shares could be formed
241    /// with respect to different polynomials and they will fail to create
242    /// threshold signatures which validate.
243    pub fn dealer(parameters: &Parameters) -> (Vec<DealtParticipant>, VerifiableSecretSharingCommitment) {
244        let mut rng: OsRng = OsRng;
245        let secret = Scalar::random(&mut rng);
246
247        generate_shares(parameters, secret, rng)
248    }
249
250    /// Construct a new participant for the distributed key generation protocol.
251    ///
252    /// # Inputs
253    ///
254    /// * The protocol instance [`Parameters`], and
255    /// * This participant's `index`.
256    ///
257    /// # Usage
258    ///
259    /// After a new participant is constructed, the `participant.index`,
260    /// `participant.commitments`, and `participant.proof_of_secret_key` should
261    /// be sent to every other participant in the protocol.
262    ///
263    /// # Returns
264    ///
265    /// A distributed key generation protocol [`Participant`] and that
266    /// participant's secret polynomial `Coefficients` which must be kept
267    /// private.
268    pub fn new(parameters: &Parameters, index: u32) -> (Self, Coefficients) {
269        // Step 1: Every participant P_i samples t random values (a_{i0}, ..., a_{i(t-1)})
270        //         uniformly in ZZ_q, and uses these values as coefficients to define a
271        //         polynomial f_i(x) = \sum_{j=0}^{t-1} a_{ij} x^{j} of degree t-1 over
272        //         ZZ_q.
273        let t: usize = parameters.t as usize;
274        let mut rng: OsRng = OsRng;
275        let mut coefficients: Vec<Scalar> = Vec::with_capacity(t);
276        let mut commitments: Vec<RistrettoPoint> = Vec::with_capacity(t);
277
278        for _ in 0..t {
279            coefficients.push(Scalar::random(&mut rng));
280        }
281
282        let coefficients = Coefficients(coefficients);
283
284        // Step 3: Every participant P_i computes a public commitment
285        //         C_i = [\phi_{i0}, ..., \phi_{i(t-1)}], where \phi_{ij} = g^{a_{ij}},
286        //         0 ≤ j ≤ t-1.
287        for j in 0..t {
288            commitments.push(&coefficients.0[j] * &RISTRETTO_BASEPOINT_TABLE);
289        }
290
291        // Yes, I know the steps are out of order.  It saves one scalar multiplication.
292
293        // Step 2: Every P_i computes a proof of knowledge to the corresponding secret
294        //         a_{i0} by calculating a Schnorr signature \alpha_i = (s, R).  (In
295        //         the FROST paper: \alpha_i = (\mu_i, c_i), but we stick with Schnorr's
296        //         original notation here.)
297        let proof: NizkOfSecretKey = NizkOfSecretKey::prove(&index, &coefficients.0[0], &commitments[0], rng);
298
299        // Step 4: Every participant P_i broadcasts C_i, \alpha_i to all other participants.
300        (Participant { index, commitments, proof_of_secret_key: proof }, coefficients)
301    }
302
303    /// Retrieve \\( \alpha_{i0} * B \\), where \\( B \\) is the Ristretto basepoint.
304    ///
305    /// This is used to pass into the final call to `DistributedKeyGeneration::<RoundTwo>.finish()`.
306    pub fn public_key(&self) -> Option<&RistrettoPoint> {
307        if !self.commitments.is_empty() {
308            return Some(&self.commitments[0]);
309        }
310        None
311    }
312}
313
314fn generate_shares(parameters: &Parameters, secret: Scalar, mut rng: OsRng) -> (Vec<DealtParticipant>, VerifiableSecretSharingCommitment) {
315    let mut participants: Vec<DealtParticipant> = Vec::with_capacity(parameters.n as usize);
316
317    // STEP 1: Every participant P_i samples t random values (a_{i0}, ..., a_{i(t-1)})
318    //         uniformly in ZZ_q, and uses these values as coefficients to define a
319    //         polynomial f_i(x) = \sum_{j=0}^{t-1} a_{ij} x^{j} of degree t-1 over
320    //         ZZ_q.
321    let t: usize = parameters.t as usize;
322    let mut coefficients: Vec<Scalar> = Vec::with_capacity(t as usize);
323    let mut commitment = VerifiableSecretSharingCommitment(Vec::with_capacity(t as usize));
324
325    coefficients.push(secret);
326    for _ in 0..t-1 {
327        coefficients.push(Scalar::random(&mut rng));
328    }
329
330    let coefficients = Coefficients(coefficients);
331
332    // Step 3: Every participant P_i computes a public commitment
333    //         C_i = [\phi_{i0}, ..., \phi_{i(t-1)}], where \phi_{ij} = g^{a_{ij}},
334    //         0 ≤ j ≤ t-1.
335    for j in 0..t {
336        commitment.0.push(&coefficients.0[j] * &RISTRETTO_BASEPOINT_TABLE);
337    }
338
339    // Generate secret shares here
340    let group_key = &RISTRETTO_BASEPOINT_TABLE * &coefficients.0[0];
341
342    // Only one polynomial because dealer, then secret shards are dependent upon index.
343    for i in 1..parameters.n + 1 {
344        let secret_share = SecretShare::evaluate_polynomial(&i, &coefficients);
345        let public_key = IndividualPublicKey {
346            index: i,
347            share: &RISTRETTO_BASEPOINT_TABLE * &secret_share.polynomial_evaluation,
348        };
349
350        participants.push(DealtParticipant { secret_share, public_key, group_key });
351    }
352    (participants, commitment)
353}
354
355impl PartialOrd for Participant {
356    fn partial_cmp(&self, other: &Participant) -> Option<Ordering> {
357        match self.index.cmp(&other.index) {
358            Ordering::Less => Some(Ordering::Less),
359            Ordering::Equal => None, // Participants cannot have the same index.
360            Ordering::Greater => Some(Ordering::Greater),
361        }
362    }
363}
364
365impl PartialEq for Participant {
366    fn eq(&self, other: &Participant) -> bool {
367        self.index == other.index
368    }
369}
370
371/// Module to implement trait sealing so that `DkgState` cannot be
372/// implemented for externally declared types.
373mod private {
374    pub trait Sealed {}
375
376    impl Sealed for super::RoundOne {}
377    impl Sealed for super::RoundTwo {}
378}
379
380/// State machine structures for holding intermediate values during a
381/// distributed key generation protocol run, to prevent misuse.
382#[derive(Clone, Debug)]
383pub struct DistributedKeyGeneration<S: DkgState> {
384    state: Box<ActualState>,
385    data: S,
386}
387
388/// Shared state which occurs across all rounds of a threshold signing protocol run.
389#[derive(Clone, Debug)]
390struct ActualState {
391    /// The parameters for this instantiation of a threshold signature.
392    parameters: Parameters,
393    /// A vector of tuples containing the index of each participant and that
394    /// respective participant's commitments to their private polynomial
395    /// coefficients.
396    their_commitments: Vec<(u32, VerifiableSecretSharingCommitment)>,
397    /// A secret share for this participant.
398    my_secret_share: SecretShare,
399    /// The secret shares this participant has calculated for all the other participants.
400    their_secret_shares: Option<Vec<SecretShare>>,
401    /// The secret shares this participant has received from all the other participants.
402    my_secret_shares: Option<Vec<SecretShare>>,
403}
404
405/// Marker trait to designate valid rounds in the distributed key generation
406/// protocol's state machine.  It is implemented using the [sealed trait design
407/// pattern][sealed] pattern to prevent external types from implementing further
408/// valid states.
409///
410/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
411pub trait DkgState: private::Sealed {}
412
413impl DkgState for RoundOne {}
414impl DkgState for RoundTwo {}
415
416/// Marker trait to designate valid variants of [`RoundOne`] in the distributed
417/// key generation protocol's state machine.  It is implemented using the
418/// [sealed trait design pattern][sealed] pattern to prevent external types from
419/// implementing further valid states.
420///
421/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
422pub trait Round1: private::Sealed {}
423
424/// Marker trait to designate valid variants of [`RoundTwo`] in the distributed
425/// key generation protocol's state machine.  It is implemented using the
426/// [sealed trait design pattern][sealed] pattern to prevent external types from
427/// implementing further valid states.
428///
429/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
430pub trait Round2: private::Sealed {}
431
432impl Round1 for RoundOne {}
433impl Round2 for RoundTwo {}
434
435/// Every participant in the distributed key generation has sent a vector of
436/// commitments and a zero-knowledge proof of a secret key to every other
437/// participant in the protocol.  During round one, each participant checks the
438/// zero-knowledge proofs of secret keys of all other participants.
439#[derive(Clone, Debug)]
440pub struct RoundOne {}
441
442impl DistributedKeyGeneration<RoundOne> {
443    /// Check the zero-knowledge proofs of knowledge of secret keys of all the
444    /// other participants.
445    ///
446    /// # Note
447    ///
448    /// The `participants` will be sorted by their indices.
449    ///
450    /// # Returns
451    ///
452    /// An updated state machine for the distributed key generation protocol if
453    /// all of the zero-knowledge proofs verified successfully, otherwise a
454    /// vector of participants whose zero-knowledge proofs were incorrect.
455    pub fn new(
456        parameters: &Parameters,
457        my_index: &u32,
458        my_coefficients: &Coefficients,
459        other_participants: &mut Vec<Participant>,
460    ) -> Result<Self, Vec<u32>>
461    {
462        let mut their_commitments: Vec<(u32, VerifiableSecretSharingCommitment)> = Vec::with_capacity(parameters.t as usize);
463        let mut misbehaving_participants: Vec<u32> = Vec::new();
464
465        // Bail if we didn't get enough participants.
466        if other_participants.len() != parameters.n as usize - 1 {
467            return Err(misbehaving_participants);
468        }
469
470        // Step 5: Upon receiving C_l, \sigma_l from participants 1 \le l \le n, l \ne i,
471        //         participant P_i verifies \sigma_l = (s_l, r_l), by checking:
472        //
473        //         s_l ?= H(l, \Phi, \phi_{l0}, g^{r_l} \mdot \phi_{l0}^{-s_i})
474        for p in other_participants.iter() {
475            let public_key = match p.commitments.get(0) {
476                Some(key) => key,
477                None      => {
478                    misbehaving_participants.push(p.index);
479                    continue;
480                }
481            };
482            match p.proof_of_secret_key.verify(&p.index, &public_key) {
483                Ok(_)  => their_commitments.push((p.index, VerifiableSecretSharingCommitment(p.commitments.clone()))),
484                Err(_) => misbehaving_participants.push(p.index),
485            }
486        }
487
488        // [DIFFERENT_TO_PAPER] If any participant was misbehaving, return their indices.
489        if !misbehaving_participants.is_empty() {
490            return Err(misbehaving_participants);
491        }
492
493        // [DIFFERENT_TO_PAPER] We pre-calculate the secret shares from Round 2
494        // Step 1 here since it doesn't require additional online activity.
495        //
496        // Round 2
497        // Step 1: Each P_i securely sends to each other participant P_l a secret share
498        //         (l, f_i(l)) and keeps (i, f_i(i)) for themselves.
499        let mut their_secret_shares: Vec<SecretShare> = Vec::with_capacity(parameters.n as usize - 1);
500
501        // XXX need a way to index their_secret_shares
502        for p in other_participants.iter() {
503            their_secret_shares.push(SecretShare::evaluate_polynomial(&p.index, my_coefficients));
504        }
505
506        let my_secret_share = SecretShare::evaluate_polynomial(my_index, my_coefficients);
507        let state = ActualState {
508            parameters: *parameters,
509            their_commitments,
510            my_secret_share,
511            their_secret_shares: Some(their_secret_shares),
512            my_secret_shares: None,
513        };
514
515        Ok(DistributedKeyGeneration::<RoundOne> {
516            state: Box::new(state),
517            data: RoundOne {},
518        })
519    }
520
521    /// Retrieve a secret share for each other participant, to be given to them
522    /// at the end of `DistributedKeyGeneration::<RoundOne>`.
523    pub fn their_secret_shares(&self) -> Result<&Vec<SecretShare>, ()> {
524        self.state.their_secret_shares.as_ref().ok_or(())
525    }
526
527    /// Progress to round two of the DKG protocol once we have sent each share
528    /// from `DistributedKeyGeneration::<RoundOne>.their_secret_shares()` to its
529    /// respective other participant, and collected our shares from the other
530    /// participants in turn.
531    #[allow(clippy::wrong_self_convention)]
532    pub fn to_round_two(
533        mut self,
534        my_secret_shares: Vec<SecretShare>,
535    ) -> Result<DistributedKeyGeneration<RoundTwo>, ()>
536    {
537        // Zero out the other participants secret shares from memory.
538        if self.state.their_secret_shares.is_some() {
539            self.state.their_secret_shares.unwrap().zeroize();
540            // XXX Does setting this to None always call drop()?
541            self.state.their_secret_shares = None;
542        }
543
544        if my_secret_shares.len() != self.state.parameters.n as usize - 1 {
545            return Err(());
546        }
547
548        // Step 2: Each P_i verifies their shares by calculating:
549        //         g^{f_l(i)} ?= \Prod_{k=0}^{t-1} \phi_{lk}^{i^{k} mod q},
550        //         aborting if the check fails.
551        for share in my_secret_shares.iter() {
552            // XXX TODO implement sorting for SecretShare and also for a new Commitment type
553            for (index, commitment) in self.state.their_commitments.iter() {
554                if index == &share.index {
555                    share.verify(commitment)?;
556                }
557            }
558        }
559        self.state.my_secret_shares = Some(my_secret_shares);
560
561        Ok(DistributedKeyGeneration::<RoundTwo> {
562            state: self.state,
563            data: RoundTwo {},
564        })
565    }
566}
567
568/// A secret share calculated by evaluating a polynomial with secret
569/// coefficients for some indeterminant.
570#[derive(Clone, Debug, Zeroize)]
571#[zeroize(drop)]
572pub struct SecretShare {
573    /// The participant index that this secret share was calculated for.
574    pub index: u32,
575    /// The final evaluation of the polynomial for the participant-respective
576    /// indeterminant.
577    pub(crate) polynomial_evaluation: Scalar,
578}
579
580impl SecretShare {
581    /// Evaluate the polynomial, `f(x)` for the secret coefficients at the value of `x`.
582    //
583    // XXX [PAPER] [CFRG] The participant index CANNOT be 0, or the secret share ends up being Scalar::zero().
584    pub(crate) fn evaluate_polynomial(index: &u32, coefficients: &Coefficients) -> SecretShare {
585        let term: Scalar = (*index).into();
586        let mut sum: Scalar = Scalar::zero();
587
588        // Evaluate using Horner's method.
589        for (index, coefficient) in coefficients.0.iter().rev().enumerate() {
590            // The secret is the constant term in the polynomial
591            sum += coefficient;
592
593            if index != (coefficients.0.len() - 1) {
594                sum *= term;
595            }
596        }
597        SecretShare { index: *index, polynomial_evaluation: sum }
598    }
599
600    /// Verify that this secret share was correctly computed w.r.t. some secret
601    /// polynomial coefficients attested to by some `commitment`.
602    pub(crate) fn verify(&self, commitment: &VerifiableSecretSharingCommitment) -> Result<(), ()> {
603        let lhs = &RISTRETTO_BASEPOINT_TABLE * &self.polynomial_evaluation;
604        let term: Scalar = self.index.into();
605        let mut rhs: RistrettoPoint = RistrettoPoint::identity();
606
607        for (index, com) in commitment.0.iter().rev().enumerate() {
608            rhs += com;
609
610            if index != (commitment.0.len() - 1) {
611                rhs *= term;
612            }
613        }
614
615        match lhs.compress() == rhs.compress() {
616            true => Ok(()),
617            false => Err(()),
618        }
619    }
620}
621
622/// During round two each participant verifies their secret shares they received
623/// from each other participant.
624#[derive(Clone, Debug)]
625pub struct RoundTwo {}
626
627impl DistributedKeyGeneration<RoundTwo> {
628    /// Calculate this threshold signing protocol participant's long-lived
629    /// secret signing keyshare and the group's public verification key.
630    ///
631    /// # Example
632    ///
633    /// ```ignore
634    /// let (group_key, secret_key) = state.finish(participant.public_key()?)?;
635    /// ```
636    pub fn finish(mut self, my_commitment: &RistrettoPoint) -> Result<(GroupKey, SecretKey), ()> {
637        let secret_key = self.calculate_signing_key()?;
638        let group_key = self.calculate_group_key(my_commitment)?;
639
640        self.state.my_secret_share.zeroize();
641        self.state.my_secret_shares.zeroize();
642
643        Ok((group_key, secret_key))
644    }
645
646    /// Calculate this threshold signing participant's long-lived secret signing
647    /// key by summing all of the polynomial evaluations from the other
648    /// participants.
649    pub(crate) fn calculate_signing_key(&self) -> Result<SecretKey, ()> {
650        let my_secret_shares = self.state.my_secret_shares.as_ref().ok_or(())?;
651        let mut key = my_secret_shares.iter().map(|x| x.polynomial_evaluation).sum();
652
653        key += self.state.my_secret_share.polynomial_evaluation;
654
655        Ok(SecretKey { index: self.state.my_secret_share.index, key })
656    }
657
658    /// Calculate the group public key used for verifying threshold signatures.
659    ///
660    /// # Returns
661    ///
662    /// A [`GroupKey`] for the set of participants.
663    pub(crate) fn calculate_group_key(&self, my_commitment: &RistrettoPoint) -> Result<GroupKey, ()> {
664        let mut keys: Vec<RistrettoPoint> = Vec::with_capacity(self.state.parameters.n as usize);
665
666        for commitment in self.state.their_commitments.iter() {
667            match commitment.1.0.get(0) {
668                Some(key) => keys.push(*key),
669                None => return Err(()),
670            }
671        }
672        keys.push(*my_commitment);
673
674        Ok(GroupKey(keys.iter().sum()))
675    }
676}
677
678/// A public verification share for a participant.
679///
680/// Any participant can recalculate the public verification share, which is the
681/// public half of a [`SecretKey`], of any other participant in the protocol.
682#[derive(Clone, Debug)]
683pub struct IndividualPublicKey {
684    /// The participant index to which this key belongs.
685    pub index: u32,
686    /// The public verification share.
687    pub share: RistrettoPoint,
688}
689
690impl IndividualPublicKey {
691    /// Any participant can compute the public verification share of any other participant.
692    ///
693    /// This is done by re-computing each [`IndividualPublicKey`] as \\(Y\_i\\) s.t.:
694    ///
695    /// \\[
696    /// Y\_i = \prod\_{j=1}^{n} \prod\_{k=0}^{t-1} \phi\_{jk}^{i^{k} \mod q}
697    /// \\]
698    ///
699    /// for each [`Participant`] index \\(i\\).
700    ///
701    /// # Inputs
702    ///
703    /// * The [`Parameters`] of this threshold signing instance, and
704    /// * A vector of `commitments` regarding the secret polynomial
705    ///   [`Coefficients`] that this [`IndividualPublicKey`] was generated with.
706    ///
707    /// # Returns
708    ///
709    /// A `Result` with either an empty `Ok` or `Err` value, depending on
710    /// whether or not the verification was successful.
711    #[allow(unused)]
712    pub fn verify(
713        &self,
714        parameters: &Parameters,
715        commitments: &[RistrettoPoint],
716    ) -> Result<(), ()>
717    {
718        let rhs = RistrettoPoint::identity();
719
720        for j in 1..parameters.n {
721            for k in 0..parameters.t {
722                // XXX ah shit we need the incoming commitments to be sorted or have indices
723            }
724        }
725        unimplemented!()
726    }
727}
728
729/// A secret key, used by one participant in a threshold signature scheme, to sign a message.
730#[derive(Debug, Zeroize)]
731#[zeroize(drop)]
732pub struct SecretKey {
733    /// The participant index to which this key belongs.
734    pub(crate) index: u32,
735    /// The participant's long-lived secret share of the group signing key.
736    pub(crate) key: Scalar,
737}
738
739impl SecretKey {
740    /// Derive the corresponding public key for this secret key.
741    pub fn to_public(&self) -> IndividualPublicKey {
742        let share = &RISTRETTO_BASEPOINT_TABLE * &self.key;
743
744        IndividualPublicKey {
745            index: self.index,
746            share,
747        }
748    }
749}
750
751impl From<&SecretKey> for IndividualPublicKey {
752    fn from(source: &SecretKey) -> IndividualPublicKey {
753        source.to_public()
754    }
755}
756
757/// A public key, used to verify a signature made by a threshold of a group of participants.
758#[derive(Clone, Copy, Debug, Eq)]
759pub struct GroupKey(pub(crate) RistrettoPoint);
760
761impl PartialEq for GroupKey {
762    fn eq(&self, other: &Self) -> bool {
763        self.0.compress() == other.0.compress()
764    }
765}
766
767impl GroupKey {
768    /// Serialise this group public key to an array of bytes.
769    pub fn to_bytes(&self) -> [u8; 32] {
770        self.0.compress().to_bytes()
771    }
772
773    /// Deserialise this group public key from an array of bytes.
774    pub fn from_bytes(bytes: [u8; 32]) -> Result<GroupKey, ()> {
775        let point = CompressedRistretto(bytes).decompress().ok_or(())?;
776
777        Ok(GroupKey(point))
778    }
779}
780
781#[cfg(test)]
782mod test {
783    use super::*;
784
785    #[cfg(feature = "std")]
786    use crate::precomputation::generate_commitment_share_lists;
787
788    #[cfg(feature = "std")]
789    use crate::signature::{calculate_lagrange_coefficients, compute_message_hash};
790    #[cfg(feature = "std")]
791    use crate::signature::SignatureAggregator;
792
793    #[cfg(feature = "std")]
794    /// Reconstruct the secret from enough (at least the threshold) already-verified shares.
795    fn reconstruct_secret(participants: &Vec<&DealtParticipant>) -> Result<Scalar, &'static str> {
796        let all_participant_indices: Vec<u32> = participants.iter().map(|p| p.public_key.index).collect();
797        let mut secret = Scalar::zero();
798
799        for this_participant in participants {
800            let my_coeff = calculate_lagrange_coefficients(&this_participant.public_key.index,
801                                                           &all_participant_indices)?;
802
803            secret += my_coeff * this_participant.secret_share.polynomial_evaluation;
804        }
805        Ok(secret)
806    }
807
808    #[test]
809    fn nizk_of_secret_key() {
810        let params = Parameters { n: 3, t: 2 };
811        let (p, _) = Participant::new(&params, 0);
812        let result = p.proof_of_secret_key.verify(&p.index, &p.commitments[0]);
813
814        assert!(result.is_ok());
815    }
816
817    #[cfg(feature = "std")]
818    #[test]
819    fn verify_secret_sharing_from_dealer() {
820        let params = Parameters { n: 3, t: 2 };
821        let mut rng: OsRng = OsRng;
822        let secret = Scalar::random(&mut rng);
823        let (participants, _commitment) = generate_shares(&params, secret, rng);
824
825        let mut subset_participants = Vec::new();
826        for i in 0..params.t{
827            subset_participants.push(&participants[i as usize]);
828        }
829        let supposed_secret = reconstruct_secret(&subset_participants);
830        assert!(secret == supposed_secret.unwrap());
831    }
832
833    #[test]
834    fn dkg_with_dealer() {
835        let params = Parameters { t: 1, n: 2 };
836        let (participants, commitment) = Participant::dealer(&params);
837        let (_, commitment2) = Participant::dealer(&params);
838
839        // Verify each of the participants' secret shares.
840        for p in participants.iter() {
841            let result = p.secret_share.verify(&commitment);
842
843            assert!(result.is_ok(), "participant {} failed to receive a valid secret share", p.public_key.index);
844
845            let result = p.secret_share.verify(&commitment2);
846
847            assert!(!result.is_ok(), "Should not validate with invalid commitment");
848        }
849    }
850
851    #[cfg(feature = "std")]
852    #[test]
853    fn dkg_with_dealer_and_signing() {
854        let params = Parameters { t: 1, n: 2 };
855        let (participants, commitment) = Participant::dealer(&params);
856
857        // Verify each of the participants' secret shares.
858        for p in participants.iter() {
859            let result = p.secret_share.verify(&commitment);
860
861            assert!(result.is_ok(), "participant {} failed to receive a valid secret share", p.public_key.index);
862        }
863
864        let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
865        let message = b"This is a test of the tsunami alert system. This is only a test.";
866        let (p1_public_comshares, mut p1_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 1, 1);
867        let (p2_public_comshares, mut p2_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 2, 1);
868
869        let p1_sk = SecretKey {
870            index: participants[0].secret_share.index,
871            key: participants[0].secret_share.polynomial_evaluation,
872        };
873        let p2_sk = SecretKey {
874            index: participants[1].secret_share.index,
875            key: participants[1].secret_share.polynomial_evaluation,
876        };
877
878        let group_key = GroupKey(participants[0].group_key);
879
880        let mut aggregator = SignatureAggregator::new(params, group_key, &context[..], &message[..]);
881
882        aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
883        aggregator.include_signer(2, p2_public_comshares.commitments[0], (&p2_sk).into());
884
885        let signers = aggregator.get_signers();
886        let message_hash = compute_message_hash(&context[..], &message[..]);
887
888        let p1_partial = p1_sk.sign(&message_hash, &group_key, &mut p1_secret_comshares, 0, signers).unwrap();
889        let p2_partial = p2_sk.sign(&message_hash, &group_key, &mut p2_secret_comshares, 0, signers).unwrap();
890
891        aggregator.include_partial_signature(p1_partial);
892        aggregator.include_partial_signature(p2_partial);
893
894        let aggregator = aggregator.finalize().unwrap();
895        let signing_result = aggregator.aggregate();
896
897        assert!(signing_result.is_ok());
898
899        let threshold_signature = signing_result.unwrap();
900
901        let verification_result = threshold_signature.verify(&group_key, &message_hash);
902
903        println!("{:?}", verification_result);
904
905        assert!(verification_result.is_ok());
906    }
907
908    #[test]
909    fn secret_share_from_one_coefficients() {
910        let mut coeffs: Vec<Scalar> = Vec::new();
911
912        for _ in 0..5 {
913            coeffs.push(Scalar::one());
914        }
915
916        let coefficients = Coefficients(coeffs);
917        let share = SecretShare::evaluate_polynomial(&1, &coefficients);
918
919        assert!(share.polynomial_evaluation == Scalar::from(5u8));
920
921        let mut commitments = VerifiableSecretSharingCommitment(Vec::new());
922
923        for i in 0..5 {
924            commitments.0.push(&RISTRETTO_BASEPOINT_TABLE * &coefficients.0[i]);
925        }
926
927        assert!(share.verify(&commitments).is_ok());
928    }
929
930    #[test]
931    fn secret_share_participant_index_zero() {
932        let mut coeffs: Vec<Scalar> = Vec::new();
933
934        for _ in 0..5 {
935            coeffs.push(Scalar::one());
936        }
937
938        let coefficients = Coefficients(coeffs);
939        let share = SecretShare::evaluate_polynomial(&0, &coefficients);
940
941        assert!(share.polynomial_evaluation == Scalar::one());
942
943        let mut commitments = VerifiableSecretSharingCommitment(Vec::new());
944
945        for i in 0..5 {
946            commitments.0.push(&RISTRETTO_BASEPOINT_TABLE * &coefficients.0[i]);
947        }
948
949        assert!(share.verify(&commitments).is_ok());
950    }
951
952    #[test]
953    fn single_party_keygen() {
954        let params = Parameters { n: 1, t: 1 };
955
956        let (p1, p1coeffs) = Participant::new(&params, 1);
957
958        p1.proof_of_secret_key.verify(&p1.index, &p1.commitments[0]).unwrap();
959
960        let mut p1_other_participants: Vec<Participant> = Vec::new();
961        let p1_state = DistributedKeyGeneration::<RoundOne>::new(&params,
962                                                                 &p1.index,
963                                                                 &p1coeffs,
964                                                                 &mut p1_other_participants).unwrap();
965        let p1_my_secret_shares = Vec::new();
966        let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
967        let result = p1_state.finish(p1.public_key().unwrap());
968
969        assert!(result.is_ok());
970
971        let (p1_group_key, p1_secret_key) = result.unwrap();
972
973        assert!(p1_group_key.0.compress() == (&p1_secret_key.key * &RISTRETTO_BASEPOINT_TABLE).compress());
974    }
975
976    #[test]
977    fn keygen_3_out_of_5() {
978        let params = Parameters { n: 5, t: 3 };
979
980        let (p1, p1coeffs) = Participant::new(&params, 1);
981        let (p2, p2coeffs) = Participant::new(&params, 2);
982        let (p3, p3coeffs) = Participant::new(&params, 3);
983        let (p4, p4coeffs) = Participant::new(&params, 4);
984        let (p5, p5coeffs) = Participant::new(&params, 5);
985
986        p1.proof_of_secret_key.verify(&p1.index, &p1.public_key().unwrap()).unwrap();
987        p2.proof_of_secret_key.verify(&p2.index, &p2.public_key().unwrap()).unwrap();
988        p3.proof_of_secret_key.verify(&p3.index, &p3.public_key().unwrap()).unwrap();
989        p4.proof_of_secret_key.verify(&p4.index, &p4.public_key().unwrap()).unwrap();
990        p5.proof_of_secret_key.verify(&p5.index, &p5.public_key().unwrap()).unwrap();
991
992        let mut p1_other_participants: Vec<Participant> = vec!(p2.clone(), p3.clone(), p4.clone(), p5.clone());
993        let p1_state = DistributedKeyGeneration::<RoundOne>::new(&params,
994                                                                 &p1.index,
995                                                                 &p1coeffs,
996                                                                 &mut p1_other_participants).unwrap();
997        let p1_their_secret_shares = p1_state.their_secret_shares().unwrap();
998
999        let mut p2_other_participants: Vec<Participant> = vec!(p1.clone(), p3.clone(), p4.clone(), p5.clone());
1000        let p2_state = DistributedKeyGeneration::<RoundOne>::new(&params,
1001                                                                 &p2.index,
1002                                                                 &p2coeffs,
1003                                                                 &mut p2_other_participants).unwrap();
1004        let p2_their_secret_shares = p2_state.their_secret_shares().unwrap();
1005
1006        let mut p3_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p4.clone(), p5.clone());
1007        let  p3_state = DistributedKeyGeneration::<RoundOne>::new(&params,
1008                                                                  &p3.index,
1009                                                                  &p3coeffs,
1010                                                                  &mut p3_other_participants).unwrap();
1011        let p3_their_secret_shares = p3_state.their_secret_shares().unwrap();
1012
1013        let mut p4_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p3.clone(), p5.clone());
1014        let p4_state = DistributedKeyGeneration::<RoundOne>::new(&params,
1015                                                                 &p4.index,
1016                                                                 &p4coeffs,
1017                                                                 &mut p4_other_participants).unwrap();
1018        let p4_their_secret_shares = p4_state.their_secret_shares().unwrap();
1019
1020        let mut p5_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p3.clone(), p4.clone());
1021        let p5_state = DistributedKeyGeneration::<RoundOne>::new(&params,
1022                                                                 &p5.index,
1023                                                                 &p5coeffs,
1024                                                                 &mut p5_other_participants).unwrap();
1025        let p5_their_secret_shares = p5_state.their_secret_shares().unwrap();
1026
1027        let p1_my_secret_shares = vec!(p2_their_secret_shares[0].clone(), // XXX FIXME indexing
1028                                       p3_their_secret_shares[0].clone(),
1029                                       p4_their_secret_shares[0].clone(),
1030                                       p5_their_secret_shares[0].clone());
1031
1032        let p2_my_secret_shares = vec!(p1_their_secret_shares[0].clone(),
1033                                       p3_their_secret_shares[1].clone(),
1034                                       p4_their_secret_shares[1].clone(),
1035                                       p5_their_secret_shares[1].clone());
1036
1037        let p3_my_secret_shares = vec!(p1_their_secret_shares[1].clone(),
1038                                       p2_their_secret_shares[1].clone(),
1039                                       p4_their_secret_shares[2].clone(),
1040                                       p5_their_secret_shares[2].clone());
1041
1042        let p4_my_secret_shares = vec!(p1_their_secret_shares[2].clone(),
1043                                       p2_their_secret_shares[2].clone(),
1044                                       p3_their_secret_shares[2].clone(),
1045                                       p5_their_secret_shares[3].clone());
1046
1047        let p5_my_secret_shares = vec!(p1_their_secret_shares[3].clone(),
1048                                       p2_their_secret_shares[3].clone(),
1049                                       p3_their_secret_shares[3].clone(),
1050                                       p4_their_secret_shares[3].clone());
1051
1052        let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
1053        let p2_state = p2_state.to_round_two(p2_my_secret_shares).unwrap();
1054        let p3_state = p3_state.to_round_two(p3_my_secret_shares).unwrap();
1055        let p4_state = p4_state.to_round_two(p4_my_secret_shares).unwrap();
1056        let p5_state = p5_state.to_round_two(p5_my_secret_shares).unwrap();
1057
1058        let (p1_group_key, _p1_secret_key) = p1_state.finish(p1.public_key().unwrap()).unwrap();
1059        let (p2_group_key, _p2_secret_key) = p2_state.finish(p2.public_key().unwrap()).unwrap();
1060        let (p3_group_key, _p3_secret_key) = p3_state.finish(p3.public_key().unwrap()).unwrap();
1061        let (p4_group_key, _p4_secret_key) = p4_state.finish(p4.public_key().unwrap()).unwrap();
1062        let (p5_group_key, _p5_secret_key) = p5_state.finish(p5.public_key().unwrap()).unwrap();
1063
1064        assert!(p1_group_key.0.compress() == p2_group_key.0.compress());
1065        assert!(p2_group_key.0.compress() == p3_group_key.0.compress());
1066        assert!(p3_group_key.0.compress() == p4_group_key.0.compress());
1067        assert!(p4_group_key.0.compress() == p5_group_key.0.compress());
1068
1069        assert!(p5_group_key.0.compress() ==
1070                (p1.public_key().unwrap() +
1071                 p2.public_key().unwrap() +
1072                 p3.public_key().unwrap() +
1073                 p4.public_key().unwrap() +
1074                 p5.public_key().unwrap()).compress());
1075    }
1076
1077
1078    #[test]
1079    fn keygen_2_out_of_3() {
1080        fn do_test() -> Result<(), ()> {
1081            let params = Parameters { n: 3, t: 2 };
1082
1083            let (p1, p1coeffs) = Participant::new(&params, 1);
1084            let (p2, p2coeffs) = Participant::new(&params, 2);
1085            let (p3, p3coeffs) = Participant::new(&params, 3);
1086
1087            p1.proof_of_secret_key.verify(&p1.index, &p1.public_key().unwrap())?;
1088            p2.proof_of_secret_key.verify(&p2.index, &p2.public_key().unwrap())?;
1089            p3.proof_of_secret_key.verify(&p3.index, &p3.public_key().unwrap())?;
1090
1091            let mut p1_other_participants: Vec<Participant> = vec!(p2.clone(), p3.clone());
1092            let p1_state = DistributedKeyGeneration::<RoundOne>::new(&params,
1093                                                                     &p1.index,
1094                                                                     &p1coeffs,
1095                                                                     &mut p1_other_participants).or(Err(()))?;
1096            let p1_their_secret_shares = p1_state.their_secret_shares()?;
1097
1098            let mut p2_other_participants: Vec<Participant> = vec!(p1.clone(), p3.clone());
1099            let p2_state = DistributedKeyGeneration::<RoundOne>::new(&params,
1100                                                                     &p2.index,
1101                                                                     &p2coeffs,
1102                                                                     &mut p2_other_participants).or(Err(()))?;
1103            let p2_their_secret_shares = p2_state.their_secret_shares()?;
1104
1105            let mut p3_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone());
1106            let  p3_state = DistributedKeyGeneration::<RoundOne>::new(&params,
1107                                                                      &p3.index,
1108                                                                      &p3coeffs,
1109                                                                      &mut p3_other_participants).or(Err(()))?;
1110            let p3_their_secret_shares = p3_state.their_secret_shares()?;
1111
1112            let p1_my_secret_shares = vec!(p2_their_secret_shares[0].clone(), // XXX FIXME indexing
1113                                           p3_their_secret_shares[0].clone());
1114            let p2_my_secret_shares = vec!(p1_their_secret_shares[0].clone(),
1115                                           p3_their_secret_shares[1].clone());
1116            let p3_my_secret_shares = vec!(p1_their_secret_shares[1].clone(),
1117                                           p2_their_secret_shares[1].clone());
1118
1119            let p1_state = p1_state.to_round_two(p1_my_secret_shares)?;
1120            let p2_state = p2_state.to_round_two(p2_my_secret_shares)?;
1121            let p3_state = p3_state.to_round_two(p3_my_secret_shares)?;
1122
1123            let (p1_group_key, _p1_secret_key) = p1_state.finish(p1.public_key().unwrap())?;
1124            let (p2_group_key, _p2_secret_key) = p2_state.finish(p2.public_key().unwrap())?;
1125            let (p3_group_key, _p3_secret_key) = p3_state.finish(p3.public_key().unwrap())?;
1126
1127            assert!(p1_group_key.0.compress() == p2_group_key.0.compress());
1128            assert!(p2_group_key.0.compress() == p3_group_key.0.compress());
1129
1130            Ok(())
1131        }
1132        assert!(do_test().is_ok());
1133    }
1134}