mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-13 14:39:25 +00:00
Add the openings of the PCs to the eVRF as necessary
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -2437,7 +2437,7 @@ dependencies = [
|
||||
"generalized-bulletproofs-circuit-abstraction",
|
||||
"generalized-bulletproofs-ec-gadgets",
|
||||
"generic-array 1.1.0",
|
||||
"multiexp",
|
||||
"pasta_curves",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
@@ -5762,8 +5762,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pasta_curves"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095"
|
||||
source = "git+https://github.com/kayabaNerve/pasta_curves?rev=a46b5be95cacbff54d06aad8d3bbcba42e05d616#a46b5be95cacbff54d06aad8d3bbcba42e05d616"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"ff",
|
||||
@@ -5772,6 +5771,7 @@ dependencies = [
|
||||
"rand",
|
||||
"static_assertions",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -161,6 +161,9 @@ matches = { path = "patches/matches" }
|
||||
option-ext = { path = "patches/option-ext" }
|
||||
directories-next = { path = "patches/directories-next" }
|
||||
|
||||
# The official pasta_curves repo doesn't support Zeroize
|
||||
pasta_curves = { git = "https://github.com/kayabaNerve/pasta_curves", rev = "a46b5be95cacbff54d06aad8d3bbcba42e05d616" }
|
||||
|
||||
[workspace.lints.clippy]
|
||||
unwrap_or_default = "allow"
|
||||
borrow_as_ptr = "deny"
|
||||
|
||||
@@ -22,11 +22,14 @@ rand_chacha = { version = "0.3", default-features = false, features = ["std"] }
|
||||
generic-array = { version = "1", default-features = false, features = ["alloc"] }
|
||||
|
||||
blake2 = { version = "0.10", default-features = false, features = ["std"] }
|
||||
|
||||
multiexp = { path = "../multiexp", version = "0.4", default-features = false, features = ["std", "batch"] }
|
||||
ciphersuite = { path = "../ciphersuite", version = "0.4", default-features = false, features = ["std"] }
|
||||
|
||||
ec-divisors = { path = "./divisors" }
|
||||
generalized-bulletproofs = { path = "./generalized-bulletproofs" }
|
||||
generalized-bulletproofs-circuit-abstraction = { path = "./circuit-abstraction" }
|
||||
generalized-bulletproofs-ec-gadgets = { path = "./ec-gadgets" }
|
||||
|
||||
[dev-dependencies]
|
||||
generalized-bulletproofs = { path = "./generalized-bulletproofs", features = ["tests"] }
|
||||
ec-divisors = { path = "./divisors", features = ["pasta"] }
|
||||
pasta_curves = "0.5"
|
||||
|
||||
@@ -20,6 +20,7 @@ group = "0.13"
|
||||
|
||||
hex = { version = "0.4", optional = true }
|
||||
dalek-ff-group = { path = "../../dalek-ff-group", features = ["std"], optional = true }
|
||||
pasta_curves = { version = "0.5", default-features = false, features = ["bits", "alloc"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand_core = { version = "0.6", features = ["getrandom"] }
|
||||
@@ -30,3 +31,4 @@ pasta_curves = { version = "0.5", default-features = false, features = ["bits",
|
||||
|
||||
[features]
|
||||
ed25519 = ["hex", "dalek-ff-group"]
|
||||
pasta = ["pasta_curves"]
|
||||
|
||||
@@ -180,6 +180,48 @@ pub fn new_divisor<C: DivisorCurve>(points: &[C]) -> Option<Poly<C::FieldElement
|
||||
Some(divs.remove(0).1)
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "pasta"))]
|
||||
mod pasta {
|
||||
use group::{ff::Field, Curve};
|
||||
use pasta_curves::{
|
||||
arithmetic::{Coordinates, CurveAffine},
|
||||
Ep, Fp, Eq, Fq,
|
||||
};
|
||||
use crate::DivisorCurve;
|
||||
|
||||
impl DivisorCurve for Ep {
|
||||
type FieldElement = Fp;
|
||||
|
||||
fn a() -> Self::FieldElement {
|
||||
Self::FieldElement::ZERO
|
||||
}
|
||||
fn b() -> Self::FieldElement {
|
||||
Self::FieldElement::from(5u64)
|
||||
}
|
||||
|
||||
fn to_xy(point: Self) -> Option<(Self::FieldElement, Self::FieldElement)> {
|
||||
Option::<Coordinates<_>>::from(point.to_affine().coordinates())
|
||||
.map(|coords| (*coords.x(), *coords.y()))
|
||||
}
|
||||
}
|
||||
|
||||
impl DivisorCurve for Eq {
|
||||
type FieldElement = Fq;
|
||||
|
||||
fn a() -> Self::FieldElement {
|
||||
Self::FieldElement::ZERO
|
||||
}
|
||||
fn b() -> Self::FieldElement {
|
||||
Self::FieldElement::from(5u64)
|
||||
}
|
||||
|
||||
fn to_xy(point: Self) -> Option<(Self::FieldElement, Self::FieldElement)> {
|
||||
Option::<Coordinates<_>>::from(point.to_affine().coordinates())
|
||||
.map(|coords| (*coords.x(), *coords.y()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "ed25519"))]
|
||||
mod ed25519 {
|
||||
use group::{
|
||||
|
||||
@@ -1,30 +1,11 @@
|
||||
use rand_core::OsRng;
|
||||
|
||||
use group::{ff::Field, Group, Curve};
|
||||
use group::{ff::Field, Group};
|
||||
use dalek_ff_group::EdwardsPoint;
|
||||
use pasta_curves::{
|
||||
arithmetic::{Coordinates, CurveAffine},
|
||||
Ep, Fp,
|
||||
};
|
||||
use pasta_curves::{Ep, Eq};
|
||||
|
||||
use crate::{DivisorCurve, Poly, new_divisor};
|
||||
|
||||
impl DivisorCurve for Ep {
|
||||
type FieldElement = Fp;
|
||||
|
||||
fn a() -> Self::FieldElement {
|
||||
Self::FieldElement::ZERO
|
||||
}
|
||||
fn b() -> Self::FieldElement {
|
||||
Self::FieldElement::from(5u64)
|
||||
}
|
||||
|
||||
fn to_xy(point: Self) -> Option<(Self::FieldElement, Self::FieldElement)> {
|
||||
Option::<Coordinates<_>>::from(point.to_affine().coordinates())
|
||||
.map(|coords| (*coords.x(), *coords.y()))
|
||||
}
|
||||
}
|
||||
|
||||
// Equation 4 in the security proofs
|
||||
fn check_divisor<C: DivisorCurve>(points: Vec<C>) {
|
||||
// Create the divisor
|
||||
@@ -208,6 +189,13 @@ fn test_divisor_pallas() {
|
||||
test_subset_sum_to_infinity::<Ep>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_divisor_vesta() {
|
||||
test_divisor::<Eq>();
|
||||
test_same_point::<Eq>();
|
||||
test_subset_sum_to_infinity::<Eq>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_divisor_ed25519() {
|
||||
// Since we're implementing Wei25519 ourselves, check the isomorphism works as expected
|
||||
|
||||
@@ -14,6 +14,10 @@ const POINT: u8 = 1;
|
||||
const CHALLENGE: u8 = 2;
|
||||
|
||||
fn challenge<F: PrimeField>(digest: &mut Blake2b512) -> F {
|
||||
// Panic if this is such a wide field, we won't successfully perform a reduction into an unbiased
|
||||
// scalar
|
||||
debug_assert!((F::NUM_BITS + 128) < 512);
|
||||
|
||||
digest.update([CHALLENGE]);
|
||||
let chl = digest.clone().finalize();
|
||||
|
||||
@@ -78,14 +82,16 @@ impl Transcript {
|
||||
Self { digest, transcript: Vec::with_capacity(1024) }
|
||||
}
|
||||
|
||||
pub(crate) fn push_scalar(&mut self, scalar: impl PrimeField) {
|
||||
/// Push a scalar onto the transcript.
|
||||
pub fn push_scalar(&mut self, scalar: impl PrimeField) {
|
||||
self.digest.update([SCALAR]);
|
||||
let bytes = scalar.to_repr();
|
||||
self.digest.update(bytes);
|
||||
self.transcript.extend(bytes.as_ref());
|
||||
}
|
||||
|
||||
pub(crate) fn push_point(&mut self, point: impl GroupEncoding) {
|
||||
/// Push a point onto the transcript.
|
||||
pub fn push_point(&mut self, point: impl GroupEncoding) {
|
||||
self.digest.update([POINT]);
|
||||
let bytes = point.to_bytes();
|
||||
self.digest.update(bytes);
|
||||
@@ -132,7 +138,8 @@ impl<'a> VerifierTranscript<'a> {
|
||||
Self { digest, transcript: proof }
|
||||
}
|
||||
|
||||
pub(crate) fn read_scalar<C: Ciphersuite>(&mut self) -> io::Result<C::F> {
|
||||
/// Read a scalar from the transcript.
|
||||
pub fn read_scalar<C: Ciphersuite>(&mut self) -> io::Result<C::F> {
|
||||
let scalar = C::read_F(&mut self.transcript)?;
|
||||
self.digest.update([SCALAR]);
|
||||
let bytes = scalar.to_repr();
|
||||
@@ -140,7 +147,8 @@ impl<'a> VerifierTranscript<'a> {
|
||||
Ok(scalar)
|
||||
}
|
||||
|
||||
pub(crate) fn read_point<C: Ciphersuite>(&mut self) -> io::Result<C::G> {
|
||||
/// Read a point from the transcript.
|
||||
pub fn read_point<C: Ciphersuite>(&mut self) -> io::Result<C::G> {
|
||||
let point = C::read_G(&mut self.transcript)?;
|
||||
self.digest.update([POINT]);
|
||||
let bytes = point.to_bytes();
|
||||
@@ -172,4 +180,9 @@ impl<'a> VerifierTranscript<'a> {
|
||||
pub fn challenge<F: PrimeField>(&mut self) -> F {
|
||||
challenge(&mut self.digest)
|
||||
}
|
||||
|
||||
/// Complete the transcript, returning the advanced slice.
|
||||
pub fn complete(self) -> &'a [u8] {
|
||||
self.transcript
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use rand_chacha::ChaCha20Rng;
|
||||
|
||||
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
|
||||
|
||||
use blake2::{Digest, Blake2s256};
|
||||
use ciphersuite::{
|
||||
group::{
|
||||
ff::{Field, PrimeField, PrimeFieldBits},
|
||||
@@ -24,6 +25,9 @@ use generalized_bulletproofs_circuit_abstraction::*;
|
||||
use ec_divisors::{DivisorCurve, new_divisor};
|
||||
use generalized_bulletproofs_ec_gadgets::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// A curve to perform the eVRF with.
|
||||
pub trait EvrfCurve: Ciphersuite {
|
||||
type EmbeddedCurve: Ciphersuite;
|
||||
@@ -39,7 +43,7 @@ pub struct EvrfProveResult<C: Ciphersuite> {
|
||||
/// A struct to prove/verify eVRFs with.
|
||||
pub struct Evrf;
|
||||
impl Evrf {
|
||||
fn seed_to_points<C: Ciphersuite>(seed: [u8; 32], quantity: usize) -> Vec<C::G> {
|
||||
fn transcript_to_points<C: Ciphersuite>(seed: [u8; 32], quantity: usize) -> Vec<C::G> {
|
||||
// We need to do two Diffie-Hellman's per point in order to achieve an unbiased result
|
||||
let quantity = 2 * quantity;
|
||||
|
||||
@@ -58,7 +62,7 @@ impl Evrf {
|
||||
fn point_with_dlogs<Parameters: DiscreteLogParameters>(
|
||||
quantity: usize,
|
||||
generators_to_use: usize,
|
||||
) -> Vec<PointWithDlog<Parameters>> {
|
||||
) -> Vec<PointWithDlog<Parameters>> {
|
||||
let quantity = 2 * quantity;
|
||||
|
||||
fn read_one_from_tape(generators_to_use: usize, start: &mut usize) -> Variable {
|
||||
@@ -91,8 +95,8 @@ impl Evrf {
|
||||
|
||||
let dlog = read_from_tape(generators_to_use, &mut start);
|
||||
|
||||
let mut res = Vec::with_capacity(quantity);
|
||||
for _ in 0 .. quantity {
|
||||
let mut res = Vec::with_capacity(quantity + 1);
|
||||
let mut read_point_with_dlog = || {
|
||||
let zero = read_one_from_tape(generators_to_use, &mut start);
|
||||
let x_from_power_of_2 = read_from_tape(generators_to_use, &mut start);
|
||||
let yx = read_from_tape(generators_to_use, &mut start);
|
||||
@@ -105,7 +109,14 @@ impl Evrf {
|
||||
);
|
||||
|
||||
res.push(PointWithDlog { dlog: dlog.clone(), divisor, point });
|
||||
};
|
||||
|
||||
for _ in 0 .. quantity {
|
||||
// One for each DH proven
|
||||
read_point_with_dlog();
|
||||
}
|
||||
// And one more for the proof this is the discrete log of the public key
|
||||
read_point_with_dlog();
|
||||
res
|
||||
}
|
||||
|
||||
@@ -175,7 +186,7 @@ impl Evrf {
|
||||
rng: &mut (impl RngCore + CryptoRng),
|
||||
generators: &Generators<C>,
|
||||
evrf_private_key: <<C as EvrfCurve>::EmbeddedCurve as Ciphersuite>::F,
|
||||
seed: [u8; 32],
|
||||
invocation: [u8; 32],
|
||||
quantity: usize,
|
||||
) -> Result<EvrfProveResult<C>, AcError>
|
||||
where
|
||||
@@ -187,7 +198,19 @@ impl Evrf {
|
||||
b: <<C as EvrfCurve>::EmbeddedCurve as Ciphersuite>::G::b(),
|
||||
};
|
||||
|
||||
let points = Self::seed_to_points::<C::EmbeddedCurve>(seed, quantity);
|
||||
// Combine the invocation and the public key into a transcript
|
||||
let transcript = Blake2s256::digest(
|
||||
[
|
||||
invocation.as_slice(),
|
||||
(<<C as EvrfCurve>::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key)
|
||||
.to_bytes()
|
||||
.as_ref(),
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
.into();
|
||||
|
||||
let points = Self::transcript_to_points::<C::EmbeddedCurve>(transcript, quantity);
|
||||
|
||||
let num_bits: u32 = <<C as EvrfCurve>::EmbeddedCurve as Ciphersuite>::F::NUM_BITS;
|
||||
|
||||
@@ -218,6 +241,8 @@ impl Evrf {
|
||||
let mut h_value = dlog[h as usize];
|
||||
let mut h_prior_value = dlog[(h as usize) - 1];
|
||||
|
||||
// TODO: Squash the following two loops by iterating from the top bit to the bottom bit
|
||||
|
||||
let mut prior_scalar = dlog[(h as usize) - 1];
|
||||
for (i, scalar) in dlog.iter().enumerate().skip(h as usize) {
|
||||
let is_zero = <C as Ciphersuite>::F::ZERO.ct_eq(scalar);
|
||||
@@ -367,7 +392,7 @@ impl Evrf {
|
||||
commitments.push(PedersenCommitment { value: **scalar, mask: C::F::random(&mut *rng) });
|
||||
}
|
||||
|
||||
let mut transcript = ProverTranscript::new(seed);
|
||||
let mut transcript = ProverTranscript::new(transcript);
|
||||
let commited_commitments = transcript.write_commitments(
|
||||
vector_commitments
|
||||
.iter()
|
||||
@@ -383,7 +408,7 @@ impl Evrf {
|
||||
.collect(),
|
||||
);
|
||||
|
||||
let mut circuit = Circuit::prove(vector_commitments, commitments);
|
||||
let mut circuit = Circuit::prove(vector_commitments, commitments.clone());
|
||||
Self::circuit::<C>(
|
||||
&curve_spec,
|
||||
evrf_public_key,
|
||||
@@ -402,7 +427,32 @@ impl Evrf {
|
||||
else {
|
||||
panic!("proving yet wasn't yielded the witness");
|
||||
};
|
||||
statement.prove(rng, &mut transcript, witness).unwrap();
|
||||
statement.prove(&mut *rng, &mut transcript, witness).unwrap();
|
||||
|
||||
// Push the reveal onto the transcript
|
||||
for scalar in &scalars {
|
||||
transcript.push_point(generators.g() * **scalar);
|
||||
}
|
||||
|
||||
// Define a weight to aggregate the commitments with
|
||||
let mut agg_weights = Vec::with_capacity(quantity);
|
||||
agg_weights.push(C::F::ONE);
|
||||
while agg_weights.len() < quantity {
|
||||
agg_weights.push(transcript.challenge::<C::F>());
|
||||
}
|
||||
let mut x = commitments
|
||||
.iter()
|
||||
.zip(&agg_weights)
|
||||
.map(|(commitment, weight)| commitment.mask * *weight)
|
||||
.sum::<C::F>();
|
||||
|
||||
// Do a Schnorr PoK for the randomness of the aggregated Pedersen commitment
|
||||
let mut r = C::F::random(&mut *rng);
|
||||
transcript.push_point(generators.h() * r);
|
||||
let c = transcript.challenge::<C::F>();
|
||||
transcript.push_scalar(r + (c * x));
|
||||
r.zeroize();
|
||||
x.zeroize();
|
||||
|
||||
Ok(EvrfProveResult { scalars, proof: transcript.complete() })
|
||||
}
|
||||
@@ -414,7 +464,7 @@ impl Evrf {
|
||||
generators: &Generators<C>,
|
||||
verifier: &mut BatchVerifier<C>,
|
||||
evrf_public_key: <<C as EvrfCurve>::EmbeddedCurve as Ciphersuite>::G,
|
||||
seed: [u8; 32],
|
||||
invocation: [u8; 32],
|
||||
quantity: usize,
|
||||
proof: &[u8],
|
||||
) -> Result<Vec<C::G>, ()>
|
||||
@@ -427,7 +477,11 @@ impl Evrf {
|
||||
b: <<C as EvrfCurve>::EmbeddedCurve as Ciphersuite>::G::b(),
|
||||
};
|
||||
|
||||
let points = Self::seed_to_points::<C::EmbeddedCurve>(seed, quantity);
|
||||
let transcript =
|
||||
Blake2s256::digest([invocation.as_slice(), evrf_public_key.to_bytes().as_ref()].concat())
|
||||
.into();
|
||||
|
||||
let points = Self::transcript_to_points::<C::EmbeddedCurve>(transcript, quantity);
|
||||
let mut generator_tables = Vec::with_capacity(1 + (2 * quantity));
|
||||
|
||||
for generator in points {
|
||||
@@ -443,14 +497,19 @@ impl Evrf {
|
||||
|
||||
let (_, generators_to_use) = Self::muls_and_generators_to_use(quantity);
|
||||
|
||||
let mut transcript = VerifierTranscript::new(seed, proof);
|
||||
let mut transcript = VerifierTranscript::new(transcript, proof);
|
||||
|
||||
let divisor_len = 1 + <C::EmbeddedCurveParameters as DiscreteLogParameters>::XCoefficientsMinusOne::USIZE + <C::EmbeddedCurveParameters as DiscreteLogParameters>::YxCoefficients::USIZE + 1;
|
||||
let dlog_len = divisor_len + 2;
|
||||
let vcs =
|
||||
(<C::EmbeddedCurveParameters as DiscreteLogParameters>::ScalarBits::USIZE + ((1 + (2 * quantity)) * dlog_len)) / (2 * generators_to_use);
|
||||
let divisor_len = 1 +
|
||||
<C::EmbeddedCurveParameters as DiscreteLogParameters>::XCoefficientsMinusOne::USIZE +
|
||||
<C::EmbeddedCurveParameters as DiscreteLogParameters>::YxCoefficients::USIZE +
|
||||
1;
|
||||
let dlog_proof_len = divisor_len + 2;
|
||||
let vcs = (<C::EmbeddedCurveParameters as DiscreteLogParameters>::ScalarBits::USIZE +
|
||||
((1 + (2 * quantity)) * dlog_proof_len))
|
||||
.div_ceil(2 * generators_to_use);
|
||||
|
||||
let commitments = transcript.read_commitments(vcs, quantity).map_err(|_| ())?;
|
||||
let all_commitments = transcript.read_commitments(vcs, quantity).map_err(|_| ())?;
|
||||
let commitments = all_commitments.V().to_vec();
|
||||
|
||||
let mut circuit = Circuit::verify();
|
||||
Self::circuit::<C>(
|
||||
@@ -464,14 +523,46 @@ impl Evrf {
|
||||
);
|
||||
|
||||
let (statement, None) =
|
||||
circuit.statement(generators.reduce(generators_to_use).ok_or(())?, commitments).unwrap()
|
||||
circuit.statement(generators.reduce(generators_to_use).ok_or(())?, all_commitments).unwrap()
|
||||
else {
|
||||
panic!("verifying yet was yielded a witness");
|
||||
};
|
||||
|
||||
statement.verify(rng, verifier, &mut transcript).map_err(|_| ())?;
|
||||
|
||||
// TODO: Unblinded PCs
|
||||
Ok(vec![])
|
||||
// Read the unblinded public keys
|
||||
let mut res = Vec::with_capacity(quantity);
|
||||
for _ in 0 .. quantity {
|
||||
res.push(transcript.read_point::<C>().map_err(|_| ())?);
|
||||
}
|
||||
|
||||
let mut agg_weights = Vec::with_capacity(quantity);
|
||||
agg_weights.push(C::F::ONE);
|
||||
while agg_weights.len() < quantity {
|
||||
agg_weights.push(transcript.challenge::<C::F>());
|
||||
}
|
||||
|
||||
let sum_points =
|
||||
res.iter().zip(&agg_weights).map(|(point, weight)| *point * *weight).sum::<C::G>();
|
||||
let sum_commitments =
|
||||
commitments.into_iter().zip(agg_weights).map(|(point, weight)| point * weight).sum::<C::G>();
|
||||
#[allow(non_snake_case)]
|
||||
let A = sum_commitments - sum_points;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
let R = transcript.read_point::<C>().map_err(|_| ())?;
|
||||
let c = transcript.challenge::<C::F>();
|
||||
let s = transcript.read_scalar::<C>().map_err(|_| ())?;
|
||||
|
||||
// Doesn't batch verify this as we can't access the internals of the GBP batch verifier
|
||||
if (R + (A * c)) != (generators.h() * s) {
|
||||
Err(())?;
|
||||
}
|
||||
|
||||
if !transcript.complete().is_empty() {
|
||||
Err(())?
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
88
crypto/evrf/src/tests.rs
Normal file
88
crypto/evrf/src/tests.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use rand_core::OsRng;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use generic_array::typenum::{Sum, Diff, Quot, U, U1, U2};
|
||||
use blake2::{Digest, Blake2b512};
|
||||
|
||||
use ciphersuite::{
|
||||
group::ff::{FromUniformBytes, PrimeField},
|
||||
Ciphersuite,
|
||||
};
|
||||
use pasta_curves::{Ep, Eq, Fp, Fq};
|
||||
|
||||
use generalized_bulletproofs::tests::generators;
|
||||
|
||||
use crate::*;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||
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)]
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
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<Self::ScalarBits, U1>, U2>, U2>;
|
||||
}
|
||||
|
||||
impl EvrfCurve for Pallas {
|
||||
type EmbeddedCurve = Vesta;
|
||||
type EmbeddedCurveParameters = VestaParams;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pasta_test() {
|
||||
let generators = generators(1024);
|
||||
let vesta_private_key = <Vesta as Ciphersuite>::F::random(&mut OsRng);
|
||||
let time = Instant::now();
|
||||
let res = Evrf::prove::<Pallas>(&mut OsRng, &generators, vesta_private_key, [0; 32], 1).unwrap();
|
||||
println!("Proving time: {:?}", Instant::now() - time);
|
||||
|
||||
let time = Instant::now();
|
||||
let mut verifier = generators.batch_verifier();
|
||||
dbg!(Evrf::verify::<Pallas>(
|
||||
&mut OsRng,
|
||||
&generators,
|
||||
&mut verifier,
|
||||
Vesta::generator() * vesta_private_key,
|
||||
[0; 32],
|
||||
1,
|
||||
&res.proof,
|
||||
)
|
||||
.unwrap());
|
||||
assert!(generators.verify(verifier));
|
||||
println!("Verifying time: {:?}", Instant::now() - time);
|
||||
}
|
||||
Reference in New Issue
Block a user