dkg-evrf crate

monero-oxide relies on ciphersuite, which is in-tree, yet we've made breaking
changes since. This commit adds a patch so
monero-oxide -> patches/ciphersuite -> crypto/ciphersuite, with
patches/ciphersuite resolving the breaking changes.
This commit is contained in:
Luke Parker
2025-08-25 04:49:54 -04:00
parent 33faa53b56
commit 738babf7e9
27 changed files with 1419 additions and 1085 deletions

View File

@@ -5,26 +5,26 @@ use rand_core::OsRng;
use rand::seq::SliceRandom;
use ciphersuite::{group::ff::Field, Ciphersuite};
use embedwards25519::Embedwards25519;
use crate::{
Participant,
evrf::*,
tests::{THRESHOLD, PARTICIPANTS, recover_key},
};
use dkg_recovery::recover_key;
use crate::{Participant, Curves, Generators, VerifyResult, Dkg, Ristretto};
mod proof;
use proof::{Pallas, Vesta};
const THRESHOLD: u16 = 3;
const PARTICIPANTS: u16 = 5;
#[test]
fn evrf_dkg() {
let generators = EvrfGenerators::<Pallas>::new(THRESHOLD, PARTICIPANTS);
fn dkg() {
let generators = Generators::<Ristretto>::new(THRESHOLD, PARTICIPANTS);
let context = [0; 32];
let mut priv_keys = vec![];
let mut pub_keys = vec![];
for i in 0 .. PARTICIPANTS {
let priv_key = <Vesta as Ciphersuite>::F::random(&mut OsRng);
pub_keys.push(<Vesta as Ciphersuite>::generator() * priv_key);
let priv_key = <Embedwards25519 as Ciphersuite>::F::random(&mut OsRng);
pub_keys.push(<Embedwards25519 as Ciphersuite>::generator() * priv_key);
priv_keys.push((Participant::new(1 + i).unwrap(), Zeroizing::new(priv_key)));
}
@@ -34,7 +34,7 @@ fn evrf_dkg() {
for (i, priv_key) in priv_keys.iter().take(usize::from(THRESHOLD)) {
participations.insert(
*i,
EvrfDkg::<Pallas>::participate(
Dkg::<Ristretto>::participate(
&mut OsRng,
&generators,
context,
@@ -46,7 +46,7 @@ fn evrf_dkg() {
);
}
let VerifyResult::Valid(dkg) = EvrfDkg::<Pallas>::verify(
let VerifyResult::Valid(dkg) = Dkg::<Ristretto>::verify(
&mut OsRng,
&generators,
context,
@@ -67,13 +67,21 @@ fn evrf_dkg() {
assert_eq!(keys.params().t(), THRESHOLD);
assert_eq!(keys.params().n(), PARTICIPANTS);
group_key = group_key.or(Some(keys.group_key()));
verification_shares = verification_shares.or(Some(keys.verification_shares()));
let these_verification_shares = Participant::iter()
.take(usize::from(PARTICIPANTS))
.map(|i| (i, keys.original_verification_share(i)))
.collect::<HashMap<_, _>>();
verification_shares = verification_shares.or(Some(these_verification_shares.clone()));
assert_eq!(Some(keys.group_key()), group_key);
assert_eq!(Some(keys.verification_shares()), verification_shares);
assert_eq!(Some(these_verification_shares), verification_shares);
all_keys.insert(i, keys);
}
// TODO: Test for all possible combinations of keys
assert_eq!(Pallas::generator() * recover_key(&all_keys), group_key.unwrap());
assert_eq!(
<<Ristretto as Curves>::ToweringCurve as Ciphersuite>::generator() *
*recover_key(&all_keys.values().cloned().collect::<Vec<_>>()).unwrap(),
group_key.unwrap()
);
}

View File

@@ -2,94 +2,49 @@ use std::time::Instant;
use rand_core::OsRng;
use zeroize::{Zeroize, Zeroizing};
use generic_array::typenum::{Sum, Diff, Quot, U, U1, U2};
use blake2::{Digest, Blake2b512};
use zeroize::Zeroizing;
use ciphersuite::{
group::{
ff::{FromUniformBytes, Field, PrimeField},
Group,
},
Ciphersuite, Secp256k1, Ed25519, Ristretto,
group::{ff::Field, Group},
Ciphersuite,
};
use pasta_curves::{Ep, Eq, Fp, Fq};
use generalized_bulletproofs::{Generators, tests::generators};
use generalized_bulletproofs_ec_gadgets::DiscreteLogParameters;
use crate::evrf::proof::*;
use crate::{
Curves, Ristretto,
proof::*,
tests::{THRESHOLD, PARTICIPANTS},
};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub(crate) struct Pallas;
impl Ciphersuite for Pallas {
type F = Fq;
type G = Ep;
type H = Blake2b512;
const ID: &'static [u8] = b"Pallas";
fn generator() -> Ep {
Ep::generator()
}
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
// This naive concat may be insecure in a real world deployment
// This is solely test code so it's fine
Self::F::from_uniform_bytes(&Self::H::digest([dst, msg].concat()).into())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub(crate) struct Vesta;
impl Ciphersuite for Vesta {
type F = Fp;
type G = Eq;
type H = Blake2b512;
const ID: &'static [u8] = b"Vesta";
fn generator() -> Eq {
Eq::generator()
}
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
// This naive concat may be insecure in a real world deployment
// This is solely test code so it's fine
Self::F::from_uniform_bytes(&Self::H::digest([dst, msg].concat()).into())
}
}
pub struct VestaParams;
impl DiscreteLogParameters for VestaParams {
type ScalarBits = U<{ <<Vesta as Ciphersuite>::F as PrimeField>::NUM_BITS as usize }>;
type XCoefficients = Quot<Sum<Self::ScalarBits, U1>, U2>;
type XCoefficientsMinusOne = Diff<Self::XCoefficients, U1>;
type YxCoefficients = Diff<Quot<Sum<Sum<Self::ScalarBits, U1>, U1>, U2>, U2>;
}
impl EvrfCurve for Pallas {
type EmbeddedCurve = Vesta;
type EmbeddedCurveParameters = VestaParams;
}
fn evrf_proof_test<C: EvrfCurve>() {
fn proof<C: Curves>() {
let generators = generators(2048);
let vesta_private_key = Zeroizing::new(<C::EmbeddedCurve as Ciphersuite>::F::random(&mut OsRng));
let ecdh_public_keys = [
<C::EmbeddedCurve as Ciphersuite>::G::random(&mut OsRng),
<C::EmbeddedCurve as Ciphersuite>::G::random(&mut OsRng),
];
let embedded_private_key =
Zeroizing::new(<C::EmbeddedCurve as Ciphersuite>::F::random(&mut OsRng));
let ecdh_public_keys: [_; PARTICIPANTS as usize] =
core::array::from_fn(|_| <C::EmbeddedCurve as Ciphersuite>::G::random(&mut OsRng));
let time = Instant::now();
let res =
Evrf::<C>::prove(&mut OsRng, &generators, [0; 32], 1, &ecdh_public_keys, &vesta_private_key)
.unwrap();
let res = Proof::<C>::prove(
&mut OsRng,
&generators,
[0; 32],
THRESHOLD.into(),
&ecdh_public_keys,
&embedded_private_key,
)
.unwrap();
println!("Proving time: {:?}", time.elapsed());
let time = Instant::now();
let mut verifier = Generators::batch_verifier();
Evrf::<C>::verify(
Proof::<C>::verify(
&mut OsRng,
&generators,
&mut verifier,
[0; 32],
1,
THRESHOLD.into(),
&ecdh_public_keys,
C::EmbeddedCurve::generator() * *vesta_private_key,
C::EmbeddedCurve::generator() * *embedded_private_key,
&res.proof,
)
.unwrap();
@@ -98,21 +53,6 @@ fn evrf_proof_test<C: EvrfCurve>() {
}
#[test]
fn pallas_evrf_proof_test() {
evrf_proof_test::<Pallas>();
}
#[test]
fn secp256k1_evrf_proof_test() {
evrf_proof_test::<Secp256k1>();
}
#[test]
fn ed25519_evrf_proof_test() {
evrf_proof_test::<Ed25519>();
}
#[test]
fn ristretto_evrf_proof_test() {
evrf_proof_test::<Ristretto>();
fn ristretto_proof() {
proof::<Ristretto>();
}