1use core::ops::Deref;
2use std::collections::HashMap;
3
4use zeroize::Zeroizing;
5use rand_core::{RngCore, CryptoRng};
6
7use ciphersuite::{group::ff::Field, Ciphersuite};
8
9use crate::{Participant, ThresholdCore, ThresholdKeys, lagrange, musig::musig as musig_fn};
10
11mod musig;
12pub use musig::test_musig;
13
14pub mod pedpop;
16use pedpop::pedpop_gen;
17
18mod promote;
20use promote::test_generator_promotion;
21
22pub const PARTICIPANTS: u16 = 5;
24pub const THRESHOLD: u16 = ((PARTICIPANTS * 2) / 3) + 1;
26
27pub fn clone_without<K: Clone + core::cmp::Eq + core::hash::Hash, V: Clone>(
29 map: &HashMap<K, V>,
30 without: &K,
31) -> HashMap<K, V> {
32 let mut res = map.clone();
33 res.remove(without).unwrap();
34 res
35}
36
37pub fn recover_key<C: Ciphersuite>(keys: &HashMap<Participant, ThresholdKeys<C>>) -> C::F {
41 let first = keys.values().next().expect("no keys provided");
42 assert!(keys.len() >= first.params().t().into(), "not enough keys provided");
43 let included = keys.keys().copied().collect::<Vec<_>>();
44
45 let group_private = keys.iter().fold(C::F::ZERO, |accum, (i, keys)| {
46 accum + (lagrange::<C::F>(*i, &included) * keys.secret_share().deref())
47 });
48 assert_eq!(C::generator() * group_private, first.group_key(), "failed to recover keys");
49 group_private
50}
51
52pub fn key_gen<R: RngCore + CryptoRng, C: Ciphersuite>(
54 rng: &mut R,
55) -> HashMap<Participant, ThresholdKeys<C>> {
56 let res = pedpop_gen(rng)
57 .drain()
58 .map(|(i, core)| {
59 assert_eq!(
60 &ThresholdCore::<C>::read::<&[u8]>(&mut core.serialize().as_ref()).unwrap(),
61 &core
62 );
63 (i, ThresholdKeys::new(core))
64 })
65 .collect();
66 assert_eq!(C::generator() * recover_key(&res), res[&Participant(1)].group_key());
67 res
68}
69
70pub fn musig_key_gen<R: RngCore + CryptoRng, C: Ciphersuite>(
72 rng: &mut R,
73) -> HashMap<Participant, ThresholdKeys<C>> {
74 let mut keys = vec![];
75 let mut pub_keys = vec![];
76 for _ in 0 .. PARTICIPANTS {
77 let key = Zeroizing::new(C::F::random(&mut *rng));
78 pub_keys.push(C::generator() * *key);
79 keys.push(key);
80 }
81
82 let mut res = HashMap::new();
83 for key in keys {
84 let these_keys = musig_fn::<C>(b"Test MuSig Key Gen", &key, &pub_keys).unwrap();
85 res.insert(these_keys.params().i(), ThresholdKeys::new(these_keys));
86 }
87
88 assert_eq!(C::generator() * recover_key(&res), res[&Participant(1)].group_key());
89 res
90}
91
92pub fn test_ciphersuite<R: RngCore + CryptoRng, C: Ciphersuite>(rng: &mut R) {
94 key_gen::<_, C>(rng);
95 test_generator_promotion::<_, C>(rng);
96}
97
98#[test]
99fn test_with_ristretto() {
100 test_ciphersuite::<_, ciphersuite::Ristretto>(&mut rand_core::OsRng);
101}