Skip to main content

wsts/state_machine/coordinator/
mod.rs

1use crate::{
2    common::{PolyCommitment, Signature, SignatureShare},
3    curve::{point::Point, scalar::Scalar},
4    errors::AggregatorError,
5    net::{DkgEnd, DkgPrivateShares, DkgPublicShares, NonceResponse, Packet, SignatureType},
6    state_machine::{DkgFailure, OperationResult, StateMachine},
7    taproot::SchnorrProof,
8};
9use core::{cmp::PartialEq, fmt::Debug};
10use hashbrown::{HashMap, HashSet};
11use std::{
12    collections::BTreeMap,
13    time::{Duration, Instant},
14};
15
16#[derive(Clone, Default, Debug, PartialEq)]
17/// Coordinator states
18pub enum State {
19    /// The coordinator is idle
20    #[default]
21    Idle,
22    /// The coordinator is asking signers to send public shares
23    DkgPublicDistribute,
24    /// The coordinator is gathering public shares
25    DkgPublicGather,
26    /// The coordinator is asking signers to send private shares
27    DkgPrivateDistribute,
28    /// The coordinator is gathering private shares
29    DkgPrivateGather,
30    /// The coordinator is asking signers to compute shares and send end
31    DkgEndDistribute,
32    /// The coordinator is gathering DKG End messages
33    DkgEndGather,
34    /// The coordinator is requesting nonces
35    NonceRequest(SignatureType),
36    /// The coordinator is gathering nonces
37    NonceGather(SignatureType),
38    /// The coordinator is requesting signature shares
39    SigShareRequest(SignatureType),
40    /// The coordinator is gathering signature shares
41    SigShareGather(SignatureType),
42}
43
44#[derive(thiserror::Error, Clone, Debug)]
45#[allow(clippy::large_enum_variant)]
46/// The error type for the coordinator
47pub enum Error {
48    /// A bad state change was made
49    #[error("Bad State Change: {0}")]
50    BadStateChange(String),
51    /// A bad dkg_id in received message
52    #[error("Bad dkg_id: got {0} expected {1}")]
53    BadDkgId(u64, u64),
54    /// A bad sign_id in received message
55    #[error("Bad sign_id: got {0} expected {1}")]
56    BadSignId(u64, u64),
57    /// A bad sign_iter_id in received message
58    #[error("Bad sign_iter_id: got {0} expected {1}")]
59    BadSignIterId(u64, u64),
60    /// A malicious signer sent the received message
61    #[error("Malicious signer {0}")]
62    MaliciousSigner(u32),
63    /// SignatureAggregator error
64    #[error("Aggregator: {0}")]
65    Aggregator(AggregatorError),
66    /// Schnorr proof failed to verify
67    #[error("Schnorr Proof failed to verify")]
68    SchnorrProofFailed,
69    /// No aggregate public key set
70    #[error("No aggregate public key set")]
71    MissingAggregatePublicKey,
72    /// No schnorr proof set
73    #[error("No schnorr proof set")]
74    MissingSchnorrProof,
75    /// No signature set
76    #[error("No signature set")]
77    MissingSignature,
78    /// Missing message response information for a signing round
79    #[error("Missing message nonce information")]
80    MissingMessageNonceInfo,
81    /// DKG failure from signers
82    #[error("DKG failure from signers")]
83    DkgFailure(HashMap<u32, DkgFailure>),
84    /// Aggregate key does not match supplied party polynomial
85    #[error(
86        "Aggregate key and computed key from party polynomials mismatch: got {0}, expected {1}"
87    )]
88    AggregateKeyPolynomialMismatch(Point, Point),
89    /// Supplied party polynomial contained duplicate party IDs
90    #[error("Supplied party polynomials contained a duplicate party ID")]
91    DuplicatePartyId,
92}
93
94impl From<AggregatorError> for Error {
95    fn from(err: AggregatorError) -> Self {
96        Error::Aggregator(err)
97    }
98}
99
100/// Config fields common to all Coordinators
101#[derive(Default, Clone, Debug, PartialEq)]
102pub struct Config {
103    /// total number of signers
104    pub num_signers: u32,
105    /// total number of keys
106    pub num_keys: u32,
107    /// threshold of keys needed to form a valid signature
108    pub threshold: u32,
109    /// threshold of keys needed to complete DKG (must be >= threshold)
110    pub dkg_threshold: u32,
111    /// private key used to sign network messages
112    pub message_private_key: Scalar,
113    /// timeout to gather DkgPublicShares messages
114    pub dkg_public_timeout: Option<Duration>,
115    /// timeout to gather DkgPrivateShares messages
116    pub dkg_private_timeout: Option<Duration>,
117    /// timeout to gather DkgEnd messages
118    pub dkg_end_timeout: Option<Duration>,
119    /// timeout to gather nonces
120    pub nonce_timeout: Option<Duration>,
121    /// timeout to gather signature shares
122    pub sign_timeout: Option<Duration>,
123    /// map of signer_id to controlled key_ids
124    pub signer_key_ids: HashMap<u32, HashSet<u32>>,
125    /// ECDSA public keys as Point objects indexed by signer_id
126    pub signer_public_keys: HashMap<u32, Point>,
127}
128
129impl Config {
130    /// Create a new config object with no timeouts
131    pub fn new(
132        num_signers: u32,
133        num_keys: u32,
134        threshold: u32,
135        message_private_key: Scalar,
136    ) -> Self {
137        Config {
138            num_signers,
139            num_keys,
140            threshold,
141            dkg_threshold: num_keys,
142            message_private_key,
143            dkg_public_timeout: None,
144            dkg_private_timeout: None,
145            dkg_end_timeout: None,
146            nonce_timeout: None,
147            sign_timeout: None,
148            signer_key_ids: Default::default(),
149            signer_public_keys: Default::default(),
150        }
151    }
152
153    #[allow(clippy::too_many_arguments)]
154    /// Create a new config object with the passed timeouts
155    pub fn with_timeouts(
156        num_signers: u32,
157        num_keys: u32,
158        threshold: u32,
159        dkg_threshold: u32,
160        message_private_key: Scalar,
161        dkg_public_timeout: Option<Duration>,
162        dkg_private_timeout: Option<Duration>,
163        dkg_end_timeout: Option<Duration>,
164        nonce_timeout: Option<Duration>,
165        sign_timeout: Option<Duration>,
166        signer_key_ids: HashMap<u32, HashSet<u32>>,
167        signer_public_keys: HashMap<u32, Point>,
168    ) -> Self {
169        Config {
170            num_signers,
171            num_keys,
172            threshold,
173            dkg_threshold,
174            message_private_key,
175            dkg_public_timeout,
176            dkg_private_timeout,
177            dkg_end_timeout,
178            nonce_timeout,
179            sign_timeout,
180            signer_key_ids,
181            signer_public_keys,
182        }
183    }
184}
185
186#[derive(Clone, Debug, Default, PartialEq)]
187/// The info for a sign round over specific message bytes
188pub struct SignRoundInfo {
189    /// the nonce response of a signer id
190    pub public_nonces: BTreeMap<u32, NonceResponse>,
191    /// which key_ids we've received nonces for this iteration
192    pub nonce_recv_key_ids: HashSet<u32>,
193    /// which key_ids we're received sig shares for this iteration
194    pub sign_recv_key_ids: HashSet<u32>,
195    /// which signer_ids we're expecting sig shares from this iteration
196    pub sign_wait_signer_ids: HashSet<u32>,
197}
198
199/// The saved state required to reconstruct a coordinator
200#[derive(Default, Clone, Debug, PartialEq)]
201pub struct SavedState {
202    /// common config fields
203    pub config: Config,
204    /// current DKG round ID
205    pub current_dkg_id: u64,
206    /// current signing round ID
207    pub current_sign_id: u64,
208    /// current signing iteration ID
209    pub current_sign_iter_id: u64,
210    /// map of DkgPublicShares indexed by signer ID
211    pub dkg_public_shares: BTreeMap<u32, DkgPublicShares>,
212    /// map of DkgPrivateShares indexed by signer ID
213    pub dkg_private_shares: BTreeMap<u32, DkgPrivateShares>,
214    /// map of DkgEnd indexed by signer ID
215    pub dkg_end_messages: BTreeMap<u32, DkgEnd>,
216    /// the current view of a successful DKG's participants' commitments
217    pub party_polynomials: HashMap<u32, PolyCommitment>,
218    /// map of SignatureShare indexed by signer ID
219    pub signature_shares: BTreeMap<u32, Vec<SignatureShare>>,
220    /// map of SignRoundInfo indexed by message bytes
221    pub message_nonces: BTreeMap<Vec<u8>, SignRoundInfo>,
222    /// aggregate public key
223    pub aggregate_public_key: Option<Point>,
224    /// current Signature
225    pub signature: Option<Signature>,
226    /// current SchnorrProof
227    pub schnorr_proof: Option<SchnorrProof>,
228    /// which signers we're currently waiting on for DKG
229    pub dkg_wait_signer_ids: HashSet<u32>,
230    /// the bytes that we're signing
231    pub message: Vec<u8>,
232    /// current state of the state machine
233    pub state: State,
234    /// start time for NonceRequest
235    pub nonce_start: Option<Instant>,
236    /// start time for DkgBegin
237    pub dkg_public_start: Option<Instant>,
238    /// start time for DkgPrivateBegin
239    pub dkg_private_start: Option<Instant>,
240    /// start time for DkgEndBegin
241    pub dkg_end_start: Option<Instant>,
242    /// start time for SignatureShareRequest
243    pub sign_start: Option<Instant>,
244    /// set of malicious signers during signing round
245    pub malicious_signer_ids: HashSet<u32>,
246    /// set of malicious signers during dkg round
247    pub malicious_dkg_signer_ids: HashSet<u32>,
248}
249
250/// Coordinator trait for handling the coordination of DKG and sign messages
251pub trait Coordinator: Clone + Debug + PartialEq + StateMachine<State, Error> {
252    /// Create a new Coordinator
253    fn new(config: Config) -> Self;
254
255    /// Load a coordinator from the previously saved `state`
256    fn load(state: &SavedState) -> Self;
257
258    /// Save the state required to reconstruct the coordinator
259    fn save(&self) -> SavedState;
260
261    /// Retrieve the config
262    fn get_config(&self) -> Config;
263
264    /// Initialize Coordinator from partial saved state
265    fn set_key_and_party_polynomials(
266        &mut self,
267        aggregate_key: Point,
268        party_polynomials: Vec<(u32, PolyCommitment)>,
269    ) -> Result<(), Error>;
270
271    /// Process inbound messages
272    fn process_inbound_messages(
273        &mut self,
274        packets: &[Packet],
275    ) -> Result<(Vec<Packet>, Vec<OperationResult>), Error>;
276
277    /// Retrieve the aggregate public key
278    fn get_aggregate_public_key(&self) -> Option<Point>;
279
280    /// Set the aggregate public key
281    fn set_aggregate_public_key(&mut self, aggregate_public_key: Option<Point>);
282
283    /// Retrieve the current message bytes being signed
284    fn get_message(&self) -> Vec<u8>;
285
286    /// Retrive the current state
287    fn get_state(&self) -> State;
288
289    /// Trigger a DKG round
290    fn start_dkg_round(&mut self) -> Result<Packet, Error>;
291
292    /// Trigger a signing round
293    fn start_signing_round(
294        &mut self,
295        message: &[u8],
296        signature_type: SignatureType,
297    ) -> Result<Packet, Error>;
298
299    /// Reset internal state
300    fn reset(&mut self);
301}
302
303/// The coordinator for the FROST algorithm
304pub mod frost;
305
306/// The coordinator for the FIRE algorithm
307pub mod fire;
308
309#[allow(missing_docs)]
310pub mod test {
311    use hashbrown::{HashMap, HashSet};
312    use rand_core::OsRng;
313    use std::{sync::Once, time::Duration};
314    use tracing_subscriber::{fmt, prelude::*, EnvFilter};
315
316    use crate::{
317        common::SignatureShare,
318        compute,
319        curve::{ecdsa, point::Point, point::G, scalar::Scalar},
320        errors::AggregatorError,
321        net::{DkgFailure, Message, Packet, SignatureShareResponse, SignatureType},
322        state_machine::{
323            coordinator::{Config, Coordinator as CoordinatorTrait, Error, State},
324            signer::{Error as SignerError, Signer},
325            DkgError, Error as StateMachineError, OperationResult, PublicKeys, SignError,
326            StateMachine,
327        },
328        traits::Signer as SignerTrait,
329        util::create_rng,
330    };
331
332    static INIT: Once = Once::new();
333
334    pub fn new_coordinator<Coordinator: CoordinatorTrait>() {
335        let mut rng = create_rng();
336        let config = Config::new(10, 40, 28, Scalar::random(&mut rng));
337        let coordinator = Coordinator::new(config.clone());
338
339        assert_eq!(coordinator.get_config().num_signers, config.num_signers);
340        assert_eq!(coordinator.get_config().num_keys, config.num_keys);
341        assert_eq!(coordinator.get_config().threshold, config.threshold);
342        assert_eq!(
343            coordinator.get_config().message_private_key,
344            config.message_private_key
345        );
346        assert_eq!(coordinator.get_state(), State::Idle);
347    }
348
349    pub fn coordinator_state_machine<Coordinator: CoordinatorTrait + StateMachine<State, Error>>() {
350        let mut rng = create_rng();
351        let config = Config::new(3, 3, 3, Scalar::random(&mut rng));
352        let mut coordinator = Coordinator::new(config);
353        assert!(coordinator.can_move_to(&State::DkgPublicDistribute).is_ok());
354        assert!(coordinator.can_move_to(&State::DkgPublicGather).is_err());
355        assert!(coordinator
356            .can_move_to(&State::DkgPrivateDistribute)
357            .is_err());
358        assert!(coordinator.can_move_to(&State::DkgPrivateGather).is_err());
359        assert!(coordinator.can_move_to(&State::DkgEndDistribute).is_err());
360        assert!(coordinator.can_move_to(&State::DkgEndGather).is_err());
361        assert!(coordinator.can_move_to(&State::Idle).is_ok());
362
363        coordinator.move_to(State::DkgPublicDistribute).unwrap();
364        assert!(coordinator
365            .can_move_to(&State::DkgPublicDistribute)
366            .is_err());
367        assert!(coordinator.can_move_to(&State::DkgPublicGather).is_ok());
368        assert!(coordinator
369            .can_move_to(&State::DkgPrivateDistribute)
370            .is_err());
371        assert!(coordinator.can_move_to(&State::DkgPrivateGather).is_err());
372        assert!(coordinator.can_move_to(&State::DkgEndDistribute).is_err());
373        assert!(coordinator.can_move_to(&State::DkgEndGather).is_err());
374        assert!(coordinator.can_move_to(&State::Idle).is_ok());
375
376        coordinator.move_to(State::DkgPublicGather).unwrap();
377        assert!(coordinator
378            .can_move_to(&State::DkgPublicDistribute)
379            .is_err());
380        assert!(coordinator.can_move_to(&State::DkgPublicGather).is_ok());
381        assert!(coordinator
382            .can_move_to(&State::DkgPrivateDistribute)
383            .is_ok());
384        assert!(coordinator.can_move_to(&State::DkgPrivateGather).is_err());
385        assert!(coordinator.can_move_to(&State::DkgEndDistribute).is_err());
386        assert!(coordinator.can_move_to(&State::DkgEndGather).is_err());
387        assert!(coordinator.can_move_to(&State::Idle).is_ok());
388
389        coordinator.move_to(State::DkgPrivateDistribute).unwrap();
390        assert!(coordinator
391            .can_move_to(&State::DkgPublicDistribute)
392            .is_err());
393        assert!(coordinator.can_move_to(&State::DkgPublicGather).is_err());
394        assert!(coordinator
395            .can_move_to(&State::DkgPrivateDistribute)
396            .is_err());
397        assert!(coordinator.can_move_to(&State::DkgPrivateGather).is_ok());
398        assert!(coordinator.can_move_to(&State::DkgEndDistribute).is_err());
399        assert!(coordinator.can_move_to(&State::DkgEndGather).is_err());
400        assert!(coordinator.can_move_to(&State::Idle).is_ok());
401
402        coordinator.move_to(State::DkgPrivateGather).unwrap();
403        assert!(coordinator
404            .can_move_to(&State::DkgPublicDistribute)
405            .is_err());
406        assert!(coordinator.can_move_to(&State::DkgPublicGather).is_err());
407        assert!(coordinator
408            .can_move_to(&State::DkgPrivateDistribute)
409            .is_err());
410        assert!(coordinator.can_move_to(&State::DkgPrivateGather).is_ok());
411        assert!(coordinator.can_move_to(&State::DkgEndDistribute).is_ok());
412        assert!(coordinator.can_move_to(&State::DkgEndGather).is_err());
413        assert!(coordinator.can_move_to(&State::Idle).is_ok());
414
415        coordinator.move_to(State::DkgEndDistribute).unwrap();
416        assert!(coordinator.can_move_to(&State::DkgEndGather).is_ok());
417
418        coordinator.move_to(State::DkgEndGather).unwrap();
419        assert!(coordinator.can_move_to(&State::Idle).is_ok());
420    }
421
422    pub fn start_dkg_round<Coordinator: CoordinatorTrait>() {
423        let mut rng = create_rng();
424        let config = Config::new(10, 40, 28, Scalar::random(&mut rng));
425        let mut coordinator = Coordinator::new(config);
426        let result = coordinator.start_dkg_round();
427
428        assert!(result.is_ok());
429        if let Message::DkgBegin(dkg_begin) = result.unwrap().msg {
430            assert_eq!(dkg_begin.dkg_id, 1);
431        } else {
432            panic!("Bad dkg_id");
433        }
434        assert_eq!(coordinator.get_state(), State::DkgPublicGather);
435    }
436
437    pub fn setup<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
438        num_signers: u32,
439        keys_per_signer: u32,
440    ) -> (Vec<Coordinator>, Vec<Signer<SignerType>>) {
441        setup_with_timeouts::<Coordinator, SignerType>(
442            num_signers,
443            keys_per_signer,
444            None,
445            None,
446            None,
447            None,
448            None,
449        )
450    }
451
452    pub fn setup_with_timeouts<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
453        num_signers: u32,
454        keys_per_signer: u32,
455        dkg_public_timeout: Option<Duration>,
456        dkg_private_timeout: Option<Duration>,
457        dkg_end_timeout: Option<Duration>,
458        nonce_timeout: Option<Duration>,
459        sign_timeout: Option<Duration>,
460    ) -> (Vec<Coordinator>, Vec<Signer<SignerType>>) {
461        INIT.call_once(|| {
462            tracing_subscriber::registry()
463                .with(fmt::layer())
464                .with(EnvFilter::from_default_env())
465                .init();
466        });
467
468        let mut rng = create_rng();
469        let num_keys = num_signers * keys_per_signer;
470        let threshold = (num_keys * 7) / 10;
471        let dkg_threshold = (num_keys * 9) / 10;
472        let key_pairs = (0..num_signers)
473            .map(|_| {
474                let private_key = Scalar::random(&mut rng);
475                let public_key = ecdsa::PublicKey::new(&private_key).unwrap();
476                (private_key, public_key)
477            })
478            .collect::<Vec<(Scalar, ecdsa::PublicKey)>>();
479        let mut key_id: u32 = 1;
480        let mut signer_ids_map = HashMap::new();
481        let mut signer_key_ids = HashMap::new();
482        let mut signer_key_ids_set = HashMap::new();
483        let mut signer_public_keys = HashMap::new();
484        let mut key_ids_map = HashMap::new();
485        for (i, (private_key, public_key)) in key_pairs.iter().enumerate() {
486            let mut key_ids = Vec::new();
487            let mut key_ids_set = HashSet::new();
488            for _ in 0..keys_per_signer {
489                key_ids_map.insert(key_id, *public_key);
490                key_ids.push(key_id);
491                key_ids_set.insert(key_id);
492                key_id += 1;
493            }
494            signer_ids_map.insert(i as u32, *public_key);
495            signer_key_ids.insert(i as u32, key_ids);
496            signer_key_ids_set.insert(i as u32, key_ids_set);
497            signer_public_keys.insert(i as u32, Point::from(private_key));
498        }
499        let public_keys = PublicKeys {
500            signers: signer_ids_map,
501            key_ids: key_ids_map,
502            signer_key_ids: signer_key_ids_set.clone(),
503        };
504
505        let signers = key_pairs
506            .iter()
507            .enumerate()
508            .map(|(signer_id, (private_key, _public_key))| {
509                Signer::<SignerType>::new(
510                    threshold,
511                    dkg_threshold,
512                    num_signers,
513                    num_keys,
514                    signer_id as u32,
515                    signer_key_ids[&(signer_id as u32)].clone(),
516                    *private_key,
517                    public_keys.clone(),
518                    &mut rng,
519                )
520                .unwrap()
521            })
522            .collect::<Vec<Signer<SignerType>>>();
523        let coordinators = key_pairs
524            .into_iter()
525            .map(|(private_key, _public_key)| {
526                let config = Config::with_timeouts(
527                    num_signers,
528                    num_keys,
529                    threshold,
530                    dkg_threshold,
531                    private_key,
532                    dkg_public_timeout,
533                    dkg_private_timeout,
534                    dkg_end_timeout,
535                    nonce_timeout,
536                    sign_timeout,
537                    signer_key_ids_set.clone(),
538                    signer_public_keys.clone(),
539                );
540                Coordinator::new(config)
541            })
542            .collect::<Vec<Coordinator>>();
543        (coordinators, signers)
544    }
545
546    /// Helper function for feeding messages back from the processor into the signing rounds and coordinators
547    pub fn feedback_messages<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
548        coordinators: &mut [Coordinator],
549        signers: &mut [Signer<SignerType>],
550        messages: &[Packet],
551    ) -> (Vec<Packet>, Vec<OperationResult>) {
552        feedback_mutated_messages(coordinators, signers, messages, |_signer, msgs| msgs)
553    }
554
555    /// Helper function for feeding mutated messages back from the processor into the signing rounds and coordinators
556    pub fn feedback_mutated_messages<
557        Coordinator: CoordinatorTrait,
558        SignerType: SignerTrait,
559        F: Fn(&Signer<SignerType>, Vec<Packet>) -> Vec<Packet>,
560    >(
561        coordinators: &mut [Coordinator],
562        signers: &mut [Signer<SignerType>],
563        messages: &[Packet],
564        signer_mutator: F,
565    ) -> (Vec<Packet>, Vec<OperationResult>) {
566        feedback_mutated_messages_with_errors(coordinators, signers, messages, signer_mutator)
567            .unwrap()
568    }
569
570    /// Helper function for feeding mutated messages back from the processor into the signing rounds and coordinators
571    pub fn feedback_messages_with_errors<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
572        coordinators: &mut [Coordinator],
573        signers: &mut [Signer<SignerType>],
574        messages: &[Packet],
575    ) -> Result<(Vec<Packet>, Vec<OperationResult>), StateMachineError> {
576        feedback_mutated_messages_with_errors(coordinators, signers, messages, |_signer, msgs| msgs)
577    }
578
579    /// Helper function for feeding mutated messages back from the processor into the signing rounds and coordinators
580    pub fn feedback_mutated_messages_with_errors<
581        Coordinator: CoordinatorTrait,
582        SignerType: SignerTrait,
583        F: Fn(&Signer<SignerType>, Vec<Packet>) -> Vec<Packet>,
584    >(
585        coordinators: &mut [Coordinator],
586        signers: &mut [Signer<SignerType>],
587        messages: &[Packet],
588        signer_mutator: F,
589    ) -> Result<(Vec<Packet>, Vec<OperationResult>), StateMachineError> {
590        let mut inbound_messages = vec![];
591        let mut feedback_messages = vec![];
592        let mut rng = create_rng();
593        for signer in signers.iter_mut() {
594            let outbound_messages = signer.process_inbound_messages(messages, &mut rng)?;
595            let outbound_messages = signer_mutator(signer, outbound_messages);
596            feedback_messages.extend_from_slice(outbound_messages.as_slice());
597            inbound_messages.extend(outbound_messages);
598        }
599        for signer in signers.iter_mut() {
600            let outbound_messages =
601                signer.process_inbound_messages(&feedback_messages, &mut rng)?;
602            inbound_messages.extend(outbound_messages);
603        }
604        for coordinator in coordinators.iter_mut() {
605            // Process all coordinator messages, but don't bother with propogating these results
606            let _ = coordinator.process_inbound_messages(messages)?;
607        }
608        let mut results = vec![];
609        let mut messages = vec![];
610        for (i, coordinator) in coordinators.iter_mut().enumerate() {
611            let (outbound_messages, outbound_results) =
612                coordinator.process_inbound_messages(&inbound_messages)?;
613            // Only propogate a single coordinator's messages and results
614            if i == 0 {
615                messages.extend(outbound_messages);
616                results.extend(outbound_results);
617            }
618        }
619        Ok((messages, results))
620    }
621
622    pub fn run_dkg<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
623        num_signers: u32,
624        keys_per_signer: u32,
625    ) -> (Vec<Coordinator>, Vec<Signer<SignerType>>) {
626        let (mut coordinators, mut signers) =
627            setup::<Coordinator, SignerType>(num_signers, keys_per_signer);
628
629        // We have started a dkg round
630        let message = coordinators.first_mut().unwrap().start_dkg_round().unwrap();
631        assert!(coordinators
632            .first_mut()
633            .unwrap()
634            .get_aggregate_public_key()
635            .is_none());
636        assert_eq!(
637            coordinators.first_mut().unwrap().get_state(),
638            State::DkgPublicGather
639        );
640
641        // Send the DKG Begin message to all signers and gather responses by sharing with all other signers and coordinator
642        let (outbound_messages, operation_results) =
643            feedback_messages(&mut coordinators, &mut signers, &[message]);
644        assert!(operation_results.is_empty());
645        for coordinator in coordinators.iter() {
646            assert_eq!(coordinator.get_state(), State::DkgPrivateGather);
647        }
648
649        assert_eq!(outbound_messages.len(), 1);
650        match &outbound_messages[0].msg {
651            Message::DkgPrivateBegin(_) => {}
652            _ => {
653                panic!("Expected DkgPrivateBegin message");
654            }
655        }
656
657        // persist the state machines before continuing
658        let new_coordinators = coordinators
659            .iter()
660            .map(|c| Coordinator::load(&c.save()))
661            .collect::<Vec<Coordinator>>();
662
663        assert_eq!(coordinators, new_coordinators);
664
665        coordinators = new_coordinators;
666
667        let new_signers = signers
668            .iter()
669            .map(|s| Signer::<SignerType>::load(&s.save()))
670            .collect::<Vec<Signer<SignerType>>>();
671
672        assert_eq!(signers, new_signers);
673
674        signers = new_signers;
675
676        // Send the DKG Private Begin message to all signers and share their responses with the coordinator and signers
677        let (outbound_messages, operation_results) =
678            feedback_messages(&mut coordinators, &mut signers, &outbound_messages);
679        assert_eq!(operation_results.len(), 0);
680        assert_eq!(outbound_messages.len(), 1);
681        match &outbound_messages[0].msg {
682            Message::DkgEndBegin(_) => {}
683            _ => {
684                panic!("Expected DkgEndBegin message");
685            }
686        }
687
688        // persist the state machines before continuing
689        let new_coordinators = coordinators
690            .iter()
691            .map(|c| Coordinator::load(&c.save()))
692            .collect::<Vec<Coordinator>>();
693
694        assert_eq!(coordinators, new_coordinators);
695
696        coordinators = new_coordinators;
697
698        let new_signers = signers
699            .iter()
700            .map(|s| Signer::<SignerType>::load(&s.save()))
701            .collect::<Vec<Signer<SignerType>>>();
702
703        assert_eq!(signers, new_signers);
704
705        signers = new_signers;
706
707        // Send the DkgEndBegin message to all signers and share their responses with the coordinator and signers
708        let (outbound_messages, operation_results) =
709            feedback_messages(&mut coordinators, &mut signers, &outbound_messages);
710        assert_eq!(outbound_messages.len(), 0);
711        assert_eq!(operation_results.len(), 1);
712        match operation_results[0] {
713            OperationResult::Dkg(point) => {
714                assert_ne!(point, Point::default());
715                for coordinator in coordinators.iter() {
716                    assert_eq!(coordinator.get_aggregate_public_key(), Some(point));
717                    assert_eq!(coordinator.get_state(), State::Idle);
718                }
719            }
720            _ => panic!("Expected Dkg Operation result"),
721        }
722
723        // clear the polynomials before persisting
724        for signer in &mut signers {
725            signer.signer.clear_polys();
726        }
727
728        // persist the state machines before continuing
729        let new_coordinators = coordinators
730            .iter()
731            .map(|c| Coordinator::load(&c.save()))
732            .collect::<Vec<Coordinator>>();
733
734        assert_eq!(coordinators, new_coordinators);
735
736        coordinators = new_coordinators;
737
738        let new_signers = signers
739            .iter()
740            .map(|s| Signer::<SignerType>::load(&s.save()))
741            .collect::<Vec<Signer<SignerType>>>();
742
743        assert_eq!(signers, new_signers);
744
745        signers = new_signers;
746
747        (coordinators, signers)
748    }
749
750    pub fn run_sign<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
751        coordinators: &mut [Coordinator],
752        signers: &mut Vec<Signer<SignerType>>,
753        msg: &[u8],
754        signature_type: SignatureType,
755    ) -> OperationResult {
756        // Start a signing round
757        let message = coordinators
758            .first_mut()
759            .unwrap()
760            .start_signing_round(msg, signature_type)
761            .unwrap();
762        assert_eq!(
763            coordinators.first_mut().unwrap().get_state(),
764            State::NonceGather(signature_type)
765        );
766
767        // Send the message to all signers and gather responses by sharing with all other signers and coordinator
768        let (outbound_messages, operation_results) =
769            feedback_messages(coordinators, signers, &[message]);
770        assert!(operation_results.is_empty());
771        assert_eq!(
772            coordinators.first_mut().unwrap().get_state(),
773            State::SigShareGather(signature_type)
774        );
775
776        assert_eq!(outbound_messages.len(), 1);
777        match &outbound_messages[0].msg {
778            Message::SignatureShareRequest(_) => {}
779            _ => {
780                panic!("Expected SignatureShareRequest message");
781            }
782        }
783
784        // persist the coordinators before continuing
785        let _new_coordinators = coordinators
786            .iter()
787            .map(|c| Coordinator::load(&c.save()))
788            .collect::<Vec<Coordinator>>();
789
790        let new_signers = signers
791            .iter()
792            .map(|s| Signer::<SignerType>::load(&s.save()))
793            .collect::<Vec<Signer<SignerType>>>();
794
795        assert_eq!(signers, &new_signers);
796
797        // Send the SignatureShareRequest message to all signers and share their responses with the coordinator and signers
798        let (outbound_messages, operation_results) =
799            feedback_messages(coordinators, signers, &outbound_messages);
800        assert!(outbound_messages.is_empty());
801        assert_eq!(operation_results.len(), 1);
802        match &operation_results[0] {
803            OperationResult::Sign(sig) => {
804                if let SignatureType::Frost = signature_type {
805                    for coordinator in coordinators.iter() {
806                        assert!(sig.verify(
807                            &coordinator
808                                .get_aggregate_public_key()
809                                .expect("No aggregate public key set!"),
810                            msg
811                        ));
812                        assert_eq!(coordinator.get_state(), State::Idle);
813                    }
814                } else {
815                    panic!("Expected OperationResult::Sign");
816                }
817            }
818            OperationResult::SignSchnorr(sig) => {
819                if let SignatureType::Schnorr = signature_type {
820                    for coordinator in coordinators.iter() {
821                        assert!(sig.verify(
822                            &coordinator
823                                .get_aggregate_public_key()
824                                .expect("No aggregate public key set!")
825                                .x(),
826                            msg
827                        ));
828                        assert_eq!(coordinator.get_state(), State::Idle);
829                    }
830                } else {
831                    panic!("Expected OperationResult::SignSchnorr");
832                }
833            }
834            OperationResult::SignTaproot(sig) => {
835                if let SignatureType::Taproot(merkle_root) = signature_type {
836                    for coordinator in coordinators.iter() {
837                        let tweaked_public_key = compute::tweaked_public_key(
838                            &coordinator
839                                .get_aggregate_public_key()
840                                .expect("No aggregate public key set!"),
841                            merkle_root,
842                        );
843
844                        assert!(sig.verify(&tweaked_public_key.x(), msg));
845                        assert_eq!(coordinator.get_state(), State::Idle);
846                    }
847                } else {
848                    panic!("Expected OperationResult::SignTaproot");
849                }
850            }
851            _ => panic!("Expected OperationResult"),
852        }
853
854        operation_results[0].clone()
855    }
856
857    pub fn run_dkg_sign<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
858        num_signers: u32,
859        keys_per_signer: u32,
860    ) {
861        let (mut coordinators, mut signers) =
862            run_dkg::<Coordinator, SignerType>(num_signers, keys_per_signer);
863
864        let msg = "It was many and many a year ago, in a kingdom by the sea"
865            .as_bytes()
866            .to_vec();
867
868        run_sign::<Coordinator, SignerType>(
869            &mut coordinators,
870            &mut signers,
871            &msg,
872            SignatureType::Frost,
873        );
874        run_sign::<Coordinator, SignerType>(
875            &mut coordinators,
876            &mut signers,
877            &msg,
878            SignatureType::Schnorr,
879        );
880        run_sign::<Coordinator, SignerType>(
881            &mut coordinators,
882            &mut signers,
883            &msg,
884            SignatureType::Taproot(None),
885        );
886        run_sign::<Coordinator, SignerType>(
887            &mut coordinators,
888            &mut signers,
889            &msg,
890            SignatureType::Taproot(Some([128u8; 32])),
891        );
892    }
893
894    /// Run DKG then sign a message, but alter the signature shares for signer 0.  This should trigger the aggregator internal check_signature_shares function to run and determine which parties signatures were bad.
895    /// Because of the differences between how parties are represented in v1 and v2, we need to pass in a vector of the expected bad parties.
896    pub fn check_signature_shares<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
897        num_signers: u32,
898        keys_per_signer: u32,
899        signature_type: SignatureType,
900        bad_parties: Vec<u32>,
901    ) {
902        let (mut coordinators, mut signers) =
903            run_dkg::<Coordinator, SignerType>(num_signers, keys_per_signer);
904
905        let msg = "It was many and many a year ago, in a kingdom by the sea"
906            .as_bytes()
907            .to_vec();
908        // Start a signing round
909        let message = coordinators
910            .first_mut()
911            .unwrap()
912            .start_signing_round(&msg, signature_type)
913            .unwrap();
914        assert_eq!(
915            coordinators.first_mut().unwrap().get_state(),
916            State::NonceGather(signature_type)
917        );
918
919        // Send the message to all signers and gather responses by sharing with all other signers and coordinator
920        let (outbound_messages, operation_results) =
921            feedback_messages(&mut coordinators, &mut signers, &[message]);
922        assert!(operation_results.is_empty());
923        assert_eq!(
924            coordinators.first_mut().unwrap().get_state(),
925            State::SigShareGather(signature_type)
926        );
927
928        assert_eq!(outbound_messages.len(), 1);
929        match &outbound_messages[0].msg {
930            Message::SignatureShareRequest(_) => {}
931            _ => {
932                panic!("Expected SignatureShareRequest message");
933            }
934        }
935
936        // Send the SignatureShareRequest message to all signers and share their responses with the coordinator and signers
937        let (outbound_messages, operation_results) = feedback_mutated_messages(
938            &mut coordinators,
939            &mut signers,
940            &outbound_messages,
941            |signer, packets| {
942                if signer.signer_id == 0 {
943                    packets
944                        .iter()
945                        .map(|packet| {
946                            if let Message::SignatureShareResponse(response) = &packet.msg {
947                                // mutate one of the shares
948                                let sshares: Vec<SignatureShare> = response
949                                    .signature_shares
950                                    .iter()
951                                    .map(|share| SignatureShare {
952                                        id: share.id,
953                                        key_ids: share.key_ids.clone(),
954                                        z_i: share.z_i + Scalar::from(1),
955                                    })
956                                    .collect();
957                                Packet {
958                                    msg: Message::SignatureShareResponse(SignatureShareResponse {
959                                        dkg_id: response.dkg_id,
960                                        sign_id: response.sign_id,
961                                        sign_iter_id: response.sign_iter_id,
962                                        signer_id: response.signer_id,
963                                        signature_shares: sshares,
964                                    }),
965                                    sig: vec![],
966                                }
967                            } else {
968                                packet.clone()
969                            }
970                        })
971                        .collect()
972                } else {
973                    packets.clone()
974                }
975            },
976        );
977        assert!(outbound_messages.is_empty());
978        assert_eq!(operation_results.len(), 1);
979        match &operation_results[0] {
980            OperationResult::SignError(SignError::Coordinator(Error::Aggregator(AggregatorError::BadPartySigs(parties)))) => {
981		if parties != &bad_parties {
982		    panic!("Expected BadPartySigs from {:?}, got {:?}", &bad_parties, &operation_results[0]);
983		}
984	    }
985            _ => panic!("Expected OperationResult::SignError(SignError::Coordinator(Error::Aggregator(AggregatorError::BadPartySigs(parties))))"),
986        }
987    }
988
989    pub fn equal_after_save_load<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
990        num_signers: u32,
991        keys_per_signer: u32,
992    ) {
993        let (coordinators, signers) =
994            setup::<Coordinator, SignerType>(num_signers, keys_per_signer);
995
996        let loaded_coordinators = coordinators
997            .iter()
998            .map(|c| Coordinator::load(&c.save()))
999            .collect::<Vec<Coordinator>>();
1000
1001        assert_eq!(coordinators, loaded_coordinators);
1002
1003        let loaded_signers = signers
1004            .iter()
1005            .map(|s| Signer::<SignerType>::load(&s.save()))
1006            .collect::<Vec<Signer<SignerType>>>();
1007
1008        assert_eq!(signers, loaded_signers);
1009    }
1010
1011    /// Test if a signer will generate a new nonce after a signing round as a defense
1012    /// against a malicious coordinator who requests multiple signing rounds
1013    /// with no nonce round in between to generate a new nonce
1014    pub fn gen_nonces<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
1015        num_signers: u32,
1016        keys_per_signer: u32,
1017    ) {
1018        let mut rng = OsRng;
1019
1020        let (mut coordinators, mut signers) =
1021            run_dkg::<Coordinator, SignerType>(num_signers, keys_per_signer);
1022
1023        let msg = "It was many and many a year ago, in a kingdom by the sea"
1024            .as_bytes()
1025            .to_vec();
1026
1027        let signature_type = SignatureType::Frost;
1028
1029        // Start a signing round
1030        let message = coordinators
1031            .first_mut()
1032            .unwrap()
1033            .start_signing_round(&msg, signature_type)
1034            .unwrap();
1035        assert_eq!(
1036            coordinators.first_mut().unwrap().get_state(),
1037            State::NonceGather(signature_type)
1038        );
1039
1040        // Send the NonceRequest to all signers and gather NonceResponses
1041        // by sharing with all other signers and coordinator
1042        let (outbound_messages, operation_results) =
1043            feedback_messages(&mut coordinators, &mut signers, &[message]);
1044        assert!(operation_results.is_empty());
1045        assert_eq!(
1046            coordinators.first_mut().unwrap().get_state(),
1047            State::SigShareGather(signature_type)
1048        );
1049
1050        // Once the coordinator has received sufficient NonceResponses,
1051        // it should send out a SignatureShareRequest
1052        assert_eq!(outbound_messages.len(), 1);
1053        match &outbound_messages[0].msg {
1054            Message::SignatureShareRequest(_) => {}
1055            _ => {
1056                panic!("Expected SignatureShareRequest message");
1057            }
1058        }
1059
1060        // Pass the SignatureShareRequest to the first signer and get his SignatureShares
1061        // which should use the nonce generated before sending out NonceResponse above
1062        let messages1 = signers[0]
1063            .process(&outbound_messages[0].msg, &mut rng)
1064            .unwrap();
1065
1066        // Pass the SignatureShareRequest to the second signer and get his SignatureShares
1067        // which should use the nonce generated just before sending out the previous SignatureShare
1068        let messages2 = signers[0]
1069            .process(&outbound_messages[0].msg, &mut rng)
1070            .unwrap();
1071
1072        // iterate through the responses and collect the embedded shares
1073        // if the signer didn't generate a nonce after sending the first signature shares
1074        // then the shares should be the same, since the message and everything else is
1075        for (message1, message2) in messages1.into_iter().zip(messages2) {
1076            let share1 = if let Message::SignatureShareResponse(response) = message1 {
1077                response.signature_shares[0].clone()
1078            } else {
1079                panic!("Message should have been SignatureShareResponse");
1080            };
1081            let share2 = if let Message::SignatureShareResponse(response) = message2 {
1082                response.signature_shares[0].clone()
1083            } else {
1084                panic!("Message should have been SignatureShareResponse");
1085            };
1086
1087            assert_ne!(share1.z_i, share2.z_i);
1088        }
1089    }
1090
1091    pub fn bad_signature_share_request<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
1092        num_signers: u32,
1093        keys_per_signer: u32,
1094    ) {
1095        let (mut coordinators, mut signers) =
1096            run_dkg::<Coordinator, SignerType>(num_signers, keys_per_signer);
1097
1098        let msg = "It was many and many a year ago, in a kingdom by the sea"
1099            .as_bytes()
1100            .to_vec();
1101
1102        // Start a signing round
1103        let signature_type = SignatureType::Frost;
1104        let message = coordinators
1105            .first_mut()
1106            .unwrap()
1107            .start_signing_round(&msg, signature_type)
1108            .unwrap();
1109        assert_eq!(
1110            coordinators.first_mut().unwrap().get_state(),
1111            State::NonceGather(signature_type)
1112        );
1113
1114        // Send the message to all signers and gather responses by sharing with all other signers and coordinator
1115        let (outbound_messages, operation_results) =
1116            feedback_messages(&mut coordinators, &mut signers, &[message]);
1117        assert!(operation_results.is_empty());
1118        assert_eq!(
1119            coordinators.first_mut().unwrap().get_state(),
1120            State::SigShareGather(signature_type)
1121        );
1122
1123        assert_eq!(outbound_messages.len(), 1);
1124        match &outbound_messages[0].msg {
1125            Message::SignatureShareRequest(_) => {}
1126            _ => {
1127                panic!("Expected SignatureShareRequest message");
1128            }
1129        }
1130
1131        let messages = outbound_messages.clone();
1132        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &messages);
1133        assert!(result.is_ok());
1134
1135        // test request with no NonceResponses
1136        let mut packet = outbound_messages[0].clone();
1137        if let Message::SignatureShareRequest(ref mut request) = packet.msg {
1138            request.nonce_responses.clear();
1139        } else {
1140            panic!("failed to match message");
1141        }
1142
1143        // Send the SignatureShareRequest message to all signers and share
1144        // their responses with the coordinator and signers
1145        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &[packet]);
1146        if !matches!(
1147            result,
1148            Err(StateMachineError::Signer(SignerError::InvalidNonceResponse))
1149        ) {
1150            panic!("Should have received signer invalid nonce response error, got {result:?}");
1151        }
1152
1153        // test request with a duplicate NonceResponse
1154        let mut packet = outbound_messages[0].clone();
1155        if let Message::SignatureShareRequest(ref mut request) = packet.msg {
1156            request
1157                .nonce_responses
1158                .push(request.nonce_responses[0].clone());
1159        } else {
1160            panic!("failed to match message");
1161        }
1162
1163        // Send the SignatureShareRequest message to all signers and share
1164        // their responses with the coordinator and signers
1165        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &[packet]);
1166        if !matches!(
1167            result,
1168            Err(StateMachineError::Signer(SignerError::InvalidNonceResponse))
1169        ) {
1170            panic!("Should have received signer invalid nonce response error, got {result:?}");
1171        }
1172
1173        // test request with an out of range signer_id
1174        let mut packet = outbound_messages[0].clone();
1175        if let Message::SignatureShareRequest(ref mut request) = packet.msg {
1176            request.nonce_responses[0].signer_id = num_signers;
1177        } else {
1178            panic!("failed to match message");
1179        }
1180
1181        // Send the SignatureShareRequest message to all signers and share
1182        // their responses with the coordinator and signers
1183        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &[packet]);
1184        if !matches!(
1185            result,
1186            Err(StateMachineError::Signer(SignerError::InvalidNonceResponse))
1187        ) {
1188            panic!("Should have received signer invalid nonce response error, got {result:?}");
1189        }
1190    }
1191
1192    pub fn invalid_nonce<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
1193        num_signers: u32,
1194        keys_per_signer: u32,
1195    ) {
1196        let (mut coordinators, mut signers) =
1197            run_dkg::<Coordinator, SignerType>(num_signers, keys_per_signer);
1198
1199        let msg = "It was many and many a year ago, in a kingdom by the sea"
1200            .as_bytes()
1201            .to_vec();
1202
1203        // Start a signing round
1204        let signature_type = SignatureType::Frost;
1205        let message = coordinators
1206            .first_mut()
1207            .unwrap()
1208            .start_signing_round(&msg, signature_type)
1209            .unwrap();
1210        assert_eq!(
1211            coordinators.first_mut().unwrap().get_state(),
1212            State::NonceGather(signature_type)
1213        );
1214
1215        // Send the message to all signers and gather responses by sharing with all other signers and coordinator
1216        let (outbound_messages, operation_results) =
1217            feedback_messages(&mut coordinators, &mut signers, &[message]);
1218        assert!(operation_results.is_empty());
1219        assert_eq!(
1220            coordinators.first_mut().unwrap().get_state(),
1221            State::SigShareGather(signature_type)
1222        );
1223
1224        assert_eq!(outbound_messages.len(), 1);
1225        match &outbound_messages[0].msg {
1226            Message::SignatureShareRequest(_) => {}
1227            _ => {
1228                panic!("Expected SignatureShareRequest message");
1229            }
1230        }
1231
1232        let messages = outbound_messages.clone();
1233        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &messages);
1234        assert!(result.is_ok());
1235
1236        // test request with NonceResponse having zero nonce
1237        let mut packet = outbound_messages[0].clone();
1238        if let Message::SignatureShareRequest(ref mut request) = packet.msg {
1239            for nonce_response in &mut request.nonce_responses {
1240                for nonce in &mut nonce_response.nonces {
1241                    nonce.D = Point::new();
1242                    nonce.E = Point::new();
1243                }
1244            }
1245        } else {
1246            panic!("failed to match message");
1247        }
1248
1249        // Send the SignatureShareRequest message to all signers and share
1250        // their responses with the coordinator and signers
1251        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &[packet]);
1252        if !matches!(
1253            result,
1254            Err(StateMachineError::Signer(SignerError::InvalidNonceResponse))
1255        ) {
1256            panic!("Should have received signer invalid nonce response error, got {result:?}");
1257        }
1258
1259        // test request with NonceResponse having generator nonce
1260        let mut packet = outbound_messages[0].clone();
1261        if let Message::SignatureShareRequest(ref mut request) = packet.msg {
1262            for nonce_response in &mut request.nonce_responses {
1263                for nonce in &mut nonce_response.nonces {
1264                    nonce.D = G;
1265                    nonce.E = G;
1266                }
1267            }
1268        } else {
1269            panic!("failed to match message");
1270        }
1271
1272        // Send the SignatureShareRequest message to all signers and share
1273        // their responses with the coordinator and signers
1274        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &[packet]);
1275        if !matches!(
1276            result,
1277            Err(StateMachineError::Signer(SignerError::InvalidNonceResponse))
1278        ) {
1279            panic!("Should have received signer invalid nonce response error, got {result:?}");
1280        }
1281
1282        // test request with a duplicate NonceResponse
1283        let mut packet = outbound_messages[0].clone();
1284        if let Message::SignatureShareRequest(ref mut request) = packet.msg {
1285            request
1286                .nonce_responses
1287                .push(request.nonce_responses[0].clone());
1288        } else {
1289            panic!("failed to match message");
1290        }
1291
1292        // Send the SignatureShareRequest message to all signers and share
1293        // their responses with the coordinator and signers
1294        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &[packet]);
1295        if !matches!(
1296            result,
1297            Err(StateMachineError::Signer(SignerError::InvalidNonceResponse))
1298        ) {
1299            panic!("Should have received signer invalid nonce response error, got {result:?}");
1300        }
1301
1302        // test request with an out of range signer_id
1303        let mut packet = outbound_messages[0].clone();
1304        if let Message::SignatureShareRequest(ref mut request) = packet.msg {
1305            request.nonce_responses[0].signer_id = num_signers;
1306        } else {
1307            panic!("failed to match message");
1308        }
1309
1310        // Send the SignatureShareRequest message to all signers and share
1311        // their responses with the coordinator and signers
1312        let result = feedback_messages_with_errors(&mut coordinators, &mut signers, &[packet]);
1313        if !matches!(
1314            result,
1315            Err(StateMachineError::Signer(SignerError::InvalidNonceResponse))
1316        ) {
1317            panic!("Should have received signer invalid nonce response error, got {result:?}");
1318        }
1319    }
1320
1321    pub fn empty_public_shares<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
1322        num_signers: u32,
1323        keys_per_signer: u32,
1324    ) {
1325        let (mut coordinators, mut signers) =
1326            setup::<Coordinator, SignerType>(num_signers, keys_per_signer);
1327
1328        // We have started a dkg round
1329        let message = coordinators.first_mut().unwrap().start_dkg_round().unwrap();
1330        assert!(coordinators
1331            .first_mut()
1332            .unwrap()
1333            .get_aggregate_public_key()
1334            .is_none());
1335        assert_eq!(
1336            coordinators.first_mut().unwrap().get_state(),
1337            State::DkgPublicGather
1338        );
1339
1340        // Send the DKG Begin message to all signers and gather responses by sharing with all other signers and coordinator
1341        let (outbound_messages, operation_results) = feedback_mutated_messages(
1342            &mut coordinators,
1343            &mut signers,
1344            &[message],
1345            |signer, packets| {
1346                if signer.signer_id == 0 {
1347                    packets
1348                        .iter()
1349                        .map(|packet| {
1350                            if let Message::DkgPublicShares(shares) = &packet.msg {
1351                                let public_shares = crate::net::DkgPublicShares {
1352                                    dkg_id: shares.dkg_id,
1353                                    signer_id: shares.signer_id,
1354                                    comms: vec![],
1355                                };
1356                                Packet {
1357                                    msg: Message::DkgPublicShares(public_shares),
1358                                    sig: vec![],
1359                                }
1360                            } else {
1361                                packet.clone()
1362                            }
1363                        })
1364                        .collect()
1365                } else {
1366                    packets.clone()
1367                }
1368            },
1369        );
1370        assert!(operation_results.is_empty());
1371        for coordinator in coordinators.iter() {
1372            assert_eq!(coordinator.get_state(), State::DkgPrivateGather);
1373        }
1374
1375        assert_eq!(outbound_messages.len(), 1);
1376        match &outbound_messages[0].msg {
1377            Message::DkgPrivateBegin(_) => {}
1378            _ => {
1379                panic!("Expected DkgPrivateBegin message")
1380            }
1381        }
1382
1383        // Send the DKG Private Begin message to all signers and share their responses with the coordinator and signers
1384        let (outbound_messages, operation_results) =
1385            feedback_messages(&mut coordinators, &mut signers, &outbound_messages);
1386        assert_eq!(operation_results.len(), 0);
1387        assert_eq!(outbound_messages.len(), 1);
1388        match &outbound_messages[0].msg {
1389            Message::DkgEndBegin(_) => {}
1390            _ => {
1391                panic!("Expected DkgEndBegin message");
1392            }
1393        }
1394
1395        // Send the DkgEndBegin message to all signers and share their responses with the coordinator and signers
1396        let (outbound_messages, operation_results) =
1397            feedback_messages(&mut coordinators, &mut signers, &outbound_messages);
1398        assert_eq!(outbound_messages.len(), 0);
1399        assert_eq!(operation_results.len(), 1);
1400        match &operation_results[0] {
1401            OperationResult::DkgError(dkg_error) => {
1402                if let DkgError::DkgEndFailure(dkg_failures) = dkg_error {
1403                    if dkg_failures.len() != num_signers as usize {
1404                        panic!(
1405                            "Expected {num_signers} DkgFailures got {}",
1406                            dkg_failures.len()
1407                        );
1408                    }
1409                    let expected_signer_ids = (0..1).collect::<HashSet<u32>>();
1410                    for dkg_failure in dkg_failures {
1411                        if let (_, DkgFailure::MissingPublicShares(signer_ids)) = dkg_failure {
1412                            if &expected_signer_ids != signer_ids {
1413                                panic!(
1414                                    "Expected signer_ids {:?} got {:?}",
1415                                    expected_signer_ids, signer_ids
1416                                );
1417                            }
1418                        } else {
1419                            panic!(
1420                                "Expected DkgFailure::MissingPublicShares got {:?}",
1421                                dkg_failure
1422                            );
1423                        }
1424                    }
1425                } else {
1426                    panic!("Expected DkgError::DkgEndFailure got {:?}", dkg_error);
1427                }
1428            }
1429            msg => panic!("Expected OperationResult::DkgError got {:?}", msg),
1430        }
1431    }
1432
1433    pub fn empty_private_shares<Coordinator: CoordinatorTrait, SignerType: SignerTrait>(
1434        num_signers: u32,
1435        keys_per_signer: u32,
1436    ) {
1437        let (mut coordinators, mut signers) =
1438            setup::<Coordinator, SignerType>(num_signers, keys_per_signer);
1439
1440        // We have started a dkg round
1441        let message = coordinators.first_mut().unwrap().start_dkg_round().unwrap();
1442        assert!(coordinators
1443            .first_mut()
1444            .unwrap()
1445            .get_aggregate_public_key()
1446            .is_none());
1447        assert_eq!(
1448            coordinators.first_mut().unwrap().get_state(),
1449            State::DkgPublicGather
1450        );
1451
1452        // Send the DKG Begin message to all signers and gather responses by sharing with all other signers and coordinator
1453        let (outbound_messages, operation_results) =
1454            feedback_messages(&mut coordinators, &mut signers, &[message]);
1455        assert!(operation_results.is_empty());
1456        for coordinator in coordinators.iter() {
1457            assert_eq!(coordinator.get_state(), State::DkgPrivateGather);
1458        }
1459
1460        assert_eq!(outbound_messages.len(), 1);
1461        match &outbound_messages[0].msg {
1462            Message::DkgPrivateBegin(_) => {}
1463            _ => {
1464                panic!("Expected DkgPrivateBegin message");
1465            }
1466        }
1467
1468        // Send the DKG Begin message to all signers and gather responses by sharing with all other signers and coordinator
1469        let (outbound_messages, operation_results) = feedback_mutated_messages(
1470            &mut coordinators,
1471            &mut signers,
1472            &[outbound_messages[0].clone()],
1473            |signer, packets| {
1474                if signer.signer_id == 0 {
1475                    packets
1476                        .iter()
1477                        .map(|packet| {
1478                            if let Message::DkgPrivateShares(shares) = &packet.msg {
1479                                let private_shares = crate::net::DkgPrivateShares {
1480                                    dkg_id: shares.dkg_id,
1481                                    signer_id: shares.signer_id,
1482                                    shares: vec![],
1483                                };
1484                                Packet {
1485                                    msg: Message::DkgPrivateShares(private_shares),
1486                                    sig: vec![],
1487                                }
1488                            } else {
1489                                packet.clone()
1490                            }
1491                        })
1492                        .collect()
1493                } else {
1494                    packets.clone()
1495                }
1496            },
1497        );
1498        assert_eq!(operation_results.len(), 0);
1499        assert_eq!(outbound_messages.len(), 1);
1500        match &outbound_messages[0].msg {
1501            Message::DkgEndBegin(_) => {}
1502            _ => {
1503                panic!("Expected DkgEndBegin message");
1504            }
1505        }
1506
1507        // Send the DkgEndBegin message to all signers and share their responses with the coordinator and signers
1508        let (outbound_messages, operation_results) =
1509            feedback_messages(&mut coordinators, &mut signers, &outbound_messages);
1510        assert_eq!(outbound_messages.len(), 0);
1511        assert_eq!(operation_results.len(), 1);
1512        match &operation_results[0] {
1513            OperationResult::DkgError(dkg_error) => {
1514                if let DkgError::DkgEndFailure(dkg_failures) = dkg_error {
1515                    if dkg_failures.len() != num_signers as usize {
1516                        panic!(
1517                            "Expected {num_signers} DkgFailures got {}",
1518                            dkg_failures.len()
1519                        );
1520                    }
1521                    let expected_signer_ids = (0..1).collect::<HashSet<u32>>();
1522                    for dkg_failure in dkg_failures {
1523                        if let (_, DkgFailure::MissingPrivateShares(signer_ids)) = dkg_failure {
1524                            if &expected_signer_ids != signer_ids {
1525                                panic!(
1526                                    "Expected signer_ids {:?} got {:?}",
1527                                    expected_signer_ids, signer_ids
1528                                );
1529                            }
1530                        } else {
1531                            panic!(
1532                                "Expected DkgFailure::MissingPublicShares got {:?}",
1533                                dkg_failure
1534                            );
1535                        }
1536                    }
1537                } else {
1538                    panic!("Expected DkgError::DkgEndFailure got {:?}", dkg_error);
1539                }
1540            }
1541            msg => panic!("Expected OperationResult::DkgError got {:?}", msg),
1542        }
1543    }
1544}