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