Skip to main content

dkls23_core/protocols/
refresh.rs

1//! Protocols for refreshing key shares when wanted/needed.
2//!
3//! This file implements a refresh protocol: periodically, all parties
4//! engage in a protocol to re-randomize their secret values (while, of
5//! course, still maintaining the same public key).
6//!
7//! The most direct way of doing this is simply executing DKG and restricting
8//! the possible random values so that we don't change our address. We
9//! implement this procedure under the name of "complete refresh".
10//!
11//! DKG also initializes the multiplication protocol, but we may take
12//! advantage of the fact the we have already initialized this protocol
13//! before. If we use this data for refresh, we don't need to execute
14//! the OT protocols and we may save some time and some rounds. This
15//! approach is implemented in another refresh protocol.
16//!
17//! ATTENTION: The protocols here work for any instance of Party, including
18//! for derived addresses. However, refreshing a derivation is not such a
19//! good idea because the refreshed derivation becomes essentially independent
20//! of the master node. We recommend that only master nodes are refreshed
21//! and derivations are calculated as needed afterwards.
22//!
23//! # Complete refresh
24//!
25//! In this case, we recompute all data from the parties. Hence, we essentially
26//! rerun DKG but we force the final public key to be the original one.
27//!
28//! To adapt the DKG protocol, we change [Step 1](super::dkg::step1): instead of sampling any random
29//! polynomial, each party generates a polynomial whose constant term is zero.
30//! In this way, the key generation provides each party with a point on a polynomial
31//! whose constant term (the "secret key") is zero. This new point is just a correction
32//! factor and must be added to the original `poly_point` variable. This refreshes each
33//! key share while preserving the same public key.
34//!
35//! Each party cannot trust that their adversaries really chose a polynomial
36//! with zero constant term. Therefore, we must add a new consistency check in
37//! [Phase 4](super::dkg::phase4): after recovering the auxiliary public key, each party must check that
38//! it is equal to the zero point on the curve. This ensures that the correction
39//! factors will not change the public key.
40//!
41//! # A faster refresh
42//!
43//! During a complete refresh, we initialize the multiplication protocol
44//! from scratch. Instead, we can use our previous data to more efficiently
45//! refresh this initialization. This results in a faster refresh and,
46//! depending on the multiplication protocol, fewer communication rounds.
47//!
48//! We will base this implementation on the article "Refresh When You Wake Up:
49//! Proactive Threshold Wallets with Offline Devices" (<https://eprint.iacr.org/2019/1328.pdf>)
50//! More specifically, we use their ideas from Section 8 (and Appendix E).
51//!
52//! In their protocol, a common random string is sampled by each pair of
53//! parties. They achieve this by using their "coin tossing functionality".
54//! Note that their suggestion of implementation for this functionality is
55//! very similar to the way our zero shares protocol computes its seeds.
56//!
57//! Hence, our new refresh protocol will work as follows: we run DKG
58//! ignoring any procedure related to the multiplication protocol (and we
59//! do the same modifications we did for the complete refresh). During
60//! the fourth phase, the initialization for the zero shares protocol
61//! generates its seeds. We reuse them to apply the Beaver trick (described
62//! in the article) to refresh the OT instances used for multiplication.
63//!
64//! # Nomenclature
65//!
66//! For the messages structs, we will use the following nomenclature:
67//!
68//! **Transmit** messages refer to only one counterparty, hence
69//! we must produce a whole vector of them. Each message in this
70//! vector contains the party index to whom we should send it.
71//!
72//! **Broadcast** messages refer to all counterparties at once,
73//! hence we only need to produce a unique instance of it.
74//! This message is broadcasted to all parties.
75//!
76//! ATTENTION: we broadcast the message to ourselves as well!
77//!
78//! **Keep** messages refer to only one counterparty, hence
79//! we must keep a whole vector of them. In this implementation,
80//! we use a `BTreeMap` instead of a vector, where one can put
81//! some party index in the key to retrieve the corresponding data.
82//!
83//! **Unique keep** messages refer to all counterparties at once,
84//! hence we only need to keep a unique instance of it.
85
86use std::collections::BTreeMap;
87
88use rustcrypto_ff::Field;
89
90use crate::curve::DklsCurve;
91use crate::utilities::hashes::{tagged_hash, HashOutput};
92use crate::utilities::multiplication::{MulReceiver, MulSender};
93use crate::utilities::oracle_tags::{TAG_REFRESH_FAST_B, TAG_REFRESH_FAST_R0, TAG_REFRESH_FAST_R1};
94use crate::utilities::ot;
95use crate::utilities::rng;
96use crate::utilities::zero_shares::{self, ZeroShare};
97
98use crate::protocols::derivation::DerivData;
99use crate::protocols::dkg::{
100    step2, step3, step5, KeepInitMulPhase3to4, KeepInitZeroSharePhase2to3,
101    KeepInitZeroSharePhase3to4, ProofCommitment, TransmitInitMulPhase3to4,
102    TransmitInitZeroSharePhase2to4, TransmitInitZeroSharePhase3to4,
103};
104use crate::protocols::{Abort, AbortReason, PartiesMessage, Party, PartyIndex};
105
106// STRUCTS FOR MESSAGES TO TRANSMIT IN COMMUNICATION ROUNDS.
107
108// "Transmit" messages refer to only one counterparty, hence
109// we must send a whole vector of them.
110
111/// Transmit - (Faster) Refresh.
112///
113/// The message is produced/sent during Phase 2 and used in Phase 4.
114#[derive(Clone, Debug)]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116pub struct TransmitRefreshPhase2to4 {
117    pub parties: PartiesMessage,
118    pub commitment: HashOutput,
119}
120
121/// Transmit - (Faster) Refresh.
122///
123/// The message is produced/sent during Phase 3 and used in Phase 4.
124#[derive(Clone, Debug)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126pub struct TransmitRefreshPhase3to4 {
127    pub parties: PartiesMessage,
128    pub seed: zero_shares::Seed,
129    pub salt: Vec<u8>,
130}
131
132// STRUCTS FOR MESSAGES TO KEEP BETWEEN PHASES.
133
134/// Keep - (Faster) Refresh.
135///
136/// The message is produced during Phase 2 and used in Phase 3.
137#[derive(Clone, Debug)]
138#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
139pub struct KeepRefreshPhase2to3 {
140    pub seed: zero_shares::Seed,
141    pub salt: Vec<u8>,
142}
143
144/// Keep - (Faster) Refresh.
145///
146/// The message is produced during Phase 3 and used in Phase 4.
147#[derive(Clone, Debug)]
148#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
149pub struct KeepRefreshPhase3to4 {
150    pub seed: zero_shares::Seed,
151}
152
153// MessageTag implementations.
154#[cfg(feature = "serde")]
155mod message_tags {
156    use super::*;
157    use crate::protocols::messages::MessageTag;
158
159    impl MessageTag for TransmitRefreshPhase2to4 {
160        const TAG: u8 = 0x20;
161    }
162    impl MessageTag for TransmitRefreshPhase3to4 {
163        const TAG: u8 = 0x21;
164    }
165}
166
167/// Implementations related to refresh protocols ([read more](self)).
168impl<C: DklsCurve> Party<C> {
169    // COMPLETE REFRESH
170
171    /// Works as [Phase 1](super::dkg::phase1) in DKG, but with
172    /// the alterations needed for the refresh protocol.
173    ///
174    /// The output should be dealt in the same way.
175    #[must_use]
176    pub fn refresh_complete_phase1(&self) -> Vec<C::Scalar> {
177        // We run Phase 1 in DKG, but we force the constant term in Step 1 to be zero.
178
179        // DKG
180        let mut secret_polynomial: Vec<C::Scalar> =
181            Vec::with_capacity(self.parameters.threshold as usize);
182        secret_polynomial.push(C::Scalar::ZERO);
183        for _ in 1..self.parameters.threshold {
184            secret_polynomial.push(C::Scalar::random(&mut rng::get_rng()));
185        }
186
187        step2::<C>(&self.parameters, &secret_polynomial)
188    }
189
190    /// Works as [Phase 2](super::dkg::phase2) in DKG, but the
191    /// derivation part is omitted.
192    ///
193    /// The output should be dealt in the same way. The only
194    /// difference is that we will refer to the scalar`poly_point`
195    /// as `correction_value`.
196    #[must_use]
197    pub fn refresh_complete_phase2(
198        &self,
199        refresh_sid: &[u8],
200        poly_fragments: &[C::Scalar],
201    ) -> (
202        C::Scalar,
203        ProofCommitment<C>,
204        BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>,
205        Vec<TransmitInitZeroSharePhase2to4>,
206    ) {
207        // We run Phase 2 in DKG, but we omit the derivation part.
208        // Note that "poly_point" is now called "correction_value".
209        // It will be used to correct self.poly_point.
210
211        // DKG
212        let (correction_value, proof_commitment) =
213            step3::<C>(self.party_index, refresh_sid, poly_fragments);
214
215        // Initialization - Zero shares.
216
217        // We will use BTreeMap to keep messages: the key indicates the party to whom the message refers.
218        let mut zero_keep: BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3> = BTreeMap::new();
219        let mut zero_transmit: Vec<TransmitInitZeroSharePhase2to4> =
220            Vec::with_capacity((self.parameters.share_count - 1) as usize);
221        for i in 1..=self.parameters.share_count {
222            let i_idx = PartyIndex::new(i).unwrap();
223            if i_idx == self.party_index {
224                continue;
225            }
226
227            // Generate initial seeds.
228            let (seed, commitment, salt) = ZeroShare::generate_seed_with_commitment();
229
230            // We first send the commitments. We keep the rest to send later.
231            let keep = KeepInitZeroSharePhase2to3 { seed, salt };
232            let transmit = TransmitInitZeroSharePhase2to4 {
233                parties: PartiesMessage {
234                    sender: self.party_index,
235                    receiver: i_idx,
236                },
237                commitment,
238            };
239
240            zero_keep.insert(i_idx, keep);
241            zero_transmit.push(transmit);
242        }
243
244        (correction_value, proof_commitment, zero_keep, zero_transmit)
245    }
246
247    /// Works as [Phase 3](super::dkg::phase3) in DKG, but the
248    /// derivation part is omitted.
249    ///
250    /// The output should be dealt in the same way.
251    #[must_use]
252    #[allow(clippy::type_complexity)]
253    pub fn refresh_complete_phase3(
254        &self,
255        refresh_sid: &[u8],
256        zero_kept: &BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>,
257    ) -> (
258        BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>,
259        Vec<TransmitInitZeroSharePhase3to4>,
260        BTreeMap<PartyIndex, KeepInitMulPhase3to4<C>>,
261        Vec<TransmitInitMulPhase3to4<C>>,
262    ) {
263        // We run Phase 3 in DKG, but we omit the derivation part.
264
265        // Initialization - Zero shares.
266        let mut zero_keep: BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4> = BTreeMap::new();
267        let mut zero_transmit: Vec<TransmitInitZeroSharePhase3to4> =
268            Vec::with_capacity((self.parameters.share_count - 1) as usize);
269        for (target_party, message_kept) in zero_kept {
270            // The messages kept contain the seed and the salt.
271            // They have to be transmitted to the target party.
272            // We keep the seed with us for the next phase.
273            let keep = KeepInitZeroSharePhase3to4 {
274                seed: message_kept.seed,
275            };
276            let transmit = TransmitInitZeroSharePhase3to4 {
277                parties: PartiesMessage {
278                    sender: self.party_index,
279                    receiver: *target_party,
280                },
281                seed: message_kept.seed,
282                salt: message_kept.salt.clone(),
283            };
284
285            zero_keep.insert(*target_party, keep);
286            zero_transmit.push(transmit);
287        }
288
289        // Initialization - Two-party multiplication.
290        // Each party prepares initialization both as
291        // a receiver and as a sender.
292        let mut mul_keep: BTreeMap<PartyIndex, KeepInitMulPhase3to4<C>> = BTreeMap::new();
293        let mut mul_transmit: Vec<TransmitInitMulPhase3to4<C>> =
294            Vec::with_capacity((self.parameters.share_count - 1) as usize);
295        for i in 1..=self.parameters.share_count {
296            let i_idx = PartyIndex::new(i).unwrap();
297            if i_idx == self.party_index {
298                continue;
299            }
300
301            // RECEIVER
302            // We are the receiver and i = sender.
303
304            // We first compute a new session id.
305            // As in Protocol 3.6 of DKLs23, we include the indexes from the parties.
306            let mul_sid_receiver = [
307                "Multiplication protocol".as_bytes(),
308                &self.party_index.as_u8().to_be_bytes(),
309                &i.to_be_bytes(),
310                refresh_sid,
311            ]
312            .concat();
313
314            let (ot_sender, dlog_proof, nonce) = MulReceiver::<C>::init_phase1(&mul_sid_receiver);
315
316            // SENDER
317            // We are the sender and i = receiver.
318
319            // New session id as above.
320            // Note that the indexes are now in the opposite order.
321            let mul_sid_sender = [
322                "Multiplication protocol".as_bytes(),
323                &i.to_be_bytes(),
324                &self.party_index.as_u8().to_be_bytes(),
325                refresh_sid,
326            ]
327            .concat();
328
329            let (ot_receiver, correlation, vec_r, enc_proofs) =
330                MulSender::<C>::init_phase1(&mul_sid_sender);
331
332            // We gather these values.
333
334            let transmit = TransmitInitMulPhase3to4 {
335                parties: PartiesMessage {
336                    sender: self.party_index,
337                    receiver: i_idx,
338                },
339
340                // Us = Receiver
341                dlog_proof,
342                nonce,
343
344                // Us = Sender
345                enc_proofs,
346                seed: ot_receiver.seed,
347            };
348            let keep = KeepInitMulPhase3to4 {
349                // Us = Receiver
350                ot_sender,
351                nonce,
352
353                // Us = Sender
354                ot_receiver,
355                correlation,
356                vec_r,
357            };
358
359            mul_keep.insert(i_idx, keep);
360            mul_transmit.push(transmit);
361        }
362
363        (zero_keep, zero_transmit, mul_keep, mul_transmit)
364    }
365
366    /// Works as [Phase 4](super::dkg::phase4) in DKG, but the
367    /// derivation part is omitted. Moreover, the variable
368    /// `poly_point` is now called `correction_value`.
369    ///
370    /// The output is a new instance of [`Party`] which is the
371    /// previous one refreshed.
372    ///
373    /// # Errors
374    ///
375    /// Will return `Err` if the verifying public key is not trivial,
376    /// if a message is not meant for the party, if the zero shares
377    /// protocol fails when verifying the seeds or if the multiplication
378    /// protocol fails.
379    #[allow(clippy::too_many_arguments)]
380    pub fn refresh_complete_phase4(
381        &self,
382        refresh_sid: &[u8],
383        correction_value: &C::Scalar,
384        proofs_commitments: &[ProofCommitment<C>],
385        zero_kept: &BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>,
386        zero_received_phase2: &[TransmitInitZeroSharePhase2to4],
387        zero_received_phase3: &[TransmitInitZeroSharePhase3to4],
388        mul_kept: &BTreeMap<PartyIndex, KeepInitMulPhase3to4<C>>,
389        mul_received: &[TransmitInitMulPhase3to4<C>],
390    ) -> Result<Party<C>, Abort> {
391        // We run Phase 4, but now we don't check if the resulting public key is zero.
392        // Actually, we have to do the opposite: it must be the zero point!
393        // After this, we use the values computed to update our values.
394        // Again, the derivation part is omitted.
395
396        // DKG
397        let (verifying_pk, _) = step5::<C>(
398            &self.parameters,
399            self.party_index,
400            refresh_sid,
401            proofs_commitments,
402        )?;
403
404        // The public key calculated above should be the zero point on the curve.
405        if verifying_pk != <C::AffinePoint as rustcrypto_group::prime::PrimeCurveAffine>::identity()
406        {
407            return Err(Abort::recoverable(
408                self.party_index,
409                AbortReason::PolynomialInconsistency,
410            ));
411        }
412
413        // Initialization - Zero shares.
414        let mut zero_received_phase2_by_sender: BTreeMap<
415            PartyIndex,
416            &TransmitInitZeroSharePhase2to4,
417        > = BTreeMap::new();
418        for message in zero_received_phase2 {
419            if message.parties.receiver != self.party_index {
420                return Err(Abort::recoverable(
421                    self.party_index,
422                    AbortReason::MisroutedMessage {
423                        expected_receiver: self.party_index,
424                        actual_receiver: message.parties.receiver,
425                    },
426                ));
427            }
428            if !zero_kept.contains_key(&message.parties.sender) {
429                return Err(Abort::recoverable(
430                    self.party_index,
431                    AbortReason::UnexpectedSender {
432                        sender: message.parties.sender,
433                    },
434                ));
435            }
436            if zero_received_phase2_by_sender
437                .insert(message.parties.sender, message)
438                .is_some()
439            {
440                return Err(Abort::recoverable(
441                    self.party_index,
442                    AbortReason::DuplicateSender {
443                        sender: message.parties.sender,
444                    },
445                ));
446            }
447        }
448        let mut zero_received_phase3_by_sender: BTreeMap<
449            PartyIndex,
450            &TransmitInitZeroSharePhase3to4,
451        > = BTreeMap::new();
452        for message in zero_received_phase3 {
453            if message.parties.receiver != self.party_index {
454                return Err(Abort::recoverable(
455                    self.party_index,
456                    AbortReason::MisroutedMessage {
457                        expected_receiver: self.party_index,
458                        actual_receiver: message.parties.receiver,
459                    },
460                ));
461            }
462            if !zero_kept.contains_key(&message.parties.sender) {
463                return Err(Abort::recoverable(
464                    self.party_index,
465                    AbortReason::UnexpectedSender {
466                        sender: message.parties.sender,
467                    },
468                ));
469            }
470            if zero_received_phase3_by_sender
471                .insert(message.parties.sender, message)
472                .is_some()
473            {
474                return Err(Abort::recoverable(
475                    self.party_index,
476                    AbortReason::DuplicateSender {
477                        sender: message.parties.sender,
478                    },
479                ));
480            }
481        }
482        if zero_received_phase2_by_sender.len() != zero_kept.len() {
483            return Err(Abort::recoverable(
484                self.party_index,
485                AbortReason::WrongMessageCount {
486                    expected: zero_kept.len(),
487                    got: zero_received_phase2_by_sender.len(),
488                },
489            ));
490        }
491        if zero_received_phase3_by_sender.len() != zero_kept.len() {
492            return Err(Abort::recoverable(
493                self.party_index,
494                AbortReason::WrongMessageCount {
495                    expected: zero_kept.len(),
496                    got: zero_received_phase3_by_sender.len(),
497                },
498            ));
499        }
500
501        let mut seeds: Vec<zero_shares::SeedPair> =
502            Vec::with_capacity((self.parameters.share_count - 1) as usize);
503        for (target_party, message_kept) in zero_kept {
504            let message_received_2 = zero_received_phase2_by_sender
505                .get(target_party)
506                .ok_or_else(|| {
507                    Abort::recoverable(
508                        self.party_index,
509                        AbortReason::MissingMessageFromParty {
510                            party: *target_party,
511                        },
512                    )
513                })?;
514            let message_received_3 = zero_received_phase3_by_sender
515                .get(target_party)
516                .ok_or_else(|| {
517                    Abort::recoverable(
518                        self.party_index,
519                        AbortReason::MissingMessageFromParty {
520                            party: *target_party,
521                        },
522                    )
523                })?;
524
525            // We verify the commitment.
526            let verification = ZeroShare::verify_seed(
527                &message_received_3.seed,
528                &message_received_2.commitment,
529                &message_received_3.salt,
530            );
531            if !verification {
532                return Err(Abort::recoverable(
533                    self.party_index,
534                    AbortReason::ZeroShareDecommitFailed {
535                        counterparty: *target_party,
536                    },
537                ));
538            }
539
540            // We form the final seed pairs.
541            seeds.push(ZeroShare::generate_seed_pair(
542                self.party_index,
543                *target_party,
544                &message_kept.seed,
545                &message_received_3.seed,
546            ));
547        }
548
549        // This finishes the initialization.
550        let zero_share = ZeroShare::initialize(seeds);
551
552        // Initialization - Two-party multiplication.
553        let mut mul_receivers: BTreeMap<PartyIndex, MulReceiver<C>> = BTreeMap::new();
554        let mut mul_senders: BTreeMap<PartyIndex, MulSender<C>> = BTreeMap::new();
555        let mut mul_received_by_sender: BTreeMap<PartyIndex, &TransmitInitMulPhase3to4<C>> =
556            BTreeMap::new();
557        for message in mul_received {
558            if message.parties.receiver != self.party_index {
559                return Err(Abort::recoverable(
560                    self.party_index,
561                    AbortReason::MisroutedMessage {
562                        expected_receiver: self.party_index,
563                        actual_receiver: message.parties.receiver,
564                    },
565                ));
566            }
567            if !mul_kept.contains_key(&message.parties.sender) {
568                return Err(Abort::recoverable(
569                    self.party_index,
570                    AbortReason::UnexpectedSender {
571                        sender: message.parties.sender,
572                    },
573                ));
574            }
575            if mul_received_by_sender
576                .insert(message.parties.sender, message)
577                .is_some()
578            {
579                return Err(Abort::recoverable(
580                    self.party_index,
581                    AbortReason::DuplicateSender {
582                        sender: message.parties.sender,
583                    },
584                ));
585            }
586        }
587        if mul_received_by_sender.len() != mul_kept.len() {
588            return Err(Abort::recoverable(
589                self.party_index,
590                AbortReason::WrongMessageCount {
591                    expected: mul_kept.len(),
592                    got: mul_received_by_sender.len(),
593                },
594            ));
595        }
596
597        for (target_party, message_kept) in mul_kept {
598            let message_received = mul_received_by_sender.get(target_party).ok_or_else(|| {
599                Abort::recoverable(
600                    self.party_index,
601                    AbortReason::MissingMessageFromParty {
602                        party: *target_party,
603                    },
604                )
605            })?;
606
607            // RECEIVER
608            // We are the receiver and target_party = sender.
609
610            // We retrieve the id used for multiplication. Note that the first party
611            // is the receiver and the second, the sender.
612            let mul_sid_receiver = [
613                "Multiplication protocol".as_bytes(),
614                &self.party_index.as_u8().to_be_bytes(),
615                &target_party.as_u8().to_be_bytes(),
616                refresh_sid,
617            ]
618            .concat();
619
620            let receiver_result = MulReceiver::<C>::init_phase2(
621                &message_kept.ot_sender,
622                &mul_sid_receiver,
623                &message_received.seed,
624                &message_received.enc_proofs,
625                &message_kept.nonce,
626            );
627
628            let mul_receiver: MulReceiver<C> = match receiver_result {
629                Ok(r) => r,
630                Err(error) => {
631                    // Complete refresh builds fresh OT from scratch (no reused COTe state),
632                    // so init failures are recoverable, matching DKG classification.
633                    return Err(Abort::recoverable(
634                        self.party_index,
635                        AbortReason::MultiplicationVerificationFailed {
636                            counterparty: *target_party,
637                            detail: error.description.clone(),
638                        },
639                    ));
640                }
641            };
642
643            // SENDER
644            // We are the sender and target_party = receiver.
645
646            // We retrieve the id used for multiplication. Note that the first party
647            // is the receiver and the second, the sender.
648            let mul_sid_sender = [
649                "Multiplication protocol".as_bytes(),
650                &target_party.as_u8().to_be_bytes(),
651                &self.party_index.as_u8().to_be_bytes(),
652                refresh_sid,
653            ]
654            .concat();
655
656            let sender_result = MulSender::<C>::init_phase2(
657                &message_kept.ot_receiver,
658                &mul_sid_sender,
659                message_kept.correlation.clone(),
660                &message_kept.vec_r,
661                &message_received.dlog_proof,
662                &message_received.nonce,
663            );
664
665            let mul_sender: MulSender<C> = match sender_result {
666                Ok(s) => s,
667                Err(error) => {
668                    // Complete refresh builds fresh OT from scratch (no reused COTe state),
669                    // so init failures are recoverable, matching DKG classification.
670                    return Err(Abort::recoverable(
671                        self.party_index,
672                        AbortReason::MultiplicationVerificationFailed {
673                            counterparty: *target_party,
674                            detail: error.description.clone(),
675                        },
676                    ));
677                }
678            };
679
680            // We finish the initialization.
681            mul_receivers.insert(*target_party, mul_receiver);
682            mul_senders.insert(*target_party, mul_sender.clone());
683        }
684
685        // For key derivation, we just update poly_point.
686        let derivation_data = DerivData {
687            depth: self.derivation_data.depth,
688            child_number: self.derivation_data.child_number,
689            parent_fingerprint: self.derivation_data.parent_fingerprint,
690            poly_point: self.poly_point + correction_value, // We update poly_point.
691            pk: self.pk,
692            chain_code: self.derivation_data.chain_code,
693        };
694
695        let party = Party {
696            parameters: self.parameters.clone(),
697            party_index: self.party_index,
698            session_id: refresh_sid.to_vec(), // We replace the old session id by the new one.
699
700            poly_point: self.poly_point + correction_value, // We update poly_point.
701            pk: self.pk,
702
703            zero_share,
704
705            mul_senders,
706            mul_receivers,
707
708            derivation_data,
709
710            address: self.address.clone(),
711        };
712
713        Ok(party)
714    }
715
716    // A FASTER REFRESH
717
718    /// Works as [Phase 1](super::dkg::phase1) in DKG, but with
719    /// the alterations needed for the refresh protocol.
720    ///
721    /// The output should be dealt in the same way.
722    #[must_use]
723    pub fn refresh_phase1(&self) -> Vec<C::Scalar> {
724        // We run Phase 1 in DKG, but we force the constant term in Step 1 to be zero.
725
726        // DKG
727        let mut secret_polynomial: Vec<C::Scalar> =
728            Vec::with_capacity(self.parameters.threshold as usize);
729        secret_polynomial.push(C::Scalar::ZERO);
730        for _ in 1..self.parameters.threshold {
731            secret_polynomial.push(C::Scalar::random(&mut rng::get_rng()));
732        }
733
734        step2::<C>(&self.parameters, &secret_polynomial)
735    }
736
737    /// Works as [Phase 2](super::dkg::phase2) in DKG, but the
738    /// derivation part is omitted.
739    ///
740    /// The output should be dealt in the same way. The only
741    /// difference is that we will refer to the scalar`poly_point`
742    /// as `correction_value`.
743    #[must_use]
744    pub fn refresh_phase2(
745        &self,
746        refresh_sid: &[u8],
747        poly_fragments: &[C::Scalar],
748    ) -> (
749        C::Scalar,
750        ProofCommitment<C>,
751        BTreeMap<PartyIndex, KeepRefreshPhase2to3>,
752        Vec<TransmitRefreshPhase2to4>,
753    ) {
754        // We run Phase 2 in DKG, but we omit the derivation part.
755        // Note that "poly_point" is now called "correction_value".
756        // It will be used to correct self.poly_point.
757
758        // DKG
759        let (correction_value, proof_commitment) =
760            step3::<C>(self.party_index, refresh_sid, poly_fragments);
761
762        // Initialization - Zero shares.
763
764        // We will use BTreeMap to keep messages: the key indicates the party to whom the message refers.
765        let mut keep: BTreeMap<PartyIndex, KeepRefreshPhase2to3> = BTreeMap::new();
766        let mut transmit: Vec<TransmitRefreshPhase2to4> =
767            Vec::with_capacity((self.parameters.share_count - 1) as usize);
768        for i in 1..=self.parameters.share_count {
769            let i_idx = PartyIndex::new(i).unwrap();
770            if i_idx == self.party_index {
771                continue;
772            }
773
774            // Generate initial seeds.
775            let (seed, commitment, salt) = ZeroShare::generate_seed_with_commitment();
776
777            // We first send the commitments. We keep the rest to send later.
778            keep.insert(i_idx, KeepRefreshPhase2to3 { seed, salt });
779            transmit.push(TransmitRefreshPhase2to4 {
780                parties: PartiesMessage {
781                    sender: self.party_index,
782                    receiver: i_idx,
783                },
784                commitment,
785            });
786        }
787
788        (correction_value, proof_commitment, keep, transmit)
789    }
790
791    /// Works as [Phase 3](super::dkg::phase3) in DKG, but the
792    /// multiplication and derivation parts are omitted.
793    ///
794    /// The output should be dealt in the same way.
795    #[must_use]
796    pub fn refresh_phase3(
797        &self,
798        kept: &BTreeMap<PartyIndex, KeepRefreshPhase2to3>,
799    ) -> (
800        BTreeMap<PartyIndex, KeepRefreshPhase3to4>,
801        Vec<TransmitRefreshPhase3to4>,
802    ) {
803        // We run Phase 3 in DKG, but we omit the multiplication and the derivation parts.
804
805        // Initialization - Zero shares.
806        let mut keep: BTreeMap<PartyIndex, KeepRefreshPhase3to4> = BTreeMap::new();
807        let mut transmit: Vec<TransmitRefreshPhase3to4> =
808            Vec::with_capacity((self.parameters.share_count - 1) as usize);
809        for (target_party, message_kept) in kept {
810            // The messages kept contain the seed and the salt.
811            // They have to be transmitted to the target party.
812            // We keep the seed with us for the next phase.
813            keep.insert(
814                *target_party,
815                KeepRefreshPhase3to4 {
816                    seed: message_kept.seed,
817                },
818            );
819            transmit.push(TransmitRefreshPhase3to4 {
820                parties: PartiesMessage {
821                    sender: self.party_index,
822                    receiver: *target_party,
823                },
824                seed: message_kept.seed,
825                salt: message_kept.salt.clone(),
826            });
827        }
828
829        (keep, transmit)
830    }
831
832    /// Works as [Phase 4](super::dkg::phase4) in DKG, but the
833    /// multiplication and derivation parts are omitted. Moreover,
834    /// the variable `poly_point` is now called `correction_value`.
835    ///
836    /// The output is a new instance of [`Party`] which is the
837    /// previous one refreshed.
838    ///
839    /// # Errors
840    ///
841    /// Will return `Err` if the verifying public key is not trivial,
842    /// if a message is not meant for the party or if the zero shares
843    /// protocol fails when verifying the seeds.
844    ///
845    /// # Panics
846    ///
847    /// Will panic if the indices of the parties are different
848    /// from the ones used in DKG.
849    pub fn refresh_phase4(
850        &self,
851        refresh_sid: &[u8],
852        correction_value: &C::Scalar,
853        proofs_commitments: &[ProofCommitment<C>],
854        kept: &BTreeMap<PartyIndex, KeepRefreshPhase3to4>,
855        received_phase2: &[TransmitRefreshPhase2to4],
856        received_phase3: &[TransmitRefreshPhase3to4],
857    ) -> Result<Party<C>, Abort> {
858        // We run Phase 4, but now we don't check if the resulting public key is zero.
859        // Actually, we have to do the opposite: it must be the zero point!
860        // After this, we use the values computed to update our values.
861        // Again, the derivation part is omitted.
862
863        // DKG
864        let (verifying_pk, _) = step5::<C>(
865            &self.parameters,
866            self.party_index,
867            refresh_sid,
868            proofs_commitments,
869        )?;
870
871        // The public key calculated above should be the zero point on the curve.
872        if verifying_pk != <C::AffinePoint as rustcrypto_group::prime::PrimeCurveAffine>::identity()
873        {
874            return Err(Abort::recoverable(
875                self.party_index,
876                AbortReason::PolynomialInconsistency,
877            ));
878        }
879
880        // Initialization - Zero shares.
881        let mut received_phase2_by_sender: BTreeMap<PartyIndex, &TransmitRefreshPhase2to4> =
882            BTreeMap::new();
883        for message in received_phase2 {
884            if message.parties.receiver != self.party_index {
885                return Err(Abort::recoverable(
886                    self.party_index,
887                    AbortReason::MisroutedMessage {
888                        expected_receiver: self.party_index,
889                        actual_receiver: message.parties.receiver,
890                    },
891                ));
892            }
893            if !kept.contains_key(&message.parties.sender) {
894                return Err(Abort::recoverable(
895                    self.party_index,
896                    AbortReason::UnexpectedSender {
897                        sender: message.parties.sender,
898                    },
899                ));
900            }
901            if received_phase2_by_sender
902                .insert(message.parties.sender, message)
903                .is_some()
904            {
905                return Err(Abort::recoverable(
906                    self.party_index,
907                    AbortReason::DuplicateSender {
908                        sender: message.parties.sender,
909                    },
910                ));
911            }
912        }
913        let mut received_phase3_by_sender: BTreeMap<PartyIndex, &TransmitRefreshPhase3to4> =
914            BTreeMap::new();
915        for message in received_phase3 {
916            if message.parties.receiver != self.party_index {
917                return Err(Abort::recoverable(
918                    self.party_index,
919                    AbortReason::MisroutedMessage {
920                        expected_receiver: self.party_index,
921                        actual_receiver: message.parties.receiver,
922                    },
923                ));
924            }
925            if !kept.contains_key(&message.parties.sender) {
926                return Err(Abort::recoverable(
927                    self.party_index,
928                    AbortReason::UnexpectedSender {
929                        sender: message.parties.sender,
930                    },
931                ));
932            }
933            if received_phase3_by_sender
934                .insert(message.parties.sender, message)
935                .is_some()
936            {
937                return Err(Abort::recoverable(
938                    self.party_index,
939                    AbortReason::DuplicateSender {
940                        sender: message.parties.sender,
941                    },
942                ));
943            }
944        }
945        if received_phase2_by_sender.len() != kept.len() {
946            return Err(Abort::recoverable(
947                self.party_index,
948                AbortReason::WrongMessageCount {
949                    expected: kept.len(),
950                    got: received_phase2_by_sender.len(),
951                },
952            ));
953        }
954        if received_phase3_by_sender.len() != kept.len() {
955            return Err(Abort::recoverable(
956                self.party_index,
957                AbortReason::WrongMessageCount {
958                    expected: kept.len(),
959                    got: received_phase3_by_sender.len(),
960                },
961            ));
962        }
963
964        let mut seeds: Vec<zero_shares::SeedPair> =
965            Vec::with_capacity((self.parameters.share_count - 1) as usize);
966        for (target_party, message_kept) in kept {
967            let message_received_2 =
968                received_phase2_by_sender.get(target_party).ok_or_else(|| {
969                    Abort::recoverable(
970                        self.party_index,
971                        AbortReason::MissingMessageFromParty {
972                            party: *target_party,
973                        },
974                    )
975                })?;
976            let message_received_3 =
977                received_phase3_by_sender.get(target_party).ok_or_else(|| {
978                    Abort::recoverable(
979                        self.party_index,
980                        AbortReason::MissingMessageFromParty {
981                            party: *target_party,
982                        },
983                    )
984                })?;
985
986            // We verify the commitment.
987            let verification = ZeroShare::verify_seed(
988                &message_received_3.seed,
989                &message_received_2.commitment,
990                &message_received_3.salt,
991            );
992            if !verification {
993                return Err(Abort::recoverable(
994                    self.party_index,
995                    AbortReason::ZeroShareDecommitFailed {
996                        counterparty: *target_party,
997                    },
998                ));
999            }
1000
1001            // We form the final seed pairs.
1002            seeds.push(ZeroShare::generate_seed_pair(
1003                self.party_index,
1004                *target_party,
1005                &message_kept.seed,
1006                &message_received_3.seed,
1007            ));
1008        }
1009
1010        // Having the seeds, we can update the data for multiplication.
1011
1012        let mut mul_senders: BTreeMap<PartyIndex, MulSender<C>> = BTreeMap::new();
1013        let mut mul_receivers: BTreeMap<PartyIndex, MulReceiver<C>> = BTreeMap::new();
1014
1015        for seed_pair in &seeds {
1016            // This is the same as running through the counterparties.
1017
1018            let their_index = seed_pair.index_counterparty;
1019            let seed = seed_pair.seed;
1020
1021            let mul_sender = self.mul_senders.get(&their_index).ok_or_else(|| {
1022                Abort::recoverable(
1023                    self.party_index,
1024                    AbortReason::MissingMulState {
1025                        counterparty: their_index,
1026                    },
1027                )
1028            })?;
1029            let mul_receiver = self.mul_receivers.get(&their_index).ok_or_else(|| {
1030                Abort::recoverable(
1031                    self.party_index,
1032                    AbortReason::MissingMulState {
1033                        counterparty: their_index,
1034                    },
1035                )
1036            })?;
1037
1038            // We update the OT data.
1039
1040            let mut new_ote_sender = mul_sender.ote_sender.clone();
1041            let mut new_ote_receiver = mul_receiver.ote_receiver.clone();
1042
1043            for i in 0..(ot::extension::KAPPA) {
1044                // We expand the seed into r0_prime, r1_prime and b_prime, as in the paper.
1045                // There will be two sets of constants: one for the sender and one
1046                // for the receiver. For the salts, note that the sender comes first.
1047
1048                // Then, we apply the trick described in the paper.
1049
1050                // Sender
1051                let i_bytes = i.to_be_bytes();
1052                let sender_bytes = u16::from(self.party_index.as_u8()).to_be_bytes();
1053                let receiver_bytes = u16::from(their_index.as_u8()).to_be_bytes();
1054
1055                let r0_prime = tagged_hash(
1056                    TAG_REFRESH_FAST_R0,
1057                    &[refresh_sid, &i_bytes, &sender_bytes, &receiver_bytes, &seed],
1058                );
1059                let r1_prime = tagged_hash(
1060                    TAG_REFRESH_FAST_R1,
1061                    &[refresh_sid, &i_bytes, &sender_bytes, &receiver_bytes, &seed],
1062                );
1063                let b_prime = (tagged_hash(
1064                    TAG_REFRESH_FAST_B,
1065                    &[refresh_sid, &i_bytes, &sender_bytes, &receiver_bytes, &seed],
1066                )[0] % 2)
1067                    == 1; // We take the first digit.
1068
1069                let b_double_prime = new_ote_sender.correlation[i as usize] ^ b_prime;
1070                let r_prime_b_double_prime = if b_double_prime { r1_prime } else { r0_prime };
1071
1072                let mut r_double_prime: HashOutput = [0; crate::SECURITY as usize];
1073                for j in 0..crate::SECURITY {
1074                    r_double_prime[j as usize] = new_ote_sender.seeds[i as usize][j as usize]
1075                        ^ r_prime_b_double_prime[j as usize];
1076                }
1077
1078                // Updates new_ote_sender with the new values.
1079                new_ote_sender.correlation[i as usize] = b_double_prime;
1080                new_ote_sender.seeds[i as usize] = r_double_prime;
1081
1082                // Receiver
1083                let i_bytes = i.to_be_bytes();
1084                let sender_bytes = u16::from(their_index.as_u8()).to_be_bytes();
1085                let receiver_bytes = u16::from(self.party_index.as_u8()).to_be_bytes();
1086
1087                let r0_prime = tagged_hash(
1088                    TAG_REFRESH_FAST_R0,
1089                    &[refresh_sid, &i_bytes, &sender_bytes, &receiver_bytes, &seed],
1090                );
1091                let r1_prime = tagged_hash(
1092                    TAG_REFRESH_FAST_R1,
1093                    &[refresh_sid, &i_bytes, &sender_bytes, &receiver_bytes, &seed],
1094                );
1095                let b_prime = (tagged_hash(
1096                    TAG_REFRESH_FAST_B,
1097                    &[refresh_sid, &i_bytes, &sender_bytes, &receiver_bytes, &seed],
1098                )[0] % 2)
1099                    == 1; // We take the first digit.
1100
1101                let r_b_prime = if b_prime {
1102                    new_ote_receiver.seeds1[i as usize]
1103                } else {
1104                    new_ote_receiver.seeds0[i as usize]
1105                };
1106                let r_opposite_b_prime = if b_prime {
1107                    new_ote_receiver.seeds0[i as usize]
1108                } else {
1109                    new_ote_receiver.seeds1[i as usize]
1110                };
1111
1112                let mut r0_double_prime: HashOutput = [0; crate::SECURITY as usize];
1113                let mut r1_double_prime: HashOutput = [0; crate::SECURITY as usize];
1114                for j in 0..crate::SECURITY {
1115                    r0_double_prime[j as usize] = r_b_prime[j as usize] ^ r0_prime[j as usize];
1116                    r1_double_prime[j as usize] =
1117                        r_opposite_b_prime[j as usize] ^ r1_prime[j as usize];
1118                }
1119
1120                // Updates new_ote_receiver with the new values.
1121                new_ote_receiver.seeds0[i as usize] = r0_double_prime;
1122                new_ote_receiver.seeds1[i as usize] = r1_double_prime;
1123            }
1124
1125            // We will not change the public gadget vector (well, it is "public" after all).
1126            mul_senders.insert(
1127                their_index,
1128                MulSender {
1129                    public_gadget: mul_sender.public_gadget.clone(),
1130                    ote_sender: new_ote_sender,
1131                    _curve: core::marker::PhantomData,
1132                },
1133            );
1134            mul_receivers.insert(
1135                their_index,
1136                MulReceiver {
1137                    public_gadget: mul_receiver.public_gadget.clone(),
1138                    ote_receiver: new_ote_receiver,
1139                    _curve: core::marker::PhantomData,
1140                },
1141            );
1142        }
1143
1144        // This finishes the initialization for the zero shares protocol.
1145        let zero_share = ZeroShare::initialize(seeds);
1146
1147        // For key derivation, we just update poly_point.
1148        let derivation_data = DerivData {
1149            depth: self.derivation_data.depth,
1150            child_number: self.derivation_data.child_number,
1151            parent_fingerprint: self.derivation_data.parent_fingerprint,
1152            poly_point: self.poly_point + correction_value, // We update poly_point.
1153            pk: self.pk,
1154            chain_code: self.derivation_data.chain_code,
1155        };
1156
1157        // We can finally create the new party.
1158        let party = Party {
1159            parameters: self.parameters.clone(),
1160            party_index: self.party_index,
1161            session_id: refresh_sid.to_vec(), // We replace the old session id by the new one.
1162
1163            poly_point: self.poly_point + correction_value, // We update poly_point.
1164            pk: self.pk,
1165
1166            zero_share,
1167
1168            mul_senders,
1169            mul_receivers,
1170
1171            derivation_data,
1172
1173            address: self.address.clone(),
1174        };
1175
1176        Ok(party)
1177    }
1178}
1179
1180#[cfg(test)]
1181mod tests {
1182
1183    use super::*;
1184
1185    use k256::Secp256k1;
1186
1187    use crate::protocols::re_key::re_key;
1188    use crate::protocols::signing::*;
1189    use crate::protocols::{AbortKind, AbortReason, Parameters};
1190    use crate::utilities::hashes::tagged_hash;
1191
1192    use rand::RngExt;
1193
1194    const SESSION_ID_LEN: usize = 32;
1195
1196    struct CompleteRefreshPhase4Inputs {
1197        parties: Vec<Party<Secp256k1>>,
1198        refresh_sid: [u8; SESSION_ID_LEN],
1199        correction_values: Vec<k256::Scalar>,
1200        proofs_commitments: Vec<ProofCommitment<Secp256k1>>,
1201        zero_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>>,
1202        zero_received_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>>,
1203        zero_received_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>>,
1204        mul_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitMulPhase3to4<Secp256k1>>>,
1205        mul_received_3to4: Vec<Vec<TransmitInitMulPhase3to4<Secp256k1>>>,
1206    }
1207
1208    fn setup_two_party_complete_refresh_phase4_inputs() -> CompleteRefreshPhase4Inputs {
1209        let parameters = Parameters {
1210            threshold: 2,
1211            share_count: 2,
1212        };
1213        let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1214        let secret_key = k256::Scalar::random(&mut rng::get_rng());
1215        let (parties, _) = re_key::<Secp256k1>(&parameters, &session_id, &secret_key, None, |_| {
1216            String::new()
1217        });
1218
1219        let refresh_sid = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1220
1221        // Phase 1
1222        let mut dkg_1: Vec<Vec<k256::Scalar>> = Vec::with_capacity(parameters.share_count as usize);
1223        for i in 0..parameters.share_count {
1224            dkg_1.push(parties[i as usize].refresh_complete_phase1());
1225        }
1226
1227        // Communication round 1
1228        let mut poly_fragments =
1229            vec![
1230                Vec::<k256::Scalar>::with_capacity(parameters.share_count as usize);
1231                parameters.share_count as usize
1232            ];
1233        for row_i in dkg_1 {
1234            for j in 0..parameters.share_count {
1235                poly_fragments[j as usize].push(row_i[j as usize]);
1236            }
1237        }
1238
1239        // Phase 2
1240        let mut correction_values: Vec<k256::Scalar> =
1241            Vec::with_capacity(parameters.share_count as usize);
1242        let mut proofs_commitments: Vec<ProofCommitment<Secp256k1>> =
1243            Vec::with_capacity(parameters.share_count as usize);
1244        let mut zero_kept_2to3: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>> =
1245            Vec::with_capacity(parameters.share_count as usize);
1246        let mut zero_transmit_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1247            Vec::with_capacity(parameters.share_count as usize);
1248        for i in 0..parameters.share_count {
1249            let (out1, out2, out3, out4) = parties[i as usize]
1250                .refresh_complete_phase2(&refresh_sid, &poly_fragments[i as usize]);
1251
1252            correction_values.push(out1);
1253            proofs_commitments.push(out2);
1254            zero_kept_2to3.push(out3);
1255            zero_transmit_2to4.push(out4);
1256        }
1257
1258        // Communication round 2
1259        let mut zero_received_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1260            Vec::with_capacity(parameters.share_count as usize);
1261        for i in 1..=parameters.share_count {
1262            let i_idx = PartyIndex::new(i).unwrap();
1263            let mut new_row: Vec<TransmitInitZeroSharePhase2to4> =
1264                Vec::with_capacity((parameters.share_count - 1) as usize);
1265            for party in &zero_transmit_2to4 {
1266                for message in party {
1267                    if message.parties.receiver == i_idx {
1268                        new_row.push(message.clone());
1269                    }
1270                }
1271            }
1272            zero_received_2to4.push(new_row);
1273        }
1274
1275        // Phase 3
1276        let mut zero_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>> =
1277            Vec::with_capacity(parameters.share_count as usize);
1278        let mut zero_transmit_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1279            Vec::with_capacity(parameters.share_count as usize);
1280        let mut mul_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitMulPhase3to4<Secp256k1>>> =
1281            Vec::with_capacity(parameters.share_count as usize);
1282        let mut mul_transmit_3to4: Vec<Vec<TransmitInitMulPhase3to4<Secp256k1>>> =
1283            Vec::with_capacity(parameters.share_count as usize);
1284        for i in 0..parameters.share_count {
1285            let (out1, out2, out3, out4) = parties[i as usize]
1286                .refresh_complete_phase3(&refresh_sid, &zero_kept_2to3[i as usize]);
1287
1288            zero_kept_3to4.push(out1);
1289            zero_transmit_3to4.push(out2);
1290            mul_kept_3to4.push(out3);
1291            mul_transmit_3to4.push(out4);
1292        }
1293
1294        // Communication round 3
1295        let mut zero_received_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1296            Vec::with_capacity(parameters.share_count as usize);
1297        let mut mul_received_3to4: Vec<Vec<TransmitInitMulPhase3to4<Secp256k1>>> =
1298            Vec::with_capacity(parameters.share_count as usize);
1299        for i in 1..=parameters.share_count {
1300            let i_idx = PartyIndex::new(i).unwrap();
1301            let mut zero_row: Vec<TransmitInitZeroSharePhase3to4> =
1302                Vec::with_capacity((parameters.share_count - 1) as usize);
1303            for party in &zero_transmit_3to4 {
1304                for message in party {
1305                    if message.parties.receiver == i_idx {
1306                        zero_row.push(message.clone());
1307                    }
1308                }
1309            }
1310            zero_received_3to4.push(zero_row);
1311
1312            let mut mul_row: Vec<TransmitInitMulPhase3to4<Secp256k1>> =
1313                Vec::with_capacity((parameters.share_count - 1) as usize);
1314            for party in &mul_transmit_3to4 {
1315                for message in party {
1316                    if message.parties.receiver == i_idx {
1317                        mul_row.push(message.clone());
1318                    }
1319                }
1320            }
1321            mul_received_3to4.push(mul_row);
1322        }
1323
1324        CompleteRefreshPhase4Inputs {
1325            parties,
1326            refresh_sid,
1327            correction_values,
1328            proofs_commitments,
1329            zero_kept_3to4,
1330            zero_received_2to4,
1331            zero_received_3to4,
1332            mul_kept_3to4,
1333            mul_received_3to4,
1334        }
1335    }
1336
1337    /// Tests that complete refresh phase 4 aborts (recoverably) on tampered OT encryption proofs.
1338    #[test]
1339    fn test_refresh_complete_phase4_aborts_on_tampered_enc_proof() {
1340        let mut data = setup_two_party_complete_refresh_phase4_inputs();
1341
1342        let tampered = data.mul_received_3to4[0]
1343            .iter_mut()
1344            .find(|message| {
1345                message.parties.sender == PartyIndex::new(2).unwrap()
1346                    && message.parties.receiver == PartyIndex::new(1).unwrap()
1347            })
1348            .expect("expected party-2 message for party 1 in complete refresh");
1349        assert!(
1350            !tampered.enc_proofs.is_empty(),
1351            "expected non-empty enc_proofs in complete refresh test setup"
1352        );
1353        tampered.enc_proofs[0].challenge0 += k256::Scalar::ONE;
1354
1355        let result = data.parties[0].refresh_complete_phase4(
1356            &data.refresh_sid,
1357            &data.correction_values[0],
1358            &data.proofs_commitments,
1359            &data.zero_kept_3to4[0],
1360            &data.zero_received_2to4[0],
1361            &data.zero_received_3to4[0],
1362            &data.mul_kept_3to4[0],
1363            &data.mul_received_3to4[0],
1364        );
1365        let abort = result.expect_err("tampered complete-refresh enc proof should be rejected");
1366        assert_eq!(abort.kind, AbortKind::Recoverable);
1367        assert!(
1368            matches!(abort.reason, AbortReason::MultiplicationVerificationFailed { counterparty, .. } if counterparty == PartyIndex::new(2).unwrap())
1369        );
1370    }
1371
1372    /// Tests that complete refresh phase 4 aborts (recoverably) on tampered OT DLog proofs.
1373    #[test]
1374    fn test_refresh_complete_phase4_aborts_on_tampered_dlog_proof() {
1375        let mut data = setup_two_party_complete_refresh_phase4_inputs();
1376
1377        let tampered = data.mul_received_3to4[0]
1378            .iter_mut()
1379            .find(|message| {
1380                message.parties.sender == PartyIndex::new(2).unwrap()
1381                    && message.parties.receiver == PartyIndex::new(1).unwrap()
1382            })
1383            .expect("expected party-2 message for party 1 in complete refresh");
1384        assert!(
1385            !tampered.dlog_proof.proofs.is_empty(),
1386            "expected non-empty DLog proof vector in complete refresh test setup"
1387        );
1388        tampered.dlog_proof.proofs[0].challenge_response += k256::Scalar::ONE;
1389
1390        let result = data.parties[0].refresh_complete_phase4(
1391            &data.refresh_sid,
1392            &data.correction_values[0],
1393            &data.proofs_commitments,
1394            &data.zero_kept_3to4[0],
1395            &data.zero_received_2to4[0],
1396            &data.zero_received_3to4[0],
1397            &data.mul_kept_3to4[0],
1398            &data.mul_received_3to4[0],
1399        );
1400        let abort = result.expect_err("tampered complete-refresh DLog proof should be rejected");
1401        assert_eq!(abort.kind, AbortKind::Recoverable);
1402        assert!(
1403            matches!(abort.reason, AbortReason::MultiplicationVerificationFailed { counterparty, .. } if counterparty == PartyIndex::new(2).unwrap())
1404        );
1405    }
1406
1407    /// Tests if complete refresh phase 4 rejects duplicate multiplication-init senders.
1408    #[test]
1409    fn test_refresh_complete_phase4_rejects_duplicate_mul_init_sender() {
1410        let mut data = setup_two_party_complete_refresh_phase4_inputs();
1411
1412        let duplicate = data.mul_received_3to4[0]
1413            .first()
1414            .expect("expected at least one mul-init message in test setup")
1415            .clone();
1416        data.mul_received_3to4[0].push(duplicate);
1417
1418        let result = data.parties[0].refresh_complete_phase4(
1419            &data.refresh_sid,
1420            &data.correction_values[0],
1421            &data.proofs_commitments,
1422            &data.zero_kept_3to4[0],
1423            &data.zero_received_2to4[0],
1424            &data.zero_received_3to4[0],
1425            &data.mul_kept_3to4[0],
1426            &data.mul_received_3to4[0],
1427        );
1428        let abort = result.expect_err("duplicate mul-init sender should be rejected");
1429        assert_eq!(abort.kind, AbortKind::Recoverable);
1430        assert!(
1431            matches!(abort.reason, AbortReason::DuplicateSender { sender } if sender == PartyIndex::new(2).unwrap())
1432        );
1433    }
1434
1435    /// Tests if the complete refresh protocol generates parties
1436    /// still capable of running the signing protocol.
1437    ///
1438    /// In this case, parties are sampled via the [`re_key`] function.
1439    #[test]
1440    fn test_refresh_complete() {
1441        let threshold = rng::get_rng().random_range(2..=5); // You can change the ranges here.
1442        let offset = rng::get_rng().random_range(0..=5);
1443
1444        let parameters = Parameters {
1445            threshold,
1446            share_count: threshold + offset,
1447        }; // You can fix the parameters if you prefer.
1448
1449        // We use the re_key function to quickly sample the parties.
1450        let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1451        let secret_key = k256::Scalar::random(&mut rng::get_rng());
1452        let (parties, _) = re_key::<Secp256k1>(&parameters, &session_id, &secret_key, None, |_| {
1453            String::new()
1454        });
1455
1456        // REFRESH (it follows test_dkg_initialization closely)
1457
1458        let refresh_sid = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1459
1460        // Phase 1
1461        let mut dkg_1: Vec<Vec<k256::Scalar>> = Vec::with_capacity(parameters.share_count as usize);
1462        for i in 0..parameters.share_count {
1463            let out1 = parties[i as usize].refresh_complete_phase1();
1464
1465            dkg_1.push(out1);
1466        }
1467
1468        // Communication round 1 - Each party receives a fragment from each counterparty.
1469        // They also produce a fragment for themselves.
1470        let mut poly_fragments =
1471            vec![
1472                Vec::<k256::Scalar>::with_capacity(parameters.share_count as usize);
1473                parameters.share_count as usize
1474            ];
1475        for row_i in dkg_1 {
1476            for j in 0..parameters.share_count {
1477                poly_fragments[j as usize].push(row_i[j as usize]);
1478            }
1479        }
1480
1481        // Phase 2
1482        let mut correction_values: Vec<k256::Scalar> =
1483            Vec::with_capacity(parameters.share_count as usize);
1484        let mut proofs_commitments: Vec<ProofCommitment<Secp256k1>> =
1485            Vec::with_capacity(parameters.share_count as usize);
1486        let mut zero_kept_2to3: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>> =
1487            Vec::with_capacity(parameters.share_count as usize);
1488        let mut zero_transmit_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1489            Vec::with_capacity(parameters.share_count as usize);
1490        for i in 0..parameters.share_count {
1491            let (out1, out2, out3, out4) = parties[i as usize]
1492                .refresh_complete_phase2(&refresh_sid, &poly_fragments[i as usize]);
1493
1494            correction_values.push(out1);
1495            proofs_commitments.push(out2);
1496            zero_kept_2to3.push(out3);
1497            zero_transmit_2to4.push(out4);
1498        }
1499
1500        // Communication round 2
1501        let mut zero_received_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1502            Vec::with_capacity(parameters.share_count as usize);
1503        for i in 1..=parameters.share_count {
1504            // We don't need to transmit the commitments because proofs_commitments is already what we need.
1505            // In practice, this should be done here.
1506
1507            let i_idx = PartyIndex::new(i).unwrap();
1508            let mut new_row: Vec<TransmitInitZeroSharePhase2to4> =
1509                Vec::with_capacity((parameters.share_count - 1) as usize);
1510            for party in &zero_transmit_2to4 {
1511                for message in party {
1512                    // Check if this message should be sent to us.
1513                    if message.parties.receiver == i_idx {
1514                        new_row.push(message.clone());
1515                    }
1516                }
1517            }
1518            zero_received_2to4.push(new_row);
1519        }
1520
1521        // Phase 3
1522        let mut zero_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>> =
1523            Vec::with_capacity(parameters.share_count as usize);
1524        let mut zero_transmit_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1525            Vec::with_capacity(parameters.share_count as usize);
1526        let mut mul_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitMulPhase3to4<Secp256k1>>> =
1527            Vec::with_capacity(parameters.share_count as usize);
1528        let mut mul_transmit_3to4: Vec<Vec<TransmitInitMulPhase3to4<Secp256k1>>> =
1529            Vec::with_capacity(parameters.share_count as usize);
1530        for i in 0..parameters.share_count {
1531            let (out1, out2, out3, out4) = parties[i as usize]
1532                .refresh_complete_phase3(&refresh_sid, &zero_kept_2to3[i as usize]);
1533
1534            zero_kept_3to4.push(out1);
1535            zero_transmit_3to4.push(out2);
1536            mul_kept_3to4.push(out3);
1537            mul_transmit_3to4.push(out4);
1538        }
1539
1540        // Communication round 3
1541        let mut zero_received_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1542            Vec::with_capacity(parameters.share_count as usize);
1543        let mut mul_received_3to4: Vec<Vec<TransmitInitMulPhase3to4<Secp256k1>>> =
1544            Vec::with_capacity(parameters.share_count as usize);
1545        for i in 1..=parameters.share_count {
1546            // We don't need to transmit the proofs because proofs_commitments is already what we need.
1547            // In practice, this should be done here.
1548
1549            let i_idx = PartyIndex::new(i).unwrap();
1550            let mut new_row: Vec<TransmitInitZeroSharePhase3to4> =
1551                Vec::with_capacity((parameters.share_count - 1) as usize);
1552            for party in &zero_transmit_3to4 {
1553                for message in party {
1554                    // Check if this message should be sent to us.
1555                    if message.parties.receiver == i_idx {
1556                        new_row.push(message.clone());
1557                    }
1558                }
1559            }
1560            zero_received_3to4.push(new_row);
1561
1562            let mut new_row: Vec<TransmitInitMulPhase3to4<Secp256k1>> =
1563                Vec::with_capacity((parameters.share_count - 1) as usize);
1564            for party in &mul_transmit_3to4 {
1565                for message in party {
1566                    // Check if this message should be sent to us.
1567                    if message.parties.receiver == i_idx {
1568                        new_row.push(message.clone());
1569                    }
1570                }
1571            }
1572            mul_received_3to4.push(new_row);
1573        }
1574
1575        // Phase 4
1576        let mut refreshed_parties: Vec<Party<Secp256k1>> =
1577            Vec::with_capacity(parameters.share_count as usize);
1578        for i in 0..parameters.share_count {
1579            let result = parties[i as usize].refresh_complete_phase4(
1580                &refresh_sid,
1581                &correction_values[i as usize],
1582                &proofs_commitments,
1583                &zero_kept_3to4[i as usize],
1584                &zero_received_2to4[i as usize],
1585                &zero_received_3to4[i as usize],
1586                &mul_kept_3to4[i as usize],
1587                &mul_received_3to4[i as usize],
1588            );
1589            match result {
1590                Err(abort) => {
1591                    panic!("Party {} aborted: {:?}", abort.index, abort.description());
1592                }
1593                Ok(party) => {
1594                    refreshed_parties.push(party);
1595                }
1596            }
1597        }
1598
1599        let parties = refreshed_parties;
1600
1601        // SIGNING (as in test_signing)
1602
1603        let sign_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1604        let message_to_sign = tagged_hash(b"test-sign", &[b"Message to sign!"]);
1605
1606        // For simplicity, we are testing only the first parties.
1607        let executing_parties: Vec<PartyIndex> = (1..=parameters.threshold)
1608            .map(|i| PartyIndex::new(i).unwrap())
1609            .collect();
1610
1611        // Each party prepares their data for this signing session.
1612        let mut all_data: BTreeMap<PartyIndex, SignData> = BTreeMap::new();
1613        for party_index in executing_parties.clone() {
1614            //Gather the counterparties
1615            let mut counterparties = executing_parties.clone();
1616            counterparties.retain(|index| *index != party_index);
1617
1618            all_data.insert(
1619                party_index,
1620                SignData {
1621                    sign_id: sign_id.to_vec(),
1622                    counterparties,
1623                    message_hash: message_to_sign,
1624                },
1625            );
1626        }
1627
1628        // Phase 1
1629        let mut unique_kept_1to2: BTreeMap<PartyIndex, UniqueKeep1to2<Secp256k1>> = BTreeMap::new();
1630        let mut kept_1to2: BTreeMap<PartyIndex, BTreeMap<PartyIndex, KeepPhase1to2<Secp256k1>>> =
1631            BTreeMap::new();
1632        let mut transmit_1to2: BTreeMap<PartyIndex, Vec<TransmitPhase1to2>> = BTreeMap::new();
1633        for party_index in executing_parties.clone() {
1634            let (unique_keep, keep, transmit) = parties[(party_index.as_u8() - 1) as usize]
1635                .sign_phase1(all_data.get(&party_index).unwrap())
1636                .unwrap();
1637
1638            unique_kept_1to2.insert(party_index, unique_keep);
1639            kept_1to2.insert(party_index, keep);
1640            transmit_1to2.insert(party_index, transmit);
1641        }
1642
1643        // Communication round 1
1644        let mut received_1to2: BTreeMap<PartyIndex, Vec<TransmitPhase1to2>> = BTreeMap::new();
1645        for &party_index in &executing_parties {
1646            let messages_for_party: Vec<TransmitPhase1to2> = transmit_1to2
1647                .values()
1648                .flatten()
1649                .filter(|message| message.parties.receiver == party_index)
1650                .cloned()
1651                .collect();
1652
1653            received_1to2.insert(party_index, messages_for_party);
1654        }
1655
1656        // Phase 2
1657        let mut unique_kept_2to3: BTreeMap<PartyIndex, UniqueKeep2to3<Secp256k1>> = BTreeMap::new();
1658        let mut kept_2to3: BTreeMap<PartyIndex, BTreeMap<PartyIndex, KeepPhase2to3<Secp256k1>>> =
1659            BTreeMap::new();
1660        let mut transmit_2to3: BTreeMap<PartyIndex, Vec<TransmitPhase2to3<Secp256k1>>> =
1661            BTreeMap::new();
1662        for party_index in executing_parties.clone() {
1663            let result = parties[(party_index.as_u8() - 1) as usize].sign_phase2(
1664                all_data.get(&party_index).unwrap(),
1665                unique_kept_1to2.get(&party_index).unwrap(),
1666                kept_1to2.get(&party_index).unwrap(),
1667                received_1to2.get(&party_index).unwrap(),
1668            );
1669            match result {
1670                Err(abort) => {
1671                    panic!("Party {} aborted: {:?}", abort.index, abort.description());
1672                }
1673                Ok((unique_keep, keep, transmit)) => {
1674                    unique_kept_2to3.insert(party_index, unique_keep);
1675                    kept_2to3.insert(party_index, keep);
1676                    transmit_2to3.insert(party_index, transmit);
1677                }
1678            }
1679        }
1680
1681        // Communication round 2
1682        let mut received_2to3: BTreeMap<PartyIndex, Vec<TransmitPhase2to3<Secp256k1>>> =
1683            BTreeMap::new();
1684
1685        for &party_index in &executing_parties {
1686            let filtered_messages: Vec<_> = transmit_2to3
1687                .values()
1688                .flatten()
1689                .filter(|msg| msg.parties.receiver == party_index)
1690                .cloned()
1691                .collect();
1692
1693            received_2to3.insert(party_index, filtered_messages);
1694        }
1695
1696        // Phase 3
1697        let mut x_coords: Vec<String> = Vec::with_capacity(parameters.threshold as usize);
1698        let mut broadcast_3to4: Vec<Broadcast3to4<Secp256k1>> =
1699            Vec::with_capacity(parameters.threshold as usize);
1700        for party_index in executing_parties.clone() {
1701            let result = parties[(party_index.as_u8() - 1) as usize].sign_phase3(
1702                all_data.get(&party_index).unwrap(),
1703                unique_kept_2to3.get(&party_index).unwrap(),
1704                kept_2to3.get(&party_index).unwrap(),
1705                received_2to3.get(&party_index).unwrap(),
1706            );
1707            match result {
1708                Err(abort) => {
1709                    panic!("Party {} aborted: {:?}", abort.index, abort.description());
1710                }
1711                Ok((x_coord, broadcast)) => {
1712                    x_coords.push(x_coord);
1713                    broadcast_3to4.push(broadcast);
1714                }
1715            }
1716        }
1717
1718        // We verify all parties got the same x coordinate.
1719        let x_coord = x_coords[0].clone(); // We take the first one as reference.
1720        for i in 1..parameters.threshold {
1721            assert_eq!(x_coord, x_coords[i as usize]);
1722        }
1723
1724        // Communication round 3
1725        // This is a broadcast to all parties. The desired result is already broadcast_3to4.
1726
1727        // Phase 4
1728        let some_index = executing_parties[0];
1729        let result = parties[(some_index.as_u8() - 1) as usize].sign_phase4(
1730            all_data.get(&some_index).unwrap(),
1731            &x_coord,
1732            &broadcast_3to4,
1733            true,
1734        );
1735        if let Err(abort) = result {
1736            panic!("Party {} aborted: {:?}", abort.index, abort.description());
1737        }
1738    }
1739
1740    /// Tests if the faster refresh protocol generates parties
1741    /// still capable of running the signing protocol.
1742    ///
1743    /// In this case, parties are sampled via the [`re_key`] function.
1744    #[test]
1745    fn test_refresh() {
1746        let threshold = rng::get_rng().random_range(2..=5); // You can change the ranges here.
1747        let offset = rng::get_rng().random_range(0..=5);
1748
1749        let parameters = Parameters {
1750            threshold,
1751            share_count: threshold + offset,
1752        }; // You can fix the parameters if you prefer.
1753
1754        // We use the re_key function to quickly sample the parties.
1755        let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1756        let secret_key = k256::Scalar::random(&mut rng::get_rng());
1757        let (parties, _) = re_key::<Secp256k1>(&parameters, &session_id, &secret_key, None, |_| {
1758            String::new()
1759        });
1760
1761        // REFRESH (faster version)
1762
1763        let refresh_sid = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1764
1765        // Phase 1
1766        let mut dkg_1: Vec<Vec<k256::Scalar>> = Vec::with_capacity(parameters.share_count as usize);
1767        for i in 0..parameters.share_count {
1768            let out1 = parties[i as usize].refresh_phase1();
1769
1770            dkg_1.push(out1);
1771        }
1772
1773        // Communication round 1 - Each party receives a fragment from each counterparty.
1774        // They also produce a fragment for themselves.
1775        let mut poly_fragments =
1776            vec![
1777                Vec::<k256::Scalar>::with_capacity(parameters.share_count as usize);
1778                parameters.share_count as usize
1779            ];
1780        for row_i in dkg_1 {
1781            for j in 0..parameters.share_count {
1782                poly_fragments[j as usize].push(row_i[j as usize]);
1783            }
1784        }
1785
1786        // Phase 2
1787        let mut correction_values: Vec<k256::Scalar> =
1788            Vec::with_capacity(parameters.share_count as usize);
1789        let mut proofs_commitments: Vec<ProofCommitment<Secp256k1>> =
1790            Vec::with_capacity(parameters.share_count as usize);
1791        let mut kept_2to3: Vec<BTreeMap<PartyIndex, KeepRefreshPhase2to3>> =
1792            Vec::with_capacity(parameters.share_count as usize);
1793        let mut transmit_2to4: Vec<Vec<TransmitRefreshPhase2to4>> =
1794            Vec::with_capacity(parameters.share_count as usize);
1795        for i in 0..parameters.share_count {
1796            let (out1, out2, out3, out4) =
1797                parties[i as usize].refresh_phase2(&refresh_sid, &poly_fragments[i as usize]);
1798
1799            correction_values.push(out1);
1800            proofs_commitments.push(out2);
1801            kept_2to3.push(out3);
1802            transmit_2to4.push(out4);
1803        }
1804
1805        // Communication round 2
1806        let mut received_2to4: Vec<Vec<TransmitRefreshPhase2to4>> =
1807            Vec::with_capacity(parameters.share_count as usize);
1808        for i in 1..=parameters.share_count {
1809            // We don't need to transmit the commitments because proofs_commitments is already what we need.
1810            // In practice, this should be done here.
1811
1812            let i_idx = PartyIndex::new(i).unwrap();
1813            let mut new_row: Vec<TransmitRefreshPhase2to4> =
1814                Vec::with_capacity((parameters.share_count - 1) as usize);
1815            for party in &transmit_2to4 {
1816                for message in party {
1817                    // Check if this message should be sent to us.
1818                    if message.parties.receiver == i_idx {
1819                        new_row.push(message.clone());
1820                    }
1821                }
1822            }
1823            received_2to4.push(new_row);
1824        }
1825
1826        // Phase 3
1827        let mut kept_3to4: Vec<BTreeMap<PartyIndex, KeepRefreshPhase3to4>> =
1828            Vec::with_capacity(parameters.share_count as usize);
1829        let mut transmit_3to4: Vec<Vec<TransmitRefreshPhase3to4>> =
1830            Vec::with_capacity(parameters.share_count as usize);
1831        for i in 0..parameters.share_count {
1832            let (out1, out2) = parties[i as usize].refresh_phase3(&kept_2to3[i as usize]);
1833
1834            kept_3to4.push(out1);
1835            transmit_3to4.push(out2);
1836        }
1837
1838        // Communication round 3
1839        let mut received_3to4: Vec<Vec<TransmitRefreshPhase3to4>> =
1840            Vec::with_capacity(parameters.share_count as usize);
1841        for i in 1..=parameters.share_count {
1842            // We don't need to transmit the proofs because proofs_commitments is already what we need.
1843            // In practice, this should be done here.
1844
1845            let i_idx = PartyIndex::new(i).unwrap();
1846            let mut new_row: Vec<TransmitRefreshPhase3to4> =
1847                Vec::with_capacity((parameters.share_count - 1) as usize);
1848            for party in &transmit_3to4 {
1849                for message in party {
1850                    // Check if this message should be sent to us.
1851                    if message.parties.receiver == i_idx {
1852                        new_row.push(message.clone());
1853                    }
1854                }
1855            }
1856            received_3to4.push(new_row);
1857        }
1858
1859        // Phase 4
1860        let mut refreshed_parties: Vec<Party<Secp256k1>> =
1861            Vec::with_capacity(parameters.share_count as usize);
1862        for i in 0..parameters.share_count {
1863            let result = parties[i as usize].refresh_phase4(
1864                &refresh_sid,
1865                &correction_values[i as usize],
1866                &proofs_commitments,
1867                &kept_3to4[i as usize],
1868                &received_2to4[i as usize],
1869                &received_3to4[i as usize],
1870            );
1871            match result {
1872                Err(abort) => {
1873                    panic!("Party {} aborted: {:?}", abort.index, abort.description());
1874                }
1875                Ok(party) => {
1876                    refreshed_parties.push(party);
1877                }
1878            }
1879        }
1880
1881        let parties = refreshed_parties;
1882
1883        // SIGNING (as in test_signing)
1884
1885        let sign_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1886        let message_to_sign = tagged_hash(b"test-sign", &[b"Message to sign!"]);
1887
1888        // For simplicity, we are testing only the first parties.
1889        let executing_parties: Vec<PartyIndex> = (1..=parameters.threshold)
1890            .map(|i| PartyIndex::new(i).unwrap())
1891            .collect();
1892
1893        // Each party prepares their data for this signing session.
1894        let mut all_data: BTreeMap<PartyIndex, SignData> = BTreeMap::new();
1895        for party_index in executing_parties.clone() {
1896            //Gather the counterparties
1897            let mut counterparties = executing_parties.clone();
1898            counterparties.retain(|index| *index != party_index);
1899
1900            all_data.insert(
1901                party_index,
1902                SignData {
1903                    sign_id: sign_id.to_vec(),
1904                    counterparties,
1905                    message_hash: message_to_sign,
1906                },
1907            );
1908        }
1909
1910        // Phase 1
1911        let mut unique_kept_1to2: BTreeMap<PartyIndex, UniqueKeep1to2<Secp256k1>> = BTreeMap::new();
1912        let mut kept_1to2: BTreeMap<PartyIndex, BTreeMap<PartyIndex, KeepPhase1to2<Secp256k1>>> =
1913            BTreeMap::new();
1914        let mut transmit_1to2: BTreeMap<PartyIndex, Vec<TransmitPhase1to2>> = BTreeMap::new();
1915        for party_index in executing_parties.clone() {
1916            let (unique_keep, keep, transmit) = parties[(party_index.as_u8() - 1) as usize]
1917                .sign_phase1(all_data.get(&party_index).unwrap())
1918                .unwrap();
1919
1920            unique_kept_1to2.insert(party_index, unique_keep);
1921            kept_1to2.insert(party_index, keep);
1922            transmit_1to2.insert(party_index, transmit);
1923        }
1924
1925        // Communication round 1
1926        let mut received_1to2: BTreeMap<PartyIndex, Vec<TransmitPhase1to2>> = BTreeMap::new();
1927
1928        for &party_index in &executing_parties {
1929            let filtered_messages: Vec<_> = transmit_1to2
1930                .values()
1931                .flatten()
1932                .filter(|msg| msg.parties.receiver == party_index)
1933                .cloned()
1934                .collect();
1935
1936            received_1to2.insert(party_index, filtered_messages);
1937        }
1938
1939        // Phase 2
1940        let mut unique_kept_2to3: BTreeMap<PartyIndex, UniqueKeep2to3<Secp256k1>> = BTreeMap::new();
1941        let mut kept_2to3: BTreeMap<PartyIndex, BTreeMap<PartyIndex, KeepPhase2to3<Secp256k1>>> =
1942            BTreeMap::new();
1943        let mut transmit_2to3: BTreeMap<PartyIndex, Vec<TransmitPhase2to3<Secp256k1>>> =
1944            BTreeMap::new();
1945        for party_index in executing_parties.clone() {
1946            let result = parties[(party_index.as_u8() - 1) as usize].sign_phase2(
1947                all_data.get(&party_index).unwrap(),
1948                unique_kept_1to2.get(&party_index).unwrap(),
1949                kept_1to2.get(&party_index).unwrap(),
1950                received_1to2.get(&party_index).unwrap(),
1951            );
1952            match result {
1953                Err(abort) => {
1954                    panic!("Party {} aborted: {:?}", abort.index, abort.description());
1955                }
1956                Ok((unique_keep, keep, transmit)) => {
1957                    unique_kept_2to3.insert(party_index, unique_keep);
1958                    kept_2to3.insert(party_index, keep);
1959                    transmit_2to3.insert(party_index, transmit);
1960                }
1961            }
1962        }
1963
1964        // Communication round 2
1965        let mut received_2to3: BTreeMap<PartyIndex, Vec<TransmitPhase2to3<Secp256k1>>> =
1966            BTreeMap::new();
1967
1968        for &party_index in &executing_parties {
1969            let messages_for_party: Vec<TransmitPhase2to3<Secp256k1>> = transmit_2to3
1970                .values()
1971                .flatten()
1972                .filter(|message| message.parties.receiver == party_index)
1973                .cloned()
1974                .collect();
1975
1976            received_2to3.insert(party_index, messages_for_party);
1977        }
1978
1979        // Phase 3
1980        let mut x_coords: Vec<String> = Vec::with_capacity(parameters.threshold as usize);
1981        let mut broadcast_3to4: Vec<Broadcast3to4<Secp256k1>> =
1982            Vec::with_capacity(parameters.threshold as usize);
1983        for party_index in executing_parties.clone() {
1984            let result = parties[(party_index.as_u8() - 1) as usize].sign_phase3(
1985                all_data.get(&party_index).unwrap(),
1986                unique_kept_2to3.get(&party_index).unwrap(),
1987                kept_2to3.get(&party_index).unwrap(),
1988                received_2to3.get(&party_index).unwrap(),
1989            );
1990            match result {
1991                Err(abort) => {
1992                    panic!("Party {} aborted: {:?}", abort.index, abort.description());
1993                }
1994                Ok((x_coord, broadcast)) => {
1995                    x_coords.push(x_coord);
1996                    broadcast_3to4.push(broadcast);
1997                }
1998            }
1999        }
2000
2001        // We verify all parties got the same x coordinate.
2002        let x_coord = x_coords[0].clone(); // We take the first one as reference.
2003        for i in 1..parameters.threshold {
2004            assert_eq!(x_coord, x_coords[i as usize]);
2005        }
2006
2007        // Communication round 3
2008        // This is a broadcast to all parties. The desired result is already broadcast_3to4.
2009
2010        // Phase 4
2011        let some_index = executing_parties[0];
2012        let result = parties[(some_index.as_u8() - 1) as usize].sign_phase4(
2013            all_data.get(&some_index).unwrap(),
2014            &x_coord,
2015            &broadcast_3to4,
2016            true,
2017        );
2018        if let Err(abort) = result {
2019            panic!("Party {} aborted: {:?}", abort.index, abort.description());
2020        }
2021    }
2022}