dkg_mirror/tests/
mod.rs

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
14/// FROST key generation testing utility.
15pub mod pedpop;
16use pedpop::pedpop_gen;
17
18// Promotion test.
19mod promote;
20use promote::test_generator_promotion;
21
22/// Constant amount of participants to use when testing.
23pub const PARTICIPANTS: u16 = 5;
24/// Constant threshold of participants to use when testing.
25pub const THRESHOLD: u16 = ((PARTICIPANTS * 2) / 3) + 1;
26
27/// Clone a map without a specific value.
28pub 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
37/// Recover the secret from a collection of keys.
38///
39/// This will panic if no keys, an insufficient amount of keys, or the wrong keys are provided.
40pub 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
52/// Generate threshold keys for tests.
53pub 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
70/// Generate MuSig keys for tests.
71pub 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
92/// Run the test suite on a ciphersuite.
93pub 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}