Skip to main content

miden_protocol/block/
validator_keys.rs

1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use crate::crypto::dsa::ecdsa_k256_keccak::PublicKey;
5use crate::utils::serde::{
6    ByteReader,
7    ByteWriter,
8    Deserializable,
9    DeserializationError,
10    Serializable,
11};
12use crate::{Felt, Hasher, WORD_SIZE, Word};
13
14// VALIDATOR KEYS ERROR
15// ================================================================================================
16
17/// Error returned when constructing an invalid [`ValidatorKeys`] set.
18#[derive(Debug, thiserror::Error)]
19#[non_exhaustive]
20pub enum ValidatorKeysError {
21    #[error("validator set must contain at least one key")]
22    EmptySet,
23    #[error(
24        "validator set contains {count} keys but must contain at most {max}",
25        max = ValidatorKeys::MAX,
26    )]
27    TooManyKeys { count: usize },
28    #[error("validator set contains duplicate public keys")]
29    DuplicateKey,
30}
31
32// VALIDATOR KEYS
33// ================================================================================================
34
35/// The ordered set of validator public keys authorized to sign a block.
36///
37/// A block header commits to the [`ValidatorKeys`] authorized to sign the *next* block. A block's
38/// signatures are verified positionally against the validator set committed to by its parent: the
39/// signature in slot `i` is checked against the key at index `i` in this set.
40///
41/// The number of validators is not fixed by the protocol: a chain may run with a single validator
42/// and grow its validator set over time by rotating in a larger [`ValidatorKeys`] set (see
43/// [`ProposedBlock::with_next_validator_keys`](crate::block::ProposedBlock::with_next_validator_keys)),
44/// up to [`ValidatorKeys::MAX`] keys. The set holds at least one key, kept in a canonical order
45/// (sorted by their serialized bytes) so that the [`ValidatorKeys::commitment`] is independent of
46/// the order in which the keys were provided.
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct ValidatorKeys {
49    /// Distinct validator public keys, sorted by their serialized bytes.
50    keys: Vec<PublicKey>,
51}
52
53impl ValidatorKeys {
54    // CONSTANTS
55    // --------------------------------------------------------------------------------------------
56
57    /// The maximum number of validator keys in a set.
58    pub const MAX: usize = 5;
59
60    // CONSTRUCTORS
61    // --------------------------------------------------------------------------------------------
62
63    /// Returns a new [`ValidatorKeys`] from the provided public keys.
64    ///
65    /// The keys are sorted into a canonical order by their serialized bytes.
66    ///
67    /// # Errors
68    ///
69    /// Returns an error if:
70    /// - `keys` is empty;
71    /// - `keys` contains more than [`ValidatorKeys::MAX`] keys;
72    /// - the set contains duplicate keys.
73    pub fn new(mut keys: Vec<PublicKey>) -> Result<Self, ValidatorKeysError> {
74        if keys.is_empty() {
75            return Err(ValidatorKeysError::EmptySet);
76        }
77        if keys.len() > Self::MAX {
78            return Err(ValidatorKeysError::TooManyKeys { count: keys.len() });
79        }
80
81        // Sort into a canonical order so the commitment is independent of input order.
82        keys.sort_by_key(|key| key.to_bytes());
83
84        // After sorting, duplicates are adjacent.
85        if keys.windows(2).any(|pair| pair[0] == pair[1]) {
86            return Err(ValidatorKeysError::DuplicateKey);
87        }
88
89        Ok(Self { keys })
90    }
91
92    // PUBLIC ACCESSORS
93    // --------------------------------------------------------------------------------------------
94
95    /// Returns the validator public keys in canonical order.
96    pub fn as_keys(&self) -> &[PublicKey] {
97        &self.keys
98    }
99
100    /// Returns the number of validator keys in the set.
101    pub fn len(&self) -> usize {
102        self.keys.len()
103    }
104
105    /// Returns `false`, as a validator set always contains at least one key.
106    pub fn is_empty(&self) -> bool {
107        false
108    }
109
110    /// Returns a commitment to the validator set.
111    ///
112    /// The commitment is a sequential hash of the per-key commitments in canonical order, and is
113    /// committed to by the [`BlockHeader`](crate::block::BlockHeader) as a single word. Since the
114    /// hash covers every key, the commitment also implicitly binds the number of validators.
115    pub fn commitment(&self) -> Word {
116        let mut elements: Vec<Felt> = Vec::with_capacity(self.keys.len() * WORD_SIZE);
117        for key in &self.keys {
118            elements.extend_from_slice(key.to_commitment().as_elements());
119        }
120        Hasher::hash_elements(&elements)
121    }
122}
123
124// SERIALIZATION
125// ================================================================================================
126
127impl Serializable for ValidatorKeys {
128    fn write_into<W: ByteWriter>(&self, target: &mut W) {
129        self.keys.write_into(target);
130    }
131}
132
133impl Deserializable for ValidatorKeys {
134    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
135        let keys = Vec::<PublicKey>::read_from(source)?;
136        Self::new(keys).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
137    }
138}
139
140// TESTS
141// ================================================================================================
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146    use crate::testing::random_secret_key::random_secret_key;
147
148    fn random_keys(count: usize) -> Vec<PublicKey> {
149        (0..count).map(|_| random_secret_key().public_key()).collect()
150    }
151
152    #[test]
153    fn new_rejects_empty_set() {
154        let result = ValidatorKeys::new(Vec::new());
155        assert!(matches!(result, Err(ValidatorKeysError::EmptySet)));
156    }
157
158    #[test]
159    fn new_accepts_single_validator() {
160        let keys = ValidatorKeys::new(random_keys(1)).unwrap();
161        assert_eq!(keys.len(), 1);
162    }
163
164    #[test]
165    fn new_accepts_max_validators() {
166        let keys = ValidatorKeys::new(random_keys(ValidatorKeys::MAX)).unwrap();
167        assert_eq!(keys.len(), ValidatorKeys::MAX);
168    }
169
170    #[test]
171    fn new_rejects_too_many_keys() {
172        let result = ValidatorKeys::new(random_keys(ValidatorKeys::MAX + 1));
173        assert!(matches!(
174            result,
175            Err(ValidatorKeysError::TooManyKeys { count }) if count == ValidatorKeys::MAX + 1
176        ));
177    }
178
179    #[test]
180    fn new_rejects_duplicate_keys() {
181        let mut keys = random_keys(3);
182        keys[1] = keys[0].clone();
183        let result = ValidatorKeys::new(keys);
184        assert!(matches!(result, Err(ValidatorKeysError::DuplicateKey)));
185    }
186
187    #[test]
188    fn new_sorts_into_canonical_order() {
189        let keys = random_keys(5);
190        let forward = ValidatorKeys::new(keys.clone()).unwrap();
191
192        let mut reversed = keys;
193        reversed.reverse();
194        let backward = ValidatorKeys::new(reversed).unwrap();
195
196        // The canonical order makes the set and its commitment independent of input order.
197        assert_eq!(forward.as_keys(), backward.as_keys());
198        assert_eq!(forward.commitment(), backward.commitment());
199    }
200
201    #[test]
202    fn serde_round_trip() {
203        let validator_keys = ValidatorKeys::new(random_keys(4)).unwrap();
204        let bytes = validator_keys.to_bytes();
205        let deserialized = ValidatorKeys::read_from_bytes(&bytes).unwrap();
206        assert_eq!(validator_keys, deserialized);
207    }
208}