mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 13:39:25 +00:00
Smash the singular Ciphersuite trait into multiple
This helps identify where the various functionalities are used, or rather, not used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating the entire FCMP++ tree, only requires the markers _and_ canonical point decoding. I've opened a PR to upstream such a trait into `group` (https://github.com/zkcrypto/group/pull/68). `WrappedGroup` is still justified for as long as `Group::generator` exists. Moving `::generator()` to its own trait, on an independent structure (upstream) would be massively appreciated. @tarcieri also wanted to update from `fn generator()` to `const GENERATOR`, which would encourage further discussion on https://github.com/zkcrypto/group/issues/32 and https://github.com/zkcrypto/group/issues/45, which have been stagnant. The `Id` trait is occasionally used yet really should be first off the chopping block. Finally, `WithPreferredHash` is only actually used around a third of the time, which more than justifies it being a separate trait. --- Updates `dalek_ff_group::Scalar` to directly re-export `curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint` also could be replaced with an export of `curve25519_dalek::RistrettoPoint`, yet the coordinator relies on how we implemented `Hash` on it for the hell of it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't implement `zeroize`, `subtle` traits within a released, non-yanked version. Relevance to https://github.com/serai-dex/serai/issues/201 and https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746. Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over `SHA2-512`. In order to maintain compliance with FROST's IETF standard, `modular-frost` defines its own ciphersuite for Ristretto which still uses `SHA2-512`.
This commit is contained in:
@@ -21,7 +21,7 @@ use ciphersuite::{
|
||||
ff::{Field, PrimeField},
|
||||
Group, GroupEncoding,
|
||||
},
|
||||
Ciphersuite,
|
||||
WrappedGroup, GroupIo,
|
||||
};
|
||||
use multiexp::multiexp_vartime;
|
||||
|
||||
@@ -49,7 +49,7 @@ mod tests;
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Participation<C: Curves> {
|
||||
proof: Vec<u8>,
|
||||
encrypted_secret_shares: HashMap<Participant, <C::ToweringCurve as Ciphersuite>::F>,
|
||||
encrypted_secret_shares: HashMap<Participant, <C::ToweringCurve as WrappedGroup>::F>,
|
||||
}
|
||||
|
||||
impl<C: Curves> Participation<C> {
|
||||
@@ -79,7 +79,7 @@ impl<C: Curves> Participation<C> {
|
||||
|
||||
let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
|
||||
for i in Participant::iter().take(usize::from(n)) {
|
||||
encrypted_secret_shares.insert(i, <C::ToweringCurve as Ciphersuite>::read_F(reader)?);
|
||||
encrypted_secret_shares.insert(i, <C::ToweringCurve as GroupIo>::read_F(reader)?);
|
||||
}
|
||||
|
||||
Ok(Self { proof, encrypted_secret_shares })
|
||||
@@ -151,14 +151,14 @@ pub enum VerifyResult<C: Curves> {
|
||||
pub struct Dkg<C: Curves> {
|
||||
t: u16,
|
||||
n: u16,
|
||||
evrf_public_keys: Vec<<C::EmbeddedCurve as Ciphersuite>::G>,
|
||||
verification_shares: HashMap<Participant, <C::ToweringCurve as Ciphersuite>::G>,
|
||||
evrf_public_keys: Vec<<C::EmbeddedCurve as WrappedGroup>::G>,
|
||||
verification_shares: HashMap<Participant, <C::ToweringCurve as WrappedGroup>::G>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
encrypted_secret_shares: HashMap<
|
||||
Participant,
|
||||
HashMap<
|
||||
Participant,
|
||||
([<C::EmbeddedCurve as Ciphersuite>::G; 2], <C::ToweringCurve as Ciphersuite>::F),
|
||||
([<C::EmbeddedCurve as WrappedGroup>::G; 2], <C::ToweringCurve as WrappedGroup>::F),
|
||||
>,
|
||||
>,
|
||||
}
|
||||
@@ -167,7 +167,7 @@ impl<C: Curves> Dkg<C> {
|
||||
// Form the initial transcript for the proofs.
|
||||
fn initial_transcript(
|
||||
invocation: [u8; 32],
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||
t: u16,
|
||||
) -> [u8; 32] {
|
||||
let mut transcript = Blake2s256::new();
|
||||
@@ -188,8 +188,8 @@ impl<C: Curves> Dkg<C> {
|
||||
generators: &Generators<C>,
|
||||
context: [u8; 32],
|
||||
t: u16,
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
||||
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as WrappedGroup>::F>,
|
||||
) -> Result<Participation<C>, Error> {
|
||||
let Ok(n) = u16::try_from(evrf_public_keys.len()) else {
|
||||
Err(Error::TooManyParticipants { provided: evrf_public_keys.len() })?
|
||||
@@ -202,7 +202,8 @@ impl<C: Curves> Dkg<C> {
|
||||
};
|
||||
// This also ensures the private key is not 0, due to the prior check the identity point wasn't
|
||||
// present
|
||||
let evrf_public_key = <C::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key.deref();
|
||||
let evrf_public_key =
|
||||
<C::EmbeddedCurve as WrappedGroup>::generator() * evrf_private_key.deref();
|
||||
if !evrf_public_keys.contains(&evrf_public_key) {
|
||||
Err(Error::NotAParticipant)?;
|
||||
};
|
||||
@@ -231,7 +232,7 @@ impl<C: Curves> Dkg<C> {
|
||||
|
||||
let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
|
||||
for (l, encryption_key) in Participant::iter().take(usize::from(n)).zip(encryption_keys) {
|
||||
let share = polynomial::<<C::ToweringCurve as Ciphersuite>::F>(&coefficients, l);
|
||||
let share = polynomial::<<C::ToweringCurve as WrappedGroup>::F>(&coefficients, l);
|
||||
encrypted_secret_shares.insert(l, *share + *encryption_key);
|
||||
}
|
||||
|
||||
@@ -243,26 +244,26 @@ impl<C: Curves> Dkg<C> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn verifiable_encryption_statements<C: Curves>(
|
||||
rng: &mut (impl RngCore + CryptoRng),
|
||||
coefficients: &[<C::ToweringCurve as Ciphersuite>::G],
|
||||
encryption_key_commitments: &[<C::ToweringCurve as Ciphersuite>::G],
|
||||
encrypted_secret_shares: &HashMap<Participant, <C::ToweringCurve as Ciphersuite>::F>,
|
||||
coefficients: &[<C::ToweringCurve as WrappedGroup>::G],
|
||||
encryption_key_commitments: &[<C::ToweringCurve as WrappedGroup>::G],
|
||||
encrypted_secret_shares: &HashMap<Participant, <C::ToweringCurve as WrappedGroup>::F>,
|
||||
) -> (
|
||||
<C::ToweringCurve as Ciphersuite>::F,
|
||||
Vec<(<C::ToweringCurve as Ciphersuite>::F, <C::ToweringCurve as Ciphersuite>::G)>,
|
||||
<C::ToweringCurve as WrappedGroup>::F,
|
||||
Vec<(<C::ToweringCurve as WrappedGroup>::F, <C::ToweringCurve as WrappedGroup>::G)>,
|
||||
) {
|
||||
let mut g_scalar = <C::ToweringCurve as Ciphersuite>::F::ZERO;
|
||||
let mut g_scalar = <C::ToweringCurve as WrappedGroup>::F::ZERO;
|
||||
let mut pairs = Vec::with_capacity(coefficients.len() + encryption_key_commitments.len());
|
||||
|
||||
// Push on the commitments to the polynomial being secret-shared
|
||||
for coefficient in coefficients {
|
||||
// This uses `0` as we'll add to it later, given its fixed position
|
||||
pairs.push((<C::ToweringCurve as Ciphersuite>::F::ZERO, *coefficient));
|
||||
pairs.push((<C::ToweringCurve as WrappedGroup>::F::ZERO, *coefficient));
|
||||
}
|
||||
|
||||
for (i, encrypted_secret_share) in encrypted_secret_shares {
|
||||
let encryption_key_commitment = encryption_key_commitments[usize::from(u16::from(*i)) - 1];
|
||||
|
||||
let weight = <C::ToweringCurve as Ciphersuite>::F::random(&mut *rng);
|
||||
let weight = <C::ToweringCurve as WrappedGroup>::F::random(&mut *rng);
|
||||
|
||||
/*
|
||||
The encrypted secret share scaling `G`, minus the encryption key commitment, minus the
|
||||
@@ -274,7 +275,7 @@ fn verifiable_encryption_statements<C: Curves>(
|
||||
pairs.push((weight, encryption_key_commitment));
|
||||
// Calculate the commitment to the secret share via the commitments to the polynomial
|
||||
{
|
||||
let i = <C::ToweringCurve as Ciphersuite>::F::from(u64::from(u16::from(*i)));
|
||||
let i = <C::ToweringCurve as WrappedGroup>::F::from(u64::from(u16::from(*i)));
|
||||
(0 .. coefficients.len()).fold(weight, |exp, j| {
|
||||
pairs[j].0 += exp;
|
||||
exp * i
|
||||
@@ -300,7 +301,7 @@ impl<C: Curves> Dkg<C> {
|
||||
generators: &Generators<C>,
|
||||
context: [u8; 32],
|
||||
t: u16,
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||
participations: &HashMap<Participant, Participation<C>>,
|
||||
) -> Result<VerifyResult<C>, Error> {
|
||||
let Ok(n) = u16::try_from(evrf_public_keys.len()) else {
|
||||
@@ -386,7 +387,7 @@ impl<C: Curves> Dkg<C> {
|
||||
{
|
||||
let mut share_verification_statements_actual = HashMap::with_capacity(valid.len());
|
||||
if !{
|
||||
let mut g_scalar = <C::ToweringCurve as Ciphersuite>::F::ZERO;
|
||||
let mut g_scalar = <C::ToweringCurve as WrappedGroup>::F::ZERO;
|
||||
let mut pairs = Vec::with_capacity(valid.len() * (usize::from(t) + evrf_public_keys.len()));
|
||||
for (i, (encrypted_secret_shares, data)) in &valid {
|
||||
let (this_g_scalar, mut these_pairs) = verifiable_encryption_statements::<C>(
|
||||
@@ -417,9 +418,11 @@ impl<C: Curves> Dkg<C> {
|
||||
let sum_encrypted_secret_share = sum_encrypted_secret_shares
|
||||
.get(j)
|
||||
.copied()
|
||||
.unwrap_or(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
||||
let sum_mask =
|
||||
sum_masks.get(j).copied().unwrap_or(<C::ToweringCurve as Ciphersuite>::G::identity());
|
||||
.unwrap_or(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||
let sum_mask = sum_masks
|
||||
.get(j)
|
||||
.copied()
|
||||
.unwrap_or(<C::ToweringCurve as WrappedGroup>::G::identity());
|
||||
sum_encrypted_secret_shares.insert(*j, sum_encrypted_secret_share + enc_share);
|
||||
|
||||
let j_index = usize::from(u16::from(*j)) - 1;
|
||||
@@ -487,7 +490,7 @@ impl<C: Curves> Dkg<C> {
|
||||
for i in Participant::iter().take(usize::from(n)) {
|
||||
verification_shares.insert(
|
||||
i,
|
||||
(<C::ToweringCurve as Ciphersuite>::generator() * sum_encrypted_secret_shares[&i]) -
|
||||
(<C::ToweringCurve as WrappedGroup>::generator() * sum_encrypted_secret_shares[&i]) -
|
||||
sum_masks[&i],
|
||||
);
|
||||
}
|
||||
@@ -506,9 +509,10 @@ impl<C: Curves> Dkg<C> {
|
||||
/// This will return _all_ keys belong to the participant.
|
||||
pub fn keys(
|
||||
&self,
|
||||
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
|
||||
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as WrappedGroup>::F>,
|
||||
) -> Vec<ThresholdKeys<C::ToweringCurve>> {
|
||||
let evrf_public_key = <C::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key.deref();
|
||||
let evrf_public_key =
|
||||
<C::EmbeddedCurve as WrappedGroup>::generator() * evrf_private_key.deref();
|
||||
let mut is = Vec::with_capacity(1);
|
||||
for (i, evrf_key) in Participant::iter().zip(self.evrf_public_keys.iter()) {
|
||||
if *evrf_key == evrf_public_key {
|
||||
@@ -518,14 +522,14 @@ impl<C: Curves> Dkg<C> {
|
||||
|
||||
let mut res = Vec::with_capacity(is.len());
|
||||
for i in is {
|
||||
let mut secret_share = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
||||
let mut secret_share = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||
for shares in self.encrypted_secret_shares.values() {
|
||||
let (ecdh_commitments, encrypted_secret_share) = shares[&i];
|
||||
|
||||
let mut ecdh = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
||||
let mut ecdh = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||
for point in ecdh_commitments {
|
||||
let (mut x, mut y) =
|
||||
<C::EmbeddedCurve as Ciphersuite>::G::to_xy(point * evrf_private_key.deref()).unwrap();
|
||||
<C::EmbeddedCurve as WrappedGroup>::G::to_xy(point * evrf_private_key.deref()).unwrap();
|
||||
*ecdh += x;
|
||||
x.zeroize();
|
||||
y.zeroize();
|
||||
@@ -534,7 +538,7 @@ impl<C: Curves> Dkg<C> {
|
||||
}
|
||||
debug_assert_eq!(
|
||||
self.verification_shares[&i],
|
||||
<C::ToweringCurve as Ciphersuite>::G::generator() * secret_share.deref()
|
||||
<C::ToweringCurve as WrappedGroup>::generator() * secret_share.deref()
|
||||
);
|
||||
|
||||
res.push(
|
||||
|
||||
Reference in New Issue
Block a user