1use hashbrown::HashMap;
2use num_traits::{One, Zero};
3use polynomial::Polynomial;
4use rand_core::{CryptoRng, RngCore};
5use tracing::warn;
6
7use crate::{
8 common::{check_public_shares, Nonce, PolyCommitment, PublicNonce, Signature, SignatureShare},
9 compute,
10 curve::{
11 point::{Point, G},
12 scalar::Scalar,
13 },
14 errors::{AggregatorError, DkgError},
15 schnorr::ID,
16 taproot::SchnorrProof,
17 traits,
18 vss::VSS,
19};
20
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct Party {
24 pub party_id: u32,
26 pub key_ids: Vec<u32>,
28 num_keys: u32,
30 num_parties: u32,
31 threshold: u32,
32 f: Option<Polynomial<Scalar>>,
33 private_keys: HashMap<u32, Scalar>,
34 group_key: Point,
35 nonce: Nonce,
36}
37
38impl Party {
39 pub fn new<RNG: RngCore + CryptoRng>(
41 party_id: u32,
42 key_ids: &[u32],
43 num_parties: u32,
44 num_keys: u32,
45 threshold: u32,
46 rng: &mut RNG,
47 ) -> Self {
48 Self {
49 party_id,
50 key_ids: key_ids.to_vec(),
51 num_keys,
52 num_parties,
53 threshold,
54 f: Some(VSS::random_poly(threshold - 1, rng)),
55 private_keys: Default::default(),
56 group_key: Point::zero(),
57 nonce: Nonce::zero(),
58 }
59 }
60
61 pub fn gen_nonce<RNG: RngCore + CryptoRng>(&mut self, rng: &mut RNG) -> PublicNonce {
63 self.nonce = Nonce::random(rng);
64 PublicNonce::from(&self.nonce)
65 }
66
67 pub fn get_poly_commitment<RNG: RngCore + CryptoRng>(
69 &self,
70 rng: &mut RNG,
71 ) -> Option<PolyCommitment> {
72 if let Some(poly) = &self.f {
73 Some(PolyCommitment {
74 id: ID::new(&self.id(), &poly.data()[0], rng),
75 poly: (0..poly.data().len())
76 .map(|i| &poly.data()[i] * G)
77 .collect(),
78 })
79 } else {
80 warn!("get_poly_commitment called with no polynomial");
81 None
82 }
83 }
84
85 pub fn get_shares(&self) -> HashMap<u32, Scalar> {
87 let mut shares = HashMap::new();
88 if let Some(poly) = &self.f {
89 for i in 1..self.num_keys + 1 {
90 shares.insert(i, poly.eval(compute::id(i)));
91 }
92 } else {
93 warn!("get_poly_commitment called with no polynomial");
94 }
95 shares
96 }
97
98 pub fn compute_secret(
104 &mut self,
105 private_shares: &HashMap<u32, HashMap<u32, Scalar>>,
106 public_shares: &HashMap<u32, PolyCommitment>,
107 ) -> Result<(), DkgError> {
108 self.private_keys.clear();
109 self.group_key = Point::zero();
110
111 let threshold: usize = self.threshold.try_into()?;
112
113 let mut bad_ids = Vec::new();
114 for (i, comm) in public_shares.iter() {
115 if !check_public_shares(comm, threshold) {
116 bad_ids.push(*i);
117 } else {
118 self.group_key += comm.poly[0];
119 }
120 }
121 if !bad_ids.is_empty() {
122 return Err(DkgError::BadPublicShares(bad_ids));
123 }
124
125 let mut missing_shares = Vec::new();
126 for dst_key_id in &self.key_ids {
127 for src_key_id in public_shares.keys() {
128 match private_shares.get(dst_key_id) {
129 Some(shares) => {
130 if shares.get(src_key_id).is_none() {
131 missing_shares.push((*dst_key_id, *src_key_id));
132 }
133 }
134 None => {
135 missing_shares.push((*dst_key_id, *src_key_id));
136 }
137 }
138 }
139 }
140 if !missing_shares.is_empty() {
141 return Err(DkgError::MissingPrivateShares(missing_shares));
142 }
143
144 let mut bad_shares = Vec::new();
145 for key_id in &self.key_ids {
146 if let Some(shares) = private_shares.get(key_id) {
147 for (sender, s) in shares {
148 if let Some(comm) = public_shares.get(sender) {
149 if s * G != compute::poly(&compute::id(*key_id), &comm.poly)? {
150 bad_shares.push(*sender);
151 }
152 } else {
153 warn!("unable to check private share from {}: no corresponding public share, even though we checked for it above", sender);
154 }
155 }
156 } else {
157 warn!(
158 "no private shares for key_id {}, even though we checked for it above",
159 key_id
160 );
161 }
162 }
163 if !bad_shares.is_empty() {
164 return Err(DkgError::BadPrivateShares(bad_shares));
165 }
166
167 for key_id in &self.key_ids {
168 self.private_keys.insert(*key_id, Scalar::zero());
169 if let Some(shares) = private_shares.get(key_id) {
170 let secret = shares.values().sum();
171 self.private_keys.insert(*key_id, secret);
172 } else {
173 warn!(
174 "no private shares for key_id {}, even though we checked for it above",
175 key_id
176 );
177 }
178 }
179
180 Ok(())
181 }
182
183 pub fn id(&self) -> Scalar {
185 compute::id(self.party_id)
186 }
187
188 pub fn sign(
190 &self,
191 msg: &[u8],
192 party_ids: &[u32],
193 key_ids: &[u32],
194 nonces: &[PublicNonce],
195 ) -> SignatureShare {
196 self.sign_with_tweak(msg, party_ids, key_ids, nonces, None)
197 }
198
199 #[allow(non_snake_case)]
204 pub fn sign_with_tweak(
205 &self,
206 msg: &[u8],
207 party_ids: &[u32],
208 key_ids: &[u32],
209 nonces: &[PublicNonce],
210 tweak: Option<Scalar>,
211 ) -> SignatureShare {
212 let mut cx_sign = Scalar::one();
217 let tweaked_public_key = if let Some(t) = tweak {
218 if t != Scalar::zero() {
219 let key = compute::tweaked_public_key_from_tweak(&self.group_key, t);
220 if key.has_even_y() ^ self.group_key.has_even_y() {
221 cx_sign = -cx_sign;
222 }
223
224 key
225 } else {
226 if !self.group_key.has_even_y() {
227 cx_sign = -cx_sign;
228 }
229 self.group_key
230 }
231 } else {
232 self.group_key
233 };
234 let (_, R) = compute::intermediate(msg, party_ids, nonces);
235 let c = compute::challenge(&tweaked_public_key, &R, msg);
236 let mut r = &self.nonce.d + &self.nonce.e * compute::binding(&self.id(), nonces, msg);
237 if tweak.is_some() && !R.has_even_y() {
238 r = -r;
239 }
240
241 let mut cx = Scalar::zero();
242 for key_id in self.key_ids.iter() {
243 cx += c * &self.private_keys[key_id] * compute::lambda(*key_id, key_ids);
244 }
245
246 cx = cx_sign * cx;
247
248 let z = r + cx;
249
250 SignatureShare {
251 id: self.party_id,
252 z_i: z,
253 key_ids: self.key_ids.clone(),
254 }
255 }
256}
257
258#[derive(Clone, Debug, PartialEq)]
260pub struct Aggregator {
261 pub num_keys: u32,
263 pub threshold: u32,
265 pub poly: Vec<Point>,
267}
268
269impl Aggregator {
270 #[allow(non_snake_case)]
275 pub fn sign_with_tweak(
276 &mut self,
277 msg: &[u8],
278 nonces: &[PublicNonce],
279 sig_shares: &[SignatureShare],
280 _key_ids: &[u32],
281 tweak: Option<Scalar>,
282 ) -> Result<(Point, Signature), AggregatorError> {
283 if nonces.len() != sig_shares.len() {
284 return Err(AggregatorError::BadNonceLen(nonces.len(), sig_shares.len()));
285 }
286
287 let party_ids: Vec<u32> = sig_shares.iter().map(|ss| ss.id).collect();
288 let (_Rs, R) = compute::intermediate(msg, &party_ids, nonces);
289 let mut z = Scalar::zero();
290 let mut cx_sign = Scalar::one();
291 let aggregate_public_key = self.poly[0];
292 let tweaked_public_key = if let Some(t) = tweak {
293 if t != Scalar::zero() {
294 let key = compute::tweaked_public_key_from_tweak(&aggregate_public_key, t);
295 if !key.has_even_y() {
296 cx_sign = -cx_sign;
297 }
298 key
299 } else {
300 aggregate_public_key
301 }
302 } else {
303 aggregate_public_key
304 };
305 let c = compute::challenge(&tweaked_public_key, &R, msg);
306 for sig_share in sig_shares {
308 z += sig_share.z_i;
309 }
310
311 if let Some(t) = tweak {
313 z += cx_sign * c * t;
314 }
315
316 let sig = Signature { R, z };
317
318 Ok((tweaked_public_key, sig))
319 }
320
321 #[allow(non_snake_case)]
326 pub fn check_signature_shares(
327 &mut self,
328 msg: &[u8],
329 nonces: &[PublicNonce],
330 sig_shares: &[SignatureShare],
331 key_ids: &[u32],
332 tweak: Option<Scalar>,
333 ) -> AggregatorError {
334 if nonces.len() != sig_shares.len() {
335 return AggregatorError::BadNonceLen(nonces.len(), sig_shares.len());
336 }
337
338 let party_ids: Vec<u32> = sig_shares.iter().map(|ss| ss.id).collect();
339 let (Rs, R) = compute::intermediate(msg, &party_ids, nonces);
340 let mut bad_party_keys = Vec::new();
341 let mut bad_party_sigs = Vec::new();
342 let aggregate_public_key = self.poly[0];
343 let tweaked_public_key = if let Some(t) = tweak {
344 if t != Scalar::zero() {
345 compute::tweaked_public_key_from_tweak(&aggregate_public_key, t)
346 } else {
347 aggregate_public_key
348 }
349 } else {
350 aggregate_public_key
351 };
352 let c = compute::challenge(&tweaked_public_key, &R, msg);
353 let mut r_sign = Scalar::one();
354 let mut cx_sign = Scalar::one();
355 if let Some(t) = tweak {
356 if !R.has_even_y() {
357 r_sign = -Scalar::one();
358 }
359 if t != Scalar::zero() {
360 if !tweaked_public_key.has_even_y() ^ !aggregate_public_key.has_even_y() {
361 cx_sign = -Scalar::one();
362 }
363 } else if !aggregate_public_key.has_even_y() {
364 cx_sign = -Scalar::one();
365 }
366 }
367
368 for i in 0..sig_shares.len() {
369 let z_i = sig_shares[i].z_i;
370 let mut cx = Point::zero();
371
372 for key_id in &sig_shares[i].key_ids {
373 let kid = compute::id(*key_id);
374 let public_key = match compute::poly(&kid, &self.poly) {
375 Ok(p) => p,
376 Err(_) => {
377 bad_party_keys.push(sig_shares[i].id);
378 Point::zero()
379 }
380 };
381
382 cx += compute::lambda(*key_id, key_ids) * c * public_key;
383 }
384
385 if z_i * G != (r_sign * Rs[i] + cx_sign * cx) {
386 bad_party_sigs.push(sig_shares[i].id);
387 }
388 }
389 if !bad_party_keys.is_empty() {
390 AggregatorError::BadPartyKeys(bad_party_keys)
391 } else if !bad_party_sigs.is_empty() {
392 AggregatorError::BadPartySigs(bad_party_sigs)
393 } else {
394 AggregatorError::BadGroupSig
395 }
396 }
397}
398
399impl traits::Aggregator for Aggregator {
400 fn new(num_keys: u32, threshold: u32) -> Self {
402 Self {
403 num_keys,
404 threshold,
405 poly: Default::default(),
406 }
407 }
408
409 fn init(&mut self, comms: &HashMap<u32, PolyCommitment>) -> Result<(), AggregatorError> {
411 let threshold: usize = self.threshold.try_into()?;
412 let mut poly = Vec::with_capacity(threshold);
413
414 for i in 0..poly.capacity() {
415 poly.push(Point::zero());
416 for (_, comm) in comms {
417 poly[i] += &comm.poly[i];
418 }
419 }
420
421 self.poly = poly;
422
423 Ok(())
424 }
425
426 fn sign(
428 &mut self,
429 msg: &[u8],
430 nonces: &[PublicNonce],
431 sig_shares: &[SignatureShare],
432 key_ids: &[u32],
433 ) -> Result<Signature, AggregatorError> {
434 let (key, sig) = self.sign_with_tweak(msg, nonces, sig_shares, key_ids, None)?;
435
436 if sig.verify(&key, msg) {
437 Ok(sig)
438 } else {
439 Err(self.check_signature_shares(msg, nonces, sig_shares, key_ids, None))
440 }
441 }
442
443 fn sign_schnorr(
445 &mut self,
446 msg: &[u8],
447 nonces: &[PublicNonce],
448 sig_shares: &[SignatureShare],
449 key_ids: &[u32],
450 ) -> Result<SchnorrProof, AggregatorError> {
451 let tweak = Scalar::from(0);
452 let (key, sig) = self.sign_with_tweak(msg, nonces, sig_shares, key_ids, Some(tweak))?;
453 let proof = SchnorrProof::new(&sig);
454
455 if proof.verify(&key.x(), msg) {
456 Ok(proof)
457 } else {
458 Err(self.check_signature_shares(msg, nonces, sig_shares, key_ids, Some(tweak)))
459 }
460 }
461
462 fn sign_taproot(
464 &mut self,
465 msg: &[u8],
466 nonces: &[PublicNonce],
467 sig_shares: &[SignatureShare],
468 key_ids: &[u32],
469 merkle_root: Option<[u8; 32]>,
470 ) -> Result<SchnorrProof, AggregatorError> {
471 let tweak = compute::tweak(&self.poly[0], merkle_root);
472 let (key, sig) = self.sign_with_tweak(msg, nonces, sig_shares, key_ids, Some(tweak))?;
473 let proof = SchnorrProof::new(&sig);
474
475 if proof.verify(&key.x(), msg) {
476 Ok(proof)
477 } else {
478 Err(self.check_signature_shares(msg, nonces, sig_shares, key_ids, Some(tweak)))
479 }
480 }
481}
482
483pub type Signer = Party;
485
486impl traits::Signer for Party {
487 fn new<RNG: RngCore + CryptoRng>(
488 party_id: u32,
489 key_ids: &[u32],
490 num_signers: u32,
491 num_keys: u32,
492 threshold: u32,
493 rng: &mut RNG,
494 ) -> Self {
495 Party::new(party_id, key_ids, num_signers, num_keys, threshold, rng)
496 }
497
498 fn load(state: &traits::SignerState) -> Self {
499 assert_eq!(state.parties.len(), 1);
501
502 let party_state = &state.parties[0].1;
503
504 Self {
505 party_id: state.id,
506 key_ids: state.key_ids.clone(),
507 num_keys: state.num_keys,
508 num_parties: state.num_parties,
509 threshold: state.threshold,
510 f: party_state.polynomial.clone(),
511 private_keys: party_state
512 .private_keys
513 .iter()
514 .map(|(k, v)| (*k, *v))
515 .collect(),
516 group_key: state.group_key,
517 nonce: party_state.nonce.clone(),
518 }
519 }
520
521 fn save(&self) -> traits::SignerState {
522 let party_state = traits::PartyState {
523 polynomial: self.f.clone(),
524 private_keys: self.private_keys.iter().map(|(k, v)| (*k, *v)).collect(),
525 nonce: self.nonce.clone(),
526 };
527 traits::SignerState {
528 id: self.party_id,
529 key_ids: self.key_ids.clone(),
530 num_keys: self.num_keys,
531 num_parties: self.num_parties,
532 threshold: self.threshold,
533 group_key: self.group_key,
534 parties: vec![(self.party_id, party_state)],
535 }
536 }
537
538 fn get_id(&self) -> u32 {
539 self.party_id
540 }
541
542 fn get_key_ids(&self) -> Vec<u32> {
543 self.key_ids.clone()
544 }
545
546 fn get_num_parties(&self) -> u32 {
547 self.num_parties
548 }
549
550 fn get_poly_commitments<RNG: RngCore + CryptoRng>(&self, rng: &mut RNG) -> Vec<PolyCommitment> {
551 if let Some(poly) = self.get_poly_commitment(rng) {
552 vec![poly.clone()]
553 } else {
554 vec![]
555 }
556 }
557
558 fn reset_polys<RNG: RngCore + CryptoRng>(&mut self, rng: &mut RNG) {
559 self.f = Some(VSS::random_poly(self.threshold - 1, rng));
560 }
561
562 fn clear_polys(&mut self) {
563 self.f = None;
564 }
565
566 fn get_shares(&self) -> HashMap<u32, HashMap<u32, Scalar>> {
567 let mut shares = HashMap::new();
568
569 shares.insert(self.party_id, self.get_shares());
570
571 shares
572 }
573
574 fn compute_secrets(
575 &mut self,
576 private_shares: &HashMap<u32, HashMap<u32, Scalar>>,
577 polys: &HashMap<u32, PolyCommitment>,
578 ) -> Result<(), HashMap<u32, DkgError>> {
579 let mut key_shares = HashMap::new();
581 for dest_key_id in self.get_key_ids() {
582 let mut shares = HashMap::new();
583 for (src_party_id, signer_shares) in private_shares.iter() {
584 if let Some(signer_share) = signer_shares.get(&dest_key_id) {
585 shares.insert(*src_party_id, *signer_share);
586 }
587 }
588 key_shares.insert(dest_key_id, shares);
589 }
590
591 match self.compute_secret(&key_shares, polys) {
592 Ok(()) => Ok(()),
593 Err(dkg_error) => {
594 let mut dkg_errors = HashMap::new();
595 dkg_errors.insert(self.party_id, dkg_error);
596 Err(dkg_errors)
597 }
598 }
599 }
600
601 fn gen_nonces<RNG: RngCore + CryptoRng>(&mut self, rng: &mut RNG) -> Vec<PublicNonce> {
602 vec![self.gen_nonce(rng)]
603 }
604
605 fn compute_intermediate(
606 msg: &[u8],
607 signer_ids: &[u32],
608 _key_ids: &[u32],
609 nonces: &[PublicNonce],
610 ) -> (Vec<Point>, Point) {
611 compute::intermediate(msg, signer_ids, nonces)
612 }
613
614 fn sign(
615 &self,
616 msg: &[u8],
617 signer_ids: &[u32],
618 key_ids: &[u32],
619 nonces: &[PublicNonce],
620 ) -> Vec<SignatureShare> {
621 vec![self.sign(msg, signer_ids, key_ids, nonces)]
622 }
623
624 fn sign_schnorr(
625 &self,
626 msg: &[u8],
627 signer_ids: &[u32],
628 key_ids: &[u32],
629 nonces: &[PublicNonce],
630 ) -> Vec<SignatureShare> {
631 vec![self.sign_with_tweak(msg, signer_ids, key_ids, nonces, Some(Scalar::from(0)))]
632 }
633
634 fn sign_taproot(
635 &self,
636 msg: &[u8],
637 signer_ids: &[u32],
638 key_ids: &[u32],
639 nonces: &[PublicNonce],
640 merkle_root: Option<[u8; 32]>,
641 ) -> Vec<SignatureShare> {
642 let tweak = compute::tweak(&self.group_key, merkle_root);
643 vec![self.sign_with_tweak(msg, signer_ids, key_ids, nonces, Some(tweak))]
644 }
645}
646
647pub mod test_helpers {
649 use crate::common::{PolyCommitment, PublicNonce};
650 use crate::errors::DkgError;
651 use crate::traits::Signer;
652 use crate::v2;
653 use crate::v2::SignatureShare;
654
655 use hashbrown::HashMap;
656 use rand_core::{CryptoRng, RngCore};
657
658 pub fn dkg<RNG: RngCore + CryptoRng>(
660 signers: &mut [v2::Party],
661 rng: &mut RNG,
662 ) -> Result<HashMap<u32, PolyCommitment>, HashMap<u32, DkgError>> {
663 let mut polys: HashMap<u32, PolyCommitment> = Default::default();
664 for signer in signers.iter() {
665 if let Some(poly) = signer.get_poly_commitment(rng) {
666 polys.insert(signer.get_id(), poly);
667 }
668 }
669
670 let mut broadcast_shares = Vec::new();
672 for party in signers.iter() {
673 broadcast_shares.push((party.party_id, party.get_shares()));
674 }
675
676 let mut secret_errors = HashMap::new();
679 for party in signers.iter_mut() {
680 let mut party_shares = HashMap::new();
681 for key_id in party.key_ids.clone() {
682 let mut key_shares = HashMap::new();
683
684 for (id, shares) in &broadcast_shares {
685 if let Some(share) = shares.get(&key_id) {
686 key_shares.insert(*id, *share);
687 }
688 }
689
690 party_shares.insert(key_id, key_shares);
691 }
692
693 if let Err(secret_error) = party.compute_secret(&party_shares, &polys) {
694 secret_errors.insert(party.party_id, secret_error);
695 }
696 }
697
698 if secret_errors.is_empty() {
699 Ok(polys)
700 } else {
701 Err(secret_errors)
702 }
703 }
704
705 pub fn sign<RNG: RngCore + CryptoRng>(
707 msg: &[u8],
708 signers: &mut [v2::Party],
709 rng: &mut RNG,
710 ) -> (Vec<PublicNonce>, Vec<SignatureShare>, Vec<u32>) {
711 let party_ids: Vec<u32> = signers.iter().map(|s| s.party_id).collect();
712 let key_ids: Vec<u32> = signers.iter().flat_map(|s| s.key_ids.clone()).collect();
713 let nonces: Vec<PublicNonce> = signers.iter_mut().map(|s| s.gen_nonce(rng)).collect();
714 let shares = signers
715 .iter()
716 .map(|s| s.sign(msg, &party_ids, &key_ids, &nonces))
717 .collect();
718
719 (nonces, shares, key_ids)
720 }
721}
722
723#[cfg(test)]
724mod tests {
725 use crate::util::create_rng;
726 use crate::{
727 traits::{
728 self, test_helpers::run_compute_secrets_missing_private_shares, Aggregator, Signer,
729 },
730 v2,
731 };
732
733 #[test]
734 fn party_save_load() {
735 let mut rng = create_rng();
736 let key_ids = [1, 2, 3];
737 let n: u32 = 10;
738 let t: u32 = 7;
739
740 let signer = v2::Party::new(0, &key_ids, 1, n, t, &mut rng);
741
742 let state = signer.save();
743 let loaded = v2::Party::load(&state);
744
745 assert_eq!(signer, loaded);
746 }
747
748 #[test]
749 fn clear_polys() {
750 let mut rng = create_rng();
751 let key_ids = [1, 2, 3];
752 let n: u32 = 10;
753 let t: u32 = 7;
754
755 let mut signer = v2::Party::new(0, &key_ids, 1, n, t, &mut rng);
756
757 assert_eq!(signer.get_poly_commitments(&mut rng).len(), 1);
758 assert_eq!(signer.get_shares().len(), usize::try_from(n).unwrap());
759
760 signer.clear_polys();
761
762 assert_eq!(signer.get_poly_commitments(&mut rng).len(), 0);
763 assert_eq!(signer.get_shares().len(), 0);
764 }
765
766 #[test]
767 fn aggregator_sign() {
768 let mut rng = create_rng();
769 let msg = "It was many and many a year ago".as_bytes();
770 let n_k: u32 = 10;
771 let t: u32 = 7;
772 let party_key_ids: Vec<Vec<u32>> = [
773 [1, 2, 3].to_vec(),
774 [4, 5].to_vec(),
775 [6, 7, 8].to_vec(),
776 [9, 10].to_vec(),
777 ]
778 .to_vec();
779 let n_p = party_key_ids.len().try_into().unwrap();
780 let mut signers: Vec<v2::Party> = party_key_ids
781 .iter()
782 .enumerate()
783 .map(|(pid, pkids)| {
784 v2::Party::new(pid.try_into().unwrap(), pkids, n_p, n_k, t, &mut rng)
785 })
786 .collect();
787
788 let comms = match traits::test_helpers::dkg(&mut signers, &mut rng) {
789 Ok(comms) => comms,
790 Err(secret_errors) => {
791 panic!("Got secret errors from DKG: {:?}", secret_errors);
792 }
793 };
794
795 {
797 let mut signers = [signers[0].clone(), signers[1].clone(), signers[3].clone()].to_vec();
798 let mut sig_agg = v2::Aggregator::new(n_k, t);
799
800 sig_agg.init(&comms).expect("aggregator init failed");
801
802 let (nonces, sig_shares, key_ids) = v2::test_helpers::sign(msg, &mut signers, &mut rng);
803 if let Err(e) = sig_agg.sign(msg, &nonces, &sig_shares, &key_ids) {
804 panic!("Aggregator sign failed: {:?}", e);
805 }
806 }
807 }
808
809 #[test]
810 pub fn run_compute_secrets_missing_shares() {
812 run_compute_secrets_missing_private_shares::<v2::Signer>()
813 }
814
815 #[test]
816 pub fn bad_polynomial_length() {
818 let gt = |t| t + 1;
819 let lt = |t| t - 1;
820 traits::test_helpers::bad_polynomial_length::<v2::Signer, _>(gt);
821 traits::test_helpers::bad_polynomial_length::<v2::Signer, _>(lt);
822 }
823
824 #[test]
825 pub fn bad_polynomial_commitment() {
827 traits::test_helpers::bad_polynomial_commitment::<v2::Signer>();
828 }
829}