wsts/state_machine/coordinator/
frost.rs

1use hashbrown::{HashMap, HashSet};
2use std::collections::BTreeMap;
3use tracing::{debug, info, warn};
4
5use crate::{
6    common::{PolyCommitment, PublicNonce, Signature, SignatureShare},
7    compute,
8    curve::{ecdsa, point::Point},
9    net::{
10        DkgBegin, DkgEnd, DkgEndBegin, DkgPrivateBegin, DkgPrivateShares, DkgPublicShares,
11        DkgStatus, Message, NonceRequest, NonceResponse, Packet, Signable, SignatureShareRequest,
12        SignatureType,
13    },
14    state_machine::{
15        coordinator::{
16            Config, Coordinator as CoordinatorTrait, Error, SavedState, SignRoundInfo, State,
17        },
18        DkgError, OperationResult, SignError, StateMachine,
19    },
20    taproot::SchnorrProof,
21    traits::Aggregator as AggregatorTrait,
22};
23
24/// The coordinator for the FROST algorithm
25#[derive(Clone, Debug, PartialEq)]
26pub struct Coordinator<Aggregator: AggregatorTrait> {
27    /// common config fields
28    config: Config,
29    /// current DKG round ID
30    pub current_dkg_id: u64,
31    /// current signing round ID
32    current_sign_id: u64,
33    /// current signing iteration ID
34    current_sign_iter_id: u64,
35    dkg_public_shares: BTreeMap<u32, DkgPublicShares>,
36    dkg_private_shares: BTreeMap<u32, DkgPrivateShares>,
37    dkg_end_messages: BTreeMap<u32, DkgEnd>,
38    party_polynomials: HashMap<u32, PolyCommitment>,
39    public_nonces: BTreeMap<u32, NonceResponse>,
40    signature_shares: BTreeMap<u32, Vec<SignatureShare>>,
41    /// aggregate public key
42    pub aggregate_public_key: Option<Point>,
43    signature: Option<Signature>,
44    schnorr_proof: Option<SchnorrProof>,
45    /// which signers we're currently waiting on
46    pub ids_to_await: HashSet<u32>,
47    /// the bytes that we're signing
48    pub message: Vec<u8>,
49    /// current state of the state machine
50    pub state: State,
51    /// Aggregator object
52    aggregator: Aggregator,
53    /// coordinator public key
54    pub coordinator_public_key: Option<ecdsa::PublicKey>,
55}
56
57impl<Aggregator: AggregatorTrait> Coordinator<Aggregator> {
58    /// Process the message inside the passed packet
59    pub fn process_message(
60        &mut self,
61        packet: &Packet,
62    ) -> Result<(Option<Packet>, Option<OperationResult>), Error> {
63        if self.config.verify_packet_sigs {
64            let Some(coordinator_public_key) = self.coordinator_public_key else {
65                return Err(Error::MissingCoordinatorPublicKey);
66            };
67            if !packet.verify(&self.config.public_keys, &coordinator_public_key) {
68                return Err(Error::InvalidPacketSignature);
69            }
70        }
71        loop {
72            match self.state.clone() {
73                State::Idle => {
74                    // Did we receive a coordinator message?
75                    if let Message::DkgBegin(dkg_begin) = &packet.msg {
76                        if self.current_dkg_id == dkg_begin.dkg_id {
77                            // We have already processed this DKG round
78                            return Ok((None, None));
79                        }
80                        // use dkg_id from DkgBegin
81                        let packet = self.start_dkg_round(Some(dkg_begin.dkg_id))?;
82                        return Ok((Some(packet), None));
83                    } else if let Message::NonceRequest(nonce_request) = &packet.msg {
84                        if self.current_sign_id == nonce_request.sign_id {
85                            // We have already processed this sign round
86                            return Ok((None, None));
87                        }
88                        self.current_sign_iter_id = nonce_request.sign_iter_id;
89                        // use sign_id from NonceRequest
90                        let packet = self.start_signing_round(
91                            nonce_request.message.as_slice(),
92                            nonce_request.signature_type,
93                            Some(nonce_request.sign_id),
94                        )?;
95                        return Ok((Some(packet), None));
96                    }
97                    return Ok((None, None));
98                }
99                State::DkgPublicDistribute => {
100                    let packet = self.start_public_shares()?;
101                    return Ok((Some(packet), None));
102                }
103                State::DkgPublicGather => {
104                    self.gather_public_shares(packet)?;
105                    if self.state == State::DkgPublicGather {
106                        // We need more data
107                        return Ok((None, None));
108                    }
109                }
110                State::DkgPrivateDistribute => {
111                    let packet = self.start_private_shares()?;
112                    return Ok((Some(packet), None));
113                }
114                State::DkgPrivateGather => {
115                    self.gather_private_shares(packet)?;
116                    if self.state == State::DkgPrivateGather {
117                        // We need more data
118                        return Ok((None, None));
119                    }
120                }
121                State::DkgEndDistribute => {
122                    let packet = self.start_dkg_end()?;
123                    return Ok((Some(packet), None));
124                }
125                State::DkgEndGather => {
126                    if let Err(error) = self.gather_dkg_end(packet) {
127                        if let Error::DkgFailure {
128                            reported_failures,
129                            malicious_signers,
130                        } = error
131                        {
132                            return Ok((
133                                None,
134                                Some(OperationResult::DkgError(DkgError::DkgEndFailure {
135                                    reported_failures,
136                                    malicious_signers,
137                                })),
138                            ));
139                        } else {
140                            return Err(error);
141                        }
142                    }
143                    if self.state == State::DkgEndGather {
144                        // We need more data
145                        return Ok((None, None));
146                    } else if self.state == State::Idle {
147                        // We are done with the DKG round! Return the operation result
148                        return Ok((
149                            None,
150                            Some(OperationResult::Dkg(
151                                self.aggregate_public_key
152                                    .ok_or(Error::MissingAggregatePublicKey)?,
153                            )),
154                        ));
155                    }
156                }
157                State::NonceRequest(signature_type) => {
158                    let packet = self.request_nonces(signature_type)?;
159                    return Ok((Some(packet), None));
160                }
161                State::NonceGather(signature_type) => {
162                    self.gather_nonces(packet, signature_type)?;
163                    if self.state == State::NonceGather(signature_type) {
164                        // We need more data
165                        return Ok((None, None));
166                    }
167                }
168                State::SigShareRequest(signature_type) => {
169                    let packet = self.request_sig_shares(signature_type)?;
170                    return Ok((Some(packet), None));
171                }
172                State::SigShareGather(signature_type) => {
173                    if let Err(e) = self.gather_sig_shares(packet, signature_type) {
174                        return Ok((
175                            None,
176                            Some(OperationResult::SignError(SignError::Coordinator(e))),
177                        ));
178                    }
179                    if self.state == State::SigShareGather(signature_type) {
180                        // We need more data
181                        return Ok((None, None));
182                    } else if self.state == State::Idle {
183                        // We are done with the DKG round! Return the operation result
184                        if let SignatureType::Taproot(_) = signature_type {
185                            let schnorr_proof = self
186                                .schnorr_proof
187                                .as_ref()
188                                .ok_or(Error::MissingSchnorrProof)?;
189                            return Ok((
190                                None,
191                                Some(OperationResult::SignTaproot(SchnorrProof {
192                                    r: schnorr_proof.r,
193                                    s: schnorr_proof.s,
194                                })),
195                            ));
196                        } else if let SignatureType::Schnorr = signature_type {
197                            let schnorr_proof = self
198                                .schnorr_proof
199                                .as_ref()
200                                .ok_or(Error::MissingSchnorrProof)?;
201                            return Ok((
202                                None,
203                                Some(OperationResult::SignSchnorr(SchnorrProof {
204                                    r: schnorr_proof.r,
205                                    s: schnorr_proof.s,
206                                })),
207                            ));
208                        } else {
209                            let signature =
210                                self.signature.as_ref().ok_or(Error::MissingSignature)?;
211                            return Ok((
212                                None,
213                                Some(OperationResult::Sign(Signature {
214                                    R: signature.R,
215                                    z: signature.z,
216                                })),
217                            ));
218                        }
219                    }
220                }
221            }
222        }
223    }
224
225    /// Ask signers to send DKG public shares
226    pub fn start_public_shares(&mut self) -> Result<Packet, Error> {
227        self.dkg_public_shares.clear();
228        self.party_polynomials.clear();
229        self.ids_to_await = (0..self.config.num_signers).collect();
230        info!(
231            dkg_id = %self.current_dkg_id,
232            "Starting Public Share Distribution"
233        );
234        let dkg_begin = DkgBegin {
235            dkg_id: self.current_dkg_id,
236        };
237
238        let dkg_begin_packet = Packet {
239            sig: dkg_begin
240                .sign(&self.config.message_private_key)
241                .expect("Failed to sign DkgBegin"),
242            msg: Message::DkgBegin(dkg_begin),
243        };
244        self.move_to(State::DkgPublicGather)?;
245        Ok(dkg_begin_packet)
246    }
247
248    /// Ask signers to send DKG private shares
249    pub fn start_private_shares(&mut self) -> Result<Packet, Error> {
250        self.ids_to_await = (0..self.config.num_signers).collect();
251        info!(
252            dkg_id = %self.current_dkg_id,
253            "Starting Private Share Distribution"
254        );
255        let dkg_begin = DkgPrivateBegin {
256            dkg_id: self.current_dkg_id,
257            key_ids: (1..self.config.num_keys + 1).collect(),
258            signer_ids: (0..self.config.num_signers).collect(),
259        };
260        let dkg_private_begin_msg = Packet {
261            sig: dkg_begin
262                .sign(&self.config.message_private_key)
263                .expect("Failed to sign DkgPrivateBegin"),
264            msg: Message::DkgPrivateBegin(dkg_begin),
265        };
266        self.move_to(State::DkgPrivateGather)?;
267        Ok(dkg_private_begin_msg)
268    }
269
270    /// Ask signers to compute secrets and send DKG end
271    pub fn start_dkg_end(&mut self) -> Result<Packet, Error> {
272        self.ids_to_await = (0..self.config.num_signers).collect();
273        info!(
274            dkg_id = %self.current_dkg_id,
275            "Starting DKG End Distribution"
276        );
277        let dkg_begin = DkgEndBegin {
278            dkg_id: self.current_dkg_id,
279            key_ids: (0..self.config.num_keys).collect(),
280            signer_ids: (0..self.config.num_signers).collect(),
281        };
282        let dkg_end_begin_msg = Packet {
283            sig: dkg_begin.sign(&self.config.message_private_key).expect(""),
284            msg: Message::DkgEndBegin(dkg_begin),
285        };
286        self.move_to(State::DkgEndGather)?;
287        Ok(dkg_end_begin_msg)
288    }
289
290    fn gather_public_shares(&mut self, packet: &Packet) -> Result<(), Error> {
291        if let Message::DkgPublicShares(dkg_public_shares) = &packet.msg {
292            if dkg_public_shares.dkg_id != self.current_dkg_id {
293                return Err(Error::BadDkgId(
294                    dkg_public_shares.dkg_id,
295                    self.current_dkg_id,
296                ));
297            }
298
299            // check that the signer_id exists in the config
300            let signer_public_keys = &self.config.public_keys.signers;
301            if !signer_public_keys.contains_key(&dkg_public_shares.signer_id) {
302                warn!(signer_id = %dkg_public_shares.signer_id, "No public key in config");
303                return Ok(());
304            };
305
306            let have_shares = self
307                .dkg_public_shares
308                .contains_key(&dkg_public_shares.signer_id);
309
310            if have_shares {
311                info!(signer_id = %dkg_public_shares.signer_id, "received duplicate DkgPublicShares");
312                return Ok(());
313            }
314
315            self.ids_to_await.remove(&dkg_public_shares.signer_id);
316
317            self.dkg_public_shares
318                .insert(dkg_public_shares.signer_id, dkg_public_shares.clone());
319            for (party_id, comm) in &dkg_public_shares.comms {
320                self.party_polynomials.insert(*party_id, comm.clone());
321            }
322
323            debug!(
324                dkg_id = %dkg_public_shares.dkg_id,
325                signer_id = %dkg_public_shares.signer_id,
326                "DkgPublicShares received"
327            );
328        }
329
330        if self.ids_to_await.is_empty() {
331            self.move_to(State::DkgPrivateDistribute)?;
332        }
333        Ok(())
334    }
335
336    fn gather_private_shares(&mut self, packet: &Packet) -> Result<(), Error> {
337        if let Message::DkgPrivateShares(dkg_private_shares) = &packet.msg {
338            if dkg_private_shares.dkg_id != self.current_dkg_id {
339                return Err(Error::BadDkgId(
340                    dkg_private_shares.dkg_id,
341                    self.current_dkg_id,
342                ));
343            }
344
345            // check that the signer_id exists in the config
346            let signer_public_keys = &self.config.public_keys.signers;
347            if !signer_public_keys.contains_key(&dkg_private_shares.signer_id) {
348                warn!(signer_id = %dkg_private_shares.signer_id, "No public key in config");
349                return Ok(());
350            };
351
352            let has_received_shares = self
353                .dkg_private_shares
354                .contains_key(&dkg_private_shares.signer_id);
355            if has_received_shares {
356                info!(signer_id = %dkg_private_shares.signer_id, "received duplicate DkgPrivateShares");
357                return Ok(());
358            }
359
360            self.ids_to_await.remove(&dkg_private_shares.signer_id);
361
362            self.dkg_private_shares
363                .insert(dkg_private_shares.signer_id, dkg_private_shares.clone());
364            info!(
365                dkg_id = %dkg_private_shares.dkg_id,
366                signer_id = %dkg_private_shares.signer_id,
367                "DkgPrivateShares received"
368            );
369        }
370
371        if self.ids_to_await.is_empty() {
372            self.move_to(State::DkgEndDistribute)?;
373        }
374        Ok(())
375    }
376
377    fn gather_dkg_end(&mut self, packet: &Packet) -> Result<(), Error> {
378        debug!(
379            dkg_id = %self.current_dkg_id,
380            waiting = ?self.ids_to_await,
381            "Waiting for Dkg End from signers"
382        );
383        if let Message::DkgEnd(dkg_end) = &packet.msg {
384            if dkg_end.dkg_id != self.current_dkg_id {
385                return Err(Error::BadDkgId(dkg_end.dkg_id, self.current_dkg_id));
386            }
387            if self.ids_to_await.contains(&dkg_end.signer_id) {
388                self.ids_to_await.remove(&dkg_end.signer_id);
389                self.dkg_end_messages
390                    .insert(dkg_end.signer_id, dkg_end.clone());
391                debug!(
392                    dkg_id = %dkg_end.dkg_id,
393                    signer_id = %dkg_end.signer_id,
394                    waiting = ?self.ids_to_await,
395                    "DkgEnd received"
396                );
397            }
398        }
399
400        if self.ids_to_await.is_empty() {
401            let mut reported_failures = HashMap::new();
402
403            for (signer_id, dkg_end) in &self.dkg_end_messages {
404                if let DkgStatus::Failure(dkg_failure) = &dkg_end.status {
405                    warn!(%signer_id, ?dkg_failure, "DkgEnd failure");
406                    reported_failures.insert(*signer_id, dkg_failure.clone());
407                }
408            }
409
410            if reported_failures.is_empty() {
411                self.dkg_end_gathered()?;
412            } else {
413                return Err(Error::DkgFailure {
414                    reported_failures,
415                    malicious_signers: Default::default(),
416                });
417            }
418        }
419        Ok(())
420    }
421
422    fn dkg_end_gathered(&mut self) -> Result<(), Error> {
423        // Cache the polynomials used in DKG for the aggregator
424        for signer_id in self.dkg_private_shares.keys() {
425            let Some(dkg_public_shares) = self.dkg_public_shares.get(signer_id) else {
426                warn!(%signer_id, "no DkgPublicShares");
427                return Err(Error::BadStateChange(format!("Should not have transitioned to DkgEndGather since we were missing DkgPublicShares from signer {signer_id}")));
428            };
429            for (party_id, comm) in &dkg_public_shares.comms {
430                self.party_polynomials.insert(*party_id, comm.clone());
431            }
432        }
433
434        // Calculate the aggregate public key
435        let key = self
436            .party_polynomials
437            .iter()
438            .fold(Point::default(), |s, (_, comm)| s + comm.poly[0]);
439
440        info!(
441            %key,
442            "Aggregate public key"
443        );
444        self.aggregate_public_key = Some(key);
445        self.move_to(State::Idle)
446    }
447
448    fn request_nonces(&mut self, signature_type: SignatureType) -> Result<Packet, Error> {
449        self.public_nonces.clear();
450        info!(
451            sign_id = %self.current_sign_id,
452            sign_iter_id = %self.current_sign_iter_id,
453            "Requesting Nonces"
454        );
455        let nonce_request = NonceRequest {
456            dkg_id: self.current_dkg_id,
457            sign_id: self.current_sign_id,
458            sign_iter_id: self.current_sign_iter_id,
459            message: self.message.clone(),
460            signature_type,
461        };
462        let nonce_request_msg = Packet {
463            sig: nonce_request
464                .sign(&self.config.message_private_key)
465                .expect(""),
466            msg: Message::NonceRequest(nonce_request),
467        };
468        self.ids_to_await = (0..self.config.num_signers).collect();
469        self.move_to(State::NonceGather(signature_type))?;
470        Ok(nonce_request_msg)
471    }
472
473    fn gather_nonces(
474        &mut self,
475        packet: &Packet,
476        signature_type: SignatureType,
477    ) -> Result<(), Error> {
478        if let Message::NonceResponse(nonce_response) = &packet.msg {
479            if nonce_response.dkg_id != self.current_dkg_id {
480                return Err(Error::BadDkgId(nonce_response.dkg_id, self.current_dkg_id));
481            }
482            if nonce_response.sign_id != self.current_sign_id {
483                return Err(Error::BadSignId(
484                    nonce_response.sign_id,
485                    self.current_sign_id,
486                ));
487            }
488            if nonce_response.sign_iter_id != self.current_sign_iter_id {
489                return Err(Error::BadSignIterId(
490                    nonce_response.sign_iter_id,
491                    self.current_sign_iter_id,
492                ));
493            }
494
495            // check that the signer_id exists in the config
496            let signer_public_keys = &self.config.public_keys.signers;
497            if !signer_public_keys.contains_key(&nonce_response.signer_id) {
498                warn!(signer_id = %nonce_response.signer_id, "No public key in config");
499                return Ok(());
500            };
501
502            // check that the key_ids match the config
503            let Some(signer_key_ids) = self
504                .config
505                .public_keys
506                .signer_key_ids
507                .get(&nonce_response.signer_id)
508            else {
509                warn!(signer_id = %nonce_response.signer_id, "No keys IDs configured");
510                return Ok(());
511            };
512
513            let nonce_response_key_ids = nonce_response
514                .key_ids
515                .iter()
516                .cloned()
517                .collect::<HashSet<u32>>();
518            if *signer_key_ids != nonce_response_key_ids {
519                warn!(signer_id = %nonce_response.signer_id, "Nonce response key_ids didn't match config");
520                return Ok(());
521            }
522
523            for nonce in &nonce_response.nonces {
524                if !nonce.is_valid() {
525                    warn!(
526                        sign_id = %nonce_response.sign_id,
527                        sign_iter_id = %nonce_response.sign_iter_id,
528                        signer_id = %nonce_response.signer_id,
529                        "Received invalid nonce in NonceResponse"
530                    );
531                    return Ok(());
532                }
533            }
534
535            let have_nonces = self.public_nonces.contains_key(&nonce_response.signer_id);
536
537            if have_nonces {
538                info!(signer_id = %nonce_response.signer_id, "Received duplicate NonceResponse");
539                return Ok(());
540            }
541
542            self.public_nonces
543                .insert(nonce_response.signer_id, nonce_response.clone());
544            self.ids_to_await.remove(&nonce_response.signer_id);
545            debug!(
546                sign_id = %nonce_response.sign_id,
547                sign_iter_id = %nonce_response.sign_iter_id,
548                signer_id = %nonce_response.signer_id,
549                waiting = ?self.ids_to_await,
550                "NonceResponse received"
551            );
552        }
553        if self.ids_to_await.is_empty() {
554            let aggregate_nonce = self.compute_aggregate_nonce();
555            info!(
556                %aggregate_nonce,
557                "Aggregate nonce"
558            );
559
560            self.move_to(State::SigShareRequest(signature_type))?;
561        }
562        Ok(())
563    }
564
565    fn request_sig_shares(&mut self, signature_type: SignatureType) -> Result<Packet, Error> {
566        self.signature_shares.clear();
567        info!(
568            sign_id = %self.current_sign_id,
569            "Requesting Signature Shares"
570        );
571        let nonce_responses = (0..self.config.num_signers)
572            .map(|i| self.public_nonces[&i].clone())
573            .collect::<Vec<NonceResponse>>();
574        let sig_share_request = SignatureShareRequest {
575            dkg_id: self.current_dkg_id,
576            sign_id: self.current_sign_id,
577            sign_iter_id: self.current_sign_iter_id,
578            nonce_responses,
579            message: self.message.clone(),
580            signature_type,
581        };
582        let sig_share_request_msg = Packet {
583            sig: sig_share_request
584                .sign(&self.config.message_private_key)
585                .expect(""),
586            msg: Message::SignatureShareRequest(sig_share_request),
587        };
588        self.ids_to_await = (0..self.config.num_signers).collect();
589        self.move_to(State::SigShareGather(signature_type))?;
590
591        Ok(sig_share_request_msg)
592    }
593
594    fn gather_sig_shares(
595        &mut self,
596        packet: &Packet,
597        signature_type: SignatureType,
598    ) -> Result<(), Error> {
599        if let Message::SignatureShareResponse(sig_share_response) = &packet.msg {
600            if sig_share_response.dkg_id != self.current_dkg_id {
601                return Err(Error::BadDkgId(
602                    sig_share_response.dkg_id,
603                    self.current_dkg_id,
604                ));
605            }
606            if sig_share_response.sign_id != self.current_sign_id {
607                return Err(Error::BadSignId(
608                    sig_share_response.sign_id,
609                    self.current_sign_id,
610                ));
611            }
612
613            // check that the signer_id exists in the config
614            let signer_public_keys = &self.config.public_keys.signers;
615            if !signer_public_keys.contains_key(&sig_share_response.signer_id) {
616                warn!(signer_id = %sig_share_response.signer_id, "No public key in config");
617                return Ok(());
618            };
619
620            // check that the key_ids match the config
621            let Some(signer_key_ids) = self
622                .config
623                .public_keys
624                .signer_key_ids
625                .get(&sig_share_response.signer_id)
626            else {
627                warn!(signer_id = %sig_share_response.signer_id, "No keys IDs configured");
628                return Ok(());
629            };
630
631            let mut sig_share_response_key_ids = HashSet::new();
632            for sig_share in &sig_share_response.signature_shares {
633                for key_id in &sig_share.key_ids {
634                    sig_share_response_key_ids.insert(*key_id);
635                }
636            }
637
638            if *signer_key_ids != sig_share_response_key_ids {
639                warn!(signer_id = %sig_share_response.signer_id, "SignatureShareResponse key_ids didn't match config");
640                return Ok(());
641            }
642
643            let have_shares = self
644                .signature_shares
645                .contains_key(&sig_share_response.signer_id);
646
647            if have_shares {
648                info!(signer_id = %sig_share_response.signer_id, "received duplicate SignatureShareResponse");
649                return Ok(());
650            }
651
652            self.signature_shares.insert(
653                sig_share_response.signer_id,
654                sig_share_response.signature_shares.clone(),
655            );
656            self.ids_to_await.remove(&sig_share_response.signer_id);
657            debug!(
658                sign_id = %sig_share_response.sign_id,
659                signer_id = %sig_share_response.signer_id,
660                waiting = ?self.ids_to_await,
661                "SignatureShareResponse received"
662            );
663        }
664        if self.ids_to_await.is_empty() {
665            // Calculate the aggregate signature
666            let nonce_responses = (0..self.config.num_signers)
667                .map(|i| self.public_nonces[&i].clone())
668                .collect::<Vec<NonceResponse>>();
669
670            let nonces = nonce_responses
671                .iter()
672                .flat_map(|nr| nr.nonces.clone())
673                .collect::<Vec<PublicNonce>>();
674
675            let key_ids = nonce_responses
676                .iter()
677                .flat_map(|nr| nr.key_ids.clone())
678                .collect::<Vec<u32>>();
679
680            let shares = &self
681                .public_nonces
682                .iter()
683                .flat_map(|(i, _)| self.signature_shares[i].clone())
684                .collect::<Vec<SignatureShare>>();
685
686            debug!(
687                nonces_len = %nonces.len(),
688                shares_len = %shares.len(),
689                "aggregator.sign"
690            );
691
692            self.aggregator.init(&self.party_polynomials)?;
693
694            if let SignatureType::Taproot(merkle_root) = signature_type {
695                let schnorr_proof = self.aggregator.sign_taproot(
696                    &self.message,
697                    &nonces,
698                    shares,
699                    &key_ids,
700                    merkle_root,
701                )?;
702                debug!(
703                    r = %schnorr_proof.r,
704                    s = %schnorr_proof.s,
705                    "SchnorrProof"
706                );
707                self.schnorr_proof = Some(schnorr_proof);
708            } else if let SignatureType::Schnorr = signature_type {
709                let schnorr_proof =
710                    self.aggregator
711                        .sign_schnorr(&self.message, &nonces, shares, &key_ids)?;
712                debug!(
713                    r = %schnorr_proof.r,
714                    s = %schnorr_proof.s,
715                    "SchnorrProof"
716                );
717                self.schnorr_proof = Some(schnorr_proof);
718            } else {
719                let signature = self
720                    .aggregator
721                    .sign(&self.message, &nonces, shares, &key_ids)?;
722                debug!(
723                    R = %signature.R,
724                    z = %signature.z,
725                    "Signature"
726                );
727                self.signature = Some(signature);
728            }
729
730            self.move_to(State::Idle)?;
731        }
732        Ok(())
733    }
734
735    #[allow(non_snake_case)]
736    fn compute_aggregate_nonce(&self) -> Point {
737        // XXX this needs to be key_ids for v1 and signer_ids for v2
738        let party_ids = self
739            .public_nonces
740            .values()
741            .flat_map(|pn| pn.key_ids.clone())
742            .collect::<Vec<u32>>();
743        let nonces = self
744            .public_nonces
745            .values()
746            .flat_map(|pn| pn.nonces.clone())
747            .collect::<Vec<PublicNonce>>();
748        let (_, R) = compute::intermediate(&self.message, &party_ids, &nonces);
749
750        R
751    }
752}
753
754impl<Aggregator: AggregatorTrait> StateMachine<State, Error> for Coordinator<Aggregator> {
755    fn move_to(&mut self, state: State) -> Result<(), Error> {
756        self.can_move_to(&state)?;
757        self.state = state;
758        Ok(())
759    }
760
761    fn can_move_to(&self, state: &State) -> Result<(), Error> {
762        let prev_state = &self.state;
763        let accepted = match state {
764            State::Idle => true,
765            State::DkgPublicDistribute => prev_state == &State::Idle,
766            State::DkgPublicGather => {
767                prev_state == &State::DkgPublicDistribute || prev_state == &State::DkgPublicGather
768            }
769            State::DkgPrivateDistribute => prev_state == &State::DkgPublicGather,
770            State::DkgPrivateGather => {
771                prev_state == &State::DkgPrivateDistribute || prev_state == &State::DkgPrivateGather
772            }
773            State::DkgEndDistribute => prev_state == &State::DkgPrivateGather,
774            State::DkgEndGather => prev_state == &State::DkgEndDistribute,
775            State::NonceRequest(_) => {
776                prev_state == &State::Idle || prev_state == &State::DkgEndGather
777            }
778            State::NonceGather(signature_type) => {
779                prev_state == &State::NonceRequest(*signature_type)
780                    || prev_state == &State::NonceGather(*signature_type)
781            }
782            State::SigShareRequest(signature_type) => {
783                prev_state == &State::NonceGather(*signature_type)
784            }
785            State::SigShareGather(signature_type) => {
786                prev_state == &State::SigShareRequest(*signature_type)
787                    || prev_state == &State::SigShareGather(*signature_type)
788            }
789        };
790        if accepted {
791            debug!("state change from {prev_state:?} to {state:?}");
792            Ok(())
793        } else {
794            Err(Error::BadStateChange(format!(
795                "{prev_state:?} to {state:?}"
796            )))
797        }
798    }
799}
800
801impl<Aggregator: AggregatorTrait> CoordinatorTrait for Coordinator<Aggregator> {
802    /// Create a new coordinator
803    fn new(config: Config) -> Self {
804        Self {
805            aggregator: Aggregator::new(config.num_keys, config.threshold),
806            config,
807            current_dkg_id: 0,
808            current_sign_id: 0,
809            current_sign_iter_id: 0,
810            dkg_public_shares: Default::default(),
811            dkg_private_shares: Default::default(),
812            dkg_end_messages: Default::default(),
813            party_polynomials: Default::default(),
814            public_nonces: Default::default(),
815            signature_shares: Default::default(),
816            aggregate_public_key: None,
817            signature: None,
818            schnorr_proof: None,
819            message: Default::default(),
820            ids_to_await: Default::default(),
821            state: State::Idle,
822            coordinator_public_key: None,
823        }
824    }
825
826    fn load(state: &SavedState) -> Self {
827        Self {
828            aggregator: Aggregator::new(state.config.num_keys, state.config.threshold),
829            config: state.config.clone(),
830            current_dkg_id: state.current_dkg_id,
831            current_sign_id: state.current_sign_id,
832            current_sign_iter_id: state.current_sign_iter_id,
833            dkg_public_shares: state.dkg_public_shares.clone(),
834            dkg_private_shares: state.dkg_private_shares.clone(),
835            dkg_end_messages: state.dkg_end_messages.clone(),
836            party_polynomials: state.party_polynomials.clone(),
837            public_nonces: state.message_nonces[&Vec::new()].public_nonces.clone(),
838            signature_shares: state.signature_shares.clone(),
839            aggregate_public_key: state.aggregate_public_key,
840            signature: state.signature.clone(),
841            schnorr_proof: state.schnorr_proof.clone(),
842            message: state.message.clone(),
843            ids_to_await: state.dkg_wait_signer_ids.clone(),
844            state: state.state.clone(),
845            coordinator_public_key: state.coordinator_public_key,
846        }
847    }
848
849    fn save(&self) -> SavedState {
850        let round_info = SignRoundInfo {
851            public_nonces: self.public_nonces.clone(),
852            nonce_recv_key_ids: Default::default(),
853            sign_recv_key_ids: Default::default(),
854            sign_wait_signer_ids: Default::default(),
855        };
856        let mut message_nonces = BTreeMap::new();
857
858        message_nonces.insert(Vec::new(), round_info);
859
860        SavedState {
861            config: self.config.clone(),
862            current_dkg_id: self.current_dkg_id,
863            current_sign_id: self.current_sign_id,
864            current_sign_iter_id: self.current_sign_iter_id,
865            dkg_public_shares: self.dkg_public_shares.clone(),
866            dkg_private_shares: self.dkg_private_shares.clone(),
867            dkg_end_messages: self.dkg_end_messages.clone(),
868            party_polynomials: self.party_polynomials.clone(),
869            message_nonces,
870            signature_shares: self.signature_shares.clone(),
871            aggregate_public_key: self.aggregate_public_key,
872            signature: self.signature.clone(),
873            schnorr_proof: self.schnorr_proof.clone(),
874            message: self.message.clone(),
875            dkg_wait_signer_ids: self.ids_to_await.clone(),
876            state: self.state.clone(),
877            dkg_public_start: Default::default(),
878            dkg_private_start: Default::default(),
879            dkg_end_start: Default::default(),
880            nonce_start: Default::default(),
881            sign_start: Default::default(),
882            malicious_signer_ids: Default::default(),
883            malicious_dkg_signer_ids: Default::default(),
884            coordinator_public_key: self.coordinator_public_key,
885        }
886    }
887
888    /// Retrieve the config
889    fn get_config(&self) -> Config {
890        self.config.clone()
891    }
892
893    #[cfg(any(test, feature = "testing"))]
894    fn get_config_mut(&mut self) -> &mut Config {
895        &mut self.config
896    }
897
898    fn set_coordinator_public_key(&mut self, key: Option<ecdsa::PublicKey>) {
899        self.coordinator_public_key = key;
900    }
901
902    /// Set the aggregate key and polynomial commitments used to form that key.
903    ///  Check if the polynomial commitments match the key
904    fn set_key_and_party_polynomials(
905        &mut self,
906        aggregate_key: Point,
907        party_polynomials: Vec<(u32, PolyCommitment)>,
908    ) -> Result<(), Error> {
909        let computed_key = party_polynomials
910            .iter()
911            .fold(Point::default(), |s, (_, comm)| s + comm.poly[0]);
912        if computed_key != aggregate_key {
913            return Err(Error::AggregateKeyPolynomialMismatch(
914                computed_key,
915                aggregate_key,
916            ));
917        }
918        let party_polynomials_len = party_polynomials.len();
919        let party_polynomials = HashMap::from_iter(party_polynomials);
920        if party_polynomials.len() != party_polynomials_len {
921            return Err(Error::DuplicatePartyId);
922        }
923        self.aggregate_public_key = Some(aggregate_key);
924        self.party_polynomials = party_polynomials;
925        Ok(())
926    }
927
928    /// Process the message inside the passed packet
929    fn process(
930        &mut self,
931        packet: &Packet,
932    ) -> Result<(Option<Packet>, Option<OperationResult>), Error> {
933        self.process_message(packet)
934    }
935
936    /// Retrieve the aggregate public key
937    fn get_aggregate_public_key(&self) -> Option<Point> {
938        self.aggregate_public_key
939    }
940
941    /// Set the aggregate public key
942    fn set_aggregate_public_key(&mut self, aggregate_public_key: Option<Point>) {
943        self.aggregate_public_key = aggregate_public_key;
944    }
945
946    /// Retrieve the current message bytes being signed
947    fn get_message(&self) -> Vec<u8> {
948        self.message.clone()
949    }
950
951    /// Retrive the current state
952    fn get_state(&self) -> State {
953        self.state.clone()
954    }
955
956    /// Start a DKG round
957    fn start_dkg_round(&mut self, dkg_id: Option<u64>) -> Result<Packet, Error> {
958        if let Some(id) = dkg_id {
959            self.current_dkg_id = id;
960        } else {
961            self.current_dkg_id = self.current_dkg_id.wrapping_add(1);
962        }
963        info!("Starting DKG round {}", self.current_dkg_id);
964        self.move_to(State::DkgPublicDistribute)?;
965        self.start_public_shares()
966    }
967
968    /// Start a signing round
969    fn start_signing_round(
970        &mut self,
971        message: &[u8],
972        signature_type: SignatureType,
973        sign_id: Option<u64>,
974    ) -> Result<Packet, Error> {
975        // We cannot sign if we haven't first set DKG (either manually or via DKG round).
976        if self.aggregate_public_key.is_none() {
977            return Err(Error::MissingAggregatePublicKey);
978        }
979        self.message = message.to_vec();
980        if let Some(id) = sign_id {
981            self.current_sign_id = id;
982        } else {
983            self.current_sign_id = self.current_sign_id.wrapping_add(1);
984        }
985        info!("Starting signing round {}", self.current_sign_id);
986        self.move_to(State::NonceRequest(signature_type))?;
987        self.request_nonces(signature_type)
988    }
989
990    // Reset internal state
991    fn reset(&mut self) {
992        self.state = State::Idle;
993        self.dkg_public_shares.clear();
994        self.party_polynomials.clear();
995        self.public_nonces.clear();
996        self.signature_shares.clear();
997        self.ids_to_await = (0..self.config.num_signers).collect();
998    }
999}
1000
1001#[cfg(test)]
1002/// Test module for coordinator functionality
1003pub mod test {
1004    use super::*;
1005    #[cfg(feature = "with_v1")]
1006    use crate::v1;
1007    use crate::{
1008        curve::scalar::Scalar,
1009        net::{DkgBegin, Message, NonceRequest, Packet, SignatureShareResponse, SignatureType},
1010        schnorr::{self, ID},
1011        state_machine::coordinator::{
1012            frost::Coordinator as FrostCoordinator,
1013            test::{
1014                bad_signature_share_request, check_signature_shares, coordinator_state_machine,
1015                empty_private_shares, empty_public_shares, equal_after_save_load, invalid_nonce,
1016                new_coordinator, run_dkg_sign, setup, start_dkg_round, start_signing_round,
1017                verify_packet_sigs,
1018            },
1019            Config, Coordinator as CoordinatorTrait, State,
1020        },
1021        traits::{Aggregator as AggregatorTrait, Signer as SignerTrait},
1022        util::create_rng,
1023        v2,
1024    };
1025
1026    #[test]
1027    #[cfg(feature = "with_v1")]
1028    fn new_coordinator_v1() {
1029        new_coordinator::<FrostCoordinator<v1::Aggregator>>();
1030    }
1031
1032    #[test]
1033    fn new_coordinator_v2() {
1034        new_coordinator::<FrostCoordinator<v2::Aggregator>>();
1035    }
1036
1037    #[test]
1038    #[cfg(feature = "with_v1")]
1039    fn equal_after_save_load_v1() {
1040        equal_after_save_load::<FrostCoordinator<v1::Aggregator>, v1::Signer>(2, 2);
1041    }
1042
1043    #[test]
1044    fn equal_after_save_load_v2() {
1045        equal_after_save_load::<FrostCoordinator<v2::Aggregator>, v2::Signer>(2, 2);
1046    }
1047
1048    #[test]
1049    #[cfg(feature = "with_v1")]
1050    fn coordinator_state_machine_v1() {
1051        coordinator_state_machine::<FrostCoordinator<v1::Aggregator>>();
1052    }
1053
1054    #[test]
1055    fn coordinator_state_machine_v2() {
1056        coordinator_state_machine::<FrostCoordinator<v2::Aggregator>>();
1057    }
1058
1059    #[test]
1060    #[cfg(feature = "with_v1")]
1061    fn start_dkg_round_v1() {
1062        start_dkg_round::<FrostCoordinator<v1::Aggregator>>(None);
1063        start_dkg_round::<FrostCoordinator<v1::Aggregator>>(Some(12345u64));
1064    }
1065
1066    #[test]
1067    fn start_dkg_round_v2() {
1068        start_dkg_round::<FrostCoordinator<v2::Aggregator>>(None);
1069        start_dkg_round::<FrostCoordinator<v2::Aggregator>>(Some(12345u64));
1070    }
1071
1072    #[test]
1073    #[cfg(feature = "with_v1")]
1074    fn start_signing_round_v1() {
1075        start_signing_round::<FrostCoordinator<v1::Aggregator>>(None);
1076        start_signing_round::<FrostCoordinator<v1::Aggregator>>(Some(12345u64));
1077    }
1078
1079    #[test]
1080    fn start_signing_round_v2() {
1081        start_signing_round::<FrostCoordinator<v2::Aggregator>>(None);
1082        start_signing_round::<FrostCoordinator<v2::Aggregator>>(Some(12345u64));
1083    }
1084
1085    #[test]
1086    #[cfg(feature = "with_v1")]
1087    fn start_public_shares_v1() {
1088        start_public_shares::<v1::Aggregator>();
1089    }
1090
1091    #[test]
1092    fn start_public_shares_v2() {
1093        start_public_shares::<v2::Aggregator>();
1094    }
1095
1096    fn start_public_shares<Aggregator: AggregatorTrait>() {
1097        let mut rng = create_rng();
1098        let config = Config::new(10, 40, 28, Scalar::random(&mut rng));
1099        let mut coordinator = FrostCoordinator::<Aggregator>::new(config);
1100
1101        coordinator.state = State::DkgPublicDistribute; // Must be in this state before calling start public shares
1102
1103        let result = coordinator.start_public_shares().unwrap();
1104
1105        assert!(matches!(result.msg, Message::DkgBegin(_)));
1106        assert_eq!(coordinator.get_state(), State::DkgPublicGather);
1107        assert_eq!(coordinator.current_dkg_id, 0);
1108    }
1109
1110    #[test]
1111    #[cfg(feature = "with_v1")]
1112    fn start_private_shares_v1() {
1113        start_private_shares::<v1::Aggregator>();
1114    }
1115
1116    #[test]
1117    fn start_private_shares_v2() {
1118        start_private_shares::<v2::Aggregator>();
1119    }
1120
1121    fn start_private_shares<Aggregator: AggregatorTrait>() {
1122        let mut rng = create_rng();
1123        let config = Config::new(10, 40, 28, Scalar::random(&mut rng));
1124        let mut coordinator = FrostCoordinator::<Aggregator>::new(config);
1125
1126        coordinator.state = State::DkgPrivateDistribute; // Must be in this state before calling start private shares
1127
1128        let message = coordinator.start_private_shares().unwrap();
1129        assert!(matches!(message.msg, Message::DkgPrivateBegin(_)));
1130        assert_eq!(coordinator.get_state(), State::DkgPrivateGather);
1131        assert_eq!(coordinator.current_dkg_id, 0);
1132    }
1133
1134    #[test]
1135    #[cfg(feature = "with_v1")]
1136    fn dkg_public_share_v1() {
1137        dkg_public_share::<v1::Aggregator, v1::Signer>();
1138    }
1139
1140    #[test]
1141    #[cfg(feature = "with_v1")]
1142    fn dkg_public_share_v2() {
1143        dkg_public_share::<v1::Aggregator, v2::Signer>();
1144    }
1145
1146    /// test basic insertion and detection of duplicates for DkgPublicShares
1147    #[allow(dead_code)]
1148    fn dkg_public_share<Aggregator: AggregatorTrait, Signer: SignerTrait>() {
1149        let ctx = 0u64.to_be_bytes();
1150        let mut rng = create_rng();
1151        let (coordinators, _) = setup::<FrostCoordinator<Aggregator>, Signer>(2, 1);
1152        let mut coordinator: FrostCoordinator<Aggregator> = coordinators[0].clone();
1153
1154        coordinator.start_dkg_round(None).unwrap(); // = State::DkgPublicGather;
1155        let public_shares = DkgPublicShares {
1156            dkg_id: 1,
1157            signer_id: 0,
1158            comms: vec![(
1159                0,
1160                PolyCommitment {
1161                    id: ID::new(&Scalar::new(), &Scalar::new(), &ctx, &mut rng),
1162                    poly: vec![],
1163                },
1164            )],
1165            kex_public_key: Point::from(Scalar::random(&mut rng)),
1166            kex_proof: schnorr::Proof {
1167                R: Point::new(),
1168                s: Scalar::new(),
1169            },
1170        };
1171        let packet = Packet {
1172            msg: Message::DkgPublicShares(public_shares.clone()),
1173            sig: Default::default(),
1174        };
1175        coordinator.gather_public_shares(&packet).unwrap();
1176        assert_eq!(1, coordinator.dkg_public_shares.len());
1177
1178        // check that a duplicate public share is ignored
1179        let dup_public_shares = DkgPublicShares {
1180            dkg_id: 1,
1181            signer_id: 0,
1182            comms: vec![(
1183                0,
1184                PolyCommitment {
1185                    id: ID::new(&Scalar::new(), &Scalar::new(), &ctx, &mut rng),
1186                    poly: vec![],
1187                },
1188            )],
1189            kex_public_key: Point::from(Scalar::random(&mut rng)),
1190            kex_proof: schnorr::Proof {
1191                R: Point::new(),
1192                s: Scalar::new(),
1193            },
1194        };
1195        let dup_packet = Packet {
1196            msg: Message::DkgPublicShares(dup_public_shares.clone()),
1197            sig: Default::default(),
1198        };
1199
1200        coordinator.gather_public_shares(&dup_packet).unwrap();
1201        assert_eq!(1, coordinator.dkg_public_shares.len());
1202        assert_eq!(
1203            public_shares,
1204            coordinator
1205                .dkg_public_shares
1206                .iter()
1207                .next()
1208                .unwrap()
1209                .1
1210                .clone()
1211        );
1212    }
1213
1214    #[test]
1215    #[cfg(feature = "with_v1")]
1216    fn dkg_private_share_v1() {
1217        dkg_private_share::<v1::Aggregator, v1::Signer>();
1218    }
1219
1220    #[test]
1221    fn dkg_private_share_v2() {
1222        dkg_private_share::<v2::Aggregator, v2::Signer>();
1223    }
1224
1225    /// test basic insertion and detection of duplicates for DkgPrivateShares
1226    fn dkg_private_share<Aggregator: AggregatorTrait, Signer: SignerTrait>() {
1227        let (coordinators, _) = setup::<FrostCoordinator<Aggregator>, Signer>(2, 1);
1228        let mut coordinator: FrostCoordinator<Aggregator> = coordinators[0].clone();
1229
1230        coordinator.state = State::DkgPrivateGather;
1231
1232        let private_share = DkgPrivateShares {
1233            dkg_id: 0,
1234            signer_id: 0,
1235            shares: vec![(1, HashMap::new())],
1236        };
1237        let packet = Packet {
1238            msg: Message::DkgPrivateShares(private_share.clone()),
1239            sig: Default::default(),
1240        };
1241        coordinator.gather_private_shares(&packet).unwrap();
1242        assert_eq!(1, coordinator.dkg_private_shares.len());
1243
1244        // check that a duplicate private share is ignored
1245        let dup_private_share = DkgPrivateShares {
1246            dkg_id: 0,
1247            signer_id: 0,
1248            shares: vec![(1, HashMap::new())],
1249        };
1250        let packet = Packet {
1251            msg: Message::DkgPrivateShares(dup_private_share.clone()),
1252            sig: Default::default(),
1253        };
1254        coordinator.gather_private_shares(&packet).unwrap();
1255        assert_eq!(1, coordinator.dkg_private_shares.len());
1256        assert_eq!(
1257            private_share,
1258            coordinator
1259                .dkg_private_shares
1260                .iter()
1261                .next()
1262                .unwrap()
1263                .1
1264                .clone()
1265        );
1266    }
1267
1268    #[test]
1269    #[cfg(feature = "with_v1")]
1270    fn nonce_response_v1() {
1271        nonce_response::<v1::Aggregator, v1::Signer>();
1272    }
1273
1274    #[test]
1275    fn nonce_response_v2() {
1276        nonce_response::<v2::Aggregator, v2::Signer>();
1277    }
1278
1279    /// test basic insertion and detection of duplicates for NonceResponse
1280    fn nonce_response<Aggregator: AggregatorTrait, Signer: SignerTrait>() {
1281        let mut rng = create_rng();
1282        let (coordinators, _) = setup::<FrostCoordinator<Aggregator>, Signer>(2, 1);
1283        let mut coordinator: FrostCoordinator<Aggregator> = coordinators[0].clone();
1284        let signature_type = SignatureType::Frost;
1285        let message = vec![0u8];
1286        coordinator.state = State::NonceGather(signature_type);
1287
1288        let nonce_response = NonceResponse {
1289            dkg_id: 0,
1290            sign_id: 0,
1291            sign_iter_id: 0,
1292            signer_id: 0,
1293            key_ids: vec![1u32],
1294            nonces: vec![PublicNonce {
1295                D: Point::from(Scalar::random(&mut rng)),
1296                E: Point::from(Scalar::random(&mut rng)),
1297            }],
1298            message: message.clone(),
1299        };
1300        let packet = Packet {
1301            msg: Message::NonceResponse(nonce_response.clone()),
1302            sig: Default::default(),
1303        };
1304        coordinator.gather_nonces(&packet, signature_type).unwrap();
1305        assert_eq!(1, coordinator.public_nonces.len());
1306
1307        // check that a duplicate private share is ignored
1308        let dup_nonce_response = NonceResponse {
1309            dkg_id: 0,
1310            sign_id: 0,
1311            sign_iter_id: 0,
1312            signer_id: 0,
1313            key_ids: vec![1u32],
1314            nonces: vec![PublicNonce {
1315                D: Point::from(Scalar::random(&mut rng)),
1316                E: Point::from(Scalar::random(&mut rng)),
1317            }],
1318            message: message.clone(),
1319        };
1320        let packet = Packet {
1321            msg: Message::NonceResponse(dup_nonce_response.clone()),
1322            sig: Default::default(),
1323        };
1324        coordinator.gather_nonces(&packet, signature_type).unwrap();
1325        assert_eq!(1, coordinator.public_nonces.len());
1326        assert_eq!(
1327            nonce_response,
1328            coordinator.public_nonces.iter().next().unwrap().1.clone()
1329        );
1330    }
1331
1332    #[test]
1333    #[cfg(feature = "with_v1")]
1334    fn sig_share_v1() {
1335        sig_share::<v1::Aggregator, v1::Signer>();
1336    }
1337
1338    #[test]
1339    #[cfg(feature = "with_v1")]
1340    fn sig_share_v2() {
1341        sig_share::<v2::Aggregator, v1::Signer>();
1342    }
1343
1344    /// test basic insertion and detection of duplicates for SignatureShareResponse
1345    #[allow(dead_code)]
1346    fn sig_share<Aggregator: AggregatorTrait, Signer: SignerTrait>() {
1347        let mut rng = create_rng();
1348        let (coordinators, _) = setup::<FrostCoordinator<Aggregator>, Signer>(2, 1);
1349        let mut coordinator = coordinators[0].clone();
1350        let signature_type = SignatureType::Frost;
1351
1352        coordinator.ids_to_await = (0..coordinator.config.num_signers).collect();
1353        coordinator.state = State::SigShareGather(signature_type);
1354
1355        let signature_share = SignatureShare {
1356            id: 1,
1357            z_i: Scalar::random(&mut rng),
1358            key_ids: vec![1],
1359        };
1360        let sig_share_response = SignatureShareResponse {
1361            dkg_id: 0,
1362            sign_id: 0,
1363            sign_iter_id: 0,
1364            signer_id: 0,
1365            signature_shares: vec![signature_share.clone()],
1366        };
1367        let packet = Packet {
1368            msg: Message::SignatureShareResponse(sig_share_response.clone()),
1369            sig: Default::default(),
1370        };
1371        coordinator
1372            .gather_sig_shares(&packet, signature_type)
1373            .unwrap();
1374        assert_eq!(1, coordinator.signature_shares.len());
1375
1376        // check that a duplicate private share is ignored
1377        let dup_signature_share = SignatureShare {
1378            id: 1,
1379            z_i: Scalar::random(&mut rng),
1380            key_ids: vec![1],
1381        };
1382        let dup_sig_share_response = SignatureShareResponse {
1383            dkg_id: 0,
1384            sign_id: 0,
1385            sign_iter_id: 0,
1386            signer_id: 0,
1387            signature_shares: vec![dup_signature_share.clone()],
1388        };
1389        let packet = Packet {
1390            msg: Message::SignatureShareResponse(dup_sig_share_response.clone()),
1391            sig: Default::default(),
1392        };
1393        coordinator
1394            .gather_sig_shares(&packet, signature_type)
1395            .unwrap();
1396        assert_eq!(1, coordinator.signature_shares.len());
1397        assert_eq!(
1398            vec![signature_share],
1399            coordinator
1400                .signature_shares
1401                .iter()
1402                .next()
1403                .unwrap()
1404                .1
1405                .clone()
1406        );
1407    }
1408
1409    #[test]
1410    #[cfg(feature = "with_v1")]
1411    fn run_dkg_sign_v1() {
1412        run_dkg_sign::<FrostCoordinator<v1::Aggregator>, v1::Signer>(5, 2);
1413    }
1414
1415    #[test]
1416    fn run_dkg_sign_v2() {
1417        run_dkg_sign::<FrostCoordinator<v2::Aggregator>, v2::Signer>(5, 2);
1418    }
1419
1420    #[test]
1421    #[cfg(feature = "with_v1")]
1422    fn check_signature_shares_v1() {
1423        check_signature_shares::<FrostCoordinator<v1::Aggregator>, v1::Signer>(
1424            5,
1425            1,
1426            SignatureType::Frost,
1427            vec![1],
1428        );
1429        check_signature_shares::<FrostCoordinator<v1::Aggregator>, v1::Signer>(
1430            5,
1431            1,
1432            SignatureType::Schnorr,
1433            vec![1],
1434        );
1435        check_signature_shares::<FrostCoordinator<v1::Aggregator>, v1::Signer>(
1436            5,
1437            1,
1438            SignatureType::Taproot(None),
1439            vec![1],
1440        );
1441        check_signature_shares::<FrostCoordinator<v1::Aggregator>, v1::Signer>(
1442            5,
1443            1,
1444            SignatureType::Taproot(Some([23u8; 32])),
1445            vec![1],
1446        );
1447    }
1448
1449    #[test]
1450    fn check_signature_shares_v2() {
1451        check_signature_shares::<FrostCoordinator<v2::Aggregator>, v2::Signer>(
1452            5,
1453            2,
1454            SignatureType::Frost,
1455            vec![0],
1456        );
1457        check_signature_shares::<FrostCoordinator<v2::Aggregator>, v2::Signer>(
1458            5,
1459            2,
1460            SignatureType::Schnorr,
1461            vec![0],
1462        );
1463        check_signature_shares::<FrostCoordinator<v2::Aggregator>, v2::Signer>(
1464            5,
1465            2,
1466            SignatureType::Taproot(None),
1467            vec![0],
1468        );
1469        check_signature_shares::<FrostCoordinator<v2::Aggregator>, v2::Signer>(
1470            5,
1471            2,
1472            SignatureType::Taproot(Some([23u8; 32])),
1473            vec![0],
1474        );
1475    }
1476
1477    #[test]
1478    #[cfg(feature = "with_v1")]
1479    fn bad_signature_share_request_v1() {
1480        bad_signature_share_request::<FrostCoordinator<v1::Aggregator>, v1::Signer>(5, 2);
1481    }
1482
1483    #[test]
1484    fn bad_signature_share_request_v2() {
1485        bad_signature_share_request::<FrostCoordinator<v2::Aggregator>, v2::Signer>(5, 2);
1486    }
1487
1488    #[test]
1489    #[cfg(feature = "with_v1")]
1490    fn invalid_nonce_v1() {
1491        invalid_nonce::<FrostCoordinator<v1::Aggregator>, v1::Signer>(5, 2);
1492    }
1493
1494    #[test]
1495    fn invalid_nonce_v2() {
1496        invalid_nonce::<FrostCoordinator<v2::Aggregator>, v2::Signer>(5, 2);
1497    }
1498
1499    #[test]
1500    fn process_inbound_messages_v2() {
1501        run_dkg_sign::<FrostCoordinator<v2::Aggregator>, v2::Signer>(5, 2);
1502    }
1503
1504    #[test]
1505    #[cfg(feature = "with_v1")]
1506    fn old_round_ids_are_ignored_v1() {
1507        old_round_ids_are_ignored::<v1::Aggregator>();
1508    }
1509
1510    #[test]
1511    fn old_round_ids_are_ignored_v2() {
1512        old_round_ids_are_ignored::<v2::Aggregator>();
1513    }
1514
1515    fn old_round_ids_are_ignored<Aggregator: AggregatorTrait>() {
1516        let mut rng = create_rng();
1517        let mut config = Config::new(10, 40, 28, Scalar::random(&mut rng));
1518        config.verify_packet_sigs = false;
1519        let mut coordinator = FrostCoordinator::<Aggregator>::new(config);
1520        let id: u64 = 10;
1521        let old_id = id;
1522        coordinator.current_dkg_id = id;
1523        coordinator.current_sign_id = id;
1524        // Attempt to start an old DKG round
1525        let (packet, result) = coordinator
1526            .process(&Packet {
1527                sig: vec![],
1528                msg: Message::DkgBegin(DkgBegin { dkg_id: old_id }),
1529            })
1530            .unwrap();
1531        assert!(packet.is_none());
1532        assert!(result.is_none());
1533        assert_eq!(coordinator.state, State::Idle);
1534        assert_eq!(coordinator.current_dkg_id, id);
1535
1536        // Attempt to start the same DKG round
1537        let (packet, result) = coordinator
1538            .process(&Packet {
1539                sig: vec![],
1540                msg: Message::DkgBegin(DkgBegin { dkg_id: id }),
1541            })
1542            .unwrap();
1543        assert!(packet.is_none());
1544        assert!(result.is_none());
1545        assert_eq!(coordinator.state, State::Idle);
1546        assert_eq!(coordinator.current_dkg_id, id);
1547
1548        // Attempt to start an old Sign round
1549        let (packet, result) = coordinator
1550            .process(&Packet {
1551                sig: vec![],
1552                msg: Message::NonceRequest(NonceRequest {
1553                    dkg_id: id,
1554                    sign_id: old_id,
1555                    message: vec![],
1556                    sign_iter_id: id,
1557                    signature_type: SignatureType::Frost,
1558                }),
1559            })
1560            .unwrap();
1561        assert!(packet.is_none());
1562        assert!(result.is_none());
1563        assert_eq!(coordinator.state, State::Idle);
1564        assert_eq!(coordinator.current_sign_id, id);
1565
1566        // Attempt to start the same Sign round
1567        let (packet, result) = coordinator
1568            .process(&Packet {
1569                sig: vec![],
1570                msg: Message::NonceRequest(NonceRequest {
1571                    dkg_id: id,
1572                    sign_id: id,
1573                    message: vec![],
1574                    sign_iter_id: id,
1575                    signature_type: SignatureType::Frost,
1576                }),
1577            })
1578            .unwrap();
1579        assert!(packet.is_none());
1580        assert!(result.is_none());
1581        assert_eq!(coordinator.state, State::Idle);
1582        assert_eq!(coordinator.current_sign_id, id);
1583    }
1584
1585    #[test]
1586    #[cfg(feature = "with_v1")]
1587    fn empty_public_shares_v1() {
1588        empty_public_shares::<FrostCoordinator<v1::Aggregator>, v1::Signer>(5, 2);
1589    }
1590
1591    #[test]
1592    fn empty_public_shares_v2() {
1593        empty_public_shares::<FrostCoordinator<v2::Aggregator>, v2::Signer>(5, 2);
1594    }
1595
1596    #[test]
1597    #[cfg(feature = "with_v1")]
1598    fn empty_private_shares_v1() {
1599        empty_private_shares::<FrostCoordinator<v1::Aggregator>, v1::Signer>(5, 2);
1600    }
1601
1602    #[test]
1603    fn empty_private_shares_v2() {
1604        empty_private_shares::<FrostCoordinator<v2::Aggregator>, v2::Signer>(5, 2);
1605    }
1606
1607    #[test]
1608    #[cfg(feature = "with_v1")]
1609    fn verify_packet_sigs_v1() {
1610        verify_packet_sigs::<FrostCoordinator<v1::Aggregator>, v1::Signer>();
1611    }
1612
1613    #[test]
1614    fn verify_packet_sigs_v2() {
1615        verify_packet_sigs::<FrostCoordinator<v2::Aggregator>, v2::Signer>();
1616    }
1617}