Start using a proper error for the eVRF DKG

This commit is contained in:
Luke Parker
2024-07-27 20:38:23 -04:00
parent 31ac0ac299
commit c960d6baaf
2 changed files with 85 additions and 33 deletions

View File

@@ -104,7 +104,7 @@ pub struct Participation<C: Ciphersuite> {
} }
impl<C: Ciphersuite> Participation<C> { impl<C: Ciphersuite> Participation<C> {
fn read<R: Read>(reader: &mut R, _params: ThresholdParams) -> io::Result<Self> { pub fn read<R: Read>(reader: &mut R, n: u16) -> io::Result<Self> {
// TODO: Replace `len` with some calculcation deterministic to the params // TODO: Replace `len` with some calculcation deterministic to the params
let mut len = [0; 4]; let mut len = [0; 4];
reader.read_exact(&mut len)?; reader.read_exact(&mut len)?;
@@ -122,13 +122,23 @@ impl<C: Ciphersuite> Participation<C> {
reader.read_exact(&mut proof[old_proof_len ..])?; reader.read_exact(&mut proof[old_proof_len ..])?;
} }
Ok(Self { proof, encrypted_secret_shares: todo!("TODO") }) let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
for i in (1 ..= n).map(Participant) {
encrypted_secret_shares.insert(i, C::read_F(reader)?);
}
Ok(Self { proof, encrypted_secret_shares })
} }
fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> { pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&u32::try_from(self.proof.len()).unwrap().to_le_bytes())?; writer.write_all(&u32::try_from(self.proof.len()).unwrap().to_le_bytes())?;
writer.write_all(&self.proof)?; writer.write_all(&self.proof)?;
// TODO: secret shares for i in (1 ..= u16::try_from(self.encrypted_secret_shares.len())
.expect("writing a Participation which has a n > u16::MAX"))
.map(Participant)
{
writer.write_all(self.encrypted_secret_shares[&i].to_repr().as_ref())?;
}
Ok(()) Ok(())
} }
} }
@@ -191,6 +201,28 @@ fn share_verification_statements<C: Ciphersuite>(
(g_scalar, pairs) (g_scalar, pairs)
} }
/// Errors from the eVRF DKG.
#[derive(Clone, PartialEq, Eq, Debug, thiserror::Error)]
pub enum EvrfError {
#[error("n, the amount of participants, exceeded a u16")]
TooManyParticipants,
#[error("the threshold t wasn't in range 1 <= t <= n")]
InvalidThreshold,
#[error("participating in a DKG we aren't a participant in")]
NotAParticipant,
#[error("a participant with an unrecognized ID participated")]
NonExistentParticipant,
#[error("the passed in generators did not have enough generators for this DKG")]
NotEnoughGenerators,
}
/// The result of calling EvrfDkg::verify.
pub enum VerifyResult<C: EvrfCurve> {
Valid(EvrfDkg<C>),
Invalid(Vec<Participant>),
NotEnoughParticipants,
}
/// Struct to perform/verify the DKG with. /// Struct to perform/verify the DKG with.
#[derive(Debug)] #[derive(Debug)]
pub struct EvrfDkg<C: EvrfCurve> { pub struct EvrfDkg<C: EvrfCurve> {
@@ -224,26 +256,44 @@ where
t: u16, t: u16,
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G], evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>, evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
) -> Result<Participation<C>, AcError> { ) -> Result<Participation<C>, EvrfError> {
if generators.g() != C::generator() { if generators.g() != C::generator() {
todo!("TODO"); todo!("TODO");
} }
let evrf_public_key = <C::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key.deref(); let evrf_public_key = <C::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key.deref();
let Ok(n) = u16::try_from(evrf_public_keys.len()) else { let Ok(n) = u16::try_from(evrf_public_keys.len()) else { Err(EvrfError::TooManyParticipants)? };
todo!("TODO");
};
if (t == 0) || (t > n) { if (t == 0) || (t > n) {
todo!("TODO"); Err(EvrfError::InvalidThreshold)?;
} }
if !evrf_public_keys.iter().any(|key| *key == evrf_public_key) { if !evrf_public_keys.iter().any(|key| *key == evrf_public_key) {
todo!("TODO"); Err(EvrfError::NotAParticipant)?;
}; };
let EvrfProveResult { coefficients, encryption_masks, proof } = let EvrfProveResult { coefficients, encryption_masks, proof } = match Evrf::prove(
Evrf::prove(rng, generators, evrf_private_key, context, usize::from(t), evrf_public_keys)?; rng,
generators,
evrf_private_key,
context,
usize::from(t),
evrf_public_keys,
) {
Ok(res) => res,
Err(AcError::NotEnoughGenerators) => Err(EvrfError::NotEnoughGenerators)?,
Err(
AcError::DifferingLrLengths |
AcError::InconsistentAmountOfConstraints |
AcError::ConstrainedNonExistentTerm |
AcError::ConstrainedNonExistentCommitment |
AcError::InconsistentWitness |
AcError::Ip(_) |
AcError::IncompleteProof,
) => {
panic!("failed to prove for the eVRF proof")
}
};
let mut encrypted_secret_shares = HashMap::new(); let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
for (l, encryption_mask) in (1 ..= n).map(Participant).zip(encryption_masks) { for (l, encryption_mask) in (1 ..= n).map(Participant).zip(encryption_masks) {
let share = polynomial::<C::F>(&coefficients, l); let share = polynomial::<C::F>(&coefficients, l);
encrypted_secret_shares.insert(l, *share + *encryption_mask); encrypted_secret_shares.insert(l, *share + *encryption_mask);
@@ -254,10 +304,10 @@ where
/// Check if a batch of `Participation`s are valid. /// Check if a batch of `Participation`s are valid.
/// ///
/// if any `Participation` is invalid, it will be returned in the `Err` of the result. If all /// If any `Participation` is invalid, the list of all invalid participants will be returned.
/// `Participation`s are valid and there's at least `t`, an instance of this struct (usable to /// If all `Participation`s are valid and there's at least `t`, an instance of this struct
/// obtain a threshold share of generated key) is returned. If all are valid and there's not at /// (usable to obtain a threshold share of generated key) is returned. If all are valid and
/// least `t`, an error of an empty list is returned after validation. /// there's not at least `t`, `VerifyResult::NotEnoughParticipants` is returned.
/// ///
/// This DKG is unbiased if all `n` people participate. This DKG is biased if only a threshold /// This DKG is unbiased if all `n` people participate. This DKG is biased if only a threshold
/// participate. /// participate.
@@ -268,22 +318,22 @@ where
t: u16, t: u16,
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G], evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
participations: &HashMap<Participant, Participation<C>>, participations: &HashMap<Participant, Participation<C>>,
) -> Result<Self, Vec<Participant>> { ) -> Result<VerifyResult<C>, EvrfError> {
if generators.g() != C::generator() { if generators.g() != C::generator() {
todo!("TODO"); todo!("TODO");
} }
let Ok(n) = u16::try_from(evrf_public_keys.len()) else { todo!("TODO") }; let Ok(n) = u16::try_from(evrf_public_keys.len()) else { Err(EvrfError::TooManyParticipants)? };
if (t == 0) || (t > n) { if (t == 0) || (t > n) {
todo!("TODO"); Err(EvrfError::InvalidThreshold)?;
} }
for i in participations.keys() { for i in participations.keys() {
if u16::from(*i) > n { if u16::from(*i) > n {
todo!("TODO"); Err(EvrfError::NonExistentParticipant)?;
} }
} }
let mut valid = HashMap::new(); let mut valid = HashMap::with_capacity(participations.len());
let mut faulty = HashSet::new(); let mut faulty = HashSet::new();
let mut evrf_verifier = generators.batch_verifier(); let mut evrf_verifier = generators.batch_verifier();
@@ -337,9 +387,9 @@ where
debug_assert_eq!(valid.len() + faulty.len(), participations.len()); debug_assert_eq!(valid.len() + faulty.len(), participations.len());
// Perform the batch verification of the shares // Perform the batch verification of the shares
let mut sum_encrypted_secret_shares = HashMap::new(); let mut sum_encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
let mut sum_masks = HashMap::new(); let mut sum_masks = HashMap::with_capacity(usize::from(n));
let mut all_encrypted_secret_shares = HashMap::new(); let mut all_encrypted_secret_shares = HashMap::with_capacity(usize::from(t));
{ {
let mut share_verification_statements_actual = HashMap::with_capacity(valid.len()); let mut share_verification_statements_actual = HashMap::with_capacity(valid.len());
if !{ if !{
@@ -366,7 +416,7 @@ where
share_verification_statements_actual.insert(*i, these_pairs); share_verification_statements_actual.insert(*i, these_pairs);
// Also format this data as we'd need it upon success // Also format this data as we'd need it upon success
let mut formatted_encrypted_secret_shares = HashMap::new(); let mut formatted_encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
for (j, enc_share) in encrypted_secret_shares { for (j, enc_share) in encrypted_secret_shares {
/* /*
We calculcate verification shares as the sum of the encrypted scalars, minus their We calculcate verification shares as the sum of the encrypted scalars, minus their
@@ -404,11 +454,11 @@ where
let mut faulty = faulty.into_iter().collect::<Vec<_>>(); let mut faulty = faulty.into_iter().collect::<Vec<_>>();
if !faulty.is_empty() { if !faulty.is_empty() {
faulty.sort_unstable(); faulty.sort_unstable();
Err(faulty)?; return Ok(VerifyResult::Invalid(faulty));
} }
if valid.len() < usize::from(t) { if valid.len() < usize::from(t) {
Err(vec![])?; return Ok(VerifyResult::NotEnoughParticipants);
} }
// If we now have >= t participations, calculate the group key and verification shares // If we now have >= t participations, calculate the group key and verification shares
@@ -417,20 +467,20 @@ where
let group_key = valid.values().map(|(_, evrf_data)| evrf_data.coefficients[0]).sum::<C::G>(); let group_key = valid.values().map(|(_, evrf_data)| evrf_data.coefficients[0]).sum::<C::G>();
// Calculate each user's verification share // Calculate each user's verification share
let mut verification_shares = HashMap::new(); let mut verification_shares = HashMap::with_capacity(usize::from(n));
for i in (1 ..= n).map(Participant) { for i in (1 ..= n).map(Participant) {
verification_shares verification_shares
.insert(i, (C::generator() * sum_encrypted_secret_shares[&i]) - sum_masks[&i]); .insert(i, (C::generator() * sum_encrypted_secret_shares[&i]) - sum_masks[&i]);
} }
Ok(EvrfDkg { Ok(VerifyResult::Valid(EvrfDkg {
t, t,
n, n,
evrf_public_keys: evrf_public_keys.to_vec(), evrf_public_keys: evrf_public_keys.to_vec(),
group_key, group_key,
verification_shares, verification_shares,
encrypted_secret_shares: all_encrypted_secret_shares, encrypted_secret_shares: all_encrypted_secret_shares,
}) }))
} }
// TODO: Return all keys for this participant, not just the first // TODO: Return all keys for this participant, not just the first

View File

@@ -46,7 +46,7 @@ fn evrf_dkg() {
); );
} }
let dkg = EvrfDkg::<Pallas>::verify( let VerifyResult::Valid(dkg) = EvrfDkg::<Pallas>::verify(
&mut OsRng, &mut OsRng,
&generators, &generators,
context, context,
@@ -54,7 +54,9 @@ fn evrf_dkg() {
&pub_keys, &pub_keys,
&participations, &participations,
) )
.unwrap(); .unwrap() else {
panic!("verify didn't return VerifyResult::Valid")
};
let mut group_key = None; let mut group_key = None;
let mut verification_shares = None; let mut verification_shares = None;