use crate::{
bls12381::{
dkg::{ops::generate_shares, Error},
primitives::{group::Share, poly, variant::Variant},
},
PublicKey,
};
use commonware_utils::{quorum, set::Ordered};
use rand_core::CryptoRngCore;
use std::{collections::HashSet, marker::PhantomData};
#[derive(Clone)]
pub struct Output {
pub active: Ordered<u32>,
pub inactive: Ordered<u32>,
}
pub struct Dealer<P: PublicKey, V: Variant> {
threshold: u32,
players: Ordered<P>,
acks: HashSet<u32>,
_phantom: PhantomData<V>,
}
impl<P: PublicKey, V: Variant> Dealer<P, V> {
pub fn new<R: CryptoRngCore>(
rng: &mut R,
share: Option<Share>,
players: Ordered<P>,
) -> (Self, poly::Public<V>, Ordered<Share>) {
let players_len = players.len() as u32;
let threshold = quorum(players_len);
let (commitment, shares) = generate_shares::<_, V>(rng, share, players_len, threshold);
(
Self {
threshold,
players,
acks: HashSet::new(),
_phantom: PhantomData,
},
commitment,
shares.into_iter().collect(),
)
}
pub fn ack(&mut self, player: P) -> Result<(), Error> {
let idx = match self.players.position(&player) {
Some(player) => player,
None => return Err(Error::PlayerInvalid),
};
match self.acks.insert(idx as u32) {
true => Ok(()),
false => Err(Error::DuplicateAck),
}
}
pub fn finalize(self) -> Option<Output> {
if self.acks.len() < self.threshold as usize {
return None;
}
let mut active = Vec::new();
let mut inactive = Vec::new();
for player in 0..self.players.len() as u32 {
if self.acks.contains(&player) {
active.push(player);
} else {
inactive.push(player);
}
}
Some(Output {
active: active.into_iter().collect(),
inactive: inactive.into_iter().collect(),
})
}
}