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> {
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
let mut len = [0; 4];
reader.read_exact(&mut len)?;
@@ -122,13 +122,23 @@ impl<C: Ciphersuite> Participation<C> {
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(&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(())
}
}
@@ -191,6 +201,28 @@ fn share_verification_statements<C: Ciphersuite>(
(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.
#[derive(Debug)]
pub struct EvrfDkg<C: EvrfCurve> {
@@ -224,26 +256,44 @@ where
t: u16,
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
) -> Result<Participation<C>, AcError> {
) -> Result<Participation<C>, EvrfError> {
if generators.g() != C::generator() {
todo!("TODO");
}
let evrf_public_key = <C::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key.deref();
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) {
todo!("TODO");
Err(EvrfError::InvalidThreshold)?;
}
if !evrf_public_keys.iter().any(|key| *key == evrf_public_key) {
todo!("TODO");
Err(EvrfError::NotAParticipant)?;
};
let EvrfProveResult { coefficients, encryption_masks, proof } =
Evrf::prove(rng, generators, evrf_private_key, context, usize::from(t), evrf_public_keys)?;
let EvrfProveResult { coefficients, encryption_masks, proof } = match Evrf::prove(
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) {
let share = polynomial::<C::F>(&coefficients, l);
encrypted_secret_shares.insert(l, *share + *encryption_mask);
@@ -254,10 +304,10 @@ where
/// 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
/// `Participation`s are valid and there's at least `t`, an instance of this struct (usable to
/// obtain a threshold share of generated key) is returned. If all are valid and there's not at
/// least `t`, an error of an empty list is returned after validation.
/// If any `Participation` is invalid, the list of all invalid participants will be returned.
/// If all `Participation`s are valid and there's at least `t`, an instance of this struct
/// (usable to obtain a threshold share of generated key) is returned. If all are valid and
/// 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
/// participate.
@@ -268,22 +318,22 @@ where
t: u16,
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
participations: &HashMap<Participant, Participation<C>>,
) -> Result<Self, Vec<Participant>> {
) -> Result<VerifyResult<C>, EvrfError> {
if generators.g() != C::generator() {
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) {
todo!("TODO");
Err(EvrfError::InvalidThreshold)?;
}
for i in participations.keys() {
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 evrf_verifier = generators.batch_verifier();
@@ -337,9 +387,9 @@ where
debug_assert_eq!(valid.len() + faulty.len(), participations.len());
// Perform the batch verification of the shares
let mut sum_encrypted_secret_shares = HashMap::new();
let mut sum_masks = HashMap::new();
let mut all_encrypted_secret_shares = HashMap::new();
let mut sum_encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
let mut sum_masks = HashMap::with_capacity(usize::from(n));
let mut all_encrypted_secret_shares = HashMap::with_capacity(usize::from(t));
{
let mut share_verification_statements_actual = HashMap::with_capacity(valid.len());
if !{
@@ -366,7 +416,7 @@ where
share_verification_statements_actual.insert(*i, these_pairs);
// 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 {
/*
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<_>>();
if !faulty.is_empty() {
faulty.sort_unstable();
Err(faulty)?;
return Ok(VerifyResult::Invalid(faulty));
}
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
@@ -417,20 +467,20 @@ where
let group_key = valid.values().map(|(_, evrf_data)| evrf_data.coefficients[0]).sum::<C::G>();
// 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) {
verification_shares
.insert(i, (C::generator() * sum_encrypted_secret_shares[&i]) - sum_masks[&i]);
}
Ok(EvrfDkg {
Ok(VerifyResult::Valid(EvrfDkg {
t,
n,
evrf_public_keys: evrf_public_keys.to_vec(),
group_key,
verification_shares,
encrypted_secret_shares: all_encrypted_secret_shares,
})
}))
}
// 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,
&generators,
context,
@@ -54,7 +54,9 @@ fn evrf_dkg() {
&pub_keys,
&participations,
)
.unwrap();
.unwrap() else {
panic!("verify didn't return VerifyResult::Valid")
};
let mut group_key = None;
let mut verification_shares = None;