use crate::{
DkgResult, Error, Participant, ParticipantImpl, ParticipantType, RefreshParticipantImpl, Round,
Round1Data, Round1OutputGenerator, RoundOutputGenerator, ScalarHash, SecretParticipantImpl,
Signature,
};
use elliptic_curve::group::GroupEncoding;
use elliptic_curve::subtle::{Choice, ConditionallySelectable};
use elliptic_curve_tools::SumOfProducts;
impl<I, G> Participant<I, G>
where
I: ParticipantImpl<G> + Default,
G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
G::Scalar: ScalarHash,
{
pub(crate) fn round1(&mut self) -> DkgResult<RoundOutputGenerator<G>> {
let k = I::random_value(rand::rng());
let r_i = self.message_generator * k;
let signature = self.compute_signature(k, r_i);
let self_round1_data = Round1Data {
sender_ordinal: self.ordinal,
sender_id: self.id,
sender_type: self.participant_impl.get_type(),
feldman_commitments: self.feldman_verifiers.clone(),
verifying_share: self.verifying_share,
signature,
};
self.received_round1_data[self.ordinal] = Some(self_round1_data);
self.round = Round::Two;
Ok(RoundOutputGenerator::Round1(Round1OutputGenerator {
participant_ids: self.all_participant_ids.clone(),
sender_type: self.participant_impl.get_type(),
sender_ordinal: self.ordinal,
sender_id: self.id,
feldman_commitments: self.feldman_verifiers.clone(),
verifying_share: self.verifying_share,
signature,
}))
}
pub(crate) fn compute_signature(&self, k: G::Scalar, r_i: G) -> Signature<G> {
let participant_type = self.participant_impl.get_type();
let context = crate::SchnorrContext {
ordinal: self.ordinal,
id: &self.id,
participant_type: &participant_type,
threshold: self.threshold,
limit: self.limit,
message_generator: &self.message_generator,
feldman_verifiers: &self.feldman_verifiers,
verifying_share: &self.verifying_share,
all_participant_ids: &self.all_participant_ids,
};
let bytes = crate::bytes_for_schnorr(&context, &r_i);
let challenge = G::Scalar::hash_to_scalar(&bytes);
let s = k + challenge * self.original_secret;
Signature { r: r_i, s }
}
pub(crate) fn verify_signature(&self, round1data: &Round1Data<G>) -> DkgResult<()> {
crate::verify_signature(
crate::SchnorrContext {
ordinal: round1data.sender_ordinal,
id: &round1data.sender_id,
participant_type: &round1data.sender_type,
threshold: self.threshold,
limit: self.limit,
message_generator: &self.message_generator,
feldman_verifiers: &round1data.feldman_commitments,
verifying_share: &round1data.verifying_share,
all_participant_ids: &self.all_participant_ids,
},
&round1data.signature,
)
}
pub(crate) fn receive_round1data(&mut self, data: Round1Data<G>) -> DkgResult<()> {
if self.round > Round::Two {
return Err(Error::Round(format!(
"Round {}: invalid round payload received",
Round::One
)));
}
if self
.received_round1_data
.get(data.sender_ordinal)
.is_some_and(Option::is_some)
{
return Err(Error::Round(format!(
"Round {}: sender has already sent data",
Round::One
)));
}
self.check_sending_participant_id(Round::One, data.sender_ordinal, data.sender_id)?;
if data.feldman_commitments.is_empty() {
return Err(Error::Round(format!(
"Round {}: Feldman commitments are empty",
Round::One
)));
}
if data.feldman_commitments.len() != self.threshold {
return Err(Error::Round(format!(
"Round {}: Feldman commitment count does not equal the threshold",
Round::One
)));
}
if data.feldman_commitments[1..]
.iter()
.fold(Choice::from(0u8), |acc, c| acc | c.is_identity())
.into()
{
return Err(Error::Round(format!(
"Round {}: Feldman commitments contain the identity point",
Round::One
)));
}
let feldman_valid = match data.sender_type {
ParticipantType::Secret => {
SecretParticipantImpl::check_feldman_verifier(*data.feldman_commitments[0])
&& data.feldman_commitments[0].0 == data.verifying_share
}
ParticipantType::Refresh => {
RefreshParticipantImpl::check_feldman_verifier(*data.feldman_commitments[0])
&& data.feldman_commitments[0].0 != data.verifying_share
}
};
if !feldman_valid {
return Err(Error::Round(format!(
"Round {}: Feldman commitment is not a valid verifier",
Round::One
)));
}
self.verify_signature(&data)?;
let sender_ordinal = data.sender_ordinal;
self.received_round1_data[sender_ordinal] = Some(data);
Ok(())
}
}