mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 13:39:25 +00:00
git checkout -f next ./crypto
Proceeds to remove the eVRF DKG after, only keeping what's relevant to this branch alone.
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
|
||||
use core::fmt::{self, Debug};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use thiserror::Error;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
@@ -63,8 +62,7 @@ impl fmt::Display for Participant {
|
||||
}
|
||||
|
||||
/// Various errors possible during key generation.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(feature = "std", derive(Error))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Error)]
|
||||
pub enum DkgError<B: Clone + PartialEq + Eq + Debug> {
|
||||
/// A parameter was zero.
|
||||
#[cfg_attr(feature = "std", error("a parameter was 0 (threshold {0}, participants {1})"))]
|
||||
@@ -205,25 +203,37 @@ mod lib {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the lagrange coefficient for a signing set.
|
||||
pub fn lagrange<F: PrimeField>(i: Participant, included: &[Participant]) -> F {
|
||||
let i_f = F::from(u64::from(u16::from(i)));
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
|
||||
pub(crate) enum Interpolation<F: Zeroize + PrimeField> {
|
||||
Constant(Vec<F>),
|
||||
Lagrange,
|
||||
}
|
||||
|
||||
let mut num = F::ONE;
|
||||
let mut denom = F::ONE;
|
||||
for l in included {
|
||||
if i == *l {
|
||||
continue;
|
||||
impl<F: Zeroize + PrimeField> Interpolation<F> {
|
||||
pub(crate) fn interpolation_factor(&self, i: Participant, included: &[Participant]) -> F {
|
||||
match self {
|
||||
Interpolation::Constant(c) => c[usize::from(u16::from(i) - 1)],
|
||||
Interpolation::Lagrange => {
|
||||
let i_f = F::from(u64::from(u16::from(i)));
|
||||
|
||||
let mut num = F::ONE;
|
||||
let mut denom = F::ONE;
|
||||
for l in included {
|
||||
if i == *l {
|
||||
continue;
|
||||
}
|
||||
|
||||
let share = F::from(u64::from(u16::from(*l)));
|
||||
num *= share;
|
||||
denom *= share - i_f;
|
||||
}
|
||||
|
||||
// Safe as this will only be 0 if we're part of the above loop
|
||||
// (which we have an if case to avoid)
|
||||
num * denom.invert().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
let share = F::from(u64::from(u16::from(*l)));
|
||||
num *= share;
|
||||
denom *= share - i_f;
|
||||
}
|
||||
|
||||
// Safe as this will only be 0 if we're part of the above loop
|
||||
// (which we have an if case to avoid)
|
||||
num * denom.invert().unwrap()
|
||||
}
|
||||
|
||||
/// Keys and verification shares generated by a DKG.
|
||||
@@ -232,6 +242,8 @@ mod lib {
|
||||
pub struct ThresholdCore<C: Ciphersuite> {
|
||||
/// Threshold Parameters.
|
||||
pub(crate) params: ThresholdParams,
|
||||
/// The interpolation method used.
|
||||
pub(crate) interpolation: Interpolation<C::F>,
|
||||
|
||||
/// Secret share key.
|
||||
pub(crate) secret_share: Zeroizing<C::F>,
|
||||
@@ -246,6 +258,7 @@ mod lib {
|
||||
fmt
|
||||
.debug_struct("ThresholdCore")
|
||||
.field("params", &self.params)
|
||||
.field("interpolation", &self.interpolation)
|
||||
.field("group_key", &self.group_key)
|
||||
.field("verification_shares", &self.verification_shares)
|
||||
.finish_non_exhaustive()
|
||||
@@ -255,6 +268,7 @@ mod lib {
|
||||
impl<C: Ciphersuite> Zeroize for ThresholdCore<C> {
|
||||
fn zeroize(&mut self) {
|
||||
self.params.zeroize();
|
||||
self.interpolation.zeroize();
|
||||
self.secret_share.zeroize();
|
||||
self.group_key.zeroize();
|
||||
for share in self.verification_shares.values_mut() {
|
||||
@@ -266,16 +280,14 @@ mod lib {
|
||||
impl<C: Ciphersuite> ThresholdCore<C> {
|
||||
pub(crate) fn new(
|
||||
params: ThresholdParams,
|
||||
interpolation: Interpolation<C::F>,
|
||||
secret_share: Zeroizing<C::F>,
|
||||
verification_shares: HashMap<Participant, C::G>,
|
||||
) -> ThresholdCore<C> {
|
||||
let t = (1 ..= params.t()).map(Participant).collect::<Vec<_>>();
|
||||
ThresholdCore {
|
||||
params,
|
||||
secret_share,
|
||||
group_key: t.iter().map(|i| verification_shares[i] * lagrange::<C::F>(*i, &t)).sum(),
|
||||
verification_shares,
|
||||
}
|
||||
let group_key =
|
||||
t.iter().map(|i| verification_shares[i] * interpolation.interpolation_factor(*i, &t)).sum();
|
||||
ThresholdCore { params, interpolation, secret_share, group_key, verification_shares }
|
||||
}
|
||||
|
||||
/// Parameters for these keys.
|
||||
@@ -304,6 +316,15 @@ mod lib {
|
||||
writer.write_all(&self.params.t.to_le_bytes())?;
|
||||
writer.write_all(&self.params.n.to_le_bytes())?;
|
||||
writer.write_all(&self.params.i.to_bytes())?;
|
||||
match &self.interpolation {
|
||||
Interpolation::Constant(c) => {
|
||||
writer.write_all(&[0])?;
|
||||
for c in c {
|
||||
writer.write_all(c.to_repr().as_ref())?;
|
||||
}
|
||||
}
|
||||
Interpolation::Lagrange => writer.write_all(&[1])?,
|
||||
};
|
||||
let mut share_bytes = self.secret_share.to_repr();
|
||||
writer.write_all(share_bytes.as_ref())?;
|
||||
share_bytes.as_mut().zeroize();
|
||||
@@ -352,6 +373,20 @@ mod lib {
|
||||
)
|
||||
};
|
||||
|
||||
let mut interpolation = [0];
|
||||
reader.read_exact(&mut interpolation)?;
|
||||
let interpolation = match interpolation[0] {
|
||||
0 => Interpolation::Constant({
|
||||
let mut res = Vec::with_capacity(usize::from(n));
|
||||
for _ in 0 .. n {
|
||||
res.push(C::read_F(reader)?);
|
||||
}
|
||||
res
|
||||
}),
|
||||
1 => Interpolation::Lagrange,
|
||||
_ => Err(io::Error::other("invalid interpolation method"))?,
|
||||
};
|
||||
|
||||
let secret_share = Zeroizing::new(C::read_F(reader)?);
|
||||
|
||||
let mut verification_shares = HashMap::new();
|
||||
@@ -361,6 +396,7 @@ mod lib {
|
||||
|
||||
Ok(ThresholdCore::new(
|
||||
ThresholdParams::new(t, n, i).map_err(|_| io::Error::other("invalid parameters"))?,
|
||||
interpolation,
|
||||
secret_share,
|
||||
verification_shares,
|
||||
))
|
||||
@@ -383,6 +419,7 @@ mod lib {
|
||||
/// View of keys, interpolated and offset for usage.
|
||||
#[derive(Clone)]
|
||||
pub struct ThresholdView<C: Ciphersuite> {
|
||||
interpolation: Interpolation<C::F>,
|
||||
offset: C::F,
|
||||
group_key: C::G,
|
||||
included: Vec<Participant>,
|
||||
@@ -395,6 +432,7 @@ mod lib {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt
|
||||
.debug_struct("ThresholdView")
|
||||
.field("interpolation", &self.interpolation)
|
||||
.field("offset", &self.offset)
|
||||
.field("group_key", &self.group_key)
|
||||
.field("included", &self.included)
|
||||
@@ -480,12 +518,13 @@ mod lib {
|
||||
included.sort();
|
||||
|
||||
let mut secret_share = Zeroizing::new(
|
||||
lagrange::<C::F>(self.params().i(), &included) * self.secret_share().deref(),
|
||||
self.core.interpolation.interpolation_factor(self.params().i(), &included) *
|
||||
self.secret_share().deref(),
|
||||
);
|
||||
|
||||
let mut verification_shares = self.verification_shares();
|
||||
for (i, share) in &mut verification_shares {
|
||||
*share *= lagrange::<C::F>(*i, &included);
|
||||
*share *= self.core.interpolation.interpolation_factor(*i, &included);
|
||||
}
|
||||
|
||||
// The offset is included by adding it to the participant with the lowest ID
|
||||
@@ -496,6 +535,7 @@ mod lib {
|
||||
*verification_shares.get_mut(&included[0]).unwrap() += C::generator() * offset;
|
||||
|
||||
Ok(ThresholdView {
|
||||
interpolation: self.core.interpolation.clone(),
|
||||
offset,
|
||||
group_key: self.group_key(),
|
||||
secret_share,
|
||||
@@ -528,6 +568,14 @@ mod lib {
|
||||
&self.included
|
||||
}
|
||||
|
||||
/// Return the interpolation factor for a signer.
|
||||
pub fn interpolation_factor(&self, participant: Participant) -> Option<C::F> {
|
||||
if !self.included.contains(&participant) {
|
||||
None?
|
||||
}
|
||||
Some(self.interpolation.interpolation_factor(participant, &self.included))
|
||||
}
|
||||
|
||||
/// Return the interpolated, offset secret share.
|
||||
pub fn secret_share(&self) -> &Zeroizing<C::F> {
|
||||
&self.secret_share
|
||||
|
||||
Reference in New Issue
Block a user