mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-13 14:39:25 +00:00
Implement eVRF traits, all the way up to the DKG, for secp256k1/ed25519
This commit is contained in:
14
Cargo.lock
generated
14
Cargo.lock
generated
@@ -2134,6 +2134,7 @@ dependencies = [
|
|||||||
"ciphersuite",
|
"ciphersuite",
|
||||||
"dleq",
|
"dleq",
|
||||||
"ec-divisors",
|
"ec-divisors",
|
||||||
|
"embedwards25519",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"generalized-bulletproofs",
|
"generalized-bulletproofs",
|
||||||
"generalized-bulletproofs-circuit-abstraction",
|
"generalized-bulletproofs-circuit-abstraction",
|
||||||
@@ -2145,6 +2146,7 @@ dependencies = [
|
|||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"schnorr-signatures",
|
"schnorr-signatures",
|
||||||
|
"secq256k1",
|
||||||
"std-shims",
|
"std-shims",
|
||||||
"subtle",
|
"subtle",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -2332,12 +2334,14 @@ dependencies = [
|
|||||||
name = "embedwards25519"
|
name = "embedwards25519"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"blake2",
|
||||||
|
"ciphersuite",
|
||||||
"crypto-bigint",
|
"crypto-bigint",
|
||||||
"dalek-ff-group",
|
"dalek-ff-group",
|
||||||
"ec-divisors",
|
"ec-divisors",
|
||||||
"ff",
|
|
||||||
"ff-group-tests",
|
"ff-group-tests",
|
||||||
"group",
|
"generalized-bulletproofs-ec-gadgets",
|
||||||
|
"generic-array 0.14.7",
|
||||||
"hex",
|
"hex",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
@@ -7915,12 +7919,13 @@ dependencies = [
|
|||||||
name = "secq256k1"
|
name = "secq256k1"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"blake2",
|
||||||
|
"ciphersuite",
|
||||||
"crypto-bigint",
|
"crypto-bigint",
|
||||||
"ec-divisors",
|
"ec-divisors",
|
||||||
"ff",
|
|
||||||
"ff-group-tests",
|
"ff-group-tests",
|
||||||
|
"generalized-bulletproofs-ec-gadgets",
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.7",
|
||||||
"group",
|
|
||||||
"hex",
|
"hex",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"k256",
|
"k256",
|
||||||
@@ -8428,6 +8433,7 @@ dependencies = [
|
|||||||
"ciphersuite",
|
"ciphersuite",
|
||||||
"const-hex",
|
"const-hex",
|
||||||
"dalek-ff-group",
|
"dalek-ff-group",
|
||||||
|
"dkg",
|
||||||
"dockertest",
|
"dockertest",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"ethereum-serai",
|
"ethereum-serai",
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ ec-divisors = { path = "../evrf/divisors", default-features = false, optional =
|
|||||||
generalized-bulletproofs-circuit-abstraction = { path = "../evrf/circuit-abstraction", optional = true }
|
generalized-bulletproofs-circuit-abstraction = { path = "../evrf/circuit-abstraction", optional = true }
|
||||||
generalized-bulletproofs-ec-gadgets = { path = "../evrf/ec-gadgets", optional = true }
|
generalized-bulletproofs-ec-gadgets = { path = "../evrf/ec-gadgets", optional = true }
|
||||||
|
|
||||||
|
secq256k1 = { path = "../evrf/secq256k1", optional = true }
|
||||||
|
embedwards25519 = { path = "../evrf/embedwards25519", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
|
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
|
||||||
rand = { version = "0.8", default-features = false, features = ["std"] }
|
rand = { version = "0.8", default-features = false, features = ["std"] }
|
||||||
@@ -90,5 +93,7 @@ evrf = [
|
|||||||
"dep:generalized-bulletproofs-circuit-abstraction",
|
"dep:generalized-bulletproofs-circuit-abstraction",
|
||||||
"dep:generalized-bulletproofs-ec-gadgets",
|
"dep:generalized-bulletproofs-ec-gadgets",
|
||||||
]
|
]
|
||||||
|
evrf-secp256k1 = ["evrf", "ciphersuite/secp256k1", "secq256k1"]
|
||||||
|
evrf-ed25519 = ["evrf", "ciphersuite/ed25519", "embedwards25519"]
|
||||||
tests = ["rand_core/getrandom"]
|
tests = ["rand_core/getrandom"]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -33,6 +33,18 @@ pub trait EvrfCurve: Ciphersuite {
|
|||||||
type EmbeddedCurveParameters: DiscreteLogParameters;
|
type EmbeddedCurveParameters: DiscreteLogParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "evrf-secp256k1")]
|
||||||
|
impl EvrfCurve for ciphersuite::Secp256k1 {
|
||||||
|
type EmbeddedCurve = secq256k1::Secq256k1;
|
||||||
|
type EmbeddedCurveParameters = secq256k1::Secq256k1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "evrf-ed25519")]
|
||||||
|
impl EvrfCurve for ciphersuite::Ed25519 {
|
||||||
|
type EmbeddedCurve = embedwards25519::Embedwards25519;
|
||||||
|
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
|
||||||
|
}
|
||||||
|
|
||||||
fn sample_point<C: Ciphersuite>(rng: &mut (impl RngCore + CryptoRng)) -> C::G {
|
fn sample_point<C: Ciphersuite>(rng: &mut (impl RngCore + CryptoRng)) -> C::G {
|
||||||
let mut repr = <C::G as GroupEncoding>::Repr::default();
|
let mut repr = <C::G as GroupEncoding>::Repr::default();
|
||||||
loop {
|
loop {
|
||||||
@@ -742,7 +754,6 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Dedicated error
|
|
||||||
/// Verify an eVRF proof, returning the commitments output.
|
/// Verify an eVRF proof, returning the commitments output.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn verify(
|
pub(crate) fn verify(
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ use generalized_bulletproofs_circuit_abstraction::*;
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Parameters for a discrete logarithm proof.
|
/// Parameters for a discrete logarithm proof.
|
||||||
|
///
|
||||||
|
/// This isn't required to be implemented by the Field/Group/Ciphersuite, solely a struct, to
|
||||||
|
/// enable parameterization of discrete log proofs to the bitlength of the discrete logarithm.
|
||||||
|
/// While that may be F::NUM_BITS, a discrete log proof a for a full scalar, it could also be 64,
|
||||||
|
/// a discrete log proof for a u64 (such as if opening a Pedersen commitment in-circuit).
|
||||||
pub trait DiscreteLogParameters {
|
pub trait DiscreteLogParameters {
|
||||||
/// The amount of bits used to represent a scalar.
|
/// The amount of bits used to represent a scalar.
|
||||||
type ScalarBits: ArrayLength;
|
type ScalarBits: ArrayLength;
|
||||||
|
|||||||
@@ -21,14 +21,15 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
|||||||
zeroize = { version = "^1.5", default-features = false, features = ["std", "zeroize_derive"] }
|
zeroize = { version = "^1.5", default-features = false, features = ["std", "zeroize_derive"] }
|
||||||
subtle = { version = "^2.4", default-features = false, features = ["std"] }
|
subtle = { version = "^2.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
ff = { version = "0.13", default-features = false, features = ["std", "bits"] }
|
generic-array = { version = "0.14", default-features = false }
|
||||||
group = { version = "0.13", default-features = false }
|
|
||||||
|
|
||||||
crypto-bigint = { version = "0.5", default-features = false, features = ["zeroize"] }
|
crypto-bigint = { version = "0.5", default-features = false, features = ["zeroize"] }
|
||||||
|
|
||||||
dalek-ff-group = { path = "../../dalek-ff-group", version = "0.4", default-features = false }
|
dalek-ff-group = { path = "../../dalek-ff-group", version = "0.4", default-features = false }
|
||||||
|
|
||||||
|
blake2 = { version = "0.10", default-features = false, features = ["std"] }
|
||||||
|
ciphersuite = { path = "../../ciphersuite", version = "0.4", default-features = false, features = ["std"] }
|
||||||
ec-divisors = { path = "../divisors" }
|
ec-divisors = { path = "../divisors" }
|
||||||
|
generalized-bulletproofs-ec-gadgets = { path = "../ec-gadgets" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|||||||
@@ -90,7 +90,9 @@ macro_rules! field {
|
|||||||
|
|
||||||
use crypto_bigint::{Integer, NonZero, Encoding, impl_modulus};
|
use crypto_bigint::{Integer, NonZero, Encoding, impl_modulus};
|
||||||
|
|
||||||
use ff::{Field, PrimeField, FieldBits, PrimeFieldBits, helpers::sqrt_ratio_generic};
|
use ciphersuite::group::ff::{
|
||||||
|
Field, PrimeField, FieldBits, PrimeFieldBits, helpers::sqrt_ratio_generic,
|
||||||
|
};
|
||||||
|
|
||||||
use $crate::backend::u8_from_bool;
|
use $crate::backend::u8_from_bool;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
|
|
||||||
|
use generic_array::typenum::{Sum, Diff, Quot, U, U1, U2};
|
||||||
|
use ciphersuite::group::{ff::PrimeField, Group};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod backend;
|
mod backend;
|
||||||
|
|
||||||
@@ -11,3 +14,34 @@ pub use dalek_ff_group::Scalar as FieldElement;
|
|||||||
|
|
||||||
mod point;
|
mod point;
|
||||||
pub use point::Point;
|
pub use point::Point;
|
||||||
|
|
||||||
|
/// Ciphersuite for Embedwards25519.
|
||||||
|
///
|
||||||
|
/// hash_to_F is implemented with a naive concatenation of the dst and data, allowing transposition
|
||||||
|
/// between the two. This means `dst: b"abc", data: b"def"`, will produce the same scalar as
|
||||||
|
/// `dst: "abcdef", data: b""`. Please use carefully, not letting dsts be substrings of each other.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, zeroize::Zeroize)]
|
||||||
|
pub struct Embedwards25519;
|
||||||
|
impl ciphersuite::Ciphersuite for Embedwards25519 {
|
||||||
|
type F = Scalar;
|
||||||
|
type G = Point;
|
||||||
|
type H = blake2::Blake2b512;
|
||||||
|
|
||||||
|
const ID: &'static [u8] = b"embedwards25519";
|
||||||
|
|
||||||
|
fn generator() -> Self::G {
|
||||||
|
Point::generator()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F {
|
||||||
|
use blake2::Digest;
|
||||||
|
Scalar::wide_reduce(Self::H::digest([dst, data].concat()).as_slice().try_into().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl generalized_bulletproofs_ec_gadgets::DiscreteLogParameters for Embedwards25519 {
|
||||||
|
type ScalarBits = U<{ Scalar::NUM_BITS as usize }>;
|
||||||
|
type XCoefficients = Quot<Sum<Self::ScalarBits, U1>, U2>;
|
||||||
|
type XCoefficientsMinusOne = Diff<Self::XCoefficients, U1>;
|
||||||
|
type YxCoefficients = Diff<Quot<Sum<Self::ScalarBits, U1>, U2>, U2>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use rand_core::RngCore;
|
|||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
use subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable};
|
use subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable};
|
||||||
|
|
||||||
use group::{
|
use ciphersuite::group::{
|
||||||
ff::{Field, PrimeField, PrimeFieldBits},
|
ff::{Field, PrimeField, PrimeFieldBits},
|
||||||
Group, GroupEncoding,
|
Group, GroupEncoding,
|
||||||
prime::PrimeGroup,
|
prime::PrimeGroup,
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
|||||||
zeroize = { version = "^1.5", default-features = false, features = ["std", "zeroize_derive"] }
|
zeroize = { version = "^1.5", default-features = false, features = ["std", "zeroize_derive"] }
|
||||||
subtle = { version = "^2.4", default-features = false, features = ["std"] }
|
subtle = { version = "^2.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
ff = { version = "0.13", default-features = false, features = ["std", "bits"] }
|
|
||||||
group = { version = "0.13", default-features = false }
|
|
||||||
|
|
||||||
generic-array = { version = "0.14", default-features = false }
|
generic-array = { version = "0.14", default-features = false }
|
||||||
crypto-bigint = { version = "0.5", default-features = false, features = ["zeroize"] }
|
crypto-bigint = { version = "0.5", default-features = false, features = ["zeroize"] }
|
||||||
|
|
||||||
k256 = { version = "0.13", default-features = false, features = ["arithmetic"] }
|
k256 = { version = "0.13", default-features = false, features = ["arithmetic"] }
|
||||||
|
|
||||||
|
blake2 = { version = "0.10", default-features = false, features = ["std"] }
|
||||||
|
ciphersuite = { path = "../../ciphersuite", version = "0.4", default-features = false, features = ["std"] }
|
||||||
ec-divisors = { path = "../divisors" }
|
ec-divisors = { path = "../divisors" }
|
||||||
|
generalized-bulletproofs-ec-gadgets = { path = "../ec-gadgets" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|||||||
@@ -90,7 +90,9 @@ macro_rules! field {
|
|||||||
|
|
||||||
use crypto_bigint::{Integer, NonZero, Encoding, impl_modulus};
|
use crypto_bigint::{Integer, NonZero, Encoding, impl_modulus};
|
||||||
|
|
||||||
use ff::{Field, PrimeField, FieldBits, PrimeFieldBits, helpers::sqrt_ratio_generic};
|
use ciphersuite::group::ff::{
|
||||||
|
Field, PrimeField, FieldBits, PrimeFieldBits, helpers::sqrt_ratio_generic,
|
||||||
|
};
|
||||||
|
|
||||||
use $crate::backend::u8_from_bool;
|
use $crate::backend::u8_from_bool;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
|
|
||||||
|
use generic_array::typenum::{Sum, Diff, Quot, U, U1, U2};
|
||||||
|
use ciphersuite::group::{ff::PrimeField, Group};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod backend;
|
mod backend;
|
||||||
|
|
||||||
@@ -11,3 +14,34 @@ pub use k256::Scalar as FieldElement;
|
|||||||
|
|
||||||
mod point;
|
mod point;
|
||||||
pub use point::Point;
|
pub use point::Point;
|
||||||
|
|
||||||
|
/// Ciphersuite for Secq256k1.
|
||||||
|
///
|
||||||
|
/// hash_to_F is implemented with a naive concatenation of the dst and data, allowing transposition
|
||||||
|
/// between the two. This means `dst: b"abc", data: b"def"`, will produce the same scalar as
|
||||||
|
/// `dst: "abcdef", data: b""`. Please use carefully, not letting dsts be substrings of each other.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, zeroize::Zeroize)]
|
||||||
|
pub struct Secq256k1;
|
||||||
|
impl ciphersuite::Ciphersuite for Secq256k1 {
|
||||||
|
type F = Scalar;
|
||||||
|
type G = Point;
|
||||||
|
type H = blake2::Blake2b512;
|
||||||
|
|
||||||
|
const ID: &'static [u8] = b"secq256k1";
|
||||||
|
|
||||||
|
fn generator() -> Self::G {
|
||||||
|
Point::generator()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F {
|
||||||
|
use blake2::Digest;
|
||||||
|
Scalar::wide_reduce(Self::H::digest([dst, data].concat()).as_slice().try_into().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl generalized_bulletproofs_ec_gadgets::DiscreteLogParameters for Secq256k1 {
|
||||||
|
type ScalarBits = U<{ Scalar::NUM_BITS as usize }>;
|
||||||
|
type XCoefficients = Quot<Sum<Self::ScalarBits, U1>, U2>;
|
||||||
|
type XCoefficientsMinusOne = Diff<Self::XCoefficients, U1>;
|
||||||
|
type YxCoefficients = Diff<Quot<Sum<Self::ScalarBits, U1>, U2>, U2>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable, Conditio
|
|||||||
|
|
||||||
use generic_array::{typenum::U33, GenericArray};
|
use generic_array::{typenum::U33, GenericArray};
|
||||||
|
|
||||||
use group::{
|
use ciphersuite::group::{
|
||||||
ff::{Field, PrimeField, PrimeFieldBits},
|
ff::{Field, PrimeField, PrimeFieldBits},
|
||||||
Group, GroupEncoding,
|
Group, GroupEncoding,
|
||||||
prime::PrimeGroup,
|
prime::PrimeGroup,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ serde_json = { version = "1", default-features = false, features = ["std"] }
|
|||||||
ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std", "ristretto"] }
|
ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std", "ristretto"] }
|
||||||
|
|
||||||
transcript = { package = "flexible-transcript", path = "../crypto/transcript", default-features = false, features = ["std"] }
|
transcript = { package = "flexible-transcript", path = "../crypto/transcript", default-features = false, features = ["std"] }
|
||||||
|
dkg = { package = "dkg", path = "../crypto/dkg", default-features = false, features = ["std"] }
|
||||||
frost = { package = "modular-frost", path = "../crypto/frost", default-features = false, features = ["ristretto"] }
|
frost = { package = "modular-frost", path = "../crypto/frost", default-features = false, features = ["ristretto"] }
|
||||||
frost-schnorrkel = { path = "../crypto/schnorrkel", default-features = false }
|
frost-schnorrkel = { path = "../crypto/schnorrkel", default-features = false }
|
||||||
|
|
||||||
@@ -81,12 +82,12 @@ dockertest = "0.4"
|
|||||||
serai-docker-tests = { path = "../tests/docker" }
|
serai-docker-tests = { path = "../tests/docker" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
secp256k1 = ["k256", "frost/secp256k1"]
|
secp256k1 = ["k256", "dkg/evrf-secp256k1", "frost/secp256k1"]
|
||||||
bitcoin = ["dep:secp256k1", "secp256k1", "bitcoin-serai", "serai-client/bitcoin"]
|
bitcoin = ["dep:secp256k1", "secp256k1", "bitcoin-serai", "serai-client/bitcoin"]
|
||||||
|
|
||||||
ethereum = ["secp256k1", "ethereum-serai/tests"]
|
ethereum = ["secp256k1", "ethereum-serai/tests"]
|
||||||
|
|
||||||
ed25519 = ["dalek-ff-group", "frost/ed25519"]
|
ed25519 = ["dalek-ff-group", "dkg/evrf-ed25519", "frost/ed25519"]
|
||||||
monero = ["ed25519", "monero-simple-request-rpc", "monero-wallet", "serai-client/monero"]
|
monero = ["ed25519", "monero-simple-request-rpc", "monero-wallet", "serai-client/monero"]
|
||||||
|
|
||||||
binaries = ["env_logger", "serai-env", "message-queue"]
|
binaries = ["env_logger", "serai-env", "message-queue"]
|
||||||
|
|||||||
Reference in New Issue
Block a user