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::ValidatorKeys;
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 = ValidatorKeys::MAX,
41 )]
42 TooManySignatures { count: usize },
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct BlockSignatures {
60 signatures: Vec<Signature>,
62}
63
64impl BlockSignatures {
65 pub fn new(signatures: Vec<Signature>) -> Result<Self, BlockSignaturesError> {
75 if signatures.len() > ValidatorKeys::MAX {
76 return Err(BlockSignaturesError::TooManySignatures { count: signatures.len() });
77 }
78 Ok(Self { signatures })
79 }
80
81 pub fn as_signatures(&self) -> &[Signature] {
86 &self.signatures
87 }
88
89 pub fn len(&self) -> usize {
91 self.signatures.len()
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.signatures.is_empty()
97 }
98
99 pub fn verify_against(
114 &self,
115 block_commitment: Word,
116 validator_keys: &ValidatorKeys,
117 ) -> Result<(), SignatureVerificationError> {
118 if self.signatures.len() != validator_keys.len() {
119 return Err(SignatureVerificationError::SignatureCountMismatch {
120 expected: validator_keys.len(),
121 actual: self.signatures.len(),
122 });
123 }
124
125 for (position, (signature, validator_key)) in
126 self.signatures.iter().zip(validator_keys.as_keys()).enumerate()
127 {
128 if !signature.verify(block_commitment, validator_key) {
129 return Err(SignatureVerificationError::InvalidSignatureAtPosition { position });
130 }
131 }
132
133 Ok(())
134 }
135}
136
137impl Serializable for BlockSignatures {
141 fn write_into<W: ByteWriter>(&self, target: &mut W) {
142 self.signatures.write_into(target);
143 }
144}
145
146impl Deserializable for BlockSignatures {
147 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
148 let signatures = Vec::<Signature>::read_from(source)?;
149 Ok(Self { signatures })
150 }
151}
152
153#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::testing::random_secret_key::random_secret_key;
160 use crate::testing::validator_keys::{random_validator_set, sign_all};
161
162 #[test]
163 fn verify_against_accepts_correctly_ordered_signatures() {
164 let (signers, keys) = random_validator_set(5);
165 let commitment = Word::empty();
166
167 let signatures = sign_all(&keys, &signers, commitment);
168
169 assert_eq!(signatures.len(), 5);
170 signatures.verify_against(commitment, &keys).unwrap();
171 }
172
173 #[test]
174 fn verify_against_rejects_invalid_signature() {
175 let (signers, keys) = random_validator_set(3);
176 let commitment = Word::empty();
177 let outsider = random_secret_key();
178
179 let mut signatures = sign_all(&keys, &signers, commitment).as_signatures().to_vec();
181 signatures[1] = outsider.sign(commitment);
182 let signatures = BlockSignatures::new(signatures).unwrap();
183
184 assert!(matches!(
185 signatures.verify_against(commitment, &keys),
186 Err(SignatureVerificationError::InvalidSignatureAtPosition { position: 1 })
187 ));
188 }
189
190 #[test]
191 fn verify_against_rejects_mismatched_keys() {
192 let (signers, keys) = random_validator_set(3);
193 let commitment = Word::empty();
194 let signatures = sign_all(&keys, &signers, commitment);
195
196 let (_, other_keys) = random_validator_set(3);
199 assert!(matches!(
200 signatures.verify_against(commitment, &other_keys),
201 Err(SignatureVerificationError::InvalidSignatureAtPosition { .. })
202 ));
203 }
204
205 #[test]
206 fn verify_against_rejects_count_mismatch() {
207 let (signers, keys) = random_validator_set(3);
208 let commitment = Word::empty();
209 let signatures = sign_all(&keys, &signers, commitment);
210
211 let (_, other_keys) = random_validator_set(4);
213 assert!(matches!(
214 signatures.verify_against(commitment, &other_keys),
215 Err(SignatureVerificationError::SignatureCountMismatch { expected: 4, actual: 3 })
216 ));
217 }
218
219 #[test]
220 fn serde_round_trip() {
221 let (signers, keys) = random_validator_set(3);
222 let commitment = Word::empty();
223 let signatures = sign_all(&keys, &signers, commitment);
224
225 let bytes = signatures.to_bytes();
226 let deserialized = BlockSignatures::read_from_bytes(&bytes).unwrap();
227 assert_eq!(signatures, deserialized);
228 }
229}