miden_protocol/block/
block_signatures.rs1use alloc::vec::Vec;
2
3use miden_crypto::dsa::ecdsa_k256_keccak::Signature;
4
5use crate::Word;
6use crate::block::ValidatorConfig;
7use crate::utils::serde::{
8 ByteReader,
9 ByteWriter,
10 Deserializable,
11 DeserializationError,
12 Serializable,
13};
14
15#[derive(Debug, thiserror::Error)]
21#[non_exhaustive]
22pub enum SignatureVerificationError {
23 #[error("block has {actual} signatures but the validator set has {expected} keys")]
24 SignatureCountMismatch { expected: usize, actual: usize },
25 #[error(
26 "block signature at position {position} does not verify against the validator key at that position"
27 )]
28 InvalidSignatureAtPosition { position: usize },
29}
30
31#[derive(Debug, thiserror::Error)]
36#[non_exhaustive]
37pub enum BlockSignaturesError {
38 #[error(
39 "block signature set contains {count} signatures but must contain at most {max}",
40 max = ValidatorConfig::MAX_VALIDATORS,
41 )]
42 TooManySignatures { count: usize },
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct BlockSignatures {
65 signatures: Vec<Signature>,
67}
68
69impl BlockSignatures {
70 pub fn new(signatures: Vec<Signature>) -> Result<Self, BlockSignaturesError> {
80 if signatures.len() > ValidatorConfig::MAX_VALIDATORS {
81 return Err(BlockSignaturesError::TooManySignatures { count: signatures.len() });
82 }
83 Ok(Self { signatures })
84 }
85
86 pub fn as_signatures(&self) -> &[Signature] {
91 &self.signatures
92 }
93
94 pub fn len(&self) -> usize {
96 self.signatures.len()
97 }
98
99 pub fn is_empty(&self) -> bool {
101 self.signatures.is_empty()
102 }
103
104 pub fn verify_against(
119 &self,
120 block_commitment: Word,
121 validator_config: &ValidatorConfig,
122 ) -> Result<(), SignatureVerificationError> {
123 if self.signatures.len() != validator_config.len() {
124 return Err(SignatureVerificationError::SignatureCountMismatch {
125 expected: validator_config.len(),
126 actual: self.signatures.len(),
127 });
128 }
129
130 for (position, (signature, validator_key)) in
131 self.signatures.iter().zip(validator_config.keys()).enumerate()
132 {
133 if !signature.verify(block_commitment, validator_key) {
134 return Err(SignatureVerificationError::InvalidSignatureAtPosition { position });
135 }
136 }
137
138 Ok(())
139 }
140}
141
142impl Serializable for BlockSignatures {
146 fn write_into<W: ByteWriter>(&self, target: &mut W) {
147 self.signatures.write_into(target);
148 }
149}
150
151impl Deserializable for BlockSignatures {
152 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
153 let signatures = Vec::<Signature>::read_from(source)?;
154 Ok(Self { signatures })
155 }
156}
157
158#[cfg(test)]
162mod tests {
163 use super::*;
164 use crate::testing::random_secret_key::random_secret_key;
165
166 #[test]
167 fn verify_against_accepts_correctly_ordered_signatures() {
168 let (signers, keys) = ValidatorConfig::random_with_signers(5);
169 let commitment = Word::empty();
170
171 let signatures = keys.sign_all(&signers, commitment);
172
173 assert_eq!(signatures.len(), 5);
174 signatures.verify_against(commitment, &keys).unwrap();
175 }
176
177 #[test]
178 fn verify_against_rejects_invalid_signature() {
179 let (signers, keys) = ValidatorConfig::random_with_signers(3);
180 let commitment = Word::empty();
181 let outsider = random_secret_key();
182
183 let mut signatures = keys.sign_all(&signers, commitment).as_signatures().to_vec();
185 signatures[1] = outsider.sign(commitment);
186 let signatures = BlockSignatures::new(signatures).unwrap();
187
188 assert!(matches!(
189 signatures.verify_against(commitment, &keys),
190 Err(SignatureVerificationError::InvalidSignatureAtPosition { position: 1 })
191 ));
192 }
193
194 #[test]
195 fn verify_against_rejects_mismatched_keys() {
196 let (signers, keys) = ValidatorConfig::random_with_signers(3);
197 let commitment = Word::empty();
198 let signatures = keys.sign_all(&signers, commitment);
199
200 let (_, other_keys) = ValidatorConfig::random_with_signers(3);
203 assert!(matches!(
204 signatures.verify_against(commitment, &other_keys),
205 Err(SignatureVerificationError::InvalidSignatureAtPosition { .. })
206 ));
207 }
208
209 #[test]
210 fn verify_against_rejects_count_mismatch() {
211 let (signers, keys) = ValidatorConfig::random_with_signers(3);
212 let commitment = Word::empty();
213 let signatures = keys.sign_all(&signers, commitment);
214
215 let (_, other_keys) = ValidatorConfig::random_with_signers(4);
217 assert!(matches!(
218 signatures.verify_against(commitment, &other_keys),
219 Err(SignatureVerificationError::SignatureCountMismatch { expected: 4, actual: 3 })
220 ));
221 }
222
223 #[test]
224 fn serde_round_trip() {
225 let (signers, keys) = ValidatorConfig::random_with_signers(3);
226 let commitment = Word::empty();
227 let signatures = keys.sign_all(&signers, commitment);
228
229 let bytes = signatures.to_bytes();
230 let deserialized = BlockSignatures::read_from_bytes(&bytes).unwrap();
231 assert_eq!(signatures, deserialized);
232 }
233}