1use core::num::TryFromIntError;
2use hashbrown::{HashMap, HashSet};
3use rand_core::{CryptoRng, RngCore};
4use std::{
5 collections::{BTreeMap, BTreeSet},
6 fmt,
7};
8use tracing::{debug, error, info, trace, warn};
9
10use crate::{
11 common::{
12 check_public_shares, validate_key_id, validate_signer_id, PolyCommitment, PublicNonce,
13 TupleProof,
14 },
15 curve::{
16 ecdsa,
17 point::{Error as PointError, Point, G},
18 scalar::Scalar,
19 },
20 errors::{DkgError, EncryptionError},
21 net::{
22 BadPrivateShare, DkgBegin, DkgEnd, DkgEndBegin, DkgFailure, DkgPrivateBegin,
23 DkgPrivateShares, DkgPrivateSharesDone, DkgPrivateSharesDoneAck, DkgPublicShares,
24 DkgPublicSharesDone, DkgPublicSharesDoneAck, DkgStatus, Message, NonceRequest,
25 NonceResponse, Packet, SignatureShareRequest, SignatureShareResponse, SignatureType,
26 },
27 state_machine::{PublicKeys, StateMachine},
28 traits::{Signer as SignerTrait, SignerState as SignerSavedState},
29 util::{decrypt, encrypt, make_shared_secret},
30};
31
32#[cfg(any(test, feature = "testing"))]
33use crate::net::Signable;
34
35#[derive(Debug, Clone, PartialEq)]
36pub enum State {
38 Idle,
40 DkgPublicDistribute,
42 DkgPublicGather,
44 DkgPublicSharesDoneAck,
46 DkgPrivateDistribute,
48 DkgPrivateGather,
50 DkgPrivateSharesDoneAck,
52 SignGather,
54}
55
56#[derive(thiserror::Error, Clone, Debug)]
57pub enum ConfigError {
59 #[error("Insufficient keys for the number of signers")]
61 InsufficientKeys,
62 #[error("InvalidThreshold")]
64 InvalidThreshold,
65 #[error("Invalid signer ID {0}")]
67 InvalidSignerId(u32),
68 #[error("Invalid key ID {0}")]
70 InvalidKeyId(u32),
71}
72
73#[derive(thiserror::Error, Clone, Debug)]
74pub enum Error {
76 #[error("Config error {0}")]
78 Config(#[from] ConfigError),
79 #[error("InvalidPartyID")]
81 InvalidPartyID,
82 #[error("InvalidDkgPublicShares")]
84 InvalidDkgPublicShares,
85 #[error("InvalidDkgPrivateShares")]
87 InvalidDkgPrivateShares(Vec<u32>),
88 #[error("InvalidNonceResponse")]
90 InvalidNonceResponse,
91 #[error("InvalidSignatureShare")]
93 InvalidSignatureShare,
94 #[error("Bad State Change: {0}")]
96 BadStateChange(String),
97 #[error("Encryption error: {0}")]
99 Encryption(#[from] EncryptionError),
100 #[error("integer conversion error")]
101 TryFromInt(#[from] TryFromIntError),
103 #[error("Missing coordinator public key")]
104 MissingCoordinatorPublicKey,
106 #[error("A packet had an invalid signature")]
107 InvalidPacketSignature,
109 #[error("A curve point error {0}")]
110 Point(#[from] PointError),
112 #[error("missing kex public key for key_id {0}")]
113 MissingKexPublicKey(u32),
115}
116
117#[derive(Clone)]
119pub struct SavedState {
120 pub dkg_id: u64,
122 pub sign_id: u64,
124 pub sign_iter_id: u64,
126 pub threshold: u32,
128 pub dkg_threshold: u32,
130 pub total_signers: u32,
132 pub total_keys: u32,
134 pub signer: SignerSavedState,
136 pub signer_id: u32,
138 pub state: State,
140 pub commitments: HashMap<u32, PolyCommitment>,
143 decrypted_shares: HashMap<u32, HashMap<u32, Scalar>>,
146 decryption_keys: HashMap<u32, (u32, Point)>,
149 pub invalid_private_shares: HashMap<u32, BadPrivateShare>,
152 pub public_nonces: Vec<PublicNonce>,
154 network_private_key: Scalar,
156 pub public_keys: PublicKeys,
158 pub dkg_public_shares: BTreeMap<u32, DkgPublicShares>,
160 pub dkg_private_shares: BTreeMap<u32, DkgPrivateShares>,
162 pub dkg_private_begin_msg: Option<DkgPrivateBegin>,
164 pub dkg_end_begin_msg: Option<DkgEndBegin>,
166 pending_public_shares_done: Option<DkgPublicSharesDone>,
168 pending_private_shares_done: Option<DkgPrivateSharesDone>,
170 pub verify_packet_sigs: bool,
172 pub coordinator_public_key: Option<ecdsa::PublicKey>,
174 kex_private_key: Scalar,
176 kex_public_keys: HashMap<u32, Point>,
178 dkg_completed: bool,
180}
181
182impl fmt::Debug for SavedState {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 f.debug_struct("SavedState")
185 .field("dkg_id", &self.dkg_id)
186 .field("sign_id", &self.sign_id)
187 .field("sign_iter_id", &self.sign_iter_id)
188 .field("threshold", &self.threshold)
189 .field("dkg_threshold", &self.dkg_threshold)
190 .field("total_signers", &self.total_signers)
191 .field("total_keys", &self.total_keys)
192 .field("signer", &self.signer)
193 .field("signer_id", &self.signer_id)
194 .field("state", &self.state)
195 .field("commitments", &self.commitments)
196 .field("invalid_private_shares", &self.invalid_private_shares)
197 .field("public_nonces", &self.public_nonces)
198 .field("public_keys", &self.public_keys)
199 .field("dkg_public_shares", &self.dkg_public_shares)
200 .field("dkg_private_begin_msg", &self.dkg_private_begin_msg)
201 .field("dkg_end_begin_msg", &self.dkg_end_begin_msg)
202 .finish_non_exhaustive()
203 }
204}
205
206#[derive(Clone, PartialEq)]
208pub struct Signer<SignerType: SignerTrait> {
209 pub dkg_id: u64,
211 pub sign_id: u64,
213 pub sign_iter_id: u64,
215 pub threshold: u32,
217 pub dkg_threshold: u32,
219 pub total_signers: u32,
221 pub total_keys: u32,
223 pub signer: SignerType,
225 pub signer_id: u32,
227 pub state: State,
229 pub commitments: HashMap<u32, PolyCommitment>,
232 pub decrypted_shares: HashMap<u32, HashMap<u32, Scalar>>,
235 pub decryption_keys: HashMap<u32, (u32, Point)>,
238 pub invalid_private_shares: HashMap<u32, BadPrivateShare>,
241 pub public_nonces: Vec<PublicNonce>,
243 pub network_private_key: Scalar,
245 pub public_keys: PublicKeys,
247 pub dkg_public_shares: BTreeMap<u32, DkgPublicShares>,
249 pub dkg_private_shares: BTreeMap<u32, DkgPrivateShares>,
251 pub dkg_private_begin_msg: Option<DkgPrivateBegin>,
253 pub dkg_end_begin_msg: Option<DkgEndBegin>,
255 pending_public_shares_done: Option<DkgPublicSharesDone>,
257 pending_private_shares_done: Option<DkgPrivateSharesDone>,
259 pub verify_packet_sigs: bool,
261 pub coordinator_public_key: Option<ecdsa::PublicKey>,
263 kex_private_key: Scalar,
265 kex_public_keys: HashMap<u32, Point>,
267 dkg_completed: bool,
269}
270
271impl<SignerType: SignerTrait> fmt::Debug for Signer<SignerType> {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 f.debug_struct("Signer")
274 .field("dkg_id", &self.dkg_id)
275 .field("sign_id", &self.sign_id)
276 .field("sign_iter_id", &self.sign_iter_id)
277 .field("threshold", &self.threshold)
278 .field("dkg_threshold", &self.dkg_threshold)
279 .field("total_signers", &self.total_signers)
280 .field("total_keys", &self.total_keys)
281 .field("signer", &self.signer)
282 .field("signer_id", &self.signer_id)
283 .field("state", &self.state)
284 .field("commitments", &self.commitments)
285 .field("invalid_private_shares", &self.invalid_private_shares)
286 .field("public_nonces", &self.public_nonces)
287 .field("public_keys", &self.public_keys)
288 .field("dkg_public_shares", &self.dkg_public_shares)
289 .field("dkg_private_begin_msg", &self.dkg_private_begin_msg)
290 .field("dkg_end_begin_msg", &self.dkg_end_begin_msg)
291 .finish_non_exhaustive()
292 }
293}
294
295impl<SignerType: SignerTrait> Signer<SignerType> {
296 #[allow(clippy::too_many_arguments)]
298 pub fn new<R: RngCore + CryptoRng>(
299 threshold: u32,
300 dkg_threshold: u32,
301 total_signers: u32,
302 total_keys: u32,
303 signer_id: u32,
304 key_ids: Vec<u32>,
305 network_private_key: Scalar,
306 public_keys: PublicKeys,
307 rng: &mut R,
308 ) -> Result<Self, Error> {
309 if total_signers > total_keys {
310 return Err(Error::Config(ConfigError::InsufficientKeys));
311 }
312
313 if threshold == 0 || threshold > total_keys {
314 return Err(Error::Config(ConfigError::InvalidThreshold));
315 }
316
317 if dkg_threshold == 0 || dkg_threshold < threshold {
318 return Err(Error::Config(ConfigError::InvalidThreshold));
319 }
320
321 if !validate_signer_id(signer_id, total_signers) {
322 return Err(Error::Config(ConfigError::InvalidSignerId(signer_id)));
323 }
324
325 for key_id in &key_ids {
326 if !validate_key_id(*key_id, total_keys) {
327 return Err(Error::Config(ConfigError::InvalidKeyId(*key_id)));
328 }
329 }
330
331 public_keys.validate(total_signers, total_keys)?;
332
333 let mut signer = SignerType::new(
334 signer_id,
335 &key_ids,
336 total_signers,
337 total_keys,
338 threshold,
339 rng,
340 );
341
342 signer.gen_nonces(&network_private_key, rng);
344
345 debug!("new Signer for signer_id {signer_id} with key_ids {key_ids:?}");
346 Ok(Self {
347 dkg_id: 0,
348 sign_id: 1,
349 sign_iter_id: 1,
350 threshold,
351 dkg_threshold,
352 total_signers,
353 total_keys,
354 signer,
355 signer_id,
356 state: State::Idle,
357 commitments: Default::default(),
358 decrypted_shares: Default::default(),
359 decryption_keys: Default::default(),
360 invalid_private_shares: Default::default(),
361 public_nonces: vec![],
362 network_private_key,
363 public_keys,
364 dkg_public_shares: Default::default(),
365 dkg_private_shares: Default::default(),
366 dkg_private_begin_msg: Default::default(),
367 dkg_end_begin_msg: Default::default(),
368 pending_public_shares_done: None,
369 pending_private_shares_done: None,
370 verify_packet_sigs: true,
371 coordinator_public_key: None,
372 kex_private_key: Scalar::random(rng),
373 kex_public_keys: Default::default(),
374 dkg_completed: false,
375 })
376 }
377
378 pub fn load(state: &SavedState) -> Self {
380 Self {
381 dkg_id: state.dkg_id,
382 sign_id: state.sign_id,
383 sign_iter_id: state.sign_iter_id,
384 threshold: state.threshold,
385 dkg_threshold: state.dkg_threshold,
386 total_signers: state.total_signers,
387 total_keys: state.total_keys,
388 signer: SignerType::load(&state.signer),
389 signer_id: state.signer_id,
390 state: state.state.clone(),
391 commitments: state.commitments.clone(),
392 decrypted_shares: state.decrypted_shares.clone(),
393 decryption_keys: state.decryption_keys.clone(),
394 invalid_private_shares: state.invalid_private_shares.clone(),
395 public_nonces: state.public_nonces.clone(),
396 network_private_key: state.network_private_key,
397 public_keys: state.public_keys.clone(),
398 dkg_public_shares: state.dkg_public_shares.clone(),
399 dkg_private_shares: state.dkg_private_shares.clone(),
400 dkg_private_begin_msg: state.dkg_private_begin_msg.clone(),
401 dkg_end_begin_msg: state.dkg_end_begin_msg.clone(),
402 pending_public_shares_done: state.pending_public_shares_done.clone(),
403 pending_private_shares_done: state.pending_private_shares_done.clone(),
404 verify_packet_sigs: state.verify_packet_sigs,
405 coordinator_public_key: state.coordinator_public_key,
406 kex_private_key: state.kex_private_key,
407 kex_public_keys: state.kex_public_keys.clone(),
408 dkg_completed: state.dkg_completed,
409 }
410 }
411
412 pub fn save(&self) -> SavedState {
414 SavedState {
415 dkg_id: self.dkg_id,
416 sign_id: self.sign_id,
417 sign_iter_id: self.sign_iter_id,
418 threshold: self.threshold,
419 dkg_threshold: self.dkg_threshold,
420 total_signers: self.total_signers,
421 total_keys: self.total_keys,
422 signer: self.signer.save(),
423 signer_id: self.signer_id,
424 state: self.state.clone(),
425 commitments: self.commitments.clone(),
426 decrypted_shares: self.decrypted_shares.clone(),
427 decryption_keys: self.decryption_keys.clone(),
428 invalid_private_shares: self.invalid_private_shares.clone(),
429 public_nonces: self.public_nonces.clone(),
430 network_private_key: self.network_private_key,
431 public_keys: self.public_keys.clone(),
432 dkg_public_shares: self.dkg_public_shares.clone(),
433 dkg_private_shares: self.dkg_private_shares.clone(),
434 dkg_private_begin_msg: self.dkg_private_begin_msg.clone(),
435 dkg_end_begin_msg: self.dkg_end_begin_msg.clone(),
436 pending_public_shares_done: self.pending_public_shares_done.clone(),
437 pending_private_shares_done: self.pending_private_shares_done.clone(),
438 verify_packet_sigs: self.verify_packet_sigs,
439 coordinator_public_key: self.coordinator_public_key,
440 kex_private_key: self.kex_private_key,
441 kex_public_keys: self.kex_public_keys.clone(),
442 dkg_completed: self.dkg_completed,
443 }
444 }
445
446 pub fn reset<T: RngCore + CryptoRng>(&mut self, dkg_id: u64, rng: &mut T) {
448 self.dkg_id = dkg_id;
449 self.commitments.clear();
450 self.decrypted_shares.clear();
451 self.decryption_keys.clear();
452 self.invalid_private_shares.clear();
453 self.public_nonces.clear();
454 self.signer.reset_polys(rng);
455 self.dkg_public_shares.clear();
456 self.dkg_private_shares.clear();
457 self.dkg_private_begin_msg = None;
458 self.dkg_end_begin_msg = None;
459 self.pending_public_shares_done = None;
460 self.pending_private_shares_done = None;
461 self.kex_private_key = Scalar::random(rng);
462 self.kex_public_keys.clear();
463 self.dkg_completed = false;
464 self.state = State::Idle;
465 }
466
467 #[cfg(any(test, feature = "testing"))]
469 pub fn process_inbound_messages<R: RngCore + CryptoRng>(
470 &mut self,
471 packets: &[Packet],
472 rng: &mut R,
473 ) -> Result<Vec<Packet>, Error> {
474 let mut responses = vec![];
475 for packet in packets {
476 let outbounds = self.process(packet, rng)?;
477 for out in outbounds {
478 let msg = Packet {
479 sig: out
480 .sign(&self.network_private_key)
481 .expect("Failed to sign message"),
482 msg: out,
483 };
484 responses.push(msg);
485 }
486 }
487 Ok(responses)
488 }
489
490 pub fn process<R: RngCore + CryptoRng>(
492 &mut self,
493 packet: &Packet,
494 rng: &mut R,
495 ) -> Result<Vec<Message>, Error> {
496 if self.verify_packet_sigs {
497 let Some(coordinator_public_key) = self.coordinator_public_key else {
498 return Err(Error::MissingCoordinatorPublicKey);
499 };
500 if !packet.verify(&self.public_keys, &coordinator_public_key) {
501 return Err(Error::InvalidPacketSignature);
502 }
503 }
504 let out_msgs = match (&self.state, &packet.msg) {
505 (_, Message::DkgBegin(msg)) => self.dkg_begin(msg, rng),
507 (State::DkgPublicGather, Message::DkgPublicShares(msg)) => self.dkg_public_share(msg),
509 (State::DkgPublicGather, Message::DkgPublicSharesDone(msg)) => {
510 self.dkg_public_shares_done(msg)
511 }
512 (State::DkgPublicSharesDoneAck, Message::DkgPrivateBegin(msg)) => {
514 self.dkg_private_begin(msg, rng)
515 }
516 (State::DkgPrivateGather, Message::DkgPrivateShares(msg)) => {
517 self.dkg_private_shares(msg, rng)
518 }
519 (State::DkgPrivateGather, Message::DkgPrivateSharesDone(msg)) => {
520 self.dkg_private_shares_done(msg)
521 }
522 (State::DkgPrivateSharesDoneAck, Message::DkgEndBegin(msg)) => {
525 let mut out = self.dkg_end_begin(msg)?;
526 out.push(self.dkg_ended(rng)?);
527 self.move_to(State::Idle)?;
528 Ok(out)
529 }
530 (State::Idle | State::SignGather, Message::NonceRequest(msg)) => {
532 self.nonce_request(msg, rng)
533 }
534 (State::SignGather, Message::SignatureShareRequest(msg)) => {
535 self.sign_share_request(msg, rng)
536 }
537 (
539 _,
540 Message::DkgEnd(_)
541 | Message::DkgPublicSharesDoneAck(_)
542 | Message::DkgPrivateSharesDoneAck(_)
543 | Message::NonceResponse(_)
544 | Message::SignatureShareResponse(_),
545 ) => Ok(vec![]),
546 (state, msg) => {
548 warn!(
549 signer_id = %self.signer_id,
550 ?state,
551 msg_type = ?std::mem::discriminant(msg),
552 "unexpected message in state, dropping"
553 );
554 Ok(vec![])
555 }
556 };
557
558 out_msgs
559 }
560
561 pub fn dkg_ended<R: RngCore + CryptoRng>(&mut self, rng: &mut R) -> Result<Message, Error> {
563 if !self.can_dkg_end() {
564 return Ok(Message::DkgEnd(DkgEnd {
565 dkg_id: self.dkg_id,
566 signer_id: self.signer_id,
567 status: DkgStatus::Failure(DkgFailure::BadState),
568 }));
569 }
570
571 let mut missing_public_shares = HashSet::new();
573 let mut missing_private_shares = HashSet::new();
574 let mut bad_public_shares = HashSet::new();
575 let threshold: usize = self.threshold.try_into().unwrap();
576
577 let Some(dkg_end_begin) = &self.dkg_end_begin_msg else {
578 return Ok(Message::DkgEnd(DkgEnd {
580 dkg_id: self.dkg_id,
581 signer_id: self.signer_id,
582 status: DkgStatus::Failure(DkgFailure::BadState),
583 }));
584 };
585
586 let signer_ids_set: HashSet<u32> = dkg_end_begin
588 .signer_ids
589 .iter()
590 .filter(|&&id| id < self.total_signers)
591 .copied()
592 .collect::<HashSet<u32>>();
593 let mut num_dkg_keys = 0u32;
594 for id in &signer_ids_set {
595 if let Some(key_ids) = self.public_keys.signer_key_ids.get(id) {
596 let len: u32 = key_ids.len().try_into()?;
597 num_dkg_keys = num_dkg_keys.saturating_add(len);
598 }
599 }
600
601 if num_dkg_keys < self.dkg_threshold {
602 return Ok(Message::DkgEnd(DkgEnd {
603 dkg_id: self.dkg_id,
604 signer_id: self.signer_id,
605 status: DkgStatus::Failure(DkgFailure::Threshold),
606 }));
607 }
608
609 for signer_id in &signer_ids_set {
610 if let Some(shares) = self.dkg_public_shares.get(signer_id) {
611 if shares.comms.is_empty() {
612 missing_public_shares.insert(*signer_id);
613 } else {
614 for (party_id, comm) in shares.comms.iter() {
615 if !check_public_shares(comm, threshold, &self.dkg_id.to_be_bytes()) {
616 bad_public_shares.insert(*signer_id);
617 } else {
618 self.commitments.insert(*party_id, comm.clone());
619 }
620 }
621 }
622 } else {
623 missing_public_shares.insert(*signer_id);
624 }
625 if let Some(shares) = self.dkg_private_shares.get(signer_id) {
626 if shares.shares.is_empty() {
628 missing_private_shares.insert(*signer_id);
629 } else {
630 for dst_key_id in self.signer.get_key_ids() {
631 for (_src_key_id, shares) in &shares.shares {
632 if shares.get(&dst_key_id).is_none() {
633 missing_private_shares.insert(*signer_id);
634 }
635 }
636 }
637 }
638 } else {
639 missing_private_shares.insert(*signer_id);
640 }
641 }
642
643 if !missing_public_shares.is_empty() {
644 return Ok(Message::DkgEnd(DkgEnd {
645 dkg_id: self.dkg_id,
646 signer_id: self.signer_id,
647 status: DkgStatus::Failure(DkgFailure::MissingPublicShares(missing_public_shares)),
648 }));
649 }
650
651 if !bad_public_shares.is_empty() {
652 return Ok(Message::DkgEnd(DkgEnd {
653 dkg_id: self.dkg_id,
654 signer_id: self.signer_id,
655 status: DkgStatus::Failure(DkgFailure::BadPublicShares(bad_public_shares)),
656 }));
657 }
658
659 if !missing_private_shares.is_empty() {
660 return Ok(Message::DkgEnd(DkgEnd {
661 dkg_id: self.dkg_id,
662 signer_id: self.signer_id,
663 status: DkgStatus::Failure(DkgFailure::MissingPrivateShares(
664 missing_private_shares,
665 )),
666 }));
667 }
668
669 let dkg_end = if self.invalid_private_shares.is_empty() {
670 match self.signer.compute_secrets(
671 &self.decrypted_shares,
672 &self.commitments,
673 &self.dkg_id.to_be_bytes(),
674 ) {
675 Ok(()) => DkgEnd {
676 dkg_id: self.dkg_id,
677 signer_id: self.signer_id,
678 status: DkgStatus::Success,
679 },
680 Err(dkg_error_map) => {
681 let mut bad_private_shares = HashMap::new();
683 for (_my_party_id, dkg_error) in dkg_error_map {
684 if let DkgError::BadPrivateShares(party_ids) = dkg_error {
685 for party_id in party_ids {
686 if let Some((party_signer_id, _shared_key)) =
687 &self.decryption_keys.get(&party_id)
688 {
689 bad_private_shares.insert(
690 *party_signer_id,
691 self.make_bad_private_share(*party_signer_id, rng)?,
692 );
693 } else {
694 warn!("DkgError::BadPrivateShares from party_id {party_id} but no (signer_id, shared_secret) cached");
695 }
696 }
697 } else {
698 warn!("Got unexpected dkg_error {dkg_error:?}");
699 }
700 }
701 DkgEnd {
702 dkg_id: self.dkg_id,
703 signer_id: self.signer_id,
704 status: DkgStatus::Failure(DkgFailure::BadPrivateShares(
705 bad_private_shares,
706 )),
707 }
708 }
709 }
710 } else {
711 DkgEnd {
712 dkg_id: self.dkg_id,
713 signer_id: self.signer_id,
714 status: DkgStatus::Failure(DkgFailure::BadPrivateShares(
715 self.invalid_private_shares.clone(),
716 )),
717 }
718 };
719
720 if matches!(dkg_end.status, DkgStatus::Success) {
721 self.dkg_completed = true;
722 }
723
724 info!(
725 signer_id = %self.signer_id,
726 dkg_id = %self.dkg_id,
727 status = ?dkg_end.status,
728 "sending DkgEnd"
729 );
730
731 let dkg_end = Message::DkgEnd(dkg_end);
732 Ok(dkg_end)
733 }
734
735 pub fn public_shares_done(&self) -> bool {
737 debug!(
738 "public_shares_done state {:?} commitments {}",
739 self.state,
740 self.commitments.len(),
741 );
742 self.state == State::DkgPublicGather
743 && self.commitments.len() == usize::try_from(self.signer.get_num_parties()).unwrap()
744 }
745
746 pub fn can_dkg_end(&self) -> bool {
748 debug!(
749 "can_dkg_end: state {:?} DkgPrivateBegin {} DkgEndBegin {}",
750 self.state,
751 self.dkg_private_begin_msg.is_some(),
752 self.dkg_end_begin_msg.is_some(),
753 );
754
755 if self.state == State::DkgPrivateGather || self.state == State::DkgPrivateSharesDoneAck {
756 if let Some(dkg_private_begin) = &self.dkg_private_begin_msg {
757 for signer_id in &dkg_private_begin.signer_ids {
759 if !self.dkg_public_shares.contains_key(signer_id) {
760 debug!("can_dkg_end: false, missing public shares from signer {signer_id}");
761 return false;
762 }
763 }
764
765 if let Some(dkg_end_begin) = &self.dkg_end_begin_msg {
766 for signer_id in &dkg_end_begin.signer_ids {
768 if !self.dkg_private_shares.contains_key(signer_id) {
769 debug!("can_dkg_end: false, missing private shares from signer {signer_id}");
770 return false;
771 }
772 }
773 debug!("can_dkg_end: true");
774
775 return true;
776 }
777 }
778 } else {
779 debug!("can_dkg_end: false, bad state {:?}", self.state);
780 return false;
781 }
782 false
783 }
784
785 fn nonce_request<R: RngCore + CryptoRng>(
786 &mut self,
787 nonce_request: &NonceRequest,
788 rng: &mut R,
789 ) -> Result<Vec<Message>, Error> {
790 if nonce_request.dkg_id != self.dkg_id {
791 warn!(
792 signer_id = %self.signer_id,
793 got = %nonce_request.dkg_id,
794 expected = %self.dkg_id,
795 "NonceRequest dkg_id mismatch"
796 );
797 return Ok(vec![]);
798 }
799 if !self.dkg_completed {
800 warn!(
801 signer_id = %self.signer_id,
802 dkg_id = %self.dkg_id,
803 "NonceRequest rejected: DKG not completed"
804 );
805 return Ok(vec![]);
806 }
807 let mut msgs = vec![];
808 let signer_id = self.signer_id;
809 let key_ids = self.signer.get_key_ids();
810 let nonces = self.signer.gen_nonces(&self.network_private_key, rng);
811
812 let response = NonceResponse {
813 dkg_id: nonce_request.dkg_id,
814 sign_id: nonce_request.sign_id,
815 sign_iter_id: nonce_request.sign_iter_id,
816 signer_id,
817 key_ids,
818 nonces,
819 message: nonce_request.message.clone(),
820 };
821
822 let response = Message::NonceResponse(response);
823
824 info!(
825 %signer_id,
826 dkg_id = %nonce_request.dkg_id,
827 sign_id = %nonce_request.sign_id,
828 sign_iter_id = %nonce_request.sign_iter_id,
829 "sending NonceResponse"
830 );
831 msgs.push(response);
832 self.move_to(State::SignGather)?;
833
834 Ok(msgs)
835 }
836
837 fn sign_share_request<R: RngCore + CryptoRng>(
838 &mut self,
839 sign_request: &SignatureShareRequest,
840 rng: &mut R,
841 ) -> Result<Vec<Message>, Error> {
842 if sign_request.dkg_id != self.dkg_id {
843 warn!(
844 signer_id = %self.signer_id,
845 got = %sign_request.dkg_id,
846 expected = %self.dkg_id,
847 "SignatureShareRequest dkg_id mismatch"
848 );
849 return Ok(vec![]);
850 }
851 if !self.dkg_completed {
852 warn!(
853 signer_id = %self.signer_id,
854 dkg_id = %self.dkg_id,
855 "SignatureShareRequest rejected: DKG not completed"
856 );
857 return Ok(vec![]);
858 }
859 let signer_id_set = sign_request
860 .nonce_responses
861 .iter()
862 .map(|nr| nr.signer_id)
863 .collect::<BTreeSet<u32>>();
864
865 let is_invalid_request = sign_request.nonce_responses.len() != signer_id_set.len()
870 || signer_id_set.is_empty()
871 || signer_id_set.last() >= Some(&self.total_signers);
872
873 if is_invalid_request {
874 warn!("received an invalid SignatureShareRequest");
875 return Err(Error::InvalidNonceResponse);
876 }
877
878 let nonces = sign_request
879 .nonce_responses
880 .iter()
881 .flat_map(|nr| nr.nonces.clone())
882 .collect::<Vec<PublicNonce>>();
883
884 for nonce in &nonces {
885 if !nonce.is_valid() {
886 warn!(
887 signer_id = %self.signer_id,
888 "received an SignatureShareRequest with invalid nonce"
889 );
890 return Err(Error::InvalidNonceResponse);
891 }
892 }
893
894 debug!(signer_id = %self.signer_id, "received a valid SignatureShareRequest");
895
896 if signer_id_set.contains(&self.signer_id) {
897 let key_ids: Vec<u32> = sign_request
898 .nonce_responses
899 .iter()
900 .flat_map(|nr| nr.key_ids.iter().copied())
901 .collect::<Vec<u32>>();
902
903 let signer_ids = signer_id_set.into_iter().collect::<Vec<_>>();
904 let msg = &sign_request.message;
905 let signature_shares = match sign_request.signature_type {
906 SignatureType::Taproot(merkle_root) => {
907 self.signer
908 .sign_taproot(msg, &signer_ids, &key_ids, &nonces, merkle_root)
909 }
910 SignatureType::Schnorr => {
911 self.signer
912 .sign_schnorr(msg, &signer_ids, &key_ids, &nonces)
913 }
914 SignatureType::Frost => self.signer.sign(msg, &signer_ids, &key_ids, &nonces),
915 };
916
917 self.signer.gen_nonces(&self.network_private_key, rng);
918
919 let response = SignatureShareResponse {
920 dkg_id: sign_request.dkg_id,
921 sign_id: sign_request.sign_id,
922 sign_iter_id: sign_request.sign_iter_id,
923 signer_id: self.signer_id,
924 signature_shares,
925 };
926 info!(
927 signer_id = %self.signer_id,
928 dkg_id = %sign_request.dkg_id,
929 sign_id = %sign_request.sign_id,
930 sign_iter_id = %sign_request.sign_iter_id,
931 "sending SignatureShareResponse"
932 );
933
934 self.move_to(State::Idle)?;
935 Ok(vec![Message::SignatureShareResponse(response)])
936 } else {
937 debug!(signer_id = %self.signer_id, "signer not included in SignatureShareRequest");
938 self.move_to(State::Idle)?;
939 Ok(Vec::new())
940 }
941 }
942
943 fn dkg_begin<R: RngCore + CryptoRng>(
944 &mut self,
945 dkg_begin: &DkgBegin,
946 rng: &mut R,
947 ) -> Result<Vec<Message>, Error> {
948 self.reset(dkg_begin.dkg_id, rng);
949 self.move_to(State::DkgPublicDistribute)?;
950
951 self.dkg_public_begin(rng)
954 }
955
956 fn dkg_public_shares_done(&mut self, msg: &DkgPublicSharesDone) -> Result<Vec<Message>, Error> {
957 if msg.dkg_id != self.dkg_id {
958 warn!(
959 signer_id = %self.signer_id,
960 got = %msg.dkg_id,
961 expected = %self.dkg_id,
962 "DkgPublicSharesDone dkg_id mismatch"
963 );
964 return Ok(vec![]);
965 }
966 let unknown_ids: Vec<u32> = msg
968 .signer_ids
969 .iter()
970 .filter(|id| !self.public_keys.signers.contains_key(*id))
971 .copied()
972 .collect();
973 if !unknown_ids.is_empty() {
974 warn!(
975 signer_id = %self.signer_id,
976 ?unknown_ids,
977 "DkgPublicSharesDone contains unknown signer_ids"
978 );
979 return Ok(vec![]);
980 }
981 if !msg.signer_ids.contains(&self.signer_id) {
982 warn!(
983 signer_id = %self.signer_id,
984 "signer_id not in DkgPublicSharesDone, coordinator did not receive our public shares"
985 );
986 self.move_to(State::Idle)?;
987 return Ok(vec![]);
988 }
989 self.dkg_public_shares
991 .retain(|id, _| msg.signer_ids.contains(id));
992
993 let have_all = msg
994 .signer_ids
995 .iter()
996 .all(|id| self.dkg_public_shares.contains_key(id));
997 if have_all {
998 let ack = DkgPublicSharesDoneAck {
999 dkg_id: self.dkg_id,
1000 signer_id: self.signer_id,
1001 };
1002 self.move_to(State::DkgPublicSharesDoneAck)?;
1003 Ok(vec![Message::DkgPublicSharesDoneAck(ack)])
1004 } else {
1005 debug!(
1006 signer_id = %self.signer_id,
1007 "DkgPublicSharesDone received but missing some public shares, waiting"
1008 );
1009 self.pending_public_shares_done = Some(msg.clone());
1010 Ok(vec![])
1011 }
1012 }
1013
1014 fn dkg_private_shares_done(
1015 &mut self,
1016 msg: &DkgPrivateSharesDone,
1017 ) -> Result<Vec<Message>, Error> {
1018 if msg.dkg_id != self.dkg_id {
1019 warn!(
1020 signer_id = %self.signer_id,
1021 got = %msg.dkg_id,
1022 expected = %self.dkg_id,
1023 "DkgPrivateSharesDone dkg_id mismatch"
1024 );
1025 return Ok(vec![]);
1026 }
1027 let unknown_ids: Vec<u32> = msg
1029 .signer_ids
1030 .iter()
1031 .filter(|id| !self.public_keys.signers.contains_key(*id))
1032 .copied()
1033 .collect();
1034 if !unknown_ids.is_empty() {
1035 warn!(
1036 signer_id = %self.signer_id,
1037 ?unknown_ids,
1038 "DkgPrivateSharesDone contains unknown signer_ids"
1039 );
1040 return Ok(vec![]);
1041 }
1042 if !msg.signer_ids.contains(&self.signer_id) {
1043 warn!(
1044 signer_id = %self.signer_id,
1045 "signer_id not in DkgPrivateSharesDone, coordinator did not receive our private shares"
1046 );
1047 self.move_to(State::Idle)?;
1048 return Ok(vec![]);
1049 }
1050 self.dkg_private_shares
1052 .retain(|id, _| msg.signer_ids.contains(id));
1053
1054 let have_all = msg
1055 .signer_ids
1056 .iter()
1057 .all(|id| self.dkg_private_shares.contains_key(id));
1058 if have_all {
1059 let ack = DkgPrivateSharesDoneAck {
1060 dkg_id: self.dkg_id,
1061 signer_id: self.signer_id,
1062 };
1063 self.move_to(State::DkgPrivateSharesDoneAck)?;
1064 Ok(vec![Message::DkgPrivateSharesDoneAck(ack)])
1065 } else {
1066 debug!(
1067 signer_id = %self.signer_id,
1068 "DkgPrivateSharesDone received but missing some private shares, waiting"
1069 );
1070 self.pending_private_shares_done = Some(msg.clone());
1071 Ok(vec![])
1072 }
1073 }
1074
1075 fn dkg_public_begin<R: RngCore + CryptoRng>(
1076 &mut self,
1077 rng: &mut R,
1078 ) -> Result<Vec<Message>, Error> {
1079 let mut msgs = vec![];
1080 let comms = self
1081 .signer
1082 .get_poly_commitments(&self.dkg_id.to_be_bytes(), rng);
1083 let comms = comms
1084 .iter()
1085 .map(|poly| (poly.id.id.get_u32(), poly.clone()))
1086 .collect();
1087
1088 info!(
1089 signer_id = %self.signer_id,
1090 dkg_id = %self.dkg_id,
1091 "sending DkgPublicShares"
1092 );
1093
1094 let kex_proof = DkgPublicShares::kex_prove(
1095 self.dkg_id,
1096 self.signer_id,
1097 &comms,
1098 &self.kex_private_key,
1099 rng,
1100 );
1101 let public_share = DkgPublicShares {
1102 dkg_id: self.dkg_id,
1103 signer_id: self.signer_id,
1104 comms,
1105 kex_public_key: self.kex_private_key * G,
1106 kex_proof,
1107 };
1108
1109 let public_share = Message::DkgPublicShares(public_share);
1110 msgs.push(public_share);
1111
1112 self.move_to(State::DkgPublicGather)?;
1113 Ok(msgs)
1114 }
1115
1116 fn dkg_private_begin<R: RngCore + CryptoRng>(
1117 &mut self,
1118 dkg_private_begin: &DkgPrivateBegin,
1119 rng: &mut R,
1120 ) -> Result<Vec<Message>, Error> {
1121 if dkg_private_begin.dkg_id != self.dkg_id {
1122 warn!(
1123 signer_id = %self.signer_id,
1124 got = %dkg_private_begin.dkg_id,
1125 expected = %self.dkg_id,
1126 "DkgPrivateBegin dkg_id mismatch"
1127 );
1128 return Ok(vec![]);
1129 }
1130 let mut msgs = vec![];
1131 let mut private_shares = DkgPrivateShares {
1132 dkg_id: self.dkg_id,
1133 signer_id: self.signer_id,
1134 shares: Vec::new(),
1135 };
1136 let mut active_key_ids = HashSet::new();
1137 for signer_id in &dkg_private_begin.signer_ids {
1138 if let Some(key_ids) = self.public_keys.signer_key_ids.get(signer_id) {
1139 for key_id in key_ids {
1140 active_key_ids.insert(*key_id);
1141 }
1142 }
1143 }
1144
1145 self.dkg_private_begin_msg = Some(dkg_private_begin.clone());
1146 self.move_to(State::DkgPrivateDistribute)?;
1147
1148 info!(
1149 signer_id = %self.signer_id,
1150 dkg_id = %self.dkg_id,
1151 "sending DkgPrivateShares"
1152 );
1153
1154 trace!(
1155 "Signer {} shares {:?}",
1156 self.signer_id,
1157 &self.signer.get_shares()
1158 );
1159 for (party_id, shares) in &self.signer.get_shares() {
1160 debug!(
1161 "Signer {} addding dkg private share for party_id {party_id}",
1162 self.signer_id
1163 );
1164 let mut encrypted_shares = HashMap::new();
1166
1167 for (dst_key_id, private_share) in shares {
1168 if active_key_ids.contains(dst_key_id) {
1169 debug!("encrypting dkg private share for key_id {dst_key_id}");
1170 let Some(kex_public_key) = self.kex_public_keys.get(dst_key_id) else {
1171 error!("No KEX public key for key_id {dst_key_id}");
1172 return Err(Error::MissingKexPublicKey(*dst_key_id));
1173 };
1174 let shared_secret = make_shared_secret(&self.kex_private_key, kex_public_key);
1175 let encrypted_share = encrypt(&shared_secret, &private_share.to_bytes(), rng)?;
1176
1177 encrypted_shares.insert(*dst_key_id, encrypted_share);
1178 }
1179 }
1180
1181 private_shares.shares.push((*party_id, encrypted_shares));
1182 }
1183
1184 let private_shares = Message::DkgPrivateShares(private_shares);
1185 msgs.push(private_shares);
1186
1187 self.move_to(State::DkgPrivateGather)?;
1188 Ok(msgs)
1189 }
1190
1191 pub fn dkg_end_begin(&mut self, dkg_end_begin: &DkgEndBegin) -> Result<Vec<Message>, Error> {
1193 if dkg_end_begin.dkg_id != self.dkg_id {
1194 warn!(
1195 signer_id = %self.signer_id,
1196 got = %dkg_end_begin.dkg_id,
1197 expected = %self.dkg_id,
1198 "DkgEndBegin dkg_id mismatch"
1199 );
1200 return Ok(vec![]);
1201 }
1202 let unknown_ids: Vec<u32> = dkg_end_begin
1204 .signer_ids
1205 .iter()
1206 .filter(|id| !self.public_keys.signers.contains_key(*id))
1207 .copied()
1208 .collect();
1209 if !unknown_ids.is_empty() {
1210 warn!(
1211 signer_id = %self.signer_id,
1212 ?unknown_ids,
1213 "DkgEndBegin contains unknown signer_ids"
1214 );
1215 return Ok(vec![]);
1216 }
1217 let num_keys: u32 = dkg_end_begin
1218 .signer_ids
1219 .iter()
1220 .filter_map(|id| self.public_keys.signer_key_ids.get(id))
1221 .map(|key_ids| key_ids.len() as u32)
1222 .sum();
1223 if num_keys < self.dkg_threshold {
1224 warn!(
1225 signer_id = %self.signer_id,
1226 num_keys,
1227 dkg_threshold = self.dkg_threshold,
1228 "DkgEndBegin below dkg_threshold"
1229 );
1230 }
1231 let msgs = vec![];
1232
1233 self.dkg_end_begin_msg = Some(dkg_end_begin.clone());
1234
1235 info!(
1236 signer_id = %self.signer_id,
1237 dkg_id = %self.dkg_id,
1238 "received DkgEndBegin"
1239 );
1240
1241 Ok(msgs)
1242 }
1243
1244 pub fn dkg_public_share(
1246 &mut self,
1247 dkg_public_shares: &DkgPublicShares,
1248 ) -> Result<Vec<Message>, Error> {
1249 if dkg_public_shares.dkg_id != self.dkg_id {
1250 warn!(
1251 signer_id = %self.signer_id,
1252 got = %dkg_public_shares.dkg_id,
1253 expected = %self.dkg_id,
1254 "DkgPublicShares dkg_id mismatch"
1255 );
1256 return Ok(vec![]);
1257 }
1258 debug!(
1259 "received DkgPublicShares from signer {} {}/{}",
1260 dkg_public_shares.signer_id,
1261 self.commitments.len(),
1262 self.signer.get_num_parties(),
1263 );
1264
1265 let signer_id = dkg_public_shares.signer_id;
1266
1267 let Some(_signer_public_key) = self.public_keys.signers.get(&signer_id) else {
1269 warn!(%signer_id, "No public key configured");
1270 return Ok(vec![]);
1271 };
1272
1273 for (party_id, _) in &dkg_public_shares.comms {
1274 if !SignerType::validate_party_id(
1275 signer_id,
1276 *party_id,
1277 &self.public_keys.signer_key_ids,
1278 ) {
1279 warn!(%signer_id, %party_id, "signer sent polynomial commitment for wrong party");
1280 return Ok(vec![]);
1281 }
1282 }
1283
1284 if let Some(pending) = &self.pending_public_shares_done {
1286 if !pending.signer_ids.contains(&signer_id) {
1287 debug!(%signer_id, "discarding DkgPublicShares from signer not in DkgPublicSharesDone");
1288 return Ok(vec![]);
1289 }
1290 }
1291
1292 let have_shares = self
1293 .dkg_public_shares
1294 .contains_key(&dkg_public_shares.signer_id);
1295
1296 if have_shares {
1297 info!(signer_id = %dkg_public_shares.signer_id, "received duplicate DkgPublicShares");
1298 return Ok(vec![]);
1299 }
1300
1301 let Some(signer_key_ids) = self.public_keys.signer_key_ids.get(&signer_id) else {
1302 warn!(%signer_id, "No key_ids configured");
1303 return Ok(vec![]);
1304 };
1305
1306 if !dkg_public_shares.kex_verify() {
1307 warn!(signer_id = %dkg_public_shares.signer_id, "received DkgPublicShares with invalid kex_proof");
1308 return Ok(vec![]);
1309 }
1310
1311 for key_id in signer_key_ids {
1312 self.kex_public_keys
1313 .insert(*key_id, dkg_public_shares.kex_public_key);
1314 }
1315
1316 self.dkg_public_shares
1317 .insert(dkg_public_shares.signer_id, dkg_public_shares.clone());
1318
1319 if let Some(pending) = self.pending_public_shares_done.take() {
1321 if pending
1322 .signer_ids
1323 .iter()
1324 .all(|id| self.dkg_public_shares.contains_key(id))
1325 {
1326 let ack = DkgPublicSharesDoneAck {
1327 dkg_id: self.dkg_id,
1328 signer_id: self.signer_id,
1329 };
1330 self.move_to(State::DkgPublicSharesDoneAck)?;
1331 return Ok(vec![Message::DkgPublicSharesDoneAck(ack)]);
1332 }
1333 self.pending_public_shares_done = Some(pending);
1334 }
1335 Ok(vec![])
1336 }
1337
1338 pub fn dkg_private_shares<R: RngCore + CryptoRng>(
1340 &mut self,
1341 dkg_private_shares: &DkgPrivateShares,
1342 rng: &mut R,
1343 ) -> Result<Vec<Message>, Error> {
1344 if dkg_private_shares.dkg_id != self.dkg_id {
1345 warn!(
1346 signer_id = %self.signer_id,
1347 got = %dkg_private_shares.dkg_id,
1348 expected = %self.dkg_id,
1349 "DkgPrivateShares dkg_id mismatch"
1350 );
1351 return Ok(vec![]);
1352 }
1353 let src_signer_id = dkg_private_shares.signer_id;
1355
1356 let Some(_signer_public_key) = self.public_keys.signers.get(&src_signer_id) else {
1358 warn!(%src_signer_id, "No public key configured");
1359 return Ok(vec![]);
1360 };
1361
1362 let Ok(kex_public_key) = self.get_kex_public_key(src_signer_id) else {
1363 return Ok(vec![]);
1364 };
1365
1366 for (party_id, _shares) in &dkg_private_shares.shares {
1367 if !SignerType::validate_party_id(
1368 src_signer_id,
1369 *party_id,
1370 &self.public_keys.signer_key_ids,
1371 ) {
1372 warn!("Signer {src_signer_id} sent a polynomial commitment for party {party_id}");
1373 return Ok(vec![]);
1374 }
1375 }
1376
1377 if let Some(pending) = &self.pending_private_shares_done {
1379 if !pending.signer_ids.contains(&src_signer_id) {
1380 debug!(%src_signer_id, "discarding DkgPrivateShares from signer not in DkgPrivateSharesDone");
1381 return Ok(vec![]);
1382 }
1383 }
1384
1385 if self.dkg_private_shares.contains_key(&src_signer_id) {
1386 info!(signer_id = %dkg_private_shares.signer_id, "received duplicate DkgPrivateShares");
1387 return Ok(vec![]);
1388 }
1389
1390 self.dkg_private_shares
1391 .insert(src_signer_id, dkg_private_shares.clone());
1392
1393 let key_ids: HashSet<u32> = self.signer.get_key_ids().into_iter().collect();
1395
1396 let shared_key = self.kex_private_key * kex_public_key;
1397 let shared_secret = make_shared_secret(&self.kex_private_key, &kex_public_key);
1398
1399 for (src_id, shares) in &dkg_private_shares.shares {
1400 let mut decrypted_shares = HashMap::new();
1401 for (dst_key_id, bytes) in shares {
1402 if key_ids.contains(dst_key_id) {
1403 match decrypt(&shared_secret, bytes) {
1404 Ok(plain) => match Scalar::try_from(&plain[..]) {
1405 Ok(s) => {
1406 decrypted_shares.insert(*dst_key_id, s);
1407 }
1408 Err(e) => {
1409 warn!("Failed to parse Scalar for dkg private share from src_id {src_id} to dst_id {dst_key_id}: {e:?}");
1410 self.invalid_private_shares.insert(
1411 src_signer_id,
1412 self.make_bad_private_share(src_signer_id, rng)?,
1413 );
1414 }
1415 },
1416 Err(e) => {
1417 warn!("Failed to decrypt dkg private share from src_id {src_id} to dst_id {dst_key_id}: {e:?}");
1418 self.invalid_private_shares.insert(
1419 src_signer_id,
1420 self.make_bad_private_share(src_signer_id, rng)?,
1421 );
1422 }
1423 }
1424 }
1425 }
1426 self.decrypted_shares.insert(*src_id, decrypted_shares);
1427 self.decryption_keys
1428 .insert(*src_id, (dkg_private_shares.signer_id, shared_key));
1429 }
1430 debug!(
1431 "received DkgPrivateShares from signer {} {}/{}",
1432 dkg_private_shares.signer_id,
1433 self.decrypted_shares.len(),
1434 self.signer.get_num_parties(),
1435 );
1436
1437 if let Some(pending) = self.pending_private_shares_done.take() {
1439 if pending
1440 .signer_ids
1441 .iter()
1442 .all(|id| self.dkg_private_shares.contains_key(id))
1443 {
1444 let ack = DkgPrivateSharesDoneAck {
1445 dkg_id: self.dkg_id,
1446 signer_id: self.signer_id,
1447 };
1448 self.move_to(State::DkgPrivateSharesDoneAck)?;
1449 return Ok(vec![Message::DkgPrivateSharesDoneAck(ack)]);
1450 }
1451 self.pending_private_shares_done = Some(pending);
1452 }
1453 Ok(vec![])
1454 }
1455
1456 fn get_kex_public_key(&self, signer_id: u32) -> Result<Point, Error> {
1457 let Some(signer_key_ids) = self.public_keys.signer_key_ids.get(&signer_id) else {
1458 warn!(%signer_id, "No key_ids configured");
1459 return Err(Error::Config(ConfigError::InvalidSignerId(signer_id)));
1460 };
1461
1462 let Some(signer_key_id) = signer_key_ids.iter().next() else {
1463 warn!(%signer_id, "No key_ids configured");
1464 return Err(Error::Config(ConfigError::InvalidSignerId(signer_id)));
1465 };
1466
1467 let Some(kex_public_key) = self.kex_public_keys.get(signer_key_id) else {
1468 warn!(%signer_id, %signer_key_id, "No KEX public key configured");
1469 return Err(Error::MissingKexPublicKey(*signer_key_id));
1470 };
1471
1472 Ok(*kex_public_key)
1473 }
1474
1475 #[allow(non_snake_case)]
1476 fn make_bad_private_share<R: RngCore + CryptoRng>(
1477 &self,
1478 signer_id: u32,
1479 rng: &mut R,
1480 ) -> Result<BadPrivateShare, Error> {
1481 let a = self.kex_private_key;
1482 let A = a * G;
1483 let B = self.get_kex_public_key(signer_id)?;
1484 let K = a * B;
1485 let tuple_proof = TupleProof::new(&a, &A, &B, &K, rng);
1486
1487 Ok(BadPrivateShare {
1488 shared_key: K,
1489 tuple_proof,
1490 })
1491 }
1492}
1493
1494impl<SignerType: SignerTrait> StateMachine<State, Error> for Signer<SignerType> {
1495 fn move_to(&mut self, state: State) -> Result<(), Error> {
1496 self.can_move_to(&state)?;
1497 self.state = state;
1498 Ok(())
1499 }
1500
1501 fn can_move_to(&self, state: &State) -> Result<(), Error> {
1502 let prev_state = &self.state;
1503 let accepted = match state {
1504 State::Idle => true,
1505 State::DkgPublicDistribute => matches!(
1507 prev_state,
1508 State::Idle
1509 | State::DkgPublicDistribute
1510 | State::DkgPublicGather
1511 | State::DkgPublicSharesDoneAck
1512 | State::DkgPrivateDistribute
1513 | State::DkgPrivateGather
1514 | State::DkgPrivateSharesDoneAck
1515 ),
1516 State::DkgPublicGather => prev_state == &State::DkgPublicDistribute,
1517 State::DkgPublicSharesDoneAck => prev_state == &State::DkgPublicGather,
1518 State::DkgPrivateDistribute => prev_state == &State::DkgPublicSharesDoneAck,
1519 State::DkgPrivateGather => prev_state == &State::DkgPrivateDistribute,
1520 State::DkgPrivateSharesDoneAck => prev_state == &State::DkgPrivateGather,
1521 State::SignGather => prev_state == &State::Idle || prev_state == &State::SignGather,
1522 };
1523 if accepted {
1524 debug!("state change from {prev_state:?} to {state:?}");
1525 Ok(())
1526 } else {
1527 Err(Error::BadStateChange(format!(
1528 "{prev_state:?} to {state:?}"
1529 )))
1530 }
1531 }
1532}
1533#[cfg(test)]
1534pub mod test {
1536 use super::*;
1537 #[cfg(feature = "with_v1")]
1538 use crate::v1;
1539 use crate::{
1540 common::PolyCommitment,
1541 curve::{ecdsa, scalar::Scalar},
1542 net::{
1543 DkgBegin, DkgEndBegin, DkgPrivateBegin, DkgPrivateSharesDone, DkgPublicShares,
1544 DkgPublicSharesDone, DkgStatus, Message,
1545 },
1546 schnorr::ID,
1547 state_machine::{
1548 signer::{ConfigError, Error, Signer, State as SignerState},
1549 PublicKeys,
1550 },
1551 traits::Signer as SignerTrait,
1552 util::create_rng,
1553 v2,
1554 };
1555
1556 use hashbrown::HashSet;
1557
1558 #[test]
1559 #[cfg(feature = "with_v1")]
1560 fn bad_config_v1() {
1561 bad_config::<v1::Signer>();
1562 }
1563
1564 #[test]
1565 #[cfg(feature = "with_v1")]
1566 fn bad_config_v2() {
1567 bad_config::<v1::Signer>();
1568 }
1569
1570 #[allow(dead_code)]
1571 fn bad_config<SignerType: SignerTrait>() {
1572 let mut rng = create_rng();
1573
1574 assert!(matches!(
1576 Signer::<SignerType>::new(
1577 1,
1578 1,
1579 2,
1580 1,
1581 0,
1582 vec![1],
1583 Default::default(),
1584 Default::default(),
1585 &mut rng,
1586 ),
1587 Err(Error::Config(ConfigError::InsufficientKeys))
1588 ));
1589
1590 assert!(matches!(
1592 Signer::<SignerType>::new(
1593 0,
1594 1,
1595 4,
1596 4,
1597 0,
1598 vec![1],
1599 Default::default(),
1600 Default::default(),
1601 &mut rng,
1602 ),
1603 Err(Error::Config(ConfigError::InvalidThreshold))
1604 ));
1605
1606 assert!(matches!(
1608 Signer::<SignerType>::new(
1609 1,
1610 0,
1611 4,
1612 4,
1613 0,
1614 vec![1],
1615 Default::default(),
1616 Default::default(),
1617 &mut rng,
1618 ),
1619 Err(Error::Config(ConfigError::InvalidThreshold))
1620 ));
1621
1622 assert!(matches!(
1624 Signer::<SignerType>::new(
1625 5,
1626 5,
1627 4,
1628 4,
1629 0,
1630 vec![1],
1631 Default::default(),
1632 Default::default(),
1633 &mut rng,
1634 ),
1635 Err(Error::Config(ConfigError::InvalidThreshold))
1636 ));
1637
1638 assert!(matches!(
1640 Signer::<SignerType>::new(
1641 2,
1642 1,
1643 4,
1644 4,
1645 0,
1646 vec![1],
1647 Default::default(),
1648 Default::default(),
1649 &mut rng,
1650 ),
1651 Err(Error::Config(ConfigError::InvalidThreshold))
1652 ));
1653
1654 assert!(matches!(
1656 Signer::<SignerType>::new(
1657 2,
1658 2,
1659 4,
1660 4,
1661 4,
1662 vec![1],
1663 Default::default(),
1664 Default::default(),
1665 &mut rng,
1666 ),
1667 Err(Error::Config(ConfigError::InvalidSignerId(4)))
1668 ));
1669
1670 assert!(matches!(
1672 Signer::<SignerType>::new(
1673 2,
1674 2,
1675 4,
1676 4,
1677 0,
1678 vec![0],
1679 Default::default(),
1680 Default::default(),
1681 &mut rng,
1682 ),
1683 Err(Error::Config(ConfigError::InvalidKeyId(0)))
1684 ));
1685
1686 assert!(matches!(
1688 Signer::<SignerType>::new(
1689 2,
1690 2,
1691 4,
1692 4,
1693 0,
1694 vec![5],
1695 Default::default(),
1696 Default::default(),
1697 &mut rng,
1698 ),
1699 Err(Error::Config(ConfigError::InvalidKeyId(5)))
1700 ));
1701
1702 }
1704
1705 #[test]
1706 #[cfg(feature = "with_v1")]
1707 fn dkg_public_share_v1() {
1708 dkg_public_share::<v1::Signer>();
1709 }
1710
1711 #[test]
1712 fn dkg_public_share_v2() {
1713 dkg_public_share::<v2::Signer>();
1714 }
1715
1716 fn dkg_public_share<SignerType: SignerTrait>() {
1717 let ctx = 0u64.to_be_bytes();
1718 let mut rng = create_rng();
1719 let private_key = Scalar::random(&mut rng);
1720 let public_key = ecdsa::PublicKey::new(&private_key).unwrap();
1721 let mut public_keys: PublicKeys = Default::default();
1722 let mut key_ids = HashSet::new();
1723
1724 public_keys.signers.insert(0, public_key);
1725 public_keys.key_ids.insert(1, public_key);
1726
1727 key_ids.insert(1);
1728 public_keys.signer_key_ids.insert(0, key_ids);
1729
1730 let mut signer =
1731 Signer::<SignerType>::new(1, 1, 1, 1, 0, vec![1], private_key, public_keys, &mut rng)
1732 .unwrap();
1733 let comms: Vec<(u32, PolyCommitment)> = signer
1734 .signer
1735 .get_poly_commitments(&ctx, &mut rng)
1736 .iter()
1737 .map(|comm| (comm.id.id.get_u32(), comm.clone()))
1738 .collect();
1739 let kex_private_key = Scalar::random(&mut rng);
1740 let kex_proof = DkgPublicShares::kex_prove(0, 0, &comms, &kex_private_key, &mut rng);
1741 let public_share = DkgPublicShares {
1742 dkg_id: 0,
1743 signer_id: 0,
1744 comms: comms.clone(),
1745 kex_public_key: Point::from(kex_private_key),
1746 kex_proof: kex_proof.clone(),
1747 };
1748 signer.dkg_public_share(&public_share).unwrap();
1749 assert_eq!(1, signer.dkg_public_shares.len());
1750
1751 let dup_public_share = DkgPublicShares {
1753 dkg_id: 0,
1754 signer_id: 0,
1755 comms: comms.clone(),
1756 kex_public_key: Point::from(kex_private_key),
1757 kex_proof: kex_proof.clone(),
1758 };
1759 signer.dkg_public_share(&dup_public_share).unwrap();
1760 assert_eq!(1, signer.dkg_public_shares.len());
1761 assert_eq!(
1762 public_share,
1763 signer.dkg_public_shares.iter().next().unwrap().1.clone()
1764 );
1765 }
1766
1767 #[test]
1768 #[cfg(feature = "with_v1")]
1769 fn public_shares_done_v1() {
1770 public_shares_done::<v1::Signer>();
1771 }
1772
1773 #[test]
1774 fn public_shares_done_v2() {
1775 public_shares_done::<v2::Signer>();
1776 }
1777
1778 fn public_shares_done<SignerType: SignerTrait>() {
1779 let ctx = 0u64.to_be_bytes();
1780 let mut rng = create_rng();
1781 let mut signer = Signer::<SignerType>::new(
1782 1,
1783 1,
1784 1,
1785 1,
1786 0,
1787 vec![1],
1788 Default::default(),
1789 Default::default(),
1790 &mut rng,
1791 )
1792 .unwrap();
1793 assert!(!signer.public_shares_done());
1795
1796 signer.state = SignerState::DkgPublicGather;
1798 signer.commitments.insert(
1799 1,
1800 PolyCommitment {
1801 id: ID::new(&Scalar::new(), &Scalar::new(), &ctx, &mut rng),
1802 poly: vec![],
1803 },
1804 );
1805
1806 assert!(signer.public_shares_done());
1808 }
1809
1810 #[test]
1811 #[cfg(feature = "with_v1")]
1812 fn dkg_private_share_v1() {
1814 let mut rng = create_rng();
1815
1816 let private_key = Scalar::random(&mut rng);
1817 let public_key = ecdsa::PublicKey::new(&private_key).unwrap();
1818 let private_key2 = Scalar::random(&mut rng);
1819 let public_key2 = ecdsa::PublicKey::new(&private_key2).unwrap();
1820 let mut public_keys: PublicKeys = Default::default();
1821 let kex_private_key = Scalar::random(&mut rng);
1822 let kex_public_key = Point::from(&kex_private_key);
1823
1824 public_keys.signers.insert(0, public_key);
1825 public_keys.signers.insert(1, public_key2);
1826 public_keys.key_ids.insert(1, public_key);
1827 public_keys.key_ids.insert(2, public_key2);
1828
1829 let mut key_ids = HashSet::new();
1830 key_ids.insert(1);
1831 public_keys.signer_key_ids.insert(0, key_ids);
1832
1833 let mut key_ids2 = HashSet::new();
1834 key_ids2.insert(2);
1835 public_keys.signer_key_ids.insert(1, key_ids2);
1836
1837 let mut signer =
1838 Signer::<v1::Signer>::new(1, 1, 2, 2, 0, vec![1], private_key, public_keys, &mut rng)
1839 .unwrap();
1840
1841 let kex_proof = DkgPublicShares::kex_prove(0, 1, &vec![], &kex_private_key, &mut rng);
1842 let public_share = DkgPublicShares {
1843 dkg_id: 0,
1844 signer_id: 1,
1845 comms: vec![],
1846 kex_public_key,
1847 kex_proof: kex_proof.clone(),
1848 };
1849 signer.dkg_public_share(&public_share).unwrap();
1850 assert_eq!(1, signer.dkg_public_shares.len());
1851
1852 let private_share = DkgPrivateShares {
1853 dkg_id: 0,
1854 signer_id: 1,
1855 shares: vec![(2, HashMap::new())],
1856 };
1857 signer.dkg_private_shares(&private_share, &mut rng).unwrap();
1858 assert_eq!(1, signer.dkg_private_shares.len());
1859
1860 let dup_private_share = DkgPrivateShares {
1862 dkg_id: 0,
1863 signer_id: 1,
1864 shares: vec![(2, HashMap::new())],
1865 };
1866 signer
1867 .dkg_private_shares(&dup_private_share, &mut rng)
1868 .unwrap();
1869 assert_eq!(1, signer.dkg_private_shares.len());
1870 assert_eq!(
1871 private_share,
1872 signer.dkg_private_shares.iter().next().unwrap().1.clone()
1873 );
1874 }
1875
1876 #[test]
1877 fn dkg_private_share_v2() {
1879 let mut rng = create_rng();
1880
1881 let private_key = Scalar::random(&mut rng);
1882 let public_key = ecdsa::PublicKey::new(&private_key).unwrap();
1883 let private_key2 = Scalar::random(&mut rng);
1884 let public_key2 = ecdsa::PublicKey::new(&private_key2).unwrap();
1885 let mut public_keys: PublicKeys = Default::default();
1886 let kex_private_key = Scalar::random(&mut rng);
1887 let kex_public_key = Point::from(&kex_private_key);
1888
1889 public_keys.signers.insert(0, public_key);
1890 public_keys.signers.insert(1, public_key2);
1891 public_keys.key_ids.insert(1, public_key);
1892 public_keys.key_ids.insert(2, public_key2);
1893
1894 let mut key_ids = HashSet::new();
1895 key_ids.insert(1);
1896 public_keys.signer_key_ids.insert(0, key_ids);
1897
1898 let mut key_ids2 = HashSet::new();
1899 key_ids2.insert(2);
1900 public_keys.signer_key_ids.insert(1, key_ids2);
1901
1902 let mut signer =
1903 Signer::<v2::Signer>::new(1, 1, 2, 2, 0, vec![1], private_key, public_keys, &mut rng)
1904 .unwrap();
1905
1906 let kex_proof = DkgPublicShares::kex_prove(0, 1, &vec![], &kex_private_key, &mut rng);
1907 let public_share = DkgPublicShares {
1908 dkg_id: 0,
1909 signer_id: 1,
1910 comms: vec![],
1911 kex_public_key,
1912 kex_proof: kex_proof.clone(),
1913 };
1914 signer.dkg_public_share(&public_share).unwrap();
1915 assert_eq!(1, signer.dkg_public_shares.len());
1916
1917 let private_share = DkgPrivateShares {
1918 dkg_id: 0,
1919 signer_id: 1,
1920 shares: vec![(1, HashMap::new())],
1921 };
1922 signer.dkg_private_shares(&private_share, &mut rng).unwrap();
1923 assert_eq!(1, signer.dkg_private_shares.len());
1924
1925 let dup_private_share = DkgPrivateShares {
1927 dkg_id: 0,
1928 signer_id: 1,
1929 shares: vec![(1, HashMap::new())],
1930 };
1931 signer
1932 .dkg_private_shares(&dup_private_share, &mut rng)
1933 .unwrap();
1934 assert_eq!(1, signer.dkg_private_shares.len());
1935 assert_eq!(
1936 private_share,
1937 signer.dkg_private_shares.iter().next().unwrap().1.clone()
1938 );
1939 }
1940
1941 #[test]
1942 #[cfg(feature = "with_v1")]
1943 fn can_dkg_end_v1() {
1944 can_dkg_end::<v1::Signer>();
1945 }
1946
1947 #[test]
1948 fn can_dkg_end_v2() {
1949 can_dkg_end::<v2::Signer>();
1950 }
1951
1952 fn can_dkg_end<SignerType: SignerTrait>() {
1953 let mut rng = create_rng();
1954 let private_key = Scalar::random(&mut rng);
1955 let public_key = ecdsa::PublicKey::new(&private_key).unwrap();
1956 let mut public_keys: PublicKeys = Default::default();
1957 let mut key_ids = HashSet::new();
1958
1959 public_keys.signers.insert(0, public_key);
1960 public_keys.key_ids.insert(1, public_key);
1961
1962 key_ids.insert(1);
1963 public_keys.signer_key_ids.insert(0, key_ids);
1964
1965 let mut signer =
1966 Signer::<SignerType>::new(1, 1, 1, 1, 0, vec![1], private_key, public_keys, &mut rng)
1967 .unwrap();
1968 signer.verify_packet_sigs = false;
1969 assert!(!signer.can_dkg_end());
1971
1972 let dkg_begin = Message::DkgBegin(DkgBegin { dkg_id: 1 });
1974 let dkg_begin_packet = Packet {
1975 msg: dkg_begin,
1976 sig: vec![],
1977 };
1978 let dkg_public_shares = signer
1979 .process(&dkg_begin_packet, &mut rng)
1980 .expect("failed to process DkgBegin");
1981 let dkg_public_shares_packet = Packet {
1982 msg: dkg_public_shares[0].clone(),
1983 sig: vec![],
1984 };
1985 let _ = signer
1986 .process(&dkg_public_shares_packet, &mut rng)
1987 .expect("failed to process DkgPublicShares");
1988 let dkg_public_shares_done = Message::DkgPublicSharesDone(DkgPublicSharesDone {
1990 dkg_id: 1,
1991 signer_ids: vec![0],
1992 });
1993 let dkg_public_shares_done_packet = Packet {
1994 msg: dkg_public_shares_done,
1995 sig: vec![],
1996 };
1997 let _ = signer
1998 .process(&dkg_public_shares_done_packet, &mut rng)
1999 .expect("failed to process DkgPublicSharesDone");
2000 let dkg_private_begin = Message::DkgPrivateBegin(DkgPrivateBegin {
2001 dkg_id: 1,
2002 signer_ids: vec![0],
2003 key_ids: vec![],
2004 });
2005 let dkg_private_begin_packet = Packet {
2006 msg: dkg_private_begin,
2007 sig: vec![],
2008 };
2009 let dkg_private_shares = signer
2010 .process(&dkg_private_begin_packet, &mut rng)
2011 .expect("failed to process DkgPrivateBegin");
2012 let dkg_private_shares_packet = Packet {
2013 msg: dkg_private_shares[0].clone(),
2014 sig: vec![],
2015 };
2016 let _ = signer
2017 .process(&dkg_private_shares_packet, &mut rng)
2018 .expect("failed to process DkgPrivateShares");
2019 let dkg_private_shares_done = Message::DkgPrivateSharesDone(DkgPrivateSharesDone {
2021 dkg_id: 1,
2022 signer_ids: vec![0],
2023 });
2024 let dkg_private_shares_done_packet = Packet {
2025 msg: dkg_private_shares_done,
2026 sig: vec![],
2027 };
2028 let _ = signer
2029 .process(&dkg_private_shares_done_packet, &mut rng)
2030 .expect("failed to process DkgPrivateSharesDone");
2031 let dkg_end_begin = DkgEndBegin {
2032 dkg_id: 1,
2033 signer_ids: vec![0],
2034 key_ids: vec![],
2035 };
2036 let _ = signer
2037 .dkg_end_begin(&dkg_end_begin)
2038 .expect("failed to process DkgPrivateShares");
2039
2040 assert!(signer.can_dkg_end());
2042 }
2043
2044 #[test]
2045 #[cfg(feature = "with_v1")]
2046 fn dkg_ended_v1() {
2047 dkg_ended::<v1::Signer>();
2048 }
2049
2050 #[test]
2051 fn dkg_ended_v2() {
2052 dkg_ended::<v2::Signer>();
2053 }
2054 fn dkg_ended<SignerType: SignerTrait>() {
2057 let mut rng = create_rng();
2062 let mut signer = Signer::<SignerType>::new(
2063 1,
2064 1,
2065 1,
2066 1,
2067 0,
2068 vec![1],
2069 Default::default(),
2070 Default::default(),
2071 &mut rng,
2072 )
2073 .unwrap();
2074
2075 let Ok(Message::DkgEnd(dkg_end)) = signer.dkg_ended(&mut rng) else {
2076 panic!("Unexpected Error");
2077 };
2078 assert!(
2079 matches!(dkg_end.status, DkgStatus::Failure(_)),
2080 "Expected DkgStatus::Failure"
2081 );
2082 }
2083}