wsts/state_machine/signer/
mod.rs

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)]
36/// Signer states
37pub enum State {
38    /// The signer is idle
39    Idle,
40    /// The signer is distributing DKG public shares
41    DkgPublicDistribute,
42    /// The signer is gathering DKG public shares
43    DkgPublicGather,
44    /// The signer has acknowledged DkgPublicSharesDone and is waiting for DkgPrivateBegin
45    DkgPublicSharesDoneAck,
46    /// The signer is distributing DKG private shares
47    DkgPrivateDistribute,
48    /// The signer is gathering DKG private shares
49    DkgPrivateGather,
50    /// The signer has acknowledged DkgPrivateSharesDone and is waiting for DkgEndBegin
51    DkgPrivateSharesDoneAck,
52    /// The signer has sent a nonce and is waiting for a signature share request
53    SignGather,
54}
55
56#[derive(thiserror::Error, Clone, Debug)]
57/// Config errors for a signer
58pub enum ConfigError {
59    /// Insufficient keys for the number of signers
60    #[error("Insufficient keys for the number of signers")]
61    InsufficientKeys,
62    /// The threshold was invalid
63    #[error("InvalidThreshold")]
64    InvalidThreshold,
65    /// The signer ID was invalid
66    #[error("Invalid signer ID {0}")]
67    InvalidSignerId(u32),
68    /// The key ID was invalid
69    #[error("Invalid key ID {0}")]
70    InvalidKeyId(u32),
71}
72
73#[derive(thiserror::Error, Clone, Debug)]
74/// The error type for a signer
75pub enum Error {
76    /// Config error
77    #[error("Config error {0}")]
78    Config(#[from] ConfigError),
79    /// The party ID was invalid
80    #[error("InvalidPartyID")]
81    InvalidPartyID,
82    /// A DKG public share was invalid
83    #[error("InvalidDkgPublicShares")]
84    InvalidDkgPublicShares,
85    /// A DKG private share was invalid
86    #[error("InvalidDkgPrivateShares")]
87    InvalidDkgPrivateShares(Vec<u32>),
88    /// A nonce response was invalid
89    #[error("InvalidNonceResponse")]
90    InvalidNonceResponse,
91    /// A signature share was invalid
92    #[error("InvalidSignatureShare")]
93    InvalidSignatureShare,
94    /// A bad state change was made
95    #[error("Bad State Change: {0}")]
96    BadStateChange(String),
97    /// An encryption error occurred
98    #[error("Encryption error: {0}")]
99    Encryption(#[from] EncryptionError),
100    #[error("integer conversion error")]
101    /// An error during integer conversion operations
102    TryFromInt(#[from] TryFromIntError),
103    #[error("Missing coordinator public key")]
104    /// Missing coordinator public key
105    MissingCoordinatorPublicKey,
106    #[error("A packet had an invalid signature")]
107    /// A packet had an invalid signature
108    InvalidPacketSignature,
109    #[error("A curve point error {0}")]
110    /// A curve point error
111    Point(#[from] PointError),
112    #[error("missing kex public key for key_id {0}")]
113    /// Missing KEX public key for a key_id
114    MissingKexPublicKey(u32),
115}
116
117/// The saved state required to reconstruct a signer
118#[derive(Clone)]
119pub struct SavedState {
120    /// current DKG round ID
121    pub dkg_id: u64,
122    /// current signing round ID
123    pub sign_id: u64,
124    /// current signing iteration ID
125    pub sign_iter_id: u64,
126    /// the threshold of the keys needed for a valid signature
127    pub threshold: u32,
128    /// the threshold of the keys needed for a valid DKG
129    pub dkg_threshold: u32,
130    /// the total number of signers
131    pub total_signers: u32,
132    /// the total number of keys
133    pub total_keys: u32,
134    /// the Signer object
135    pub signer: SignerSavedState,
136    /// the Signer ID
137    pub signer_id: u32,
138    /// the current state
139    pub state: State,
140    /// map of polynomial commitments for each party
141    /// party_id => PolyCommitment
142    pub commitments: HashMap<u32, PolyCommitment>,
143    /// map of decrypted DKG private shares
144    /// src_party_id => (dst_key_id => private_share)
145    decrypted_shares: HashMap<u32, HashMap<u32, Scalar>>,
146    /// shared secrets used to decrypt private shares
147    /// src_party_id => (signer_id, dh shared key)
148    decryption_keys: HashMap<u32, (u32, Point)>,
149    /// invalid private shares
150    /// signer_id => {shared_key, tuple_proof}
151    pub invalid_private_shares: HashMap<u32, BadPrivateShare>,
152    /// public nonces for this signing round
153    pub public_nonces: Vec<PublicNonce>,
154    /// the private key used to sign messages sent over the network
155    network_private_key: Scalar,
156    /// the public keys for all signers and coordinator
157    pub public_keys: PublicKeys,
158    /// the DKG public shares received in this round
159    pub dkg_public_shares: BTreeMap<u32, DkgPublicShares>,
160    /// the DKG private shares received in this round
161    pub dkg_private_shares: BTreeMap<u32, DkgPrivateShares>,
162    /// the DKG private begin message received in this round
163    pub dkg_private_begin_msg: Option<DkgPrivateBegin>,
164    /// the DKG end begin message received in this round
165    pub dkg_end_begin_msg: Option<DkgEndBegin>,
166    /// pending DkgPublicSharesDone waiting for all public shares to arrive
167    pending_public_shares_done: Option<DkgPublicSharesDone>,
168    /// pending DkgPrivateSharesDone waiting for all private shares to arrive
169    pending_private_shares_done: Option<DkgPrivateSharesDone>,
170    /// whether to verify the signature on Packets
171    pub verify_packet_sigs: bool,
172    /// coordinator public key
173    pub coordinator_public_key: Option<ecdsa::PublicKey>,
174    /// Ephemeral private key for key exchange
175    kex_private_key: Scalar,
176    /// Ephemeral public keys for key exchange indexed by key_id
177    kex_public_keys: HashMap<u32, Point>,
178    /// whether this signer successfully completed DKG for the current dkg_id
179    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/// A state machine for a signing round
207#[derive(Clone, PartialEq)]
208pub struct Signer<SignerType: SignerTrait> {
209    /// current DKG round ID
210    pub dkg_id: u64,
211    /// current signing round ID
212    pub sign_id: u64,
213    /// current signing iteration ID
214    pub sign_iter_id: u64,
215    /// the threshold of the keys needed for a valid signature
216    pub threshold: u32,
217    /// the threshold of the keys needed for a valid DKG
218    pub dkg_threshold: u32,
219    /// the total number of signers
220    pub total_signers: u32,
221    /// the total number of keys
222    pub total_keys: u32,
223    /// the Signer object
224    pub signer: SignerType,
225    /// the Signer ID
226    pub signer_id: u32,
227    /// the current state
228    pub state: State,
229    /// map of polynomial commitments for each party
230    /// party_id => PolyCommitment
231    pub commitments: HashMap<u32, PolyCommitment>,
232    /// map of decrypted DKG private shares
233    /// src_party_id => (dst_key_id => private_share)
234    pub decrypted_shares: HashMap<u32, HashMap<u32, Scalar>>,
235    /// shared secrets used to decrypt private shares
236    /// src_party_id => (signer_id, dh shared key)
237    pub decryption_keys: HashMap<u32, (u32, Point)>,
238    /// invalid private shares
239    /// signer_id => {shared_key, tuple_proof}
240    pub invalid_private_shares: HashMap<u32, BadPrivateShare>,
241    /// public nonces for this signing round
242    pub public_nonces: Vec<PublicNonce>,
243    /// the private key used to sign messages sent over the network
244    pub network_private_key: Scalar,
245    /// the public keys for all signers and coordinator
246    pub public_keys: PublicKeys,
247    /// the DKG public shares received in this round
248    pub dkg_public_shares: BTreeMap<u32, DkgPublicShares>,
249    /// the DKG private shares received in this round
250    pub dkg_private_shares: BTreeMap<u32, DkgPrivateShares>,
251    /// the DKG private begin message received in this round
252    pub dkg_private_begin_msg: Option<DkgPrivateBegin>,
253    /// the DKG end begin message received in this round
254    pub dkg_end_begin_msg: Option<DkgEndBegin>,
255    /// pending DkgPublicSharesDone waiting for all public shares to arrive
256    pending_public_shares_done: Option<DkgPublicSharesDone>,
257    /// pending DkgPrivateSharesDone waiting for all private shares to arrive
258    pending_private_shares_done: Option<DkgPrivateSharesDone>,
259    /// whether to verify the signature on Packets
260    pub verify_packet_sigs: bool,
261    /// coordinator public key
262    pub coordinator_public_key: Option<ecdsa::PublicKey>,
263    /// Ephemeral private key for key exchange
264    kex_private_key: Scalar,
265    /// Ephemeral public keys for key exchange indexed by key_id
266    kex_public_keys: HashMap<u32, Point>,
267    /// whether this signer successfully completed DKG for the current dkg_id
268    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    /// create a Signer
297    #[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        // immediately generate nonces with good entropy to avoid protocol attacks
343        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    /// Load a coordinator from the previously saved `state`
379    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    /// Save the state required to reconstruct the coordinator
413    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    /// Reset internal state
447    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    /// Process the slice of packets
468    #[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    /// process the passed incoming message, and return any outgoing messages needed in response
491    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            // DkgBegin restarts DKG from any state
506            (_, Message::DkgBegin(msg)) => self.dkg_begin(msg, rng),
507            // DKG public phase
508            (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            // DKG private phase
513            (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            // DKG end phase: by the time we reach DkgPrivateSharesDoneAck we have all
523            // public and private shares, so DkgEndBegin directly triggers dkg_ended
524            (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            // Signing phase: NonceRequest accepted from Idle or SignGather (coordinator retry)
531            (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            // Messages signers never process
538            (
539                _,
540                Message::DkgEnd(_)
541                | Message::DkgPublicSharesDoneAck(_)
542                | Message::DkgPrivateSharesDoneAck(_)
543                | Message::NonceResponse(_)
544                | Message::SignatureShareResponse(_),
545            ) => Ok(vec![]),
546            // Unexpected state+message combination
547            (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    /// DKG is done so compute secrets
562    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        // only use the public shares from the DkgEndBegin signers
572        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            // no cached DkgEndBegin message
579            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        // fist check to see if dkg_threshold has been met
587        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                // signer_id sent shares, but make sure that it sent shares for every one of this signer's key_ids
627                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                    // we've handled everything except BadPrivateShares and Point both of which should map to DkgFailure::BadPrivateShares
682                    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    /// do we have all DkgPublicShares?
736    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    /// do we have all DkgPublicShares and DkgPrivateShares?
747    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                // need public shares from active signers
758                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                    // need private shares from active signers
767                    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        // The expected usage is that Signer IDs start at zero and
866        // increment by one until self.total_signers - 1. So the checks
867        // here should be sufficient for catching empty signer ID sets,
868        // duplicate signer IDs, or unknown signer IDs.
869        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        //let _party_state = self.signer.save();
952
953        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        // Reject any unknown signer IDs
967        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        // Discard any shares already collected from signers not in the coordinator's accepted list
990        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        // Reject any unknown signer IDs
1028        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        // Discard any shares already collected from signers not in the coordinator's accepted list
1051        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            // encrypt each share for the recipient
1165            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    /// handle incoming DkgEndBegin
1192    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        // Reject any unknown signer IDs
1203        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    /// handle incoming DkgPublicShares
1245    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        // check that the signer_id exists in the config
1268        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 we already know which signers the coordinator accepted, discard others
1285        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 DkgPublicSharesDone arrived before this share, check if we now have everything
1320        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    /// handle incoming DkgPrivateShares
1339    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        // go ahead and decrypt here, since we know the signer_id and hence the pubkey of the sender
1354        let src_signer_id = dkg_private_shares.signer_id;
1355
1356        // check that the signer_id exists in the config
1357        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 we already know which signers the coordinator accepted, discard others
1378        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        // make a HashSet of our key_ids so we can quickly query them
1394        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 DkgPrivateSharesDone arrived before this share, check if we now have everything
1438        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            // DkgBegin can restart from any state
1506            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)]
1534/// Test module for signer functionality
1535pub 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        // more signers than keys
1575        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        // threshold == 0
1591        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        // dkg_threshold == 0
1607        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        // threshold > total_keys
1623        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        // dkg_threshold < threshold
1639        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        // signer_id >= num_signers
1655        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        // key_id == 0
1671        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        // key_id > num_keys
1687        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        // public_keys: key_id == 0
1703    }
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        // check that a duplicate public share is ignored
1752        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        // publich_shares_done starts out as false
1794        assert!(!signer.public_shares_done());
1795
1796        // meet the conditions for all public keys received
1797        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        // public_shares_done should be true
1807        assert!(signer.public_shares_done());
1808    }
1809
1810    #[test]
1811    #[cfg(feature = "with_v1")]
1812    /// test basic insertion and detection of duplicates for DkgPrivateShares for v1
1813    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        // check that a duplicate private share is ignored
1861        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    /// test basic insertion and detection of duplicates for DkgPrivateShares for v2
1878    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        // check that a duplicate private share is ignored
1926        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        // can_dkg_end starts out as false
1970        assert!(!signer.can_dkg_end());
1971
1972        // meet the conditions for DKG_END
1973        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        // coordinator signals all public shares received; signer moves to DkgPublicSharesDoneAck
1989        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        // coordinator signals all private shares received; signer moves to DkgPrivateSharesDoneAck
2020        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        // can_dkg_end should be true
2041        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    //use tracing_subscriber::{fmt, prelude::*, EnvFilter};
2055
2056    fn dkg_ended<SignerType: SignerTrait>() {
2057        /*tracing_subscriber::registry()
2058        .with(fmt::layer())
2059        .with(EnvFilter::from_default_env())
2060        .init();*/
2061        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}