use core::marker::PhantomData; use std::collections::HashMap; use zeroize::{Zeroize, Zeroizing}; use rand_core::OsRng; use ciphersuite::{ group::{ff::Field, Group}, Ciphersuite, Ristretto, }; use dkg::*; use dkg_recovery::recover_key; use crate::{GeneratorPromotion, GeneratorProof}; #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] struct AltGenerator { _curve: PhantomData, } impl Ciphersuite for AltGenerator { type F = C::F; type G = C::G; type H = C::H; const ID: &'static [u8] = b"Alternate Ciphersuite"; fn generator() -> Self::G { C::G::generator() * ::hash_to_F(b"DKG Promotion Test", b"generator") } fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F { ::hash_to_F(dst, data) } } /// Clone a map without a specific value. pub fn clone_without( map: &HashMap, without: &K, ) -> HashMap { let mut res = map.clone(); res.remove(without).unwrap(); res } // Test promotion of threshold keys to another generator #[test] fn test_generator_promotion() { // Generate a set of `ThresholdKeys` const PARTICIPANTS: u16 = 5; let keys: [ThresholdKeys<_>; PARTICIPANTS as usize] = { let shares: [::F; PARTICIPANTS as usize] = core::array::from_fn(|_| ::F::random(&mut OsRng)); let verification_shares = (0 .. PARTICIPANTS) .map(|i| { ( Participant::new(i + 1).unwrap(), ::generator() * shares[usize::from(i)], ) }) .collect::>(); core::array::from_fn(|i| { ThresholdKeys::new( ThresholdParams::new( PARTICIPANTS, PARTICIPANTS, Participant::new(u16::try_from(i + 1).unwrap()).unwrap(), ) .unwrap(), Interpolation::Constant(vec![::F::ONE; PARTICIPANTS as usize]), Zeroizing::new(shares[i]), verification_shares.clone(), ) .unwrap() }) }; // Perform the promotion let mut promotions = HashMap::new(); let mut proofs = HashMap::new(); for keys in &keys { let i = keys.params().i(); let (promotion, proof) = GeneratorPromotion::<_, AltGenerator>::promote(&mut OsRng, keys.clone()); promotions.insert(i, promotion); proofs.insert( i, GeneratorProof::::read::<&[u8]>(&mut proof.serialize().as_ref()).unwrap(), ); } // Complete the promotion, and verify it worked let new_group_key = AltGenerator::::generator() * *recover_key(&keys).unwrap(); for (i, promoting) in promotions.drain() { let promoted = promoting.complete(&clone_without(&proofs, &i)).unwrap(); assert_eq!(keys[usize::from(u16::from(i) - 1)].params(), promoted.params()); assert_eq!( keys[usize::from(u16::from(i) - 1)].original_secret_share(), promoted.original_secret_share() ); assert_eq!(new_group_key, promoted.group_key()); for l in 0 .. PARTICIPANTS { let verification_share = promoted.original_verification_share(Participant::new(l + 1).unwrap()); assert_eq!( AltGenerator::::generator() * **keys[usize::from(l)].original_secret_share(), verification_share ); } } }