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(pk_1, 1).unwrap();
309 let entry2 = RegistrationEntry::new(pk_2, 1).unwrap();
310
311 key_reg.register_by_entry(&entry1).unwrap();
312 key_reg.register_by_entry(&entry2).unwrap();
313 let closed_key_reg = key_reg.close_registration();
314
315 let clerk = Clerk::new_clerk_from_closed_key_registration(¶ms, &closed_key_reg);
316
317 let signer_1: Signer<D> = Signer::new(
318 0,
319 ConcatenationProofSigner::new(
320 1,
321 2,
322 params,
323 sk_1,
324 pk_1.vk,
325 closed_key_reg.clone().key_registration.into_merkle_tree(),
326 ),
327 closed_key_reg.clone(),
328 params,
329 1,
330 );
331
332 let signer_2: Signer<D> = Signer::new(
333 1,
334 ConcatenationProofSigner::new(
335 1,
336 2,
337 params,
338 sk_2,
339 pk_2.vk,
340 closed_key_reg.clone().key_registration.into_merkle_tree(),
341 ),
342 closed_key_reg.clone(),
343 params,
344 1,
345 );
346 let signature_1 = signer_1.create_single_signature(&msg).unwrap();
347 let signature_2 = signer_2.create_single_signature(&msg).unwrap();
348
349 clerk
350 .aggregate_signatures_with_type(
351 &[signature_1, signature_2],
352 &msg,
353 AggregateSignatureType::Concatenation,
354 )
355 .unwrap()
356 }
357
358 #[test]
359 fn golden_conversions() {
360 let value: AggregateSignature<D> = serde_json::from_str(GOLDEN_JSON)
361 .expect("This JSON deserialization should not fail");
362
363 let serialized =
364 serde_json::to_string(&value).expect("This JSON serialization should not fail");
365 let golden_serialized = serde_json::to_string(&golden_value())
366 .expect("This JSON serialization should not fail");
367 assert_eq!(golden_serialized, serialized);
368 }
369 }
370}