frost-dkg 0.6.0

An implementation of the FROST Distributed Key Generation protocol
Documentation
use crate::{
    DkgResult, Error, Participant, ParticipantImpl, ParticipantType, Round, RoundOutputGenerator,
    ScalarHash, SecretShare,
};
use elliptic_curve::Field;
use elliptic_curve::group::GroupEncoding;
use elliptic_curve::subtle::ConditionallySelectable;
use elliptic_curve_tools::SumOfProducts;
use vsss_rs::{IdentifierPrimeField, Share, ValueGroup};

impl<I, G> Participant<I, G>
where
    I: ParticipantImpl<G> + Default,
    G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
    G::Scalar: ScalarHash,
{
    pub(crate) fn round3_ready(&self) -> bool {
        self.round == Round::Three
            && self.received_round2_data.iter().flatten().count() >= self.threshold
    }

    pub(crate) fn round3(&mut self) -> DkgResult<RoundOutputGenerator<G>> {
        if !self.round3_ready() {
            return Err(Error::Round(format!(
                "Round 3 is not ready: not enough data has been received from other participants; need {} more",
                self.threshold - self.received_round2_data.iter().flatten().count()
            )));
        }

        let mut secret_share = SecretShare::<G::Scalar>::with_identifier_and_value(
            self.id,
            IdentifierPrimeField(G::Scalar::ZERO),
        );
        let mut public_key = ValueGroup::<G>::default();
        let original_share = self
            .received_round2_data
            .get(self.ordinal)
            .and_then(Option::as_ref)
            .ok_or_else(|| {
                Error::Round(format!(
                    "Round {}: participant does not have its own round 2 data",
                    Round::Three
                ))
            })?
            .secret_share;

        let mut all_refresh = true;

        for (ordinal, round2data) in self.received_round2_data.iter().enumerate() {
            let Some(round2data) = round2data else {
                continue;
            };
            let round1data = self.received_round1_data[ordinal].as_ref().ok_or_else(|| {
                Error::Round(format!(
                    "Round {}: sender has not sent round 1 data",
                    Round::Three
                ))
            })?;
            let participant_type = round1data.sender_type;
            all_refresh &= matches!(participant_type, ParticipantType::Refresh);

            public_key.0 += round1data.feldman_commitments[0].0;
            secret_share.value.0 += round2data.secret_share.value.0;
        }

        let public_key_identity = bool::from(public_key.is_identity());
        if all_refresh && !public_key_identity || !all_refresh && public_key_identity {
            return Err(Error::Round(
                "Round 3: The resulting public key is invalid".to_string(),
            ));
        }

        if secret_share.value == original_share.value {
            return Err(Error::Round(format!(
                "Round {}: The resulting secret key share is invalid",
                Round::Three
            )));
        }
        self.round = Round::Four;
        self.completed = true;
        self.public_key = public_key;
        self.secret_share = secret_share;
        Ok(RoundOutputGenerator::Round3)
    }
}