mithril_stm/protocol/aggregate_signature/
clerk.rs1use anyhow::{Context, anyhow};
2use std::collections::{BTreeMap, HashMap, HashSet};
3
4use crate::{
5 ClosedKeyRegistration, Index, MembershipDigest, Parameters, Signer, SingleSignature,
6 SingleSignatureWithRegisteredParty, Stake, StmResult, VerificationKey,
7 proof_system::ConcatenationProof,
8};
9
10use super::{
11 AggregateSignature, AggregateSignatureType, AggregateVerificationKey, AggregationError,
12};
13
14#[derive(Debug, Clone)]
18pub struct Clerk<D: MembershipDigest> {
19 pub(crate) closed_reg: ClosedKeyRegistration<D>,
20 pub(crate) params: Parameters,
21}
22
23impl<D: MembershipDigest> Clerk<D> {
24 pub fn new_clerk_from_closed_key_registration(
26 params: &Parameters,
27 closed_reg: &ClosedKeyRegistration<D>,
28 ) -> Self {
29 Self {
30 params: *params,
31 closed_reg: closed_reg.clone(),
32 }
33 }
34
35 pub fn new_clerk_from_signer(signer: &Signer<D>) -> Self {
37 let closed_reg = signer
38 .get_closed_key_registration()
39 .clone()
40 .expect("Core signer does not include closed registration. Clerk, and so, the Stm certificate cannot be built without closed registration!")
41 ;
42
43 Self {
44 params: signer.get_parameters(),
45 closed_reg,
46 }
47 }
48
49 pub fn aggregate_signatures_with_type(
51 &self,
52 sigs: &[SingleSignature],
53 msg: &[u8],
54 aggregate_signature_type: AggregateSignatureType,
55 ) -> StmResult<AggregateSignature<D>> {
56 match aggregate_signature_type {
57 AggregateSignatureType::Concatenation => Ok(AggregateSignature::Concatenation(
58 ConcatenationProof::aggregate_signatures(self, sigs, msg).with_context(|| {
59 format!(
60 "Signatures failed to aggregate for type {}",
61 AggregateSignatureType::Concatenation
62 )
63 })?,
64 )),
65 #[cfg(feature = "future_snark")]
66 AggregateSignatureType::Future => Err(anyhow!(
67 AggregationError::UnsupportedProofSystem(aggregate_signature_type)
68 )),
69 }
70 }
71
72 pub fn compute_aggregate_verification_key(&self) -> AggregateVerificationKey<D> {
74 AggregateVerificationKey::from(&self.closed_reg)
75 }
76
77 pub fn get_registered_party_for_index(
79 &self,
80 party_index: &Index,
81 ) -> Option<(VerificationKey, Stake)> {
82 self.closed_reg
83 .reg_parties
84 .get(*party_index as usize)
85 .map(|&r| r.into())
86 }
87
88 pub fn select_valid_signatures_for_k_indices(
97 params: &Parameters,
98 msg: &[u8],
99 sigs: &[SingleSignatureWithRegisteredParty],
100 avk: &AggregateVerificationKey<D>,
101 ) -> StmResult<Vec<SingleSignatureWithRegisteredParty>> {
102 let mut sig_by_index: BTreeMap<Index, &SingleSignatureWithRegisteredParty> =
103 BTreeMap::new();
104 let mut removal_idx_by_vk: HashMap<&SingleSignatureWithRegisteredParty, Vec<Index>> =
105 HashMap::new();
106
107 for sig_reg in sigs.iter() {
108 if sig_reg
109 .sig
110 .verify(params, &sig_reg.reg_party.0, &sig_reg.reg_party.1, avk, msg)
111 .is_err()
112 {
113 continue;
114 }
115 for index in sig_reg.sig.get_concatenation_signature_indices().iter() {
116 let mut insert_this_sig = false;
117 if let Some(&previous_sig) = sig_by_index.get(index) {
118 let sig_to_remove_index = if sig_reg.sig.get_concatenation_signature_sigma()
119 < previous_sig.sig.get_concatenation_signature_sigma()
120 {
121 insert_this_sig = true;
122 previous_sig
123 } else {
124 sig_reg
125 };
126
127 if let Some(indexes) = removal_idx_by_vk.get_mut(sig_to_remove_index) {
128 indexes.push(*index);
129 } else {
130 removal_idx_by_vk.insert(sig_to_remove_index, vec![*index]);
131 }
132 } else {
133 insert_this_sig = true;
134 }
135
136 if insert_this_sig {
137 sig_by_index.insert(*index, sig_reg);
138 }
139 }
140 }
141
142 let mut dedup_sigs: HashSet<SingleSignatureWithRegisteredParty> = HashSet::new();
143 let mut count: u64 = 0;
144
145 for (_, &sig_reg) in sig_by_index.iter() {
146 if dedup_sigs.contains(sig_reg) {
147 continue;
148 }
149 let mut deduped_sig = sig_reg.clone();
150 if let Some(indexes) = removal_idx_by_vk.get(sig_reg) {
151 let indices = deduped_sig
152 .sig
153 .get_concatenation_signature_indices()
154 .into_iter()
155 .filter(|i| !indexes.contains(i))
156 .collect::<Vec<Index>>();
157 deduped_sig.sig.set_concatenation_signature_indices(&indices);
158 }
159
160 let size: Result<u64, _> =
161 deduped_sig.sig.get_concatenation_signature_indices().len().try_into();
162 if let Ok(size) = size {
163 if dedup_sigs.contains(&deduped_sig) {
164 panic!("Should not reach!");
165 }
166 dedup_sigs.insert(deduped_sig);
167 count += size;
168
169 if count >= params.k {
170 return Ok(dedup_sigs.into_iter().collect());
171 }
172 }
173 }
174 Err(anyhow!(AggregationError::NotEnoughSignatures(
175 count, params.k
176 )))
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use proptest::prelude::*;
183 use rand_chacha::ChaCha20Rng;
184 use rand_core::{RngCore, SeedableRng};
185
186 use crate::{
187 Clerk, ClosedKeyRegistration, Initializer, KeyRegistration, MithrilMembershipDigest,
188 Parameters, SingleSignatureWithRegisteredParty,
189 };
190
191 use super::AggregationError;
192
193 type D = MithrilMembershipDigest;
194
195 proptest! {
196 #![proptest_config(ProptestConfig::with_cases(50))]
197
198 #[test]
199 fn test_dedup(
200 seed in any::<[u8; 32]>(),
201 msg in any::<[u8;16]>(),
202 nparties in 1_usize..10,
203 m in 1_u64..20,
204 k in 1_u64..10,
205 phi_f in 0.1_f64..1.0,
206 num_invalid_sigs_per_party in 0_usize..3,
207 ) {
208 let params = Parameters { m, k, phi_f };
209 let mut rng = ChaCha20Rng::from_seed(seed);
210
211 let mut false_msgs = Vec::new();
213 for _ in 0..num_invalid_sigs_per_party {
214 let mut false_msg = vec![0u8; 32];
215 rng.fill_bytes(&mut false_msg);
216 if false_msg == msg {
217 false_msg[0] = msg[0].wrapping_add(1);
218 }
219 false_msgs.push(false_msg);
220 }
221
222 let mut key_registration = KeyRegistration::init();
223 let mut initializers = Vec::new();
224
225 for i in 0..nparties {
226 let stake = (i as u64 + 1) * 10;
227 let initializer = Initializer::new(params, stake, &mut rng);
228 key_registration.register(initializer.stake, initializer.pk).unwrap();
229 initializers.push(initializer);
230 }
231
232 let closed_registration: ClosedKeyRegistration<D> = key_registration.close();
233
234 let signers: Vec<_> = initializers
235 .into_iter()
236 .map(|init| init.create_signer(closed_registration.clone()).unwrap())
237 .collect();
238
239 let clerk = Clerk::new_clerk_from_signer(&signers[0]);
240 let avk = clerk.compute_aggregate_verification_key();
241
242 let mut all_sigs = Vec::new();
243 for signer in &signers {
244 for false_msg in &false_msgs {
246 if let Some(sig) = signer.sign(false_msg) {
247 all_sigs.push(sig);
248 }
249 }
250 if let Some(sig) = signer.sign(&msg) {
252 all_sigs.push(sig);
253 }
254 }
255
256 let sig_reg_list = all_sigs
257 .iter()
258 .map(|sig| SingleSignatureWithRegisteredParty {
259 sig: sig.clone(),
260 reg_party: clerk.closed_reg.reg_parties[sig.signer_index as usize],
261 })
262 .collect::<Vec<SingleSignatureWithRegisteredParty>>();
263
264 let dedup_result =
265 Clerk::select_valid_signatures_for_k_indices(¶ms, &msg, &sig_reg_list, &avk);
266
267 match dedup_result {
268 Ok(valid_sigs) => {
269 assert!(!valid_sigs.is_empty(), "Should have at least one valid signature");
270
271 for passed_sigs in valid_sigs {
272 let signer = &signers[passed_sigs.sig.signer_index as usize];
273 let verify_result = passed_sigs.sig.verify(
274 ¶ms,
275 &signer.get_verification_key(),
276 &signer.get_stake(),
277 &avk,
278 &msg,
279 );
280 assert!(verify_result.is_ok(), "All returned signatures should verify: {:?}", verify_result);
281 }
282 }
283 Err(error) => {
284 assert!(
285 matches!(
286 error.downcast_ref::<AggregationError>(),
287 Some(AggregationError::NotEnoughSignatures(..))
288 ),
289 "Expected NotEnoughSignatures, got: {:?}", error
290 );
291 }
292 }
293 }
294 }
295}