#![allow( clippy::unwrap_used, clippy::indexing_slicing, clippy::missing_panics_doc )] use std::collections::HashMap; use rand::seq::SliceRandom as _; use rand_core::OsRng; use threshold_signatures::{ self, Ciphersuite, Element, KeygenOutput, ReconstructionThreshold, Scalar, errors::ProtocolError, frost_core::VerifyingKey, keygen, participants::Participant, protocol::{Action, Protocol}, reshare, }; pub type GenProtocol = Vec<(Participant, Box>)>; pub fn generate_participants(number: u32) -> Vec { (0..number).map(Participant::from).collect::>() } pub fn choose_coordinator_at_random(participants: &[Participant]) -> Participant { *participants .choose(&mut OsRng) .expect("participants list is not empty") } /// Run a protocol to completion, synchronously. /// /// This works by executing each participant in order. /// /// The reason this function exists is as a convenient testing utility. /// In practice each protocol participant is likely running on a different machine, /// and so orchestrating the protocol would happen differently. pub fn run_protocol( mut ps: Vec<(Participant, Box>)>, ) -> Result, ProtocolError> { let indices: HashMap = ps.iter().enumerate().map(|(i, (p, _))| (*p, i)).collect(); let size = ps.len(); let mut out = Vec::with_capacity(size); while out.len() < size { for i in 0..size { while { let action = ps[i].1.poke()?; match action { Action::Wait => false, // Keep poking; a yield needs no executor here. Action::Yield => true, Action::SendMany(m) => { for j in 0..size { if i == j { continue; } let from = ps[i].0; ps[j].1.message(from, m.clone())?; } true } Action::SendPrivate(to, m) => { let from = ps[i].0; ps[indices[&to]].1.message(from, m)?; true } Action::Return(r) => { out.push((ps[i].0, r)); false } } } {} } } Ok(out) } #[allow(clippy::missing_panics_doc)] pub fn run_keygen( participants: &[Participant], threshold: ReconstructionThreshold, ) -> HashMap> where Element: std::marker::Send, Scalar: std::marker::Send, { let protocols: GenProtocol> = participants .iter() .map(|p| { let protocol: Box>> = Box::new(keygen::(participants, *p, threshold, OsRng).unwrap()); (*p, protocol) }) .collect(); run_protocol(protocols).unwrap().into_iter().collect() } #[allow(clippy::missing_panics_doc)] pub fn run_reshare( participants: &[Participant], pub_key: &VerifyingKey, keys: &[(Participant, KeygenOutput)], old_threshold: ReconstructionThreshold, new_threshold: ReconstructionThreshold, new_participants: &[Participant], ) -> HashMap> where Element: Send, Scalar: Send, { assert!(!new_participants.is_empty()); let mut setup = vec![]; for new_participant in new_participants { let mut is_break = false; for (p, k) in keys { if p == new_participant { setup.push((*p, (Some(k.private_share), k.public_key))); is_break = true; break; } } if !is_break { setup.push((*new_participant, (None, *pub_key))); } } let protocols: GenProtocol> = setup .iter() .map(|(p, out)| { let protocol: Box>> = Box::new( reshare( participants, old_threshold, out.0, out.1, new_participants, new_threshold, *p, OsRng, ) .unwrap(), ); (*p, protocol) }) .collect(); run_protocol(protocols).unwrap().into_iter().collect() }