1#[cfg(feature = "std")]
13use std::boxed::Box;
14#[cfg(feature = "alloc")]
15use alloc::boxed::Box;
16
17#[cfg(feature = "std")]
18use std::collections::HashMap;
19#[cfg(feature = "std")]
20use std::collections::hash_map::Values;
21#[cfg(feature = "std")]
22use std::cmp::Ordering;
23#[cfg(feature = "std")]
24use std::vec::Vec;
25
26use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE;
27use curve25519_dalek::ristretto::CompressedRistretto;
28use curve25519_dalek::ristretto::RistrettoPoint;
29use curve25519_dalek::scalar::Scalar;
30
31use sha2::Digest;
32use sha2::Sha512;
33
34use crate::keygen::GroupKey;
35use crate::keygen::IndividualPublicKey;
36use crate::parameters::Parameters;
37use crate::precomputation::SecretCommitmentShareList;
38
39pub use crate::keygen::SecretKey;
40
41#[derive(Clone, Copy, Debug, Eq)]
46pub struct Signer {
47 pub participant_index: u32,
49 pub published_commitment_share: (RistrettoPoint, RistrettoPoint),
52}
53
54impl Ord for Signer {
55 fn cmp(&self, other: &Signer) -> Ordering {
56 self.partial_cmp(other).unwrap()
57 }
58}
59
60impl PartialOrd for Signer {
61 fn partial_cmp(&self, other: &Signer) -> Option<Ordering> {
62 match self.participant_index.cmp(&other.participant_index) {
63 Ordering::Less => Some(Ordering::Less),
64 Ordering::Equal => Some(Ordering::Equal),
66 Ordering::Greater => Some(Ordering::Greater),
67 }
68 }
69}
70
71impl PartialEq for Signer {
72 fn eq(&self, other: &Signer) -> bool {
73 self.participant_index == other.participant_index
74 }
75}
76
77#[derive(Debug)]
80pub struct PartialThresholdSignature {
81 pub(crate) index: u32,
82 pub(crate) z: Scalar,
83}
84
85#[derive(Debug)]
87pub struct ThresholdSignature {
88 pub(crate) R: RistrettoPoint,
89 pub(crate) z: Scalar,
90}
91
92impl ThresholdSignature {
93 pub fn to_bytes(&self) -> [u8; 64] {
95 let mut bytes = [0u8; 64];
96
97 bytes[..32].copy_from_slice(&self.R.compress().as_bytes()[..]);
98 bytes[32..].copy_from_slice(&self.z.as_bytes()[..]);
99 bytes
100 }
101
102 pub fn from_bytes(bytes: [u8; 64]) -> Result<ThresholdSignature, ()> {
104 let mut array = [0u8; 32];
105
106 array.copy_from_slice(&bytes[..32]);
107
108 let R = CompressedRistretto(array).decompress().ok_or(())?;
109
110 array.copy_from_slice(&bytes[32..]);
111
112 let z = Scalar::from_canonical_bytes(array).ok_or(())?;
113
114 Ok(ThresholdSignature { R, z })
115 }
116}
117
118macro_rules! impl_indexed_hashmap {
119 (Type = $type:ident, Item = $item:ident) => {
120
121impl $type {
122 pub(crate) fn new() -> $type {
123 $type(HashMap::new())
124 }
125
126 pub(crate) fn insert(&mut self, index: &u32, point: $item) {
130 self.0.insert(index.to_be_bytes(), point);
131 }
132
133 pub(crate) fn get(&self, index: &u32) -> Option<&$item> {
134 self.0.get(&index.to_be_bytes())
135 }
136
137 #[allow(unused)]
138 pub(crate) fn sorted(&self) -> Vec<(u32, $item)> {
139 let mut sorted: Vec<(u32, $item)> = Vec::with_capacity(self.0.len());
140
141 for (i, point) in self.0.iter() {
142 let index = u32::from_be_bytes(*i);
143 sorted.insert(index as usize, (index, *point));
144 }
145 sorted
146 }
147
148 #[allow(unused)]
149 pub(crate) fn values(&self) -> Values<'_, [u8; 4], $item> {
150 self.0.values()
151 }
152}
153
154}} #[derive(Debug)]
163struct SignerRs(pub(crate) HashMap<[u8; 4], RistrettoPoint>);
164
165impl_indexed_hashmap!(Type = SignerRs, Item = RistrettoPoint);
166
167#[derive(Debug)]
170pub(crate) struct PartialThresholdSignatures(pub(crate) HashMap<[u8; 4], Scalar>);
171
172impl_indexed_hashmap!(Type = PartialThresholdSignatures, Item = Scalar);
173
174#[derive(Debug)]
177pub(crate) struct IndividualPublicKeys(pub(crate) HashMap<[u8; 4], RistrettoPoint>);
178
179impl_indexed_hashmap!(Type = IndividualPublicKeys, Item = RistrettoPoint);
180
181pub fn compute_message_hash(context_string: &[u8], message: &[u8]) -> [u8; 64] {
183 let mut h = Sha512::new();
184
185 h.update(context_string);
186 h.update(message);
187
188 let mut output = [0u8; 64];
189
190 output.copy_from_slice(h.finalize().as_slice());
191 output
192}
193
194fn compute_binding_factors_and_group_commitment(
195 message_hash: &[u8; 64],
196 signers: &[Signer],
197) -> (HashMap<u32, Scalar>, SignerRs)
198{
199 let mut binding_factors: HashMap<u32, Scalar> = HashMap::with_capacity(signers.len());
200 let mut Rs: SignerRs = SignerRs::new();
201
202 let mut h = Sha512::new();
205
206 h.update(b"FROST-SHA512");
209 h.update(&message_hash[..]);
210
211 for signer in signers.iter() {
215 let hiding = signer.published_commitment_share.0;
216 let binding = signer.published_commitment_share.1;
217
218 h.update(signer.participant_index.to_be_bytes());
219 h.update(hiding.compress().as_bytes());
220 h.update(binding.compress().as_bytes());
221 }
222
223 for signer in signers.iter() {
224 let hiding = signer.published_commitment_share.0;
225 let binding = signer.published_commitment_share.1;
226
227 let mut h1 = h.clone();
228
229 h1.update(signer.participant_index.to_be_bytes());
232 h1.update(hiding.compress().as_bytes());
233 h1.update(binding.compress().as_bytes());
234
235 let binding_factor = Scalar::from_hash(h1); Rs.insert(&signer.participant_index, hiding + (binding_factor * binding));
239 binding_factors.insert(signer.participant_index, binding_factor);
240 }
241 (binding_factors, Rs)
242}
243
244fn compute_challenge(message_hash: &[u8; 64], group_key: &GroupKey, R: &RistrettoPoint) -> Scalar {
245 let mut h2 = Sha512::new();
246
247 h2.update(b"FROST-SHA512");
250 h2.update(R.compress().as_bytes());
251 h2.update(group_key.to_bytes());
252 h2.update(&message_hash[..]);
253
254 Scalar::from_hash(h2)
255}
256
257pub(crate) fn calculate_lagrange_coefficients(
264 participant_index: &u32,
265 all_participant_indices: &[u32],
266) -> Result<Scalar, &'static str>
267{
268 let mut num = Scalar::one();
269 let mut den = Scalar::one();
270
271 let mine = Scalar::from(*participant_index);
272
273 for j in all_participant_indices.iter() {
274 if j == participant_index {
275 continue;
276 }
277 let s = Scalar::from(*j);
278
279 num *= s;
280 den *= s - mine; }
282
283 if den == Scalar::zero() {
284 return Err("Duplicate shares provided");
285 }
286 Ok(num * den.invert())
287}
288
289impl SecretKey {
290 pub fn sign(
316 &self,
317 message_hash: &[u8; 64],
318 group_key: &GroupKey,
319 my_secret_commitment_share_list: &mut SecretCommitmentShareList,
322 my_commitment_share_index: usize,
323 signers: &[Signer],
324 ) -> Result<PartialThresholdSignature, &'static str>
325 {
326 if my_commitment_share_index + 1 > my_secret_commitment_share_list.commitments.len() {
327 return Err("Commitment share index out of bounds");
328 }
329
330 let (binding_factors, Rs) = compute_binding_factors_and_group_commitment(&message_hash, &signers);
331 let R: RistrettoPoint = Rs.values().sum();
332 let challenge = compute_challenge(&message_hash, &group_key, &R);
333 let my_binding_factor = binding_factors.get(&self.index).ok_or("Could not compute our blinding factor")?;
334 let all_participant_indices: Vec<u32> = signers.iter().map(|x| x.participant_index).collect();
335 let lambda: Scalar = calculate_lagrange_coefficients(&self.index, &all_participant_indices)?;
336 let my_commitment_share = my_secret_commitment_share_list.commitments[my_commitment_share_index].clone();
337 let z = my_commitment_share.hiding.nonce +
338 (my_commitment_share.binding.nonce * my_binding_factor) +
339 (lambda * self.key * challenge);
340
341 my_secret_commitment_share_list.drop_share(my_commitment_share);
353
354 Ok(PartialThresholdSignature { index: self.index, z })
355 }
356}
357
358pub trait Aggregator {}
360
361#[derive(Debug)]
363pub(crate) struct AggregatorState {
364 pub(crate) parameters: Parameters,
366 pub(crate) signers: Vec<Signer>,
368 pub(crate) public_keys: IndividualPublicKeys,
370 pub(crate) partial_signatures: PartialThresholdSignatures,
373 pub(crate) group_key: GroupKey,
375}
376
377#[derive(Debug)]
383pub struct SignatureAggregator<A: Aggregator> {
384 pub(crate) state: Box<AggregatorState>,
386 pub(crate) aggregator: A,
388}
389
390#[derive(Debug)]
393pub struct Initial<'sa> {
394 pub(crate) context: &'sa [u8],
396 pub(crate) message: &'sa [u8],
398}
399
400impl Aggregator for Initial<'_> {}
401
402#[derive(Debug)]
417pub struct Finalized {
418 pub(crate) message_hash: [u8; 64],
420}
421
422impl Aggregator for Finalized {}
423
424impl SignatureAggregator<Initial<'_>> {
425 pub fn new<'sa>(
445 parameters: Parameters,
446 group_key: GroupKey,
447 context: &'sa [u8],
448 message: &'sa [u8],
449 ) -> SignatureAggregator<Initial<'sa>> {
450 let signers: Vec<Signer> = Vec::with_capacity(parameters.t as usize);
451 let public_keys = IndividualPublicKeys::new();
452 let partial_signatures = PartialThresholdSignatures::new();
453 let state = AggregatorState { parameters, signers, public_keys, partial_signatures, group_key };
454
455 SignatureAggregator { state: Box::new(state), aggregator: Initial { context, message } }
456 }
457
458 pub fn include_signer(
471 &mut self,
472 participant_index: u32,
473 published_commitment_share: (RistrettoPoint, RistrettoPoint),
474 public_key: IndividualPublicKey)
475 {
476 assert_eq!(participant_index, public_key.index,
477 "Tried to add signer with participant index {}, but public key is for participant with index {}",
478 participant_index, public_key.index);
479
480 self.state.signers.push(Signer { participant_index, published_commitment_share });
481 self.state.public_keys.insert(&public_key.index, public_key.share);
482 }
483
484 pub fn get_signers<'sa>(&'sa mut self) -> &'sa Vec<Signer> {
490 self.state.signers.sort();
493 self.state.signers.dedup();
494
495 &self.state.signers
496 }
497
498 pub fn get_remaining_signers(&self) -> Vec<Signer> {
511 let mut remaining_signers: Vec<Signer> = Vec::new();
512
513 for signer in self.state.signers.iter() {
514 if self.state.partial_signatures.get(&signer.participant_index).is_none() {
515 remaining_signers.push(*signer);
516 }
517 }
518 remaining_signers.sort();
519 remaining_signers.dedup();
520 remaining_signers
521 }
522
523 pub fn include_partial_signature(&mut self, partial_signature: PartialThresholdSignature) {
525 self.state.partial_signatures.insert(&partial_signature.index, partial_signature.z);
526 }
527
528 pub fn finalize(mut self) -> Result<SignatureAggregator<Finalized>, HashMap<u32, &'static str>> {
540 let mut misbehaving_participants: HashMap<u32, &'static str> = HashMap::new();
541 let remaining_signers = self.get_remaining_signers();
542
543 if ! remaining_signers.is_empty() {
547 misbehaving_participants.insert(0, "Missing remaining signer(s)");
549
550 for signer in remaining_signers.iter() {
551 misbehaving_participants.insert(signer.participant_index, "Missing partial signature");
552 }
553 }
554
555 self.state.signers = self.get_signers().clone();
557
558 for signer in self.state.signers.iter() {
559 if self.state.public_keys.get(&signer.participant_index).is_none() {
560 misbehaving_participants.insert(signer.participant_index, "Missing public key");
562 }
563 }
564
565 if ! misbehaving_participants.is_empty() {
566 return Err(misbehaving_participants);
567 }
568
569 let message_hash = compute_message_hash(&self.aggregator.context, &self.aggregator.message);
570
571 Ok(SignatureAggregator { state: self.state, aggregator: Finalized { message_hash } })
572 }
573}
574
575impl SignatureAggregator<Finalized> {
576 pub fn aggregate(&self) -> Result<ThresholdSignature, HashMap<u32, &'static str>> {
584 let mut misbehaving_participants: HashMap<u32, &'static str> = HashMap::new();
585
586 let (_, Rs) = compute_binding_factors_and_group_commitment(&self.aggregator.message_hash, &self.state.signers);
587 let R: RistrettoPoint = Rs.values().sum();
588 let c = compute_challenge(&self.aggregator.message_hash, &self.state.group_key, &R);
589 let all_participant_indices: Vec<u32> = self.state.signers.iter().map(|x| x.participant_index).collect();
590 let mut z = Scalar::zero();
591
592 for signer in self.state.signers.iter() {
593 let lambda = calculate_lagrange_coefficients(&signer.participant_index, &all_participant_indices).unwrap();
605
606 let partial_sig = self.state.partial_signatures.get(&signer.participant_index).unwrap();
610
611 let Y_i = self.state.public_keys.get(&signer.participant_index).unwrap();
613
614 let check = &RISTRETTO_BASEPOINT_TABLE * partial_sig;
615
616 let R_i = Rs.get(&signer.participant_index).unwrap();
619
620 if check == R_i + (Y_i * (c * lambda)) {
621 z += partial_sig;
622 } else {
623 misbehaving_participants.insert(signer.participant_index, "Incorrect partial signature");
625 }
626 }
627
628 match ! misbehaving_participants.is_empty() {
629 true => Err(misbehaving_participants),
630 false => Ok(ThresholdSignature {z, R}),
631 }
632 }
633}
634
635impl ThresholdSignature {
636 pub fn verify(&self, group_key: &GroupKey, message_hash: &[u8; 64]) -> Result<(), ()> {
644 let c_prime = compute_challenge(&message_hash, &group_key, &self.R);
645 let R_prime = RistrettoPoint::vartime_double_scalar_mul_basepoint(&c_prime, &-group_key.0, &self.z);
646
647 match self.R.compress() == R_prime.compress() {
648 true => Ok(()),
649 false => Err(()),
650 }
651 }
652}
653
654#[cfg(test)]
655mod test {
656 use super::*;
657
658 use crate::keygen::Participant;
659 use crate::keygen::{DistributedKeyGeneration, RoundOne};
660 use crate::precomputation::generate_commitment_share_lists;
661
662 use curve25519_dalek::traits::Identity;
663
664 use rand::rngs::OsRng;
665
666 #[test]
667 fn signing_and_verification_single_party() {
668 let params = Parameters { n: 1, t: 1 };
669
670 let (p1, p1coeffs) = Participant::new(¶ms, 1);
671
672 p1.proof_of_secret_key.verify(&p1.index, &p1.commitments[0]).unwrap();
673
674 let mut p1_other_participants: Vec<Participant> = Vec::new();
675 let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
676 &p1.index,
677 &p1coeffs,
678 &mut p1_other_participants).unwrap();
679 let p1_my_secret_shares = Vec::new();
680 let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
681 let result = p1_state.finish(p1.public_key().unwrap());
682
683 assert!(result.is_ok());
684
685 let (group_key, p1_sk) = result.unwrap();
686
687 let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
688 let message = b"This is a test of the tsunami alert system. This is only a test.";
689 let (p1_public_comshares, mut p1_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 1, 1);
690
691 let mut aggregator = SignatureAggregator::new(params, group_key, &context[..], &message[..]);
692
693 aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
694
695 let signers = aggregator.get_signers();
696 let message_hash = compute_message_hash(&context[..], &message[..]);
697
698 let p1_partial = p1_sk.sign(&message_hash, &group_key, &mut p1_secret_comshares, 0, signers).unwrap();
699
700 aggregator.include_partial_signature(p1_partial);
701
702 let aggregator = aggregator.finalize().unwrap();
703 let signing_result = aggregator.aggregate();
704
705 assert!(signing_result.is_ok());
706
707 let threshold_signature = signing_result.unwrap();
708 let verification_result = threshold_signature.verify(&group_key, &message_hash);
709
710 println!("{:?}", verification_result);
711
712 assert!(verification_result.is_ok());
713 }
714
715 #[test]
716 fn signing_and_verification_1_out_of_1() {
717 let params = Parameters { n: 1, t: 1 };
718
719 let (p1, p1coeffs) = Participant::new(¶ms, 1);
720
721 let mut p1_other_participants: Vec<Participant> = Vec::with_capacity(0);
722 let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
723 &p1.index,
724 &p1coeffs,
725 &mut p1_other_participants).unwrap();
726 let p1_my_secret_shares = Vec::with_capacity(0);
727 let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
728
729 let (group_key, p1_sk) = p1_state.finish(p1.public_key().unwrap()).unwrap();
730
731 let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
732 let message = b"This is a test of the tsunami alert system. This is only a test.";
733 let (p1_public_comshares, mut p1_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 1, 1);
734
735 let mut aggregator = SignatureAggregator::new(params, group_key, &context[..], &message[..]);
736
737 aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
738
739 let signers = aggregator.get_signers();
740 let message_hash = compute_message_hash(&context[..], &message[..]);
741
742 let p1_partial = p1_sk.sign(&message_hash, &group_key, &mut p1_secret_comshares, 0, signers).unwrap();
743
744 aggregator.include_partial_signature(p1_partial);
745
746 let aggregator = aggregator.finalize().unwrap();
747 let threshold_signature = aggregator.aggregate().unwrap();
748 let verification_result = threshold_signature.verify(&group_key, &message_hash);
749
750 assert!(verification_result.is_ok());
751 }
752
753 #[test]
754 fn signing_and_verification_1_out_of_2() {
755 let params = Parameters { n: 2, t: 1 };
756
757 let (p1, p1coeffs) = Participant::new(¶ms, 1);
758 let (p2, p2coeffs) = Participant::new(¶ms, 2);
759
760 let mut p1_other_participants: Vec<Participant> = vec!(p2.clone());
761 let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
762 &p1.index,
763 &p1coeffs,
764 &mut p1_other_participants).unwrap();
765 let p1_their_secret_shares = p1_state.their_secret_shares().unwrap();
766
767 let mut p2_other_participants: Vec<Participant> = vec!(p1.clone());
768 let p2_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
769 &p2.index,
770 &p2coeffs,
771 &mut p2_other_participants).unwrap();
772 let p2_their_secret_shares = p2_state.their_secret_shares().unwrap();
773
774 let p1_my_secret_shares = vec!(p2_their_secret_shares[0].clone()); let p2_my_secret_shares = vec!(p1_their_secret_shares[0].clone());
776
777 let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
778 let p2_state = p2_state.to_round_two(p2_my_secret_shares).unwrap();
779
780 let (group_key, p1_sk) = p1_state.finish(p1.public_key().unwrap()).unwrap();
781 let (_, _p2_sk) = p2_state.finish(p2.public_key().unwrap()).unwrap();
782
783 let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
784 let message = b"This is a test of the tsunami alert system. This is only a test.";
785 let (p1_public_comshares, mut p1_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 1, 1);
786
787 let mut aggregator = SignatureAggregator::new(params, group_key, &context[..], &message[..]);
788
789 aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
790
791 let signers = aggregator.get_signers();
792 let message_hash = compute_message_hash(&context[..], &message[..]);
793
794 let p1_partial = p1_sk.sign(&message_hash, &group_key, &mut p1_secret_comshares, 0, signers).unwrap();
795
796 aggregator.include_partial_signature(p1_partial);
797
798 let aggregator = aggregator.finalize().unwrap();
799 let threshold_signature = aggregator.aggregate().unwrap();
800 let verification_result = threshold_signature.verify(&group_key, &message_hash);
801
802 assert!(verification_result.is_ok());
803 }
804
805 #[test]
806 fn signing_and_verification_3_out_of_5() {
807 let params = Parameters { n: 5, t: 3 };
808
809 let (p1, p1coeffs) = Participant::new(¶ms, 1);
810 let (p2, p2coeffs) = Participant::new(¶ms, 2);
811 let (p3, p3coeffs) = Participant::new(¶ms, 3);
812 let (p4, p4coeffs) = Participant::new(¶ms, 4);
813 let (p5, p5coeffs) = Participant::new(¶ms, 5);
814
815 let mut p1_other_participants: Vec<Participant> = vec!(p2.clone(), p3.clone(), p4.clone(), p5.clone());
816 let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
817 &p1.index,
818 &p1coeffs,
819 &mut p1_other_participants).unwrap();
820 let p1_their_secret_shares = p1_state.their_secret_shares().unwrap();
821
822 let mut p2_other_participants: Vec<Participant> = vec!(p1.clone(), p3.clone(), p4.clone(), p5.clone());
823 let p2_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
824 &p2.index,
825 &p2coeffs,
826 &mut p2_other_participants).unwrap();
827 let p2_their_secret_shares = p2_state.their_secret_shares().unwrap();
828
829 let mut p3_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p4.clone(), p5.clone());
830 let p3_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
831 &p3.index,
832 &p3coeffs,
833 &mut p3_other_participants).unwrap();
834 let p3_their_secret_shares = p3_state.their_secret_shares().unwrap();
835
836 let mut p4_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p3.clone(), p5.clone());
837 let p4_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
838 &p4.index,
839 &p4coeffs,
840 &mut p4_other_participants).unwrap();
841 let p4_their_secret_shares = p4_state.their_secret_shares().unwrap();
842
843 let mut p5_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone(), p3.clone(), p4.clone());
844 let p5_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
845 &p5.index,
846 &p5coeffs,
847 &mut p5_other_participants).unwrap();
848 let p5_their_secret_shares = p5_state.their_secret_shares().unwrap();
849
850 let p1_my_secret_shares = vec!(p2_their_secret_shares[0].clone(), p3_their_secret_shares[0].clone(),
852 p4_their_secret_shares[0].clone(),
853 p5_their_secret_shares[0].clone());
854
855 let p2_my_secret_shares = vec!(p1_their_secret_shares[0].clone(),
856 p3_their_secret_shares[1].clone(),
857 p4_their_secret_shares[1].clone(),
858 p5_their_secret_shares[1].clone());
859
860 let p3_my_secret_shares = vec!(p1_their_secret_shares[1].clone(),
861 p2_their_secret_shares[1].clone(),
862 p4_their_secret_shares[2].clone(),
863 p5_their_secret_shares[2].clone());
864
865 let p4_my_secret_shares = vec!(p1_their_secret_shares[2].clone(),
866 p2_their_secret_shares[2].clone(),
867 p3_their_secret_shares[2].clone(),
868 p5_their_secret_shares[3].clone());
869
870 let p5_my_secret_shares = vec!(p1_their_secret_shares[3].clone(),
871 p2_their_secret_shares[3].clone(),
872 p3_their_secret_shares[3].clone(),
873 p4_their_secret_shares[3].clone());
874
875 let p1_state = p1_state.to_round_two(p1_my_secret_shares).unwrap();
876 let p2_state = p2_state.to_round_two(p2_my_secret_shares).unwrap();
877 let p3_state = p3_state.to_round_two(p3_my_secret_shares).unwrap();
878 let p4_state = p4_state.to_round_two(p4_my_secret_shares).unwrap();
879 let p5_state = p5_state.to_round_two(p5_my_secret_shares).unwrap();
880
881 let (group_key, p1_sk) = p1_state.finish(p1.public_key().unwrap()).unwrap();
882 let (_, _) = p2_state.finish(p2.public_key().unwrap()).unwrap();
883 let (_, p3_sk) = p3_state.finish(p3.public_key().unwrap()).unwrap();
884 let (_, p4_sk) = p4_state.finish(p4.public_key().unwrap()).unwrap();
885 let (_, _) = p5_state.finish(p5.public_key().unwrap()).unwrap();
886
887 let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
888 let message = b"This is a test of the tsunami alert system. This is only a test.";
889 let (p1_public_comshares, mut p1_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 1, 1);
890 let (p3_public_comshares, mut p3_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 3, 1);
891 let (p4_public_comshares, mut p4_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 4, 1);
892
893 let mut aggregator = SignatureAggregator::new(params, group_key, &context[..], &message[..]);
894
895 aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
896 aggregator.include_signer(3, p3_public_comshares.commitments[0], (&p3_sk).into());
897 aggregator.include_signer(4, p4_public_comshares.commitments[0], (&p4_sk).into());
898
899 let signers = aggregator.get_signers();
900 let message_hash = compute_message_hash(&context[..], &message[..]);
901
902 let p1_partial = p1_sk.sign(&message_hash, &group_key, &mut p1_secret_comshares, 0, signers).unwrap();
903 let p3_partial = p3_sk.sign(&message_hash, &group_key, &mut p3_secret_comshares, 0, signers).unwrap();
904 let p4_partial = p4_sk.sign(&message_hash, &group_key, &mut p4_secret_comshares, 0, signers).unwrap();
905
906 aggregator.include_partial_signature(p1_partial);
907 aggregator.include_partial_signature(p3_partial);
908 aggregator.include_partial_signature(p4_partial);
909
910 let aggregator = aggregator.finalize().unwrap();
911 let threshold_signature = aggregator.aggregate().unwrap();
912 let verification_result = threshold_signature.verify(&group_key, &message_hash);
913
914 assert!(verification_result.is_ok());
915 }
916
917 #[test]
918 fn signing_and_verification_2_out_of_3() {
919 fn do_keygen() -> Result<(Parameters, SecretKey, SecretKey, SecretKey, GroupKey), ()> {
920 let params = Parameters { n: 3, t: 2 };
921
922 let (p1, p1coeffs) = Participant::new(¶ms, 1);
923 let (p2, p2coeffs) = Participant::new(¶ms, 2);
924 let (p3, p3coeffs) = Participant::new(¶ms, 3);
925
926 p2.proof_of_secret_key.verify(&p2.index, &p2.commitments[0])?;
927 p3.proof_of_secret_key.verify(&p3.index, &p3.commitments[0])?;
928
929 let mut p1_other_participants: Vec<Participant> = vec!(p2.clone(), p3.clone());
930 let p1_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
931 &p1.index,
932 &p1coeffs,
933 &mut p1_other_participants).or(Err(()))?;
934 let p1_their_secret_shares = p1_state.their_secret_shares()?;
935
936 let mut p2_other_participants: Vec<Participant> = vec!(p1.clone(), p3.clone());
937 let p2_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
938 &p2.index,
939 &p2coeffs,
940 &mut p2_other_participants).or(Err(()))?;
941 let p2_their_secret_shares = p2_state.their_secret_shares()?;
942
943 let mut p3_other_participants: Vec<Participant> = vec!(p1.clone(), p2.clone());
944 let p3_state = DistributedKeyGeneration::<RoundOne>::new(¶ms,
945 &p3.index,
946 &p3coeffs,
947 &mut p3_other_participants).or(Err(()))?;
948 let p3_their_secret_shares = p3_state.their_secret_shares()?;
949
950 let p1_my_secret_shares = vec!(p2_their_secret_shares[0].clone(), p3_their_secret_shares[0].clone());
952 let p2_my_secret_shares = vec!(p1_their_secret_shares[0].clone(),
953 p3_their_secret_shares[1].clone());
954 let p3_my_secret_shares = vec!(p1_their_secret_shares[1].clone(),
955 p2_their_secret_shares[1].clone());
956
957 let p1_state = p1_state.to_round_two(p1_my_secret_shares)?;
958 let p2_state = p2_state.to_round_two(p2_my_secret_shares)?;
959 let p3_state = p3_state.to_round_two(p3_my_secret_shares)?;
960
961 let (p1_group_key, p1_secret_key) = p1_state.finish(p1.public_key().unwrap())?;
962 let (p2_group_key, p2_secret_key) = p2_state.finish(p2.public_key().unwrap())?;
963 let (p3_group_key, p3_secret_key) = p3_state.finish(p3.public_key().unwrap())?;
964
965 assert!(p1_group_key.0.compress() == p2_group_key.0.compress());
966 assert!(p2_group_key.0.compress() == p3_group_key.0.compress());
967
968 Ok((params, p1_secret_key, p2_secret_key, p3_secret_key, p1_group_key))
969 }
970 let keygen_protocol = do_keygen();
971
972 assert!(keygen_protocol.is_ok());
973
974 let (params, p1_sk, p2_sk, _p3_sk, group_key) = keygen_protocol.unwrap();
975
976 let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
977 let message = b"This is a test of the tsunami alert system. This is only a test.";
978 let (p1_public_comshares, mut p1_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 1, 1);
979 let (p2_public_comshares, mut p2_secret_comshares) = generate_commitment_share_lists(&mut OsRng, 2, 1);
980
981 let mut aggregator = SignatureAggregator::new(params, group_key.clone(), &context[..], &message[..]);
982
983 aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
984 aggregator.include_signer(2, p2_public_comshares.commitments[0], (&p2_sk).into());
985
986 let signers = aggregator.get_signers();
987 let message_hash = compute_message_hash(&context[..], &message[..]);
988
989 let p1_partial = p1_sk.sign(&message_hash, &group_key, &mut p1_secret_comshares, 0, signers).unwrap();
990 let p2_partial = p2_sk.sign(&message_hash, &group_key, &mut p2_secret_comshares, 0, signers).unwrap();
991
992 aggregator.include_partial_signature(p1_partial);
993 aggregator.include_partial_signature(p2_partial);
994
995 let aggregator = aggregator.finalize().unwrap();
996 let signing_result = aggregator.aggregate();
997
998 assert!(signing_result.is_ok());
999
1000 let threshold_signature = signing_result.unwrap();
1001 let verification_result = threshold_signature.verify(&group_key, &message_hash);
1002
1003 println!("{:?}", verification_result);
1004
1005 assert!(verification_result.is_ok());
1006 }
1007
1008 #[test]
1009 fn aggregator_get_signers() {
1010 let params = Parameters { n: 3, t: 2 };
1011 let context = b"CONTEXT STRING STOLEN FROM DALEK TEST SUITE";
1012 let message = b"This is a test of the tsunami alert system. This is only a test.";
1013
1014 let (p1_public_comshares, _) = generate_commitment_share_lists(&mut OsRng, 1, 1);
1015 let (p2_public_comshares, _) = generate_commitment_share_lists(&mut OsRng, 2, 1);
1016
1017 let mut aggregator = SignatureAggregator::new(params, GroupKey(RistrettoPoint::identity()), &context[..], &message[..]);
1018
1019 let p1_sk = SecretKey{ index: 1, key: Scalar::random(&mut OsRng) };
1020 let p2_sk = SecretKey{ index: 2, key: Scalar::random(&mut OsRng) };
1021
1022 aggregator.include_signer(2, p2_public_comshares.commitments[0], (&p2_sk).into());
1023 aggregator.include_signer(1, p1_public_comshares.commitments[0], (&p1_sk).into());
1024 aggregator.include_signer(2, p2_public_comshares.commitments[0], (&p2_sk).into());
1025
1026 let signers = aggregator.get_signers();
1027
1028 assert!(signers.len() == 2);
1030
1031 assert!(signers[0].participant_index == 1);
1033 assert!(signers[1].participant_index == 2);
1034
1035 assert!(signers[0].published_commitment_share.0 == p1_public_comshares.commitments[0].0);
1037 assert!(signers[0].published_commitment_share.1 == p1_public_comshares.commitments[0].1);
1038
1039 assert!(signers[1].published_commitment_share.0 == p2_public_comshares.commitments[0].0);
1041 assert!(signers[1].published_commitment_share.1 == p2_public_comshares.commitments[0].1);
1042 }
1043}