1use crate::bls_multi_signature::{Signature, VerificationKey};
109use crate::eligibility_check::ev_lt_phi;
110use crate::error::{
111 AggregationError, CoreVerifierError, RegisterError, StmAggregateSignatureError,
112 StmSignatureError,
113};
114use crate::key_reg::{ClosedKeyReg, RegParty};
115use crate::merkle_tree::{BatchPath, MTLeaf, MerkleTreeCommitmentBatchCompat};
116use crate::participant::{StmSigner, StmVerificationKey};
117use blake2::digest::{Digest, FixedOutput};
118use serde::ser::SerializeTuple;
119use serde::{Deserialize, Serialize, Serializer};
120use std::cmp::Ordering;
121use std::collections::{BTreeMap, HashMap, HashSet};
122use std::convert::{From, TryFrom, TryInto};
123use std::hash::{Hash, Hasher};
124
125pub type Stake = u64;
127
128pub type Index = u64;
131
132#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
140pub struct StmParameters {
141 pub m: u64,
143 pub k: u64,
145 pub phi_f: f64,
147}
148
149impl StmParameters {
150 pub fn to_bytes(&self) -> [u8; 24] {
156 let mut out = [0; 24];
157 out[..8].copy_from_slice(&self.m.to_be_bytes());
158 out[8..16].copy_from_slice(&self.k.to_be_bytes());
159 out[16..].copy_from_slice(&self.phi_f.to_be_bytes());
160 out
161 }
162
163 pub fn from_bytes(bytes: &[u8]) -> Result<Self, RegisterError> {
167 if bytes.len() != 24 {
168 return Err(RegisterError::SerializationError);
169 }
170
171 let mut u64_bytes = [0u8; 8];
172 u64_bytes.copy_from_slice(&bytes[..8]);
173 let m = u64::from_be_bytes(u64_bytes);
174 u64_bytes.copy_from_slice(&bytes[8..16]);
175 let k = u64::from_be_bytes(u64_bytes);
176 u64_bytes.copy_from_slice(&bytes[16..]);
177 let phi_f = f64::from_be_bytes(u64_bytes);
178
179 Ok(Self { m, k, phi_f })
180 }
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
186#[serde(bound(
187 serialize = "BatchPath<D>: Serialize",
188 deserialize = "BatchPath<D>: Deserialize<'de>"
189))]
190pub struct StmAggrVerificationKey<D: Clone + Digest + FixedOutput> {
191 mt_commitment: MerkleTreeCommitmentBatchCompat<D>,
192 total_stake: Stake,
193}
194
195impl<D: Digest + Clone + FixedOutput> PartialEq for StmAggrVerificationKey<D> {
196 fn eq(&self, other: &Self) -> bool {
197 self.mt_commitment == other.mt_commitment && self.total_stake == other.total_stake
198 }
199}
200
201impl<D: Digest + Clone + FixedOutput> Eq for StmAggrVerificationKey<D> {}
202
203impl<D: Clone + Digest + FixedOutput> From<&ClosedKeyReg<D>> for StmAggrVerificationKey<D> {
204 fn from(reg: &ClosedKeyReg<D>) -> Self {
205 Self {
206 mt_commitment: reg.merkle_tree.to_commitment_batch_compat(),
207 total_stake: reg.total_stake,
208 }
209 }
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct StmSig {
215 pub sigma: Signature,
217 pub indexes: Vec<Index>,
219 pub signer_index: Index,
221}
222
223impl StmSig {
224 pub fn verify<D: Clone + Digest + FixedOutput>(
227 &self,
228 params: &StmParameters,
229 pk: &StmVerificationKey,
230 stake: &Stake,
231 avk: &StmAggrVerificationKey<D>,
232 msg: &[u8],
233 ) -> Result<(), StmSignatureError> {
234 let msgp = avk.mt_commitment.concat_with_msg(msg);
235 self.verify_core(params, pk, stake, &msgp, &avk.total_stake)?;
236 Ok(())
237 }
238
239 pub(crate) fn check_indices(
241 &self,
242 params: &StmParameters,
243 stake: &Stake,
244 msg: &[u8],
245 total_stake: &Stake,
246 ) -> Result<(), StmSignatureError> {
247 for &index in &self.indexes {
248 if index > params.m {
249 return Err(StmSignatureError::IndexBoundFailed(index, params.m));
250 }
251
252 let ev = self.sigma.eval(msg, index);
253
254 if !ev_lt_phi(params.phi_f, ev, *stake, *total_stake) {
255 return Err(StmSignatureError::LotteryLost);
256 }
257 }
258
259 Ok(())
260 }
261
262 pub fn to_bytes(&self) -> Vec<u8> {
272 let mut output = Vec::new();
273 output.extend_from_slice(&(self.indexes.len() as u64).to_be_bytes());
274
275 for index in &self.indexes {
276 output.extend_from_slice(&index.to_be_bytes());
277 }
278
279 output.extend_from_slice(&self.sigma.to_bytes());
280
281 output.extend_from_slice(&self.signer_index.to_be_bytes());
282 output
283 }
284
285 pub fn from_bytes<D: Clone + Digest + FixedOutput>(
287 bytes: &[u8],
288 ) -> Result<StmSig, StmSignatureError> {
289 let mut u64_bytes = [0u8; 8];
290
291 u64_bytes.copy_from_slice(&bytes[0..8]);
292 let nr_indexes = u64::from_be_bytes(u64_bytes) as usize;
293
294 let mut indexes = Vec::new();
295 for i in 0..nr_indexes {
296 u64_bytes.copy_from_slice(&bytes[8 + i * 8..16 + i * 8]);
297 indexes.push(u64::from_be_bytes(u64_bytes));
298 }
299
300 let offset = 8 + nr_indexes * 8;
301 let sigma = Signature::from_bytes(&bytes[offset..offset + 48])?;
302
303 u64_bytes.copy_from_slice(&bytes[offset + 48..offset + 56]);
304 let signer_index = u64::from_be_bytes(u64_bytes);
305
306 Ok(StmSig {
307 sigma,
308 indexes,
309 signer_index,
310 })
311 }
312
313 pub fn cmp_stm_sig(&self, other: &Self) -> Ordering {
315 self.signer_index.cmp(&other.signer_index)
316 }
317
318 pub fn verify_core(
321 &self,
322 params: &StmParameters,
323 pk: &StmVerificationKey,
324 stake: &Stake,
325 msg: &[u8],
326 total_stake: &Stake,
327 ) -> Result<(), StmSignatureError> {
328 self.sigma.verify(msg, pk)?;
329 self.check_indices(params, stake, msg, total_stake)?;
330
331 Ok(())
332 }
333}
334
335impl Hash for StmSig {
336 fn hash<H: Hasher>(&self, state: &mut H) {
337 Hash::hash_slice(&self.sigma.to_bytes(), state)
338 }
339}
340
341impl PartialEq for StmSig {
342 fn eq(&self, other: &Self) -> bool {
343 self.sigma == other.sigma
344 }
345}
346
347impl Eq for StmSig {}
348
349impl PartialOrd for StmSig {
350 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
351 Some(std::cmp::Ord::cmp(self, other))
352 }
353}
354
355impl Ord for StmSig {
356 fn cmp(&self, other: &Self) -> Ordering {
357 self.cmp_stm_sig(other)
358 }
359}
360
361#[derive(Debug, Clone, Hash, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
363pub struct StmSigRegParty {
364 pub sig: StmSig,
366 pub reg_party: RegParty,
368}
369
370impl StmSigRegParty {
371 pub fn to_bytes(&self) -> Vec<u8> {
376 let mut out = Vec::new();
377 out.extend_from_slice(&self.reg_party.to_bytes());
378 out.extend_from_slice(&self.sig.to_bytes());
379
380 out
381 }
382 pub fn from_bytes<D: Digest + Clone + FixedOutput>(
384 bytes: &[u8],
385 ) -> Result<StmSigRegParty, StmSignatureError> {
386 let reg_party = RegParty::from_bytes(&bytes[0..104])?;
387 let sig = StmSig::from_bytes::<D>(&bytes[104..])?;
388
389 Ok(StmSigRegParty { sig, reg_party })
390 }
391}
392
393impl Serialize for StmSigRegParty {
394 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
395 where
396 S: Serializer,
397 {
398 let mut tuple = serializer.serialize_tuple(2)?;
399 tuple.serialize_element(&self.sig)?;
400 tuple.serialize_element(&self.reg_party)?;
401 tuple.end()
402 }
403}
404
405#[derive(Debug, Clone)]
409pub struct StmClerk<D: Clone + Digest> {
410 pub(crate) closed_reg: ClosedKeyReg<D>,
411 pub(crate) params: StmParameters,
412}
413
414impl<D: Digest + Clone + FixedOutput> StmClerk<D> {
415 pub fn from_registration(params: &StmParameters, closed_reg: &ClosedKeyReg<D>) -> Self {
417 Self {
418 params: *params,
419 closed_reg: closed_reg.clone(),
420 }
421 }
422
423 pub fn from_signer(signer: &StmSigner<D>) -> Self {
425 let closed_reg = signer
426 .get_closed_reg()
427 .clone()
428 .expect("Core signer does not include closed registration. StmClerk, and so, the Stm certificate cannot be built without closed registration!")
429 ;
430
431 Self {
432 params: signer.get_params(),
433 closed_reg,
434 }
435 }
436
437 pub fn aggregate(
444 &self,
445 sigs: &[StmSig],
446 msg: &[u8],
447 ) -> Result<StmAggrSig<D>, AggregationError> {
448 let sig_reg_list = sigs
449 .iter()
450 .map(|sig| StmSigRegParty {
451 sig: sig.clone(),
452 reg_party: self.closed_reg.reg_parties[sig.signer_index as usize],
453 })
454 .collect::<Vec<StmSigRegParty>>();
455
456 let avk = StmAggrVerificationKey::from(&self.closed_reg);
457 let msgp = avk.mt_commitment.concat_with_msg(msg);
458 let mut unique_sigs = CoreVerifier::dedup_sigs_for_indices(
459 &self.closed_reg.total_stake,
460 &self.params,
461 &msgp,
462 &sig_reg_list,
463 )?;
464
465 unique_sigs.sort_unstable();
466
467 let mt_index_list = unique_sigs
468 .iter()
469 .map(|sig_reg| sig_reg.sig.signer_index as usize)
470 .collect::<Vec<usize>>();
471
472 let batch_proof = self.closed_reg.merkle_tree.get_batched_path(mt_index_list);
473
474 Ok(StmAggrSig {
475 signatures: unique_sigs,
476 batch_proof,
477 })
478 }
479
480 pub fn compute_avk(&self) -> StmAggrVerificationKey<D> {
482 StmAggrVerificationKey::from(&self.closed_reg)
483 }
484
485 pub fn get_reg_party(&self, party_index: &Index) -> Option<(StmVerificationKey, Stake)> {
487 self.closed_reg
488 .reg_parties
489 .get(*party_index as usize)
490 .map(|&r| r.into())
491 }
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize)]
498#[serde(bound(
499 serialize = "BatchPath<D>: Serialize",
500 deserialize = "BatchPath<D>: Deserialize<'de>"
501))]
502pub struct StmAggrSig<D: Clone + Digest + FixedOutput> {
503 pub(crate) signatures: Vec<StmSigRegParty>,
504 pub batch_proof: BatchPath<D>,
506}
507
508impl<D: Clone + Digest + FixedOutput + Send + Sync> StmAggrSig<D> {
509 fn preliminary_verify(
516 &self,
517 msg: &[u8],
518 avk: &StmAggrVerificationKey<D>,
519 parameters: &StmParameters,
520 ) -> Result<(Vec<Signature>, Vec<VerificationKey>), StmAggregateSignatureError<D>> {
521 let msgp = avk.mt_commitment.concat_with_msg(msg);
522 CoreVerifier::preliminary_verify(&avk.total_stake, &self.signatures, parameters, &msgp)?;
523
524 let leaves = self
525 .signatures
526 .iter()
527 .map(|r| r.reg_party)
528 .collect::<Vec<RegParty>>();
529
530 avk.mt_commitment.check(&leaves, &self.batch_proof)?;
531
532 Ok(CoreVerifier::collect_sigs_vks(&self.signatures))
533 }
534
535 pub fn verify(
542 &self,
543 msg: &[u8],
544 avk: &StmAggrVerificationKey<D>,
545 parameters: &StmParameters,
546 ) -> Result<(), StmAggregateSignatureError<D>> {
547 let msgp = avk.mt_commitment.concat_with_msg(msg);
548 let (sigs, vks) = self.preliminary_verify(msg, avk, parameters)?;
549
550 Signature::verify_aggregate(msgp.as_slice(), &vks, &sigs)?;
551 Ok(())
552 }
553
554 #[cfg(feature = "batch-verify-aggregates")]
556 pub fn batch_verify(
557 stm_signatures: &[Self],
558 msgs: &[Vec<u8>],
559 avks: &[StmAggrVerificationKey<D>],
560 parameters: &[StmParameters],
561 ) -> Result<(), StmAggregateSignatureError<D>> {
562 let batch_size = stm_signatures.len();
563 assert_eq!(
564 batch_size,
565 msgs.len(),
566 "Number of messages should correspond to size of the batch"
567 );
568 assert_eq!(
569 batch_size,
570 avks.len(),
571 "Number of avks should correspond to size of the batch"
572 );
573 assert_eq!(
574 batch_size,
575 parameters.len(),
576 "Number of parameters should correspond to size of the batch"
577 );
578
579 let mut aggr_sigs = Vec::with_capacity(batch_size);
580 let mut aggr_vks = Vec::with_capacity(batch_size);
581 for (idx, sig_group) in stm_signatures.iter().enumerate() {
582 sig_group.preliminary_verify(&msgs[idx], &avks[idx], ¶meters[idx])?;
583 let grouped_sigs: Vec<Signature> = sig_group
584 .signatures
585 .iter()
586 .map(|sig_reg| sig_reg.sig.sigma)
587 .collect();
588 let grouped_vks: Vec<VerificationKey> = sig_group
589 .signatures
590 .iter()
591 .map(|sig_reg| sig_reg.reg_party.0)
592 .collect();
593
594 let (aggr_vk, aggr_sig) = Signature::aggregate(&grouped_vks, &grouped_sigs).unwrap();
595 aggr_sigs.push(aggr_sig);
596 aggr_vks.push(aggr_vk);
597 }
598
599 let concat_msgs: Vec<Vec<u8>> = msgs
600 .iter()
601 .zip(avks.iter())
602 .map(|(msg, avk)| avk.mt_commitment.concat_with_msg(msg))
603 .collect();
604
605 Signature::batch_verify_aggregates(&concat_msgs, &aggr_vks, &aggr_sigs)?;
606 Ok(())
607 }
608
609 pub fn to_bytes(&self) -> Vec<u8> {
616 let mut out = Vec::new();
617 out.extend_from_slice(&u64::try_from(self.signatures.len()).unwrap().to_be_bytes());
618 out.extend_from_slice(
619 &u64::try_from(self.signatures[0].to_bytes().len())
620 .unwrap()
621 .to_be_bytes(),
622 );
623 for sig_reg in &self.signatures {
624 out.extend_from_slice(&sig_reg.to_bytes());
625 }
626 let proof = &self.batch_proof;
627 out.extend_from_slice(&proof.to_bytes());
628
629 out
630 }
631
632 pub fn from_bytes(bytes: &[u8]) -> Result<StmAggrSig<D>, StmAggregateSignatureError<D>> {
634 let mut u64_bytes = [0u8; 8];
635
636 u64_bytes.copy_from_slice(&bytes[..8]);
637 let size = usize::try_from(u64::from_be_bytes(u64_bytes))
638 .map_err(|_| StmAggregateSignatureError::SerializationError)?;
639
640 u64_bytes.copy_from_slice(&bytes[8..16]);
641 let sig_reg_size = usize::try_from(u64::from_be_bytes(u64_bytes))
642 .map_err(|_| StmAggregateSignatureError::SerializationError)?;
643
644 let mut sig_reg_list = Vec::with_capacity(size);
645 for i in 0..size {
646 let sig_reg = StmSigRegParty::from_bytes::<D>(
647 &bytes[16 + (sig_reg_size * i)..16 + (sig_reg_size * (i + 1))],
648 )?;
649 sig_reg_list.push(sig_reg);
650 }
651
652 let offset = 16 + sig_reg_size * size;
653 let batch_proof = BatchPath::from_bytes(&bytes[offset..])?;
654
655 Ok(StmAggrSig {
656 signatures: sig_reg_list,
657 batch_proof,
658 })
659 }
660}
661
662pub struct CoreVerifier {
664 pub eligible_parties: Vec<RegParty>,
666 pub total_stake: Stake,
668}
669
670impl CoreVerifier {
671 pub fn setup(public_signers: &[(VerificationKey, Stake)]) -> Self {
676 let mut total_stake: Stake = 0;
677 let mut unique_parties = HashSet::new();
678 for signer in public_signers.iter() {
679 let (res, overflow) = total_stake.overflowing_add(signer.1);
680 if overflow {
681 panic!("Total stake overflow");
682 }
683 total_stake = res;
684 unique_parties.insert(MTLeaf(signer.0, signer.1));
685 }
686
687 let mut eligible_parties: Vec<_> = unique_parties.into_iter().collect();
688 eligible_parties.sort_unstable();
689 CoreVerifier {
690 eligible_parties,
691 total_stake,
692 }
693 }
694
695 fn preliminary_verify(
697 total_stake: &Stake,
698 signatures: &[StmSigRegParty],
699 parameters: &StmParameters,
700 msg: &[u8],
701 ) -> Result<(), CoreVerifierError> {
702 let mut nr_indices = 0;
703 let mut unique_indices = HashSet::new();
704
705 for sig_reg in signatures {
706 sig_reg
707 .sig
708 .check_indices(parameters, &sig_reg.reg_party.1, msg, total_stake)?;
709 for &index in &sig_reg.sig.indexes {
710 unique_indices.insert(index);
711 nr_indices += 1;
712 }
713 }
714
715 if nr_indices != unique_indices.len() {
716 return Err(CoreVerifierError::IndexNotUnique);
717 }
718 if (nr_indices as u64) < parameters.k {
719 return Err(CoreVerifierError::NoQuorum(nr_indices as u64, parameters.k));
720 }
721
722 Ok(())
723 }
724
725 pub fn dedup_sigs_for_indices(
734 total_stake: &Stake,
735 params: &StmParameters,
736 msg: &[u8],
737 sigs: &[StmSigRegParty],
738 ) -> Result<Vec<StmSigRegParty>, AggregationError> {
739 let mut sig_by_index: BTreeMap<Index, &StmSigRegParty> = BTreeMap::new();
740 let mut removal_idx_by_vk: HashMap<&StmSigRegParty, Vec<Index>> = HashMap::new();
741
742 for sig_reg in sigs.iter() {
743 if sig_reg
744 .sig
745 .verify_core(
746 params,
747 &sig_reg.reg_party.0,
748 &sig_reg.reg_party.1,
749 msg,
750 total_stake,
751 )
752 .is_err()
753 {
754 continue;
755 }
756 for index in sig_reg.sig.indexes.iter() {
757 let mut insert_this_sig = false;
758 if let Some(&previous_sig) = sig_by_index.get(index) {
759 let sig_to_remove_index = if sig_reg.sig.sigma < previous_sig.sig.sigma {
760 insert_this_sig = true;
761 previous_sig
762 } else {
763 sig_reg
764 };
765
766 if let Some(indexes) = removal_idx_by_vk.get_mut(sig_to_remove_index) {
767 indexes.push(*index);
768 } else {
769 removal_idx_by_vk.insert(sig_to_remove_index, vec![*index]);
770 }
771 } else {
772 insert_this_sig = true;
773 }
774
775 if insert_this_sig {
776 sig_by_index.insert(*index, sig_reg);
777 }
778 }
779 }
780
781 let mut dedup_sigs: HashSet<StmSigRegParty> = HashSet::new();
782 let mut count: u64 = 0;
783
784 for (_, &sig_reg) in sig_by_index.iter() {
785 if dedup_sigs.contains(sig_reg) {
786 continue;
787 }
788 let mut deduped_sig = sig_reg.clone();
789 if let Some(indexes) = removal_idx_by_vk.get(sig_reg) {
790 deduped_sig.sig.indexes = deduped_sig
791 .sig
792 .indexes
793 .clone()
794 .into_iter()
795 .filter(|i| !indexes.contains(i))
796 .collect();
797 }
798
799 let size: Result<u64, _> = deduped_sig.sig.indexes.len().try_into();
800 if let Ok(size) = size {
801 if dedup_sigs.contains(&deduped_sig) {
802 panic!("Should not reach!");
803 }
804 dedup_sigs.insert(deduped_sig);
805 count += size;
806
807 if count >= params.k {
808 return Ok(dedup_sigs.into_iter().collect());
809 }
810 }
811 }
812
813 Err(AggregationError::NotEnoughSignatures(count, params.k))
814 }
815
816 fn collect_sigs_vks(sig_reg_list: &[StmSigRegParty]) -> (Vec<Signature>, Vec<VerificationKey>) {
819 let sigs = sig_reg_list
820 .iter()
821 .map(|sig_reg| sig_reg.sig.sigma)
822 .collect::<Vec<Signature>>();
823 let vks = sig_reg_list
824 .iter()
825 .map(|sig_reg| sig_reg.reg_party.0)
826 .collect::<Vec<VerificationKey>>();
827
828 (sigs, vks)
829 }
830
831 pub fn verify(
835 &self,
836 signatures: &[StmSig],
837 parameters: &StmParameters,
838 msg: &[u8],
839 ) -> Result<(), CoreVerifierError> {
840 let sig_reg_list = signatures
841 .iter()
842 .map(|sig| StmSigRegParty {
843 sig: sig.clone(),
844 reg_party: self.eligible_parties[sig.signer_index as usize],
845 })
846 .collect::<Vec<StmSigRegParty>>();
847
848 let unique_sigs =
849 Self::dedup_sigs_for_indices(&self.total_stake, parameters, msg, &sig_reg_list)?;
850
851 Self::preliminary_verify(&self.total_stake, &unique_sigs, parameters, msg)?;
852
853 let (sigs, vks) = Self::collect_sigs_vks(&unique_sigs);
854
855 Signature::verify_aggregate(msg.to_vec().as_slice(), &vks, &sigs)?;
856
857 Ok(())
858 }
859}
860
861#[cfg(test)]
862mod tests {
863 use super::*;
864 use crate::key_reg::*;
865 use blake2::{digest::consts::U32, Blake2b};
866 use proptest::collection::{hash_map, vec};
867 use proptest::prelude::*;
868 use proptest::test_runner::{RngAlgorithm::ChaCha, TestRng};
869 use std::collections::{HashMap, HashSet};
870
871 use crate::participant::{StmInitializer, StmSigner};
872 use rand_chacha::ChaCha20Rng;
873 use rand_core::SeedableRng;
874
875 type Sig = StmAggrSig<D>;
876 type D = Blake2b<U32>;
877
878 fn setup_equal_parties(params: StmParameters, nparties: usize) -> Vec<StmSigner<D>> {
879 let stake = vec![1; nparties];
880 setup_parties(params, stake)
881 }
882
883 fn setup_parties(params: StmParameters, stake: Vec<Stake>) -> Vec<StmSigner<D>> {
884 let mut kr = KeyReg::init();
885 let mut trng = TestRng::deterministic_rng(ChaCha);
886 let mut rng = ChaCha20Rng::from_seed(trng.gen());
887
888 #[allow(clippy::needless_collect)]
889 let ps = stake
890 .into_iter()
891 .map(|stake| {
892 let p = StmInitializer::setup(params, stake, &mut rng);
893 kr.register(stake, p.pk).unwrap();
894 p
895 })
896 .collect::<Vec<_>>();
897 let closed_reg = kr.close();
898 ps.into_iter()
899 .map(|p| p.new_signer(closed_reg.clone()).unwrap())
900 .collect()
901 }
902
903 fn arb_honest_for_adversaries(
906 num_parties: usize,
907 honest_stake: Stake,
908 adversaries: HashMap<usize, Stake>,
909 ) -> impl Strategy<Value = Vec<Stake>> {
910 vec(1..honest_stake, num_parties).prop_map(move |parties| {
911 let honest_sum = parties.iter().enumerate().fold(0, |acc, (i, s)| {
912 if !adversaries.contains_key(&i) {
913 acc + s
914 } else {
915 acc
916 }
917 });
918
919 parties
920 .iter()
921 .enumerate()
922 .map(|(i, s)| {
923 if let Some(a) = adversaries.get(&i) {
924 *a
925 } else {
926 (*s * honest_stake) / honest_sum
927 }
928 })
929 .collect()
930 })
931 }
932
933 fn arb_parties_with_adversaries(
937 num_parties: usize,
938 num_adversaries: usize,
939 total_stake: Stake,
940 adversary_stake: Stake,
941 ) -> impl Strategy<Value = (HashSet<usize>, Vec<Stake>)> {
942 hash_map(0..num_parties, 1..total_stake, num_adversaries).prop_flat_map(
943 move |adversaries| {
944 let adversary_sum: Stake = adversaries.values().sum();
945 let adversaries_normed = adversaries
946 .iter()
947 .map(|(a, stake)| (*a, (stake * adversary_stake) / adversary_sum))
948 .collect();
949
950 let adversaries = adversaries.into_keys().collect();
951 (
952 Just(adversaries),
953 arb_honest_for_adversaries(
954 num_parties,
955 total_stake - adversary_stake,
956 adversaries_normed,
957 ),
958 )
959 },
960 )
961 }
962
963 fn find_signatures(msg: &[u8], ps: &[StmSigner<D>], is: &[usize]) -> Vec<StmSig> {
964 let mut sigs = Vec::new();
965 for i in is {
966 if let Some(sig) = ps[*i].sign(msg) {
967 sigs.push(sig);
968 }
969 }
970 sigs
971 }
972
973 fn arb_parties_adversary_stake(
978 min: usize,
979 max: usize,
980 tstake: Stake,
981 astake: Stake,
982 ) -> impl Strategy<Value = (HashSet<usize>, Vec<Stake>)> {
983 (min..max)
984 .prop_flat_map(|n| (Just(n), 1..=n / 2))
985 .prop_flat_map(move |(n, nadv)| {
986 arb_parties_with_adversaries(n, nadv, tstake * n as Stake, astake * n as Stake)
987 })
988 }
989
990 #[derive(Debug)]
991 struct ProofTest {
992 msig: Result<Sig, AggregationError>,
993 clerk: StmClerk<D>,
994 msg: [u8; 16],
995 }
996 fn arb_proof_setup(max_parties: usize) -> impl Strategy<Value = ProofTest> {
999 any::<[u8; 16]>().prop_flat_map(move |msg| {
1000 (2..max_parties).prop_map(move |n| {
1001 let params = StmParameters {
1002 m: 5,
1003 k: 5,
1004 phi_f: 1.0,
1005 };
1006 let ps = setup_equal_parties(params, n);
1007 let clerk = StmClerk::from_signer(&ps[0]);
1008
1009 let all_ps: Vec<usize> = (0..n).collect();
1010 let sigs = find_signatures(&msg, &ps, &all_ps);
1011
1012 let msig = clerk.aggregate(&sigs, &msg);
1013 ProofTest { msig, clerk, msg }
1014 })
1015 })
1016 }
1017
1018 fn with_proof_mod<F>(mut tc: ProofTest, f: F)
1019 where
1020 F: Fn(&mut Sig, &mut StmClerk<D>, &mut [u8; 16]),
1021 {
1022 match tc.msig {
1023 Ok(mut aggr) => {
1024 f(&mut aggr, &mut tc.clerk, &mut tc.msg);
1025 assert!(aggr
1026 .verify(&tc.msg, &tc.clerk.compute_avk(), &tc.clerk.params)
1027 .is_err())
1028 }
1029 Err(e) => unreachable!("Reached an unexpected error: {:?}", e),
1030 }
1031 }
1032
1033 proptest! {
1034 #![proptest_config(ProptestConfig::with_cases(50))]
1035
1036 #[test]
1037 fn test_dedup(msg in any::<[u8; 16]>()) {
1039 let false_msg = [1u8; 20];
1040 let params = StmParameters { m: 1, k: 1, phi_f: 1.0 };
1041 let ps = setup_equal_parties(params, 1);
1042 let clerk = StmClerk::from_signer(&ps[0]);
1043 let avk = clerk.compute_avk();
1044 let mut sigs = Vec::with_capacity(2);
1045
1046 if let Some(sig) = ps[0].sign(&false_msg) {
1047 sigs.push(sig);
1048 }
1049
1050 if let Some(sig) = ps[0].sign(&msg) {
1051 sigs.push(sig);
1052 }
1053
1054 let sig_reg_list = sigs
1055 .iter()
1056 .map(|sig| StmSigRegParty {
1057 sig: sig.clone(),
1058 reg_party: clerk.closed_reg.reg_parties[sig.signer_index as usize],
1059 })
1060 .collect::<Vec<StmSigRegParty>>();
1061
1062 let msgp = avk.mt_commitment.concat_with_msg(&msg);
1063 let dedup_result = CoreVerifier::dedup_sigs_for_indices(
1064 &clerk.closed_reg.total_stake,
1065 ¶ms,
1066 &msgp,
1067 &sig_reg_list,
1068 );
1069 assert!(dedup_result.is_ok(), "dedup failure {dedup_result:?}");
1070 for passed_sigs in dedup_result.unwrap() {
1071 let verify_result = passed_sigs.sig.verify(¶ms, &ps[0].get_vk(), &ps[0].get_stake(), &avk, &msg);
1072 assert!(verify_result.is_ok(), "verify {verify_result:?}");
1073 }
1074 }
1075 }
1076
1077 proptest! {
1078 #![proptest_config(ProptestConfig::with_cases(50))]
1079
1080 #[test]
1081 fn test_aggregate_sig(nparties in 2_usize..30,
1084 m in 10_u64..20,
1085 k in 1_u64..5,
1086 msg in any::<[u8;16]>()) {
1087 let params = StmParameters { m, k, phi_f: 0.2 };
1088 let ps = setup_equal_parties(params, nparties);
1089 let clerk = StmClerk::from_signer(&ps[0]);
1090
1091 let all_ps: Vec<usize> = (0..nparties).collect();
1092 let sigs = find_signatures(&msg, &ps, &all_ps);
1093 let msig = clerk.aggregate(&sigs, &msg);
1094
1095 match msig {
1096 Ok(aggr) => {
1097 let verify_result = aggr.verify(&msg, &clerk.compute_avk(), ¶ms);
1098 assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}");
1099 }
1100 Err(AggregationError::NotEnoughSignatures(n, k)) =>
1101 assert!(n < params.k || k == params.k),
1102 Err(AggregationError::UsizeConversionInvalid) =>
1103 unreachable!()
1104 }
1105 }
1106
1107 #[test]
1108 fn batch_verify(nparties in 2_usize..30,
1110 m in 10_u64..20,
1111 k in 1_u64..4,
1112 seed in any::<[u8;32]>(),
1113 batch_size in 2..10,
1114 ) {
1115 let mut rng = ChaCha20Rng::from_seed(seed);
1116 let mut aggr_avks = Vec::new();
1117 let mut aggr_stms = Vec::new();
1118 let mut batch_msgs = Vec::new();
1119 let mut batch_params = Vec::new();
1120 for _ in 0..batch_size {
1121 let mut msg = [0u8; 32];
1122 rng.fill_bytes(&mut msg);
1123 let params = StmParameters { m, k, phi_f: 0.95 };
1124 let ps = setup_equal_parties(params, nparties);
1125 let clerk = StmClerk::from_signer(&ps[0]);
1126
1127 let all_ps: Vec<usize> = (0..nparties).collect();
1128 let sigs = find_signatures(&msg, &ps, &all_ps);
1129 let msig = clerk.aggregate(&sigs, &msg);
1130
1131 match msig {
1132 Ok(aggr) => {
1133 aggr_avks.push(clerk.compute_avk());
1134 aggr_stms.push(aggr);
1135 batch_msgs.push(msg.to_vec());
1136 batch_params.push(params);
1137 }
1138 Err(AggregationError::NotEnoughSignatures(_n, _k)) => {
1139 assert!(sigs.len() < params.k as usize)
1140 }
1141 Err(AggregationError::UsizeConversionInvalid) => unreachable!(),
1142 }
1143 }
1144
1145 assert!(StmAggrSig::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_ok());
1146
1147 let mut msg = [0u8; 32];
1148 rng.fill_bytes(&mut msg);
1149 let params = StmParameters { m, k, phi_f: 0.8 };
1150 let ps = setup_equal_parties(params, nparties);
1151 let clerk = StmClerk::from_signer(&ps[0]);
1152
1153 let all_ps: Vec<usize> = (0..nparties).collect();
1154 let sigs = find_signatures(&msg, &ps, &all_ps);
1155 let fake_msig = clerk.aggregate(&sigs, &msg);
1156
1157 aggr_stms[0] = fake_msig.unwrap();
1158 assert!(StmAggrSig::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_err());
1159 }
1160 }
1161
1162 proptest! {
1163 #[test]
1164 fn test_sig(msg in any::<[u8;16]>()) {
1166 let params = StmParameters { m: 1, k: 1, phi_f: 0.2 };
1167 let ps = setup_equal_parties(params, 1);
1168 let clerk = StmClerk::from_signer(&ps[0]);
1169 let avk = clerk.compute_avk();
1170
1171 if let Some(sig) = ps[0].sign(&msg) {
1172 assert!(sig.verify(¶ms, &ps[0].get_vk(), &ps[0].get_stake(), &avk, &msg).is_ok());
1173 }
1174 }
1175 }
1176
1177 proptest! {
1178 #![proptest_config(ProptestConfig::with_cases(10))]
1179 #[test]
1180 fn test_parameters_serialize_deserialize(m in any::<u64>(), k in any::<u64>(), phi_f in any::<f64>()) {
1181 let params = StmParameters { m, k, phi_f };
1182
1183 let bytes = params.to_bytes();
1184 let deserialised = StmParameters::from_bytes(&bytes);
1185 assert!(deserialised.is_ok())
1186 }
1187
1188 #[test]
1189 fn test_initializer_serialize_deserialize(seed in any::<[u8;32]>()) {
1190 let mut rng = ChaCha20Rng::from_seed(seed);
1191 let params = StmParameters { m: 1, k: 1, phi_f: 1.0 };
1192 let stake = rng.next_u64();
1193 let initializer = StmInitializer::setup(params, stake, &mut rng);
1194
1195 let bytes = initializer.to_bytes();
1196 assert!(StmInitializer::from_bytes(&bytes).is_ok());
1197
1198 let bytes = bincode::serialize(&initializer).unwrap();
1199 assert!(bincode::deserialize::<StmInitializer>(&bytes).is_ok())
1200 }
1201
1202 #[test]
1203 fn test_sig_serialize_deserialize(msg in any::<[u8;16]>()) {
1204 let params = StmParameters { m: 1, k: 1, phi_f: 0.2 };
1205 let ps = setup_equal_parties(params, 1);
1206 let clerk = StmClerk::from_signer(&ps[0]);
1207 let avk = clerk.compute_avk();
1208
1209 if let Some(sig) = ps[0].sign(&msg) {
1210 let bytes = sig.to_bytes();
1211 let sig_deser = StmSig::from_bytes::<D>(&bytes).unwrap();
1212 assert!(sig_deser.verify(¶ms, &ps[0].get_vk(), &ps[0].get_stake(), &avk, &msg).is_ok());
1213
1214 let encoded = bincode::serialize(&sig).unwrap();
1215 let decoded: StmSig = bincode::deserialize(&encoded).unwrap();
1216 assert!(decoded.verify(¶ms, &ps[0].get_vk(), &ps[0].get_stake(), &avk, &msg).is_ok());
1217 }
1218 }
1219
1220 #[test]
1221 fn test_multisig_serialize_deserialize(nparties in 2_usize..10,
1222 msg in any::<[u8;16]>()) {
1223 let params = StmParameters { m: 10, k: 5, phi_f: 1.0 };
1224 let ps = setup_equal_parties(params, nparties);
1225 let clerk = StmClerk::from_signer(&ps[0]);
1226
1227 let all_ps: Vec<usize> = (0..nparties).collect();
1228 let sigs = find_signatures(&msg, &ps, &all_ps);
1229 let msig = clerk.aggregate(&sigs, &msg);
1230 if let Ok(aggr) = msig {
1231 let bytes: Vec<u8> = aggr.to_bytes();
1232 let aggr2 = StmAggrSig::from_bytes(&bytes).unwrap();
1233 assert!(aggr2.verify(&msg, &clerk.compute_avk(), ¶ms).is_ok());
1234
1235 let encoded = bincode::serialize(&aggr).unwrap();
1236 let decoded: StmAggrSig::<D> = bincode::deserialize(&encoded).unwrap();
1237 assert!(decoded.verify(&msg, &clerk.compute_avk(), ¶ms).is_ok());
1238 }
1239 }
1240 }
1241
1242 proptest! {
1243 #![proptest_config(ProptestConfig::with_cases(10))]
1244
1245 #[test]
1246 fn test_adversary_quorum(
1248 (adversaries, parties) in arb_parties_adversary_stake(8, 30, 16, 4),
1249 msg in any::<[u8;16]>(),
1250 ) {
1251 let (good, bad) = parties.iter().enumerate().fold((0,0), |(acc1, acc2), (i, st)| {
1254 if adversaries.contains(&i) {
1255 (acc1, acc2 + *st)
1256 } else {
1257 (acc1 + *st, acc2)
1258 }
1259 });
1260 assert!(bad as f64 / ((good + bad) as f64) < 0.4);
1261
1262 let params = StmParameters { m: 2642, k: 357, phi_f: 0.2 }; let ps = setup_parties(params, parties);
1264
1265 let sigs = find_signatures(&msg, &ps, &adversaries.into_iter().collect::<Vec<_>>());
1266
1267 assert!(sigs.len() < params.k as usize);
1268
1269 let clerk = StmClerk::from_signer(&ps[0]);
1270
1271 let msig = clerk.aggregate(&sigs, &msg);
1272 match msig {
1273 Err(AggregationError::NotEnoughSignatures(n, k)) =>
1274 assert!(n < params.k && params.k == k),
1275 _ =>
1276 unreachable!(),
1277 }
1278 }
1279 }
1280
1281 proptest! {
1282 #[test]
1285 fn test_invalid_proof_quorum(tc in arb_proof_setup(10)) {
1286 with_proof_mod(tc, |_aggr, clerk, _msg| {
1287 clerk.params.k += 7;
1288 })
1289 }
1290 #[test]
1292 fn test_invalid_proof_index_bound(tc in arb_proof_setup(10)) {
1293 with_proof_mod(tc, |_aggr, clerk, _msg| {
1294 clerk.params.m = 1;
1295 })
1296 }
1297 #[test]
1298 fn test_invalid_proof_index_unique(tc in arb_proof_setup(10)) {
1299 with_proof_mod(tc, |aggr, clerk, _msg| {
1300 for sig_reg in aggr.signatures.iter_mut() {
1301 for index in sig_reg.sig.indexes.iter_mut() {
1302 *index %= clerk.params.k - 1
1303 }
1304 }
1305 })
1306 }
1307 #[test]
1308 fn test_invalid_proof_path(tc in arb_proof_setup(10)) {
1309 with_proof_mod(tc, |aggr, _, _msg| {
1310 let p = aggr.batch_proof.clone();
1311 let mut index_list = p.indices.clone();
1312 let values = p.values;
1313 let batch_proof = {
1314 index_list[0] += 1;
1315 BatchPath {
1316 values,
1317 indices: index_list,
1318 hasher: Default::default()
1319 }
1320 };
1321 aggr.batch_proof = batch_proof;
1322 })
1323 }
1324 }
1325
1326 fn setup_equal_core_parties(
1330 params: StmParameters,
1331 nparties: usize,
1332 ) -> (Vec<StmInitializer>, Vec<(VerificationKey, Stake)>) {
1333 let stake = vec![1; nparties];
1334 setup_core_parties(params, stake)
1335 }
1336
1337 fn setup_core_parties(
1338 params: StmParameters,
1339 stake: Vec<Stake>,
1340 ) -> (Vec<StmInitializer>, Vec<(VerificationKey, Stake)>) {
1341 let mut trng = TestRng::deterministic_rng(ChaCha);
1342 let mut rng = ChaCha20Rng::from_seed(trng.gen());
1343
1344 let ps = stake
1345 .into_iter()
1346 .map(|stake| StmInitializer::setup(params, stake, &mut rng))
1347 .collect::<Vec<StmInitializer>>();
1348
1349 let public_signers = ps
1350 .iter()
1351 .map(|s| (s.pk.vk, s.stake))
1352 .collect::<Vec<(VerificationKey, Stake)>>();
1353
1354 (ps, public_signers)
1355 }
1356
1357 fn find_core_signatures(
1358 msg: &[u8],
1359 ps: &[StmSigner<D>],
1360 total_stake: Stake,
1361 is: &[usize],
1362 ) -> Vec<StmSig> {
1363 let mut sigs = Vec::new();
1364 for i in is {
1365 if let Some(sig) = ps[*i].core_sign(msg, total_stake) {
1366 sigs.push(sig);
1367 }
1368 }
1369 sigs
1370 }
1371
1372 proptest! {
1373 #![proptest_config(ProptestConfig::with_cases(50))]
1374
1375 #[test]
1376 fn test_core_verifier(nparties in 2_usize..30,
1377 m in 10_u64..20,
1378 k in 1_u64..5,
1379 msg in any::<[u8;16]>()) {
1380
1381 let params = StmParameters { m, k, phi_f: 0.2 };
1382 let (initializers, public_signers) = setup_equal_core_parties(params, nparties);
1383 let all_ps: Vec<usize> = (0..nparties).collect();
1384
1385 let core_verifier = CoreVerifier::setup(&public_signers);
1386
1387 let signers = initializers
1388 .into_iter()
1389 .filter_map(|s| s.new_core_signer(&core_verifier.eligible_parties))
1390 .collect::<Vec<StmSigner<D>>>();
1391
1392 let signatures = find_core_signatures(&msg, &signers, core_verifier.total_stake, &all_ps);
1393
1394 let verify_result = core_verifier.verify(&signatures, ¶ms, &msg);
1395
1396 match verify_result{
1397 Ok(_) => {
1398 assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}");
1399 }
1400 Err(CoreVerifierError::NoQuorum(nr_indices, _k)) => {
1401 assert!((nr_indices) < params.k);
1402 }
1403 Err(CoreVerifierError::IndexNotUnique) => unreachable!(),
1404 _ => unreachable!(),
1405 }
1406 }
1407
1408 #[test]
1409 fn test_total_stake_core_verifier(nparties in 2_usize..30,
1410 m in 10_u64..20,
1411 k in 1_u64..5,) {
1412 let params = StmParameters { m, k, phi_f: 0.2 };
1413 let (_initializers, public_signers) = setup_equal_core_parties(params, nparties);
1414 let core_verifier = CoreVerifier::setup(&public_signers);
1415 assert_eq!(nparties as u64, core_verifier.total_stake, "Total stake expected: {}, got: {}.", nparties, core_verifier.total_stake);
1416 }
1417 }
1418}