mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +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:
@@ -32,7 +32,9 @@ rand_chacha = { version = "0.3", default-features = false, features = ["std"] }
|
||||
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
||||
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", default-features = false, features = ["std"] }
|
||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std", "ristretto"] }
|
||||
embedwards25519 = { path = "../../crypto/embedwards25519", default-features = false, features = ["std"] }
|
||||
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std"] }
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false, features = ["ristretto"] }
|
||||
|
||||
# Substrate
|
||||
serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std"] }
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
||||
use ciphersuite::{group::GroupEncoding, *};
|
||||
use dkg::*;
|
||||
|
||||
use serai_validator_sets_primitives::Session;
|
||||
@@ -11,15 +11,15 @@ use serai_validator_sets_primitives::Session;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
use serai_db::{Get, DbTxn};
|
||||
|
||||
use crate::KeyGenParams;
|
||||
use crate::{Ristretto, KeyGenParams};
|
||||
|
||||
pub(crate) struct Params<P: KeyGenParams> {
|
||||
pub(crate) t: u16,
|
||||
pub(crate) n: u16,
|
||||
pub(crate) substrate_evrf_public_keys:
|
||||
Vec<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::G>,
|
||||
Vec<<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::G>,
|
||||
pub(crate) network_evrf_public_keys:
|
||||
Vec<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::G>,
|
||||
Vec<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::G>,
|
||||
}
|
||||
|
||||
#[derive(BorshSerialize, BorshDeserialize)]
|
||||
@@ -85,17 +85,16 @@ impl<P: KeyGenParams> KeyGenDb<P> {
|
||||
.substrate_evrf_public_keys
|
||||
.into_iter()
|
||||
.map(|key| {
|
||||
<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::read_G(&mut key.as_slice())
|
||||
.unwrap()
|
||||
<<Ristretto as Curves>::EmbeddedCurve as GroupIo>::read_G(&mut key.as_slice()).unwrap()
|
||||
})
|
||||
.collect(),
|
||||
network_evrf_public_keys: params
|
||||
.network_evrf_public_keys
|
||||
.into_iter()
|
||||
.map(|key| {
|
||||
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::read_G::<
|
||||
&[u8],
|
||||
>(&mut key.as_ref())
|
||||
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as GroupIo>::read_G::<&[u8]>(
|
||||
&mut key.as_ref(),
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
.collect(),
|
||||
|
||||
@@ -13,7 +13,7 @@ use blake2::{Digest, Blake2s256};
|
||||
use transcript::{Transcript, RecommendedTranscript};
|
||||
use ciphersuite::{
|
||||
group::{Group, GroupEncoding},
|
||||
Ciphersuite,
|
||||
*,
|
||||
};
|
||||
use dkg::*;
|
||||
|
||||
@@ -28,6 +28,14 @@ use generators::generators;
|
||||
mod db;
|
||||
use db::{Params, Participations, KeyGenDb};
|
||||
|
||||
/// Ristretto, and an elliptic curve defined over its scalar field (embedwards25519).
|
||||
pub struct Ristretto;
|
||||
impl Curves for Ristretto {
|
||||
type ToweringCurve = frost::curve::Ristretto;
|
||||
type EmbeddedCurve = embedwards25519::Embedwards25519;
|
||||
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
|
||||
}
|
||||
|
||||
/// Parameters for a key generation.
|
||||
pub trait KeyGenParams {
|
||||
/// The ID for this instantiation.
|
||||
@@ -49,7 +57,7 @@ pub trait KeyGenParams {
|
||||
///
|
||||
/// A default implementation is provided which calls the traditional `to_bytes`.
|
||||
fn encode_key(
|
||||
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G,
|
||||
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G,
|
||||
) -> Vec<u8> {
|
||||
key.to_bytes().as_ref().to_vec()
|
||||
}
|
||||
@@ -59,11 +67,10 @@ pub trait KeyGenParams {
|
||||
/// A default implementation is provided which calls the traditional `from_bytes`.
|
||||
fn decode_key(
|
||||
mut key: &[u8],
|
||||
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G> {
|
||||
let res = <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::read_G(
|
||||
&mut key,
|
||||
)
|
||||
.ok()?;
|
||||
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G> {
|
||||
let res =
|
||||
<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as GroupIo>::read_G(&mut key)
|
||||
.ok()?;
|
||||
if !key.is_empty() {
|
||||
None?;
|
||||
}
|
||||
@@ -101,14 +108,14 @@ pub trait KeyGenParams {
|
||||
*/
|
||||
fn coerce_keys<C: 'static + Curves>(
|
||||
key_bytes: &[impl AsRef<[u8]>],
|
||||
) -> (Vec<<C::EmbeddedCurve as Ciphersuite>::G>, Vec<Participant>) {
|
||||
fn evrf_key<C: 'static + Curves>(key: &[u8]) -> Option<<C::EmbeddedCurve as Ciphersuite>::G> {
|
||||
let mut repr = <<C::EmbeddedCurve as Ciphersuite>::G as GroupEncoding>::Repr::default();
|
||||
) -> (Vec<<C::EmbeddedCurve as WrappedGroup>::G>, Vec<Participant>) {
|
||||
fn evrf_key<C: 'static + Curves>(key: &[u8]) -> Option<<C::EmbeddedCurve as WrappedGroup>::G> {
|
||||
let mut repr = <<C::EmbeddedCurve as WrappedGroup>::G as GroupEncoding>::Repr::default();
|
||||
if repr.as_ref().len() != key.len() {
|
||||
None?;
|
||||
}
|
||||
repr.as_mut().copy_from_slice(key);
|
||||
let point = Option::<<C::EmbeddedCurve as Ciphersuite>::G>::from(<_>::from_bytes(&repr))?;
|
||||
let point = Option::<<C::EmbeddedCurve as WrappedGroup>::G>::from(<_>::from_bytes(&repr))?;
|
||||
if bool::from(point.is_identity()) {
|
||||
None?;
|
||||
}
|
||||
@@ -131,10 +138,10 @@ fn coerce_keys<C: 'static + Curves>(
|
||||
// Generate a random key
|
||||
let mut rng = ChaCha20Rng::from_seed(Blake2s256::digest(key).into());
|
||||
loop {
|
||||
let mut repr = <<C::EmbeddedCurve as Ciphersuite>::G as GroupEncoding>::Repr::default();
|
||||
let mut repr = <<C::EmbeddedCurve as WrappedGroup>::G as GroupEncoding>::Repr::default();
|
||||
rng.fill_bytes(repr.as_mut());
|
||||
if let Some(key) =
|
||||
Option::<<C::EmbeddedCurve as Ciphersuite>::G>::from(<_>::from_bytes(&repr))
|
||||
Option::<<C::EmbeddedCurve as WrappedGroup>::G>::from(<_>::from_bytes(&repr))
|
||||
{
|
||||
break key;
|
||||
}
|
||||
@@ -149,18 +156,20 @@ fn coerce_keys<C: 'static + Curves>(
|
||||
/// An instance of the Serai key generation protocol.
|
||||
#[derive(Debug)]
|
||||
pub struct KeyGen<P: KeyGenParams> {
|
||||
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
||||
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::F>,
|
||||
network_evrf_private_key:
|
||||
Zeroizing<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
||||
Zeroizing<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::F>,
|
||||
}
|
||||
|
||||
impl<P: KeyGenParams> KeyGen<P> {
|
||||
/// Create a new key generation instance.
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(
|
||||
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
||||
substrate_evrf_private_key: Zeroizing<
|
||||
<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::F,
|
||||
>,
|
||||
network_evrf_private_key: Zeroizing<
|
||||
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::F,
|
||||
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::F,
|
||||
>,
|
||||
) -> KeyGen<P> {
|
||||
KeyGen { substrate_evrf_private_key, network_evrf_private_key }
|
||||
@@ -214,8 +223,8 @@ impl<P: KeyGenParams> KeyGen<P> {
|
||||
fn participate<C: 'static + Curves>(
|
||||
context: [u8; 32],
|
||||
threshold: 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>,
|
||||
output: &mut impl io::Write,
|
||||
) {
|
||||
let participation = Dkg::<C>::participate(
|
||||
@@ -411,7 +420,7 @@ impl<P: KeyGenParams> KeyGen<P> {
|
||||
session: Session,
|
||||
true_if_substrate_false_if_network: bool,
|
||||
threshold: u16,
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
||||
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||
substrate_participations: &mut HashMap<Participant, Vec<u8>>,
|
||||
network_participations: &mut HashMap<Participant, Vec<u8>>,
|
||||
) -> Result<Dkg<C>, Vec<ProcessorMessage>> {
|
||||
|
||||
Reference in New Issue
Block a user