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)]
17pub enum State {
19 #[default]
21 Idle,
22 DkgPublicDistribute,
24 DkgPublicGather,
26 DkgPrivateDistribute,
28 DkgPrivateGather,
30 DkgEndDistribute,
32 DkgEndGather,
34 NonceRequest(SignatureType),
36 NonceGather(SignatureType),
38 SigShareRequest(SignatureType),
40 SigShareGather(SignatureType),
42}
43
44#[derive(thiserror::Error, Clone, Debug)]
45#[allow(clippy::large_enum_variant)]
46pub enum Error {
48 #[error("Bad State Change: {0}")]
50 BadStateChange(String),
51 #[error("Bad dkg_id: got {0} expected {1}")]
53 BadDkgId(u64, u64),
54 #[error("Bad sign_id: got {0} expected {1}")]
56 BadSignId(u64, u64),
57 #[error("Bad sign_iter_id: got {0} expected {1}")]
59 BadSignIterId(u64, u64),
60 #[error("Malicious signer {0}")]
62 MaliciousSigner(u32),
63 #[error("Aggregator: {0}")]
65 Aggregator(AggregatorError),
66 #[error("Schnorr Proof failed to verify")]
68 SchnorrProofFailed,
69 #[error("No aggregate public key set")]
71 MissingAggregatePublicKey,
72 #[error("No schnorr proof set")]
74 MissingSchnorrProof,
75 #[error("No signature set")]
77 MissingSignature,
78 #[error("Missing message nonce information")]
80 MissingMessageNonceInfo,
81 #[error("DKG failure from signers")]
83 DkgFailure(HashMap<u32, DkgFailure>),
84 #[error(
86 "Aggregate key and computed key from party polynomials mismatch: got {0}, expected {1}"
87 )]
88 AggregateKeyPolynomialMismatch(Point, Point),
89 #[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#[derive(Default, Clone, Debug, PartialEq)]
102pub struct Config {
103 pub num_signers: u32,
105 pub num_keys: u32,
107 pub threshold: u32,
109 pub dkg_threshold: u32,
111 pub message_private_key: Scalar,
113 pub dkg_public_timeout: Option<Duration>,
115 pub dkg_private_timeout: Option<Duration>,
117 pub dkg_end_timeout: Option<Duration>,
119 pub nonce_timeout: Option<Duration>,
121 pub sign_timeout: Option<Duration>,
123 pub signer_key_ids: HashMap<u32, HashSet<u32>>,
125 pub signer_public_keys: HashMap<u32, Point>,
127}
128
129impl Config {
130 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 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)]
187pub struct SignRoundInfo {
189 pub public_nonces: BTreeMap<u32, NonceResponse>,
191 pub nonce_recv_key_ids: HashSet<u32>,
193 pub sign_recv_key_ids: HashSet<u32>,
195 pub sign_wait_signer_ids: HashSet<u32>,
197}
198
199#[derive(Default, Clone, Debug, PartialEq)]
201pub struct SavedState {
202 pub config: Config,
204 pub current_dkg_id: u64,
206 pub current_sign_id: u64,
208 pub current_sign_iter_id: u64,
210 pub dkg_public_shares: BTreeMap<u32, DkgPublicShares>,
212 pub dkg_private_shares: BTreeMap<u32, DkgPrivateShares>,
214 pub dkg_end_messages: BTreeMap<u32, DkgEnd>,
216 pub party_polynomials: HashMap<u32, PolyCommitment>,
218 pub signature_shares: BTreeMap<u32, Vec<SignatureShare>>,
220 pub message_nonces: BTreeMap<Vec<u8>, SignRoundInfo>,
222 pub aggregate_public_key: Option<Point>,
224 pub signature: Option<Signature>,
226 pub schnorr_proof: Option<SchnorrProof>,
228 pub dkg_wait_signer_ids: HashSet<u32>,
230 pub message: Vec<u8>,
232 pub state: State,
234 pub nonce_start: Option<Instant>,
236 pub dkg_public_start: Option<Instant>,
238 pub dkg_private_start: Option<Instant>,
240 pub dkg_end_start: Option<Instant>,
242 pub sign_start: Option<Instant>,
244 pub malicious_signer_ids: HashSet<u32>,
246 pub malicious_dkg_signer_ids: HashSet<u32>,
248}
249
250pub trait Coordinator: Clone + Debug + PartialEq + StateMachine<State, Error> {
252 fn new(config: Config) -> Self;
254
255 fn load(state: &SavedState) -> Self;
257
258 fn save(&self) -> SavedState;
260
261 fn get_config(&self) -> Config;
263
264 fn set_key_and_party_polynomials(
266 &mut self,
267 aggregate_key: Point,
268 party_polynomials: Vec<(u32, PolyCommitment)>,
269 ) -> Result<(), Error>;
270
271 fn process_inbound_messages(
273 &mut self,
274 packets: &[Packet],
275 ) -> Result<(Vec<Packet>, Vec<OperationResult>), Error>;
276
277 fn get_aggregate_public_key(&self) -> Option<Point>;
279
280 fn set_aggregate_public_key(&mut self, aggregate_public_key: Option<Point>);
282
283 fn get_message(&self) -> Vec<u8>;
285
286 fn get_state(&self) -> State;
288
289 fn start_dkg_round(&mut self) -> Result<Packet, Error>;
291
292 fn start_signing_round(
294 &mut self,
295 message: &[u8],
296 signature_type: SignatureType,
297 ) -> Result<Packet, Error>;
298
299 fn reset(&mut self);
301}
302
303pub mod frost;
305
306pub 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 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 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 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 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 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 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 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 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 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 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 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 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 for signer in &mut signers {
725 signer.signer.clear_polys();
726 }
727
728 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let messages1 = signers[0]
1063 .process(&outbound_messages[0].msg, &mut rng)
1064 .unwrap();
1065
1066 let messages2 = signers[0]
1069 .process(&outbound_messages[0].msg, &mut rng)
1070 .unwrap();
1071
1072 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}