wsts/state_machine/
mod.rs

1use std::collections::BTreeMap;
2
3use hashbrown::{HashMap, HashSet};
4use thiserror::Error as ThisError;
5
6use crate::{
7    common::{validate_key_id, validate_signer_id, Signature},
8    curve::{ecdsa, point::Point},
9    errors::AggregatorError,
10    net::DkgFailure,
11    state_machine::coordinator::Error as CoordinatorError,
12    state_machine::signer::{ConfigError, Error as SignerError},
13    taproot::SchnorrProof,
14};
15
16/// A generic state machine
17pub trait StateMachine<S, E> {
18    /// Attempt to move the state machine to a new state
19    fn move_to(&mut self, state: S) -> Result<(), E>;
20    /// Check if the state machine can move to a new state
21    fn can_move_to(&self, state: &S) -> Result<(), E>;
22}
23
24/// All possible state machine errors
25#[derive(ThisError, Debug, Clone)]
26#[allow(clippy::large_enum_variant)]
27pub enum Error {
28    /// signer error
29    #[error("signer error {0:?}")]
30    Signer(#[from] SignerError),
31    /// coordinator error
32    #[error("coordinator error {0:?}")]
33    Coordinator(#[from] CoordinatorError),
34}
35
36/// DKG errors
37#[derive(ThisError, Debug, Clone)]
38pub enum DkgError {
39    /// DKG public timeout
40    #[error("DKG public timeout, waiting for {0:?}")]
41    DkgPublicTimeout(Vec<u32>),
42    /// DKG private timeout
43    #[error("DKG private timeout, waiting for {0:?}")]
44    DkgPrivateTimeout(Vec<u32>),
45    /// DKG end timeout
46    #[error("DKG end timeout, waiting for {0:?}")]
47    DkgEndTimeout(Vec<u32>),
48    /// DKG end failure
49    #[error("DKG end failure")]
50    DkgEndFailure {
51        /// failures reported by signers during DkgEnd
52        reported_failures: HashMap<u32, DkgFailure>,
53        /// signers who were discovered to be malicious during this DKG round
54        malicious_signers: HashSet<u32>,
55    },
56}
57
58/// Sign errors
59#[derive(ThisError, Debug, Clone)]
60#[allow(clippy::large_enum_variant)]
61pub enum SignError {
62    /// Nonce timeout
63    #[error("Nonce timeout, valid responses from {0:?}, signers {1:?} are malicious")]
64    NonceTimeout(Vec<u32>, Vec<u32>),
65    /// Insufficient signers
66    #[error("Insufficient signers, {0:?} are malicious")]
67    InsufficientSigners(Vec<u32>),
68    /// Signature aggregator error
69    #[error("Signature aggregator error")]
70    Aggregator(#[from] AggregatorError),
71    /// Coordinator error
72    #[error("Coordinator error")]
73    Coordinator(#[from] CoordinatorError),
74}
75
76/// Result of a DKG or sign operation
77#[derive(Debug, Clone)]
78pub enum OperationResult {
79    /// DKG succeeded with the wrapped public key
80    Dkg(Point),
81    /// Sign succeeded with the wrapped Signature
82    Sign(Signature),
83    /// Sign schnorr succeeded with the wrapped SchnorrProof
84    SignSchnorr(SchnorrProof),
85    /// Sign taproot succeeded with the wrapped SchnorrProof
86    SignTaproot(SchnorrProof),
87    /// DKG error
88    DkgError(DkgError),
89    /// Sign error
90    SignError(SignError),
91}
92
93#[derive(Clone, Default, PartialEq, Eq)]
94/// Map of signer_id and key_id to the relevant ecdsa public keys
95pub struct PublicKeys {
96    /// signer_id -> public key
97    pub signers: HashMap<u32, ecdsa::PublicKey>,
98    /// key_id -> public key
99    pub key_ids: HashMap<u32, ecdsa::PublicKey>,
100    /// map of signer_id to controlled key_ids
101    pub signer_key_ids: HashMap<u32, HashSet<u32>>,
102}
103
104impl PublicKeys {
105    /// Check that all of the signer_ids and key_ids are valid
106    pub fn validate(&self, num_signers: u32, num_keys: u32) -> Result<(), SignerError> {
107        for (signer_id, _key) in &self.signers {
108            if !validate_signer_id(*signer_id, num_signers) {
109                return Err(SignerError::Config(ConfigError::InvalidSignerId(
110                    *signer_id,
111                )));
112            }
113        }
114
115        for (key_id, _key) in &self.key_ids {
116            if !validate_key_id(*key_id, num_keys) {
117                return Err(SignerError::Config(ConfigError::InvalidKeyId(*key_id)));
118            }
119        }
120
121        for (signer_id, key_ids) in &self.signer_key_ids {
122            if !validate_signer_id(*signer_id, num_signers) {
123                return Err(SignerError::Config(ConfigError::InvalidSignerId(
124                    *signer_id,
125                )));
126            }
127
128            for key_id in key_ids {
129                if !validate_key_id(*key_id, num_keys) {
130                    return Err(SignerError::Config(ConfigError::InvalidKeyId(*key_id)));
131                }
132            }
133        }
134
135        Ok(())
136    }
137}
138
139impl std::fmt::Debug for PublicKeys {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        f.debug_struct("PublicKeys")
142            .field("signers", &BTreeMap::from_iter(self.signers.iter()))
143            .field("key_ids", &BTreeMap::from_iter(self.key_ids.iter()))
144            .finish()
145    }
146}
147
148/// State machine for a simple FROST coordinator
149pub mod coordinator;
150
151/// State machine for signers
152pub mod signer;