1use std::collections::HashMap;
2use std::fmt::Display;
3use std::hash::Hash;
4
5use blake2::digest::{Digest, FixedOutput};
6use serde::{Deserialize, Serialize};
7
8use crate::error::StmAggregateSignatureError;
9use crate::merkle_tree::MerkleBatchPath;
10use crate::{AggregateVerificationKey, Parameters};
11
12use super::ConcatenationProof;
13
14#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
16pub enum AggregateSignatureType {
17 #[default]
19 Concatenation,
20 #[cfg(feature = "future_proof_system")]
22 Future,
23}
24
25impl AggregateSignatureType {
26 pub fn get_byte_encoding_prefix(&self) -> u8 {
30 match self {
31 AggregateSignatureType::Concatenation => 0,
32 #[cfg(feature = "future_proof_system")]
33 AggregateSignatureType::Future => 255,
34 }
35 }
36
37 pub fn from_byte_encoding_prefix(byte: u8) -> Option<Self> {
41 match byte {
42 0 => Some(AggregateSignatureType::Concatenation),
43 #[cfg(feature = "future_proof_system")]
44 255 => Some(AggregateSignatureType::Future),
45 _ => None,
46 }
47 }
48}
49
50impl<D: Clone + Digest + FixedOutput + Send + Sync> From<&AggregateSignature<D>>
51 for AggregateSignatureType
52{
53 fn from(aggr_sig: &AggregateSignature<D>) -> Self {
54 match aggr_sig {
55 AggregateSignature::Concatenation(_) => AggregateSignatureType::Concatenation,
56 #[cfg(feature = "future_proof_system")]
57 AggregateSignature::Future => AggregateSignatureType::Future,
58 }
59 }
60}
61
62impl Display for AggregateSignatureType {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 match self {
65 AggregateSignatureType::Concatenation => write!(f, "Concatenation"),
66 #[cfg(feature = "future_proof_system")]
67 AggregateSignatureType::Future => write!(f, "Future"),
68 }
69 }
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(bound(
75 serialize = "MerkleBatchPath<D>: Serialize",
76 deserialize = "MerkleBatchPath<D>: Deserialize<'de>"
77))]
78pub enum AggregateSignature<D: Clone + Digest + FixedOutput + Send + Sync> {
79 #[cfg(feature = "future_proof_system")]
81 Future,
82
83 #[serde(untagged)]
88 Concatenation(ConcatenationProof<D>),
89}
90
91impl<D: Clone + Digest + FixedOutput + Send + Sync> AggregateSignature<D> {
92 pub fn verify(
94 &self,
95 msg: &[u8],
96 avk: &AggregateVerificationKey<D>,
97 parameters: &Parameters,
98 ) -> Result<(), StmAggregateSignatureError<D>> {
99 match self {
100 AggregateSignature::Concatenation(concatenation_proof) => {
101 concatenation_proof.verify(msg, avk, parameters)
102 }
103 #[cfg(feature = "future_proof_system")]
104 AggregateSignature::Future => Err(StmAggregateSignatureError::UnsupportedProofSystem(
105 self.into(),
106 )),
107 }
108 }
109
110 pub fn batch_verify(
112 stm_signatures: &[Self],
113 msgs: &[Vec<u8>],
114 avks: &[AggregateVerificationKey<D>],
115 parameters: &[Parameters],
116 ) -> Result<(), StmAggregateSignatureError<D>> {
117 let stm_signatures: HashMap<AggregateSignatureType, Vec<Self>> =
118 stm_signatures.iter().fold(HashMap::new(), |mut acc, sig| {
119 acc.entry(sig.into()).or_default().push(sig.clone());
120 acc
121 });
122 stm_signatures
123 .into_iter()
124 .try_for_each(|(aggregate_signature_type, aggregate_signatures)| {
125 match aggregate_signature_type {
126 AggregateSignatureType::Concatenation => {
127 let aggregate_signatures_length = aggregate_signatures.len();
128 let concatenation_proofs = aggregate_signatures
129 .into_iter()
130 .filter_map(|s| s.to_concatenation_proof().cloned())
131 .collect::<Vec<_>>();
132 if concatenation_proofs.len() != aggregate_signatures_length {
133 return Err(StmAggregateSignatureError::BatchInvalid);
134 }
135
136 ConcatenationProof::batch_verify(
137 &concatenation_proofs,
138 msgs,
139 avks,
140 parameters,
141 )
142 }
143 #[cfg(feature = "future_proof_system")]
144 AggregateSignatureType::Future => {
145 Err(StmAggregateSignatureError::UnsupportedProofSystem(
146 aggregate_signature_type,
147 ))
148 }
149 }
150 })
151 .map_err(|_| StmAggregateSignatureError::BatchInvalid)
152 }
153
154 pub fn to_bytes(&self) -> Vec<u8> {
156 let mut aggregate_signature_bytes = Vec::new();
157 let aggregate_signature_type: AggregateSignatureType = self.into();
158 aggregate_signature_bytes
159 .extend_from_slice(&[aggregate_signature_type.get_byte_encoding_prefix()]);
160
161 let mut proof_bytes = match self {
162 AggregateSignature::Concatenation(concatenation_proof) => {
163 concatenation_proof.to_bytes()
164 }
165 #[cfg(feature = "future_proof_system")]
166 AggregateSignature::Future => vec![],
167 };
168 aggregate_signature_bytes.append(&mut proof_bytes);
169
170 aggregate_signature_bytes
171 }
172
173 pub fn from_bytes(bytes: &[u8]) -> Result<Self, StmAggregateSignatureError<D>> {
175 let proof_type_byte =
176 bytes.first().ok_or(StmAggregateSignatureError::SerializationError)?;
177 let proof_bytes = &bytes[1..];
178 let proof_type = AggregateSignatureType::from_byte_encoding_prefix(*proof_type_byte)
179 .ok_or(StmAggregateSignatureError::SerializationError)?;
180 match proof_type {
181 AggregateSignatureType::Concatenation => Ok(AggregateSignature::Concatenation(
182 ConcatenationProof::from_bytes(proof_bytes)?,
183 )),
184 #[cfg(feature = "future_proof_system")]
185 AggregateSignatureType::Future => Ok(AggregateSignature::Future),
186 }
187 }
188
189 pub fn to_concatenation_proof(&self) -> Option<&ConcatenationProof<D>> {
191 match self {
192 AggregateSignature::Concatenation(proof) => Some(proof),
193 #[cfg(feature = "future_proof_system")]
194 AggregateSignature::Future => None,
195 }
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 mod aggregate_signature_type_golden {
204 use super::*;
205
206 #[test]
207 fn golden_bytes_encoding_prefix() {
208 assert_eq!(
209 0u8,
210 AggregateSignatureType::Concatenation.get_byte_encoding_prefix()
211 );
212 assert_eq!(
213 AggregateSignatureType::from_byte_encoding_prefix(0u8),
214 Some(AggregateSignatureType::Concatenation)
215 );
216 }
217 }
218
219 mod aggregate_signature_golden_concatenation {
220 use blake2::{Blake2b, digest::consts::U32};
221 use rand_chacha::ChaCha20Rng;
222 use rand_core::SeedableRng;
223
224 use crate::bls_multi_signature::{BlsSigningKey, BlsVerificationKeyProofOfPossession};
225 use crate::{
226 AggregateSignature, AggregateSignatureType, Clerk, ClosedKeyRegistration,
227 KeyRegistration, Parameters, Signer,
228 };
229
230 type D = Blake2b<U32>;
231
232 const GOLDEN_JSON: &str = r#"
233 {
234 "signatures": [
235 [
236 {
237 "sigma": [
238 149, 157, 201, 187, 140, 54, 0, 128, 209, 88, 16, 203, 61, 78, 77, 98,
239 161, 133, 58, 152, 29, 74, 217, 113, 64, 100, 10, 161, 186, 167, 133,
240 114, 211, 153, 218, 56, 223, 84, 105, 242, 41, 54, 224, 170, 208, 185,
241 126, 83
242 ],
243 "indexes": [1, 4, 5, 8],
244 "signer_index": 0
245 },
246 [
247 [
248 143, 161, 255, 48, 78, 57, 204, 220, 25, 221, 164, 252, 248, 14, 56,
249 126, 186, 135, 228, 188, 145, 181, 52, 200, 97, 99, 213, 46, 0, 199,
250 193, 89, 187, 88, 29, 135, 173, 244, 86, 36, 83, 54, 67, 164, 6, 137,
251 94, 72, 6, 105, 128, 128, 93, 48, 176, 11, 4, 246, 138, 48, 180, 133,
252 90, 142, 192, 24, 193, 111, 142, 31, 76, 111, 110, 234, 153, 90, 208,
253 192, 31, 124, 95, 102, 49, 158, 99, 52, 220, 165, 94, 251, 68, 69,
254 121, 16, 224, 194
255 ],
256 1
257 ]
258 ],
259 [
260 {
261 "sigma": [
262 149, 169, 22, 201, 216, 97, 163, 188, 115, 210, 217, 236, 233, 161,
263 201, 13, 42, 132, 12, 63, 5, 31, 120, 22, 78, 177, 125, 134, 208, 205,
264 73, 58, 247, 141, 59, 62, 187, 81, 213, 30, 153, 218, 41, 42, 110,
265 156, 161, 205
266 ],
267 "indexes": [0, 3, 6],
268 "signer_index": 1
269 },
270 [
271 [
272 145, 56, 175, 32, 122, 187, 214, 226, 251, 148, 88, 9, 1, 103, 159,
273 146, 80, 166, 107, 243, 251, 236, 41, 28, 111, 128, 207, 164, 132,
274 147, 228, 83, 246, 228, 170, 68, 89, 78, 60, 28, 123, 130, 88, 234,
275 38, 97, 42, 65, 1, 100, 53, 18, 78, 131, 8, 61, 122, 131, 238, 84,
276 233, 223, 154, 118, 118, 73, 28, 27, 101, 78, 80, 233, 123, 206, 220,
277 174, 134, 205, 71, 110, 112, 180, 97, 98, 0, 113, 69, 145, 231, 168,
278 43, 173, 172, 56, 104, 208
279 ],
280 1
281 ]
282 ]
283 ],
284 "batch_proof": { "values": [], "indices": [0, 1], "hasher": null }
285 }
286 "#;
287
288 fn golden_value() -> AggregateSignature<D> {
289 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
290 let msg = [0u8; 16];
291 let params = Parameters {
292 m: 10,
293 k: 5,
294 phi_f: 0.8,
295 };
296 let sk_1 = BlsSigningKey::generate(&mut rng);
297 let sk_2 = BlsSigningKey::generate(&mut rng);
298 let pk_1 = BlsVerificationKeyProofOfPossession::from(&sk_1);
299 let pk_2 = BlsVerificationKeyProofOfPossession::from(&sk_2);
300 let mut key_reg = KeyRegistration::init();
301 key_reg.register(1, pk_1).unwrap();
302 key_reg.register(1, pk_2).unwrap();
303 let closed_key_reg: ClosedKeyRegistration<D> = key_reg.close();
304 let clerk = Clerk::new_clerk_from_closed_key_registration(¶ms, &closed_key_reg);
305 let signer_1 = Signer::set_signer(0, 1, params, sk_1, pk_1.vk, closed_key_reg.clone());
306 let signer_2 = Signer::set_signer(1, 1, params, sk_2, pk_2.vk, closed_key_reg);
307 let signature_1 = signer_1.sign(&msg).unwrap();
308 let signature_2 = signer_2.sign(&msg).unwrap();
309
310 clerk
311 .aggregate_signatures_with_type(
312 &[signature_1, signature_2],
313 &msg,
314 AggregateSignatureType::Concatenation,
315 )
316 .unwrap()
317 }
318
319 #[test]
320 fn golden_conversions() {
321 let value: AggregateSignature<D> = serde_json::from_str(GOLDEN_JSON)
322 .expect("This JSON deserialization should not fail");
323
324 let serialized =
325 serde_json::to_string(&value).expect("This JSON serialization should not fail");
326 let golden_serialized = serde_json::to_string(&golden_value())
327 .expect("This JSON serialization should not fail");
328 assert_eq!(golden_serialized, serialized);
329 }
330 }
331}