Files
serai/crypto/dkg/evrf/src/curves.rs
2025-08-29 06:42:37 -04:00

108 lines
3.7 KiB
Rust

#[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::vec::Vec;
use rand_core::SeedableRng;
use rand_chacha::ChaCha20Rng;
use blake2::{
digest::{
array::{typenum::U32, Array},
crypto_common::KeySizeUser,
KeyInit, Mac,
},
Blake2sMac,
};
type Blake2s256Keyed = Blake2sMac<U32>;
use ciphersuite::{
group::{ff::FromUniformBytes, GroupEncoding},
Ciphersuite,
};
use ec_divisors::DivisorCurve;
use generalized_bulletproofs::Generators as BpGenerators;
use generalized_bulletproofs_ec_gadgets::*;
/// A pair of curves to perform the eVRF with.
pub trait Curves {
/// The towering curve, for which the resulting key is on.
type ToweringCurve: Ciphersuite<F: FromUniformBytes<64>>;
/// The embedded curve which participants represent their public keys over.
type EmbeddedCurve: Ciphersuite<
G: DivisorCurve<FieldElement = <Self::ToweringCurve as Ciphersuite>::F>,
>;
/// The parameters to use the embedded curve with the discrete-log gadget.
type EmbeddedCurveParameters: DiscreteLogParameters;
}
/// Generators for an eVRF DKG.
///
/// These should be kept within a static. They're non-trivial to generate.
#[derive(Clone, Debug)]
pub struct Generators<C: Curves>(pub(crate) BpGenerators<C::ToweringCurve>);
impl<C: Curves> Generators<C> {
/// Create a new set of generators.
///
/// This is deterministic to the towering curve's (possibly truncated) ID and generator.
pub fn new(max_threshold: u16, max_participants: u16) -> Generators<C> {
let entropy = <Blake2s256Keyed as KeyInit>::new(&{
let mut key = Array::<u8, <Blake2s256Keyed as KeySizeUser>::KeySize>::default();
let key_len = key.len().min(<C::ToweringCurve as Ciphersuite>::ID.len());
{
let key: &mut [u8] = key.as_mut();
key[.. key_len].copy_from_slice(&<C::ToweringCurve as Ciphersuite>::ID[.. key_len])
}
key
})
.chain_update(<C::ToweringCurve as Ciphersuite>::generator().to_bytes())
.finalize()
.into_bytes();
let mut rng = ChaCha20Rng::from_seed(entropy.into());
let h = crate::sample_point::<C::ToweringCurve>(&mut rng);
let generators =
crate::Proof::<C>::generators_to_use(max_threshold.into(), max_participants.into());
let mut g_bold = Vec::with_capacity(generators);
let mut h_bold = Vec::with_capacity(generators);
for _ in 0 .. generators {
g_bold.push(crate::sample_point::<C::ToweringCurve>(&mut rng));
h_bold.push(crate::sample_point::<C::ToweringCurve>(&mut rng));
}
Self(
BpGenerators::new(<C::ToweringCurve as Ciphersuite>::generator(), h, g_bold, h_bold).unwrap(),
)
}
}
/// Secp256k1, and an elliptic curve defined over its scalar field (secq256k1).
#[cfg(feature = "secp256k1")]
pub struct Secp256k1;
#[cfg(feature = "secp256k1")]
impl Curves for Secp256k1 {
type ToweringCurve = ciphersuite_kp256::Secp256k1;
type EmbeddedCurve = secq256k1::Secq256k1;
type EmbeddedCurveParameters = secq256k1::Secq256k1;
}
/// Ed25519, and an elliptic curve defined over its scalar field (embedwards25519).
#[cfg(feature = "ed25519")]
pub struct Ed25519;
#[cfg(feature = "ed25519")]
impl Curves for Ed25519 {
type ToweringCurve = dalek_ff_group::Ed25519;
type EmbeddedCurve = embedwards25519::Embedwards25519;
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
}
/// Ristretto, and an elliptic curve defined over its scalar field (embedwards25519).
#[cfg(any(test, feature = "ristretto"))]
pub struct Ristretto;
#[cfg(any(test, feature = "ristretto"))]
impl Curves for Ristretto {
type ToweringCurve = dalek_ff_group::Ristretto;
type EmbeddedCurve = embedwards25519::Embedwards25519;
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
}