start implementing GM17 proof system
This commit is contained in:
parent
e775b47d99
commit
ff6c46240b
700
src/gm17/generator.rs
Normal file
700
src/gm17/generator.rs
Normal file
@ -0,0 +1,700 @@
|
|||||||
|
use super::super::verbose_flag;
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use pairing::{
|
||||||
|
Engine,
|
||||||
|
Wnaf,
|
||||||
|
CurveProjective,
|
||||||
|
CurveAffine
|
||||||
|
};
|
||||||
|
|
||||||
|
use ff::{
|
||||||
|
PrimeField,
|
||||||
|
Field
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
Parameters,
|
||||||
|
VerifyingKey
|
||||||
|
};
|
||||||
|
|
||||||
|
use ::{
|
||||||
|
SynthesisError,
|
||||||
|
Circuit,
|
||||||
|
ConstraintSystem,
|
||||||
|
LinearCombination,
|
||||||
|
Variable,
|
||||||
|
Index
|
||||||
|
};
|
||||||
|
|
||||||
|
use ::domain::{
|
||||||
|
EvaluationDomain,
|
||||||
|
Scalar
|
||||||
|
};
|
||||||
|
|
||||||
|
use ::multicore::{
|
||||||
|
Worker
|
||||||
|
};
|
||||||
|
|
||||||
|
// /// Generates a random common reference string for
|
||||||
|
// /// a circuit.
|
||||||
|
// pub fn generate_random_parameters<E, C, R>(
|
||||||
|
// circuit: C,
|
||||||
|
// rng: &mut R
|
||||||
|
// ) -> Result<Parameters<E>, SynthesisError>
|
||||||
|
// where E: Engine, C: Circuit<E>, R: Rng
|
||||||
|
// {
|
||||||
|
// let g1 = rng.gen();
|
||||||
|
// let g2 = rng.gen();
|
||||||
|
// let alpha = rng.gen();
|
||||||
|
// let beta = rng.gen();
|
||||||
|
// let gamma = rng.gen();
|
||||||
|
// let delta = rng.gen();
|
||||||
|
// let tau = rng.gen();
|
||||||
|
|
||||||
|
// generate_parameters::<E, C>(
|
||||||
|
// circuit,
|
||||||
|
// g1,
|
||||||
|
// g2,
|
||||||
|
// alpha,
|
||||||
|
// beta,
|
||||||
|
// gamma,
|
||||||
|
// delta,
|
||||||
|
// tau
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// This is our assembly structure that we'll use to synthesize the
|
||||||
|
/// circuit into a SAP. Square arithmetic problem is different from QAP in a form:
|
||||||
|
/// it's A*A - C = 0 instead of A*B - C = 0
|
||||||
|
struct KeypairAssembly<E: Engine> {
|
||||||
|
num_inputs: usize,
|
||||||
|
num_aux: usize,
|
||||||
|
num_constraints: usize,
|
||||||
|
num_r1cs_aux: usize,
|
||||||
|
num_r1cs_constraints: usize,
|
||||||
|
at_inputs: Vec<Vec<(E::Fr, usize)>>,
|
||||||
|
ct_inputs: Vec<Vec<(E::Fr, usize)>>,
|
||||||
|
at_aux: Vec<Vec<(E::Fr, usize)>>,
|
||||||
|
ct_aux: Vec<Vec<(E::Fr, usize)>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
|
||||||
|
type Root = Self;
|
||||||
|
|
||||||
|
fn alloc<F, A, AR>(
|
||||||
|
&mut self,
|
||||||
|
_: A,
|
||||||
|
_: F
|
||||||
|
) -> Result<Variable, SynthesisError>
|
||||||
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||||
|
{
|
||||||
|
// There is no assignment, so we don't even invoke the
|
||||||
|
// function for obtaining one.
|
||||||
|
|
||||||
|
let index = self.num_aux;
|
||||||
|
self.num_aux += 1;
|
||||||
|
|
||||||
|
self.num_r1cs_aux += 1;
|
||||||
|
|
||||||
|
self.at_aux.push(vec![]);
|
||||||
|
self.ct_aux.push(vec![]);
|
||||||
|
|
||||||
|
Ok(Variable(Index::Aux(index)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_input<F, A, AR>(
|
||||||
|
&mut self,
|
||||||
|
_: A,
|
||||||
|
_: F
|
||||||
|
) -> Result<Variable, SynthesisError>
|
||||||
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||||
|
{
|
||||||
|
// There is no assignment, so we don't even invoke the
|
||||||
|
// function for obtaining one.
|
||||||
|
|
||||||
|
let index = self.num_inputs;
|
||||||
|
self.num_inputs += 1;
|
||||||
|
|
||||||
|
self.at_inputs.push(vec![]);
|
||||||
|
self.ct_inputs.push(vec![]);
|
||||||
|
|
||||||
|
Ok(Variable(Index::Input(index)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce<A, AR, LA, LB, LC>(
|
||||||
|
&mut self,
|
||||||
|
_: A,
|
||||||
|
a: LA,
|
||||||
|
b: LB,
|
||||||
|
c: LC
|
||||||
|
)
|
||||||
|
where A: FnOnce() -> AR, AR: Into<String>,
|
||||||
|
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||||
|
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||||
|
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
|
||||||
|
{
|
||||||
|
use std::ops::{Add, Sub};
|
||||||
|
|
||||||
|
// this is where reduction happens. First we need to re-arrange initial constraints
|
||||||
|
// from the form <a,x>*<b,x> = <c,x> to an artificial
|
||||||
|
// <a - b,x> * <a - b,x> = y
|
||||||
|
// <a + b,x> * <a + b,x> = 4*<c,x> + y
|
||||||
|
|
||||||
|
fn quadruple<E: Engine>(
|
||||||
|
coeff: E::Fr
|
||||||
|
) -> E::Fr {
|
||||||
|
let mut tmp = coeff;
|
||||||
|
tmp.double();
|
||||||
|
tmp.double();
|
||||||
|
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval<E: Engine>(
|
||||||
|
l: LinearCombination<E>,
|
||||||
|
inputs: &mut [Vec<(E::Fr, usize)>],
|
||||||
|
aux: &mut [Vec<(E::Fr, usize)>],
|
||||||
|
this_constraint: usize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (index, coeff) in l.0 {
|
||||||
|
match index {
|
||||||
|
Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)),
|
||||||
|
Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <a - b,x> * <a - b,x> = x_i
|
||||||
|
let i = self.num_constraints;
|
||||||
|
let y = self.alloc(
|
||||||
|
|| format!("SAP reduction y_{}", i),
|
||||||
|
|| Ok(E::Fr::one())
|
||||||
|
).expect("must allocate SAP reduction variable");
|
||||||
|
self.num_r1cs_aux -= 1;
|
||||||
|
|
||||||
|
let lc_a = a(LinearCombination::zero());
|
||||||
|
let lc_b = b(LinearCombination::zero());
|
||||||
|
let lc_c = c(LinearCombination::zero());
|
||||||
|
|
||||||
|
let lc_a_minus_b = lc_a.clone().sub(&lc_b);
|
||||||
|
|
||||||
|
let mut lc_y: LinearCombination<E> = LinearCombination::zero();
|
||||||
|
lc_y = lc_y.add(y);
|
||||||
|
|
||||||
|
eval(lc_a_minus_b, &mut self.at_inputs, &mut self.at_aux, self.num_constraints);
|
||||||
|
eval(lc_y, &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints);
|
||||||
|
|
||||||
|
self.num_constraints += 1;
|
||||||
|
|
||||||
|
// <a + b,x> * <a + b,x> = 4*<c,x> + y
|
||||||
|
let lc_a_plus_b = lc_a.add(&lc_b);
|
||||||
|
|
||||||
|
let mut lc_c_quadrupled: LinearCombination<E> = LinearCombination::zero();
|
||||||
|
for s in &lc_c.0 {
|
||||||
|
let tmp = quadruple::<E>(s.1);
|
||||||
|
lc_c_quadrupled = lc_c_quadrupled + (tmp, s.0);
|
||||||
|
}
|
||||||
|
lc_c_quadrupled = lc_c_quadrupled.add(y);
|
||||||
|
|
||||||
|
eval(lc_a_plus_b, &mut self.at_inputs, &mut self.at_aux, self.num_constraints);
|
||||||
|
eval(lc_c_quadrupled, &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints);
|
||||||
|
|
||||||
|
self.num_constraints += 1;
|
||||||
|
|
||||||
|
self.num_r1cs_constraints += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_namespace<NR, N>(&mut self, _: N)
|
||||||
|
where NR: Into<String>, N: FnOnce() -> NR
|
||||||
|
{
|
||||||
|
// Do nothing; we don't care about namespaces in this context.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_namespace(&mut self)
|
||||||
|
{
|
||||||
|
// Do nothing; we don't care about namespaces in this context.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_root(&mut self) -> &mut Self::Root {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create parameters for a circuit, given some toxic waste.
|
||||||
|
pub fn generate_parameters<E, C>(
|
||||||
|
circuit: C,
|
||||||
|
g1: E::G1,
|
||||||
|
g2: E::G2,
|
||||||
|
alpha: E::Fr,
|
||||||
|
beta: E::Fr,
|
||||||
|
gamma: E::Fr,
|
||||||
|
// delta: E::Fr,
|
||||||
|
tau: E::Fr
|
||||||
|
) -> Result<(), SynthesisError>
|
||||||
|
// Result<Parameters<E>, SynthesisError>
|
||||||
|
where E: Engine, C: Circuit<E>
|
||||||
|
{
|
||||||
|
let verbose = verbose_flag();
|
||||||
|
|
||||||
|
let mut assembly = KeypairAssembly {
|
||||||
|
num_inputs: 0,
|
||||||
|
num_aux: 0,
|
||||||
|
num_constraints: 0,
|
||||||
|
num_r1cs_aux: 0,
|
||||||
|
num_r1cs_constraints: 0,
|
||||||
|
at_inputs: vec![],
|
||||||
|
ct_inputs: vec![],
|
||||||
|
at_aux: vec![],
|
||||||
|
ct_aux: vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allocate the "one" input variable
|
||||||
|
let input_0 = assembly.alloc_input(|| "", || Ok(E::Fr::one()))?;
|
||||||
|
|
||||||
|
// Synthesize the circuit.
|
||||||
|
circuit.synthesize(&mut assembly)?;
|
||||||
|
|
||||||
|
let num_inputs_without_identity = assembly.num_inputs - 1;
|
||||||
|
|
||||||
|
// inputs must be constrained manually in SAP style,
|
||||||
|
// so input 0 (identity) is constrained as 1*1=1
|
||||||
|
{
|
||||||
|
use std::ops::{Add, Sub};
|
||||||
|
|
||||||
|
fn eval_lc<E: Engine>(
|
||||||
|
l: LinearCombination<E>,
|
||||||
|
inputs: &mut [Vec<(E::Fr, usize)>],
|
||||||
|
aux: &mut [Vec<(E::Fr, usize)>],
|
||||||
|
this_constraint: usize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (index, coeff) in l.0 {
|
||||||
|
match index {
|
||||||
|
Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)),
|
||||||
|
Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lc_input_0_a: LinearCombination<E> = LinearCombination::zero();
|
||||||
|
lc_input_0_a = lc_input_0_a.add(input_0.clone());
|
||||||
|
eval_lc(lc_input_0_a, &mut assembly.at_inputs, &mut assembly.at_aux, assembly.num_constraints);
|
||||||
|
|
||||||
|
assembly.num_constraints += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let num_constraints_before_inputs_constraining = assembly.num_constraints;
|
||||||
|
let num_aux_before_inputs_constraining = assembly.num_aux;
|
||||||
|
|
||||||
|
// Other inputs are constrained as x_i * 1 = x_i where
|
||||||
|
// 1 is actually input number 0 (identity)
|
||||||
|
|
||||||
|
for i in 1..assembly.num_inputs {
|
||||||
|
assembly.enforce(|| "",
|
||||||
|
|lc| lc + Variable(Index::Input(i)),
|
||||||
|
|lc| lc + Variable(Index::Input(0)),
|
||||||
|
|lc| lc + Variable(Index::Input(i)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that each input generates 2 constraints
|
||||||
|
assert_eq!(num_inputs_without_identity * 2 +
|
||||||
|
num_constraints_before_inputs_constraining,
|
||||||
|
assembly.num_constraints,
|
||||||
|
"each input must produce two extra constraints");
|
||||||
|
// and that it creates one extra variable
|
||||||
|
assert_eq!(num_inputs_without_identity +
|
||||||
|
num_aux_before_inputs_constraining,
|
||||||
|
assembly.num_aux,
|
||||||
|
"each input must generate an extra variable");
|
||||||
|
|
||||||
|
assert_eq!(assembly.num_inputs + assembly.num_r1cs_constraints + assembly.num_r1cs_aux,
|
||||||
|
assembly.num_inputs + assembly.num_aux,
|
||||||
|
"each constraint in principle adds one variable");
|
||||||
|
|
||||||
|
if verbose {eprintln!("Constraint system size is {}", assembly.num_constraints)};
|
||||||
|
// Create bases for blind evaluation of polynomials at tau
|
||||||
|
let powers_of_tau = vec![Scalar::<E>(E::Fr::zero()); assembly.num_constraints];
|
||||||
|
let mut domain = EvaluationDomain::from_coeffs(powers_of_tau)?;
|
||||||
|
|
||||||
|
// Compute G1 window table
|
||||||
|
let mut g1_wnaf = Wnaf::new();
|
||||||
|
let g1_wnaf = g1_wnaf.base(g1, {
|
||||||
|
2*(assembly.num_inputs + assembly.num_r1cs_constraints + assembly.num_r1cs_aux)
|
||||||
|
+ assembly.num_r1cs_constraints + assembly.num_r1cs_aux
|
||||||
|
+ 2*(assembly.num_inputs + assembly.num_r1cs_constraints)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compute gamma*G2 window table
|
||||||
|
let mut g2_wnaf = Wnaf::new();
|
||||||
|
// let gamma_g2 = g2.into_affine().mul(gamma.into_repr());
|
||||||
|
let g2_wnaf = g2_wnaf.base(g2, {
|
||||||
|
// B query
|
||||||
|
assembly.num_inputs + assembly.num_aux
|
||||||
|
// alternatively expressed as
|
||||||
|
// assembly.num_inputs + assembly.num_r1cs_constraints + assembly.num_r1cs_aux
|
||||||
|
});
|
||||||
|
|
||||||
|
let worker = Worker::new();
|
||||||
|
|
||||||
|
// let z_at_tau = {
|
||||||
|
// // Compute powers of tau
|
||||||
|
// if verbose {eprintln!("computing powers of tau...")};
|
||||||
|
|
||||||
|
// let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let domain = domain.as_mut();
|
||||||
|
// worker.scope(domain.len(), |scope, chunk| {
|
||||||
|
// for (i, subdomain) in domain.chunks_mut(chunk).enumerate()
|
||||||
|
// {
|
||||||
|
// scope.spawn(move || {
|
||||||
|
// let mut current_power = tau.pow(&[(i*chunk) as u64]);
|
||||||
|
|
||||||
|
// for p in subdomain {
|
||||||
|
// p.0 = current_power;
|
||||||
|
// current_power.mul_assign(&tau);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// if verbose {eprintln!("powers of tau stage 1 done in {} s", start.elapsed().as_millis() as f64 / 1000.0);};
|
||||||
|
|
||||||
|
// // z_at_tau = t(x)
|
||||||
|
// let z_at_tau = domain.z(&tau);
|
||||||
|
|
||||||
|
// z_at_tau
|
||||||
|
// };
|
||||||
|
|
||||||
|
let domain_length = domain.as_ref().len();
|
||||||
|
|
||||||
|
if verbose {eprintln!("Domain length is {} ", domain_length)};
|
||||||
|
|
||||||
|
// G1^{gamma^2 * Z(t) * t^i} for 0 <= i < 2^m - 1 for 2^m domains
|
||||||
|
let mut gamma2_z_t_g1 = vec![E::G1::zero(); domain.as_ref().len() - 1];
|
||||||
|
let mut z_at_tau = E::Fr::zero();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Compute powers of tau
|
||||||
|
if verbose {eprintln!("computing powers of tau...")};
|
||||||
|
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
{
|
||||||
|
let domain = domain.as_mut();
|
||||||
|
worker.scope(domain.len(), |scope, chunk| {
|
||||||
|
for (i, subdomain) in domain.chunks_mut(chunk).enumerate()
|
||||||
|
{
|
||||||
|
scope.spawn(move || {
|
||||||
|
let mut current_power = tau.pow(&[(i*chunk) as u64]);
|
||||||
|
|
||||||
|
for p in subdomain {
|
||||||
|
p.0 = current_power;
|
||||||
|
current_power.mul_assign(&tau);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if verbose {eprintln!("powers of tau stage 1 done in {} s", start.elapsed().as_millis() as f64 / 1000.0);};
|
||||||
|
|
||||||
|
// z_at_tau = t(x)
|
||||||
|
z_at_tau = domain.z(&tau);
|
||||||
|
|
||||||
|
let mut gamma2_z_t = z_at_tau;
|
||||||
|
gamma2_z_t.mul_assign(&gamma);
|
||||||
|
gamma2_z_t.mul_assign(&gamma);
|
||||||
|
|
||||||
|
if verbose {eprintln!("computing the `G1^(gamma^2 * Z(t) * t^i)` query with multiple threads...")};
|
||||||
|
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
// Compute the H query with multiple threads
|
||||||
|
worker.scope(gamma2_z_t_g1.len(), |scope, chunk| {
|
||||||
|
for (gamma2_z_t_g1, p) in gamma2_z_t_g1.chunks_mut(chunk).zip(domain.as_ref().chunks(chunk))
|
||||||
|
{
|
||||||
|
let mut g1_wnaf = g1_wnaf.shared();
|
||||||
|
scope.spawn(move || {
|
||||||
|
// Set values of the H query to g1^{(tau^i * t(tau)) / delta}
|
||||||
|
for (gamma2_z_t_g1, p) in gamma2_z_t_g1.iter_mut().zip(p.iter())
|
||||||
|
{
|
||||||
|
// Compute final exponent
|
||||||
|
let mut exp = p.0;
|
||||||
|
exp.mul_assign(&gamma2_z_t);
|
||||||
|
|
||||||
|
// Exponentiate
|
||||||
|
*gamma2_z_t_g1 = g1_wnaf.scalar(exp.into_repr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batch normalize
|
||||||
|
E::G1::batch_normalization(gamma2_z_t_g1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if verbose {eprintln!("computing the `G1^(gamma^2 * Z(t) * t^i)` query done in {} s", start.elapsed().as_millis() as f64 / 1000.0);};
|
||||||
|
}
|
||||||
|
|
||||||
|
// G1^{gamma * A_i(t)} for 0 <= i <= num_variables
|
||||||
|
let mut a_g1 = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux];
|
||||||
|
// G2^{gamma * A_i(t)} for 0 <= i <= num_variables
|
||||||
|
let mut a_g2 = vec![E::G2::zero(); assembly.num_inputs + assembly.num_aux];
|
||||||
|
|
||||||
|
// G1^{gamma^2 * C_i(t) + (alpha + beta) * gamma * A_i(t)}
|
||||||
|
// for num_inputs + 1 < i <= num_variables
|
||||||
|
let mut c_1_g1 = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux];
|
||||||
|
// G1^{2 * gamma^2 * Z(t) * A_i(t)} for 0 <= i <= num_variables
|
||||||
|
let mut c_2_g1 = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux];
|
||||||
|
|
||||||
|
// G1^{gamma * Z(t)}
|
||||||
|
let mut gamma_zt = gamma;
|
||||||
|
gamma_zt.mul_assign(&z_at_tau);
|
||||||
|
|
||||||
|
let gamma_z = g1.into_affine().mul(gamma.into_repr());
|
||||||
|
// G2^{gamma * Z(t)}
|
||||||
|
let gamma_z_g2 = g2.into_affine().mul(gamma.into_repr());
|
||||||
|
|
||||||
|
let mut ab_gamma = alpha;
|
||||||
|
ab_gamma.add_assign(&beta);
|
||||||
|
ab_gamma.mul_assign(&gamma);
|
||||||
|
// G1^{(alpha + beta) * gamma * Z(t)}
|
||||||
|
let ab_gamma_z_g1 = g1.into_affine().mul(ab_gamma.into_repr());
|
||||||
|
|
||||||
|
let mut gamma2_z2 = gamma;
|
||||||
|
gamma2_z2.mul_assign(&z_at_tau);
|
||||||
|
gamma2_z2.square();
|
||||||
|
// G1^{gamma^2 * Z(t)^2}
|
||||||
|
let gamma2_z2_g1 = g1.into_affine().mul(gamma2_z2.into_repr());
|
||||||
|
|
||||||
|
// G^{gamma^2 * Z(t) * t^i} for 0 <= i < 2^m - 1 for 2^m domains
|
||||||
|
let mut gamma2_z_t = vec![E::G1::zero(); domain.as_ref().len() - 1];
|
||||||
|
|
||||||
|
if verbose {eprintln!("using inverse FFT to convert to intepolation coefficients...")};
|
||||||
|
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
// Use inverse FFT to convert to intepolation coefficients
|
||||||
|
domain.ifft(&worker);
|
||||||
|
let powers_of_tau = domain.into_coeffs();
|
||||||
|
// domain is now a set of scalars
|
||||||
|
|
||||||
|
if verbose {eprintln!("powers of tau evaluation in radix2 domain in {} s", start.elapsed().as_millis() as f64 / 1000.0)};
|
||||||
|
|
||||||
|
if verbose {eprintln!("evaluating polynomials...")};
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
// overall strategy:
|
||||||
|
// a_g1, a_g2, c_1_g1, c_2_g1 should be combined together by computing
|
||||||
|
// ab = (alpha + beta)
|
||||||
|
// g_2 = gamma^2
|
||||||
|
// t0 = gamma*A_i(t)
|
||||||
|
// t1 = g_2*C_t(t)
|
||||||
|
// a_g1 = t0*G1
|
||||||
|
// a_g2 = t0*G2
|
||||||
|
// c_1_g1 = (t1 + ab*t0)*G1
|
||||||
|
// c_2_g1 = (2*gamma*z_at_tau*t0)*G1
|
||||||
|
|
||||||
|
fn eval_stage_1<E: Engine>(
|
||||||
|
// wNAF window tables
|
||||||
|
g1_wnaf: &Wnaf<usize, &[E::G1], &mut Vec<i64>>,
|
||||||
|
g2_wnaf: &Wnaf<usize, &[E::G2], &mut Vec<i64>>,
|
||||||
|
|
||||||
|
// powers of tau coefficients
|
||||||
|
powers_of_tau: &[Scalar<E>],
|
||||||
|
|
||||||
|
// SAP polynomials
|
||||||
|
at: &[Vec<(E::Fr, usize)>],
|
||||||
|
ct: &[Vec<(E::Fr, usize)>],
|
||||||
|
|
||||||
|
// Resulting evaluated SAP polynomials
|
||||||
|
a_g1: &mut [E::G1],
|
||||||
|
a_g2: &mut [E::G2],
|
||||||
|
c_1_g1: &mut [E::G1],
|
||||||
|
c_2_g1: &mut [E::G1],
|
||||||
|
|
||||||
|
// Trapdoors
|
||||||
|
alpha: &E::Fr,
|
||||||
|
beta: &E::Fr,
|
||||||
|
gamma: &E::Fr,
|
||||||
|
z_at_tau: &E::Fr,
|
||||||
|
|
||||||
|
// Worker
|
||||||
|
worker: &Worker
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
// Sanity check
|
||||||
|
assert_eq!(a_g1.len(), at.len());
|
||||||
|
assert_eq!(a_g1.len(), ct.len());
|
||||||
|
assert_eq!(a_g1.len(), a_g2.len());
|
||||||
|
assert_eq!(a_g1.len(), c_1_g1.len());
|
||||||
|
assert_eq!(a_g1.len(), c_2_g1.len());
|
||||||
|
|
||||||
|
// compute once
|
||||||
|
let mut ab = *alpha;
|
||||||
|
ab.add_assign(&beta);
|
||||||
|
|
||||||
|
let mut gamma2 = *gamma;
|
||||||
|
gamma2.square();
|
||||||
|
|
||||||
|
// Evaluate polynomials in multiple threads
|
||||||
|
worker.scope(a_g1.len(), |scope, chunk| {
|
||||||
|
for (((((a_g1, a_g2), c_1_g1), c_2_g1), at), ct) in a_g1.chunks_mut(chunk)
|
||||||
|
.zip(a_g2.chunks_mut(chunk))
|
||||||
|
.zip(c_1_g1.chunks_mut(chunk))
|
||||||
|
.zip(c_2_g1.chunks_mut(chunk))
|
||||||
|
.zip(at.chunks(chunk))
|
||||||
|
.zip(ct.chunks(chunk))
|
||||||
|
{
|
||||||
|
let mut g1_wnaf = g1_wnaf.shared();
|
||||||
|
let mut g2_wnaf = g2_wnaf.shared();
|
||||||
|
|
||||||
|
scope.spawn(move || {
|
||||||
|
for (((((a_g1, a_g2), c_1_g1), c_2_g1), at), ct) in a_g1.iter_mut()
|
||||||
|
.zip(a_g2.iter_mut())
|
||||||
|
.zip(c_1_g1.iter_mut())
|
||||||
|
.zip(c_2_g1.iter_mut())
|
||||||
|
.zip(at.iter())
|
||||||
|
.zip(ct.iter())
|
||||||
|
{
|
||||||
|
fn eval_at_tau<E: Engine>(
|
||||||
|
powers_of_tau: &[Scalar<E>],
|
||||||
|
p: &[(E::Fr, usize)]
|
||||||
|
) -> E::Fr
|
||||||
|
{
|
||||||
|
let mut acc = E::Fr::zero();
|
||||||
|
|
||||||
|
for &(ref coeff, index) in p {
|
||||||
|
let mut n = powers_of_tau[index].0;
|
||||||
|
n.mul_assign(coeff);
|
||||||
|
acc.add_assign(&n);
|
||||||
|
}
|
||||||
|
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate SAP polynomials at tau
|
||||||
|
// t0 = gamma*A_i(t)
|
||||||
|
let mut t0 = eval_at_tau(powers_of_tau, at);
|
||||||
|
t0.mul_assign(&gamma);
|
||||||
|
// t1 = gamma^2*C_t(t)
|
||||||
|
let mut t1 = eval_at_tau(powers_of_tau, ct);
|
||||||
|
t1.mul_assign(&gamma2);
|
||||||
|
|
||||||
|
// a_g1 = t0*G1
|
||||||
|
// a_g2 = t0*G2
|
||||||
|
// c_1_g1 = (t1 + ab*t0)*G1
|
||||||
|
// c_2_g1 = (2*gamma*z_at_tau*t0)*G1
|
||||||
|
|
||||||
|
// Compute a_g1 and a_g2
|
||||||
|
if !t0.is_zero() {
|
||||||
|
*a_g1 = g1_wnaf.scalar(t0.into_repr());
|
||||||
|
*a_g2 = g2_wnaf.scalar(t0.into_repr());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut c_1_g1_factor = t0;
|
||||||
|
c_1_g1_factor.mul_assign(&ab);
|
||||||
|
c_1_g1_factor.add_assign(&t1);
|
||||||
|
|
||||||
|
// (2*gamma*z_at_tau*t0) inplace
|
||||||
|
t0.mul_assign(&z_at_tau);
|
||||||
|
t0.mul_assign(&gamma);
|
||||||
|
t0.double();
|
||||||
|
|
||||||
|
*c_1_g1 = g1_wnaf.scalar(c_1_g1_factor.into_repr());
|
||||||
|
*c_2_g1 = g1_wnaf.scalar(t0.into_repr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batch normalize
|
||||||
|
E::G1::batch_normalization(a_g1);
|
||||||
|
E::G2::batch_normalization(a_g2);
|
||||||
|
E::G1::batch_normalization(c_1_g1);
|
||||||
|
E::G1::batch_normalization(c_2_g1);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate for inputs.
|
||||||
|
eval_stage_1(
|
||||||
|
&g1_wnaf,
|
||||||
|
&g2_wnaf,
|
||||||
|
&powers_of_tau,
|
||||||
|
&assembly.at_inputs,
|
||||||
|
&assembly.ct_inputs,
|
||||||
|
&mut a_g1[0..assembly.num_inputs],
|
||||||
|
&mut a_g2[0..assembly.num_inputs],
|
||||||
|
&mut c_1_g1[0..assembly.num_inputs],
|
||||||
|
&mut c_2_g1[0..assembly.num_inputs],
|
||||||
|
&alpha,
|
||||||
|
&beta,
|
||||||
|
&gamma,
|
||||||
|
&z_at_tau,
|
||||||
|
&worker
|
||||||
|
);
|
||||||
|
|
||||||
|
// Evaluate for inputs.
|
||||||
|
eval_stage_1(
|
||||||
|
&g1_wnaf,
|
||||||
|
&g2_wnaf,
|
||||||
|
&powers_of_tau,
|
||||||
|
&assembly.at_aux,
|
||||||
|
&assembly.ct_aux,
|
||||||
|
&mut a_g1[assembly.num_inputs..],
|
||||||
|
&mut a_g2[assembly.num_inputs..],
|
||||||
|
&mut c_1_g1[assembly.num_inputs..],
|
||||||
|
&mut c_2_g1[assembly.num_inputs..],
|
||||||
|
&alpha,
|
||||||
|
&beta,
|
||||||
|
&gamma,
|
||||||
|
&z_at_tau,
|
||||||
|
&worker
|
||||||
|
);
|
||||||
|
|
||||||
|
// for _ in 0..assembly.num_inputs {
|
||||||
|
// c_1_g1.remove(0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if verbose {eprintln!("evaluating polynomials done in {} s", start.elapsed().as_millis() as f64 / 1000.0);};
|
||||||
|
|
||||||
|
// // Don't allow any elements be unconstrained, so that
|
||||||
|
// // the L query is always fully dense.
|
||||||
|
// for e in l.iter() {
|
||||||
|
// if e.is_zero() {
|
||||||
|
// return Err(SynthesisError::UnconstrainedVariable);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let g1 = g1.into_affine();
|
||||||
|
// let g2 = g2.into_affine();
|
||||||
|
|
||||||
|
// let vk = VerifyingKey::<E> {
|
||||||
|
// alpha_g1: g1.mul(alpha).into_affine(),
|
||||||
|
// beta_g1: g1.mul(beta).into_affine(),
|
||||||
|
// beta_g2: g2.mul(beta).into_affine(),
|
||||||
|
// gamma_g2: g2.mul(gamma).into_affine(),
|
||||||
|
// delta_g1: g1.mul(delta).into_affine(),
|
||||||
|
// delta_g2: g2.mul(delta).into_affine(),
|
||||||
|
// ic: ic.into_iter().map(|e| e.into_affine()).collect()
|
||||||
|
// };
|
||||||
|
|
||||||
|
println!("Has generated {} points", a_g1.len());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
// Ok(Parameters {
|
||||||
|
// vk: vk,
|
||||||
|
// h: Arc::new(h.into_iter().map(|e| e.into_affine()).collect()),
|
||||||
|
// l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()),
|
||||||
|
|
||||||
|
// // Filter points at infinity away from A/B queries
|
||||||
|
// a: Arc::new(a.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()),
|
||||||
|
// b_g1: Arc::new(b_g1.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()),
|
||||||
|
// b_g2: Arc::new(b_g2.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect())
|
||||||
|
// })
|
||||||
|
}
|
563
src/gm17/mod.rs
Normal file
563
src/gm17/mod.rs
Normal file
@ -0,0 +1,563 @@
|
|||||||
|
use pairing::{
|
||||||
|
Engine,
|
||||||
|
CurveAffine,
|
||||||
|
EncodedPoint
|
||||||
|
};
|
||||||
|
|
||||||
|
use ::{
|
||||||
|
SynthesisError
|
||||||
|
};
|
||||||
|
|
||||||
|
use multiexp::SourceBuilder;
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
mod generator;
|
||||||
|
// mod prover;
|
||||||
|
// mod verifier;
|
||||||
|
|
||||||
|
pub use self::generator::*;
|
||||||
|
// pub use self::prover::*;
|
||||||
|
// pub use self::verifier::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Proof<E: Engine> {
|
||||||
|
pub a: E::G1Affine,
|
||||||
|
pub b: E::G2Affine,
|
||||||
|
pub c: E::G1Affine
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> PartialEq for Proof<E> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.a == other.a &&
|
||||||
|
self.b == other.b &&
|
||||||
|
self.c == other.c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> Proof<E> {
|
||||||
|
pub fn write<W: Write>(
|
||||||
|
&self,
|
||||||
|
mut writer: W
|
||||||
|
) -> io::Result<()>
|
||||||
|
{
|
||||||
|
writer.write_all(self.a.into_compressed().as_ref())?;
|
||||||
|
writer.write_all(self.b.into_compressed().as_ref())?;
|
||||||
|
writer.write_all(self.c.into_compressed().as_ref())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read>(
|
||||||
|
mut reader: R
|
||||||
|
) -> io::Result<Self>
|
||||||
|
{
|
||||||
|
let mut g1_repr = <E::G1Affine as CurveAffine>::Compressed::empty();
|
||||||
|
let mut g2_repr = <E::G2Affine as CurveAffine>::Compressed::empty();
|
||||||
|
|
||||||
|
reader.read_exact(g1_repr.as_mut())?;
|
||||||
|
let a = g1_repr
|
||||||
|
.into_affine()
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
.and_then(|e| if e.is_zero() {
|
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||||
|
} else {
|
||||||
|
Ok(e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
reader.read_exact(g2_repr.as_mut())?;
|
||||||
|
let b = g2_repr
|
||||||
|
.into_affine()
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
.and_then(|e| if e.is_zero() {
|
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||||
|
} else {
|
||||||
|
Ok(e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
reader.read_exact(g1_repr.as_mut())?;
|
||||||
|
let c = g1_repr
|
||||||
|
.into_affine()
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
.and_then(|e| if e.is_zero() {
|
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||||
|
} else {
|
||||||
|
Ok(e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Proof {
|
||||||
|
a: a,
|
||||||
|
b: b,
|
||||||
|
c: c
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VerifyingKey<E: Engine> {
|
||||||
|
pub h_g2: E::G2Affine,
|
||||||
|
|
||||||
|
// alpha in g1 for verifying and for creating A/C elements of
|
||||||
|
// proof. Never the point at infinity.
|
||||||
|
pub alpha_g1: E::G1Affine,
|
||||||
|
|
||||||
|
// beta in g2 for verifying. Never the point at infinity.
|
||||||
|
pub beta_g2: E::G2Affine,
|
||||||
|
|
||||||
|
// gamma in g1 for verifying. Never the point at infinity.
|
||||||
|
pub gamma_g1: E::G1Affine,
|
||||||
|
|
||||||
|
// gamma in g2 for verifying. Never the point at infinity.
|
||||||
|
pub gamma_g2: E::G2Affine,
|
||||||
|
|
||||||
|
// Elements of the form G^{gamma * A_i(t) + (alpha + beta) * A_i(t)}
|
||||||
|
// for all public inputs. Because all public inputs have a dummy constraint,
|
||||||
|
// this is the same size as the number of inputs, and never contains points
|
||||||
|
// at infinity.
|
||||||
|
pub ic: Vec<E::G1Affine>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> PartialEq for VerifyingKey<E> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.h_g2 == other.h_g2 &&
|
||||||
|
self.alpha_g1 == other.alpha_g1 &&
|
||||||
|
self.beta_g2 == other.beta_g2 &&
|
||||||
|
self.gamma_g1 == other.gamma_g1 &&
|
||||||
|
self.gamma_g2 == other.gamma_g2 &&
|
||||||
|
self.ic == other.ic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> VerifyingKey<E> {
|
||||||
|
pub fn write<W: Write>(
|
||||||
|
&self,
|
||||||
|
mut writer: W
|
||||||
|
) -> io::Result<()>
|
||||||
|
{
|
||||||
|
writer.write_all(self.h_g2.into_uncompressed().as_ref())?;
|
||||||
|
writer.write_all(self.alpha_g1.into_uncompressed().as_ref())?;
|
||||||
|
writer.write_all(self.beta_g2.into_uncompressed().as_ref())?;
|
||||||
|
writer.write_all(self.gamma_g1.into_uncompressed().as_ref())?;
|
||||||
|
writer.write_all(self.gamma_g2.into_uncompressed().as_ref())?;
|
||||||
|
writer.write_u32::<BigEndian>(self.ic.len() as u32)?;
|
||||||
|
for ic in &self.ic {
|
||||||
|
writer.write_all(ic.into_uncompressed().as_ref())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read>(
|
||||||
|
mut reader: R
|
||||||
|
) -> io::Result<Self>
|
||||||
|
{
|
||||||
|
let mut g1_repr = <E::G1Affine as CurveAffine>::Uncompressed::empty();
|
||||||
|
let mut g2_repr = <E::G2Affine as CurveAffine>::Uncompressed::empty();
|
||||||
|
|
||||||
|
reader.read_exact(g2_repr.as_mut())?;
|
||||||
|
let h_h2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
reader.read_exact(g1_repr.as_mut())?;
|
||||||
|
let alpha_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
reader.read_exact(g2_repr.as_mut())?;
|
||||||
|
let beta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
reader.read_exact(g1_repr.as_mut())?;
|
||||||
|
let gamma_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
reader.read_exact(g2_repr.as_mut())?;
|
||||||
|
let gamma_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
let ic_len = reader.read_u32::<BigEndian>()? as usize;
|
||||||
|
|
||||||
|
let mut ic = vec![];
|
||||||
|
|
||||||
|
for _ in 0..ic_len {
|
||||||
|
reader.read_exact(g1_repr.as_mut())?;
|
||||||
|
let g1 = g1_repr
|
||||||
|
.into_affine()
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
.and_then(|e| if e.is_zero() {
|
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||||
|
} else {
|
||||||
|
Ok(e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
ic.push(g1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(VerifyingKey {
|
||||||
|
h_g2: h_h2,
|
||||||
|
alpha_g1: alpha_g1,
|
||||||
|
beta_g2: beta_g2,
|
||||||
|
gamma_g1: gamma_g1,
|
||||||
|
gamma_g2: gamma_g2,
|
||||||
|
ic: ic
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Parameters<E: Engine> {
|
||||||
|
pub vk: VerifyingKey<E>,
|
||||||
|
pub a_g1: Arc<Vec<E::G1Affine>>,
|
||||||
|
pub a_g2: Arc<Vec<E::G2Affine>>,
|
||||||
|
|
||||||
|
pub c_1_g1: Arc<Vec<E::G1Affine>>,
|
||||||
|
pub c_2_g1: Arc<Vec<E::G1Affine>>,
|
||||||
|
|
||||||
|
pub gamma_z: E::G1Affine,
|
||||||
|
pub gamma_z_g2: E::G2Affine,
|
||||||
|
|
||||||
|
pub ab_gamma_z_g1: E::G1Affine,
|
||||||
|
pub gamma2_z2_g1: E::G1Affine,
|
||||||
|
|
||||||
|
pub gamma2_z_t: Arc<Vec<E::G1Affine>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> PartialEq for Parameters<E> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.vk == other.vk &&
|
||||||
|
self.a_g1 == other.a_g1 &&
|
||||||
|
self.a_g2 == other.a_g2 &&
|
||||||
|
self.c_1_g1 == other.c_1_g1 &&
|
||||||
|
self.c_2_g1 == other.c_2_g1 &&
|
||||||
|
self.gamma_z == other.gamma_z &&
|
||||||
|
self.gamma_z_g2 == other.gamma_z_g2 &&
|
||||||
|
self.ab_gamma_z_g1 == other.ab_gamma_z_g1 &&
|
||||||
|
self.gamma2_z2_g1 == other.gamma2_z2_g1 &&
|
||||||
|
self.gamma2_z_t == other.gamma2_z_t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl<E: Engine> Parameters<E> {
|
||||||
|
// pub fn write<W: Write>(
|
||||||
|
// &self,
|
||||||
|
// mut writer: W
|
||||||
|
// ) -> io::Result<()>
|
||||||
|
// {
|
||||||
|
// self.vk.write(&mut writer)?;
|
||||||
|
|
||||||
|
// writer.write_u32::<BigEndian>(self.h.len() as u32)?;
|
||||||
|
// for g in &self.h[..] {
|
||||||
|
// writer.write_all(g.into_uncompressed().as_ref())?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// writer.write_u32::<BigEndian>(self.l.len() as u32)?;
|
||||||
|
// for g in &self.l[..] {
|
||||||
|
// writer.write_all(g.into_uncompressed().as_ref())?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// writer.write_u32::<BigEndian>(self.a.len() as u32)?;
|
||||||
|
// for g in &self.a[..] {
|
||||||
|
// writer.write_all(g.into_uncompressed().as_ref())?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// writer.write_u32::<BigEndian>(self.b_g1.len() as u32)?;
|
||||||
|
// for g in &self.b_g1[..] {
|
||||||
|
// writer.write_all(g.into_uncompressed().as_ref())?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// writer.write_u32::<BigEndian>(self.b_g2.len() as u32)?;
|
||||||
|
// for g in &self.b_g2[..] {
|
||||||
|
// writer.write_all(g.into_uncompressed().as_ref())?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn read<R: Read>(
|
||||||
|
// mut reader: R,
|
||||||
|
// checked: bool
|
||||||
|
// ) -> io::Result<Self>
|
||||||
|
// {
|
||||||
|
// let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
||||||
|
// let mut repr = <E::G1Affine as CurveAffine>::Uncompressed::empty();
|
||||||
|
// reader.read_exact(repr.as_mut())?;
|
||||||
|
|
||||||
|
// if checked {
|
||||||
|
// repr
|
||||||
|
// .into_affine()
|
||||||
|
// } else {
|
||||||
|
// repr
|
||||||
|
// .into_affine_unchecked()
|
||||||
|
// }
|
||||||
|
// .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
// .and_then(|e| if e.is_zero() {
|
||||||
|
// Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||||
|
// } else {
|
||||||
|
// Ok(e)
|
||||||
|
// })
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let read_g2 = |reader: &mut R| -> io::Result<E::G2Affine> {
|
||||||
|
// let mut repr = <E::G2Affine as CurveAffine>::Uncompressed::empty();
|
||||||
|
// reader.read_exact(repr.as_mut())?;
|
||||||
|
|
||||||
|
// if checked {
|
||||||
|
// repr
|
||||||
|
// .into_affine()
|
||||||
|
// } else {
|
||||||
|
// repr
|
||||||
|
// .into_affine_unchecked()
|
||||||
|
// }
|
||||||
|
// .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
// .and_then(|e| if e.is_zero() {
|
||||||
|
// Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||||
|
// } else {
|
||||||
|
// Ok(e)
|
||||||
|
// })
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let vk = VerifyingKey::<E>::read(&mut reader)?;
|
||||||
|
|
||||||
|
// let mut h = vec![];
|
||||||
|
// let mut l = vec![];
|
||||||
|
// let mut a = vec![];
|
||||||
|
// let mut b_g1 = vec![];
|
||||||
|
// let mut b_g2 = vec![];
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let len = reader.read_u32::<BigEndian>()? as usize;
|
||||||
|
// for _ in 0..len {
|
||||||
|
// h.push(read_g1(&mut reader)?);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let len = reader.read_u32::<BigEndian>()? as usize;
|
||||||
|
// for _ in 0..len {
|
||||||
|
// l.push(read_g1(&mut reader)?);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let len = reader.read_u32::<BigEndian>()? as usize;
|
||||||
|
// for _ in 0..len {
|
||||||
|
// a.push(read_g1(&mut reader)?);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let len = reader.read_u32::<BigEndian>()? as usize;
|
||||||
|
// for _ in 0..len {
|
||||||
|
// b_g1.push(read_g1(&mut reader)?);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let len = reader.read_u32::<BigEndian>()? as usize;
|
||||||
|
// for _ in 0..len {
|
||||||
|
// b_g2.push(read_g2(&mut reader)?);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Ok(Parameters {
|
||||||
|
// vk: vk,
|
||||||
|
// h: Arc::new(h),
|
||||||
|
// l: Arc::new(l),
|
||||||
|
// a: Arc::new(a),
|
||||||
|
// b_g1: Arc::new(b_g1),
|
||||||
|
// b_g2: Arc::new(b_g2)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub struct PreparedVerifyingKey<E: Engine> {
|
||||||
|
// /// Pairing result of alpha*beta
|
||||||
|
// alpha_g1_beta_g2: E::Fqk,
|
||||||
|
// /// -gamma in G2
|
||||||
|
// neg_gamma_g2: <E::G2Affine as CurveAffine>::Prepared,
|
||||||
|
// /// -delta in G2
|
||||||
|
// neg_delta_g2: <E::G2Affine as CurveAffine>::Prepared,
|
||||||
|
// /// Copy of IC from `VerifiyingKey`.
|
||||||
|
// ic: Vec<E::G1Affine>
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub trait ParameterSource<E: Engine> {
|
||||||
|
// type G1Builder: SourceBuilder<E::G1Affine>;
|
||||||
|
// type G2Builder: SourceBuilder<E::G2Affine>;
|
||||||
|
|
||||||
|
// fn get_vk(
|
||||||
|
// &mut self,
|
||||||
|
// num_ic: usize
|
||||||
|
// ) -> Result<VerifyingKey<E>, SynthesisError>;
|
||||||
|
// fn get_h(
|
||||||
|
// &mut self,
|
||||||
|
// num_h: usize
|
||||||
|
// ) -> Result<Self::G1Builder, SynthesisError>;
|
||||||
|
// fn get_l(
|
||||||
|
// &mut self,
|
||||||
|
// num_l: usize
|
||||||
|
// ) -> Result<Self::G1Builder, SynthesisError>;
|
||||||
|
// fn get_a(
|
||||||
|
// &mut self,
|
||||||
|
// num_inputs: usize,
|
||||||
|
// num_aux: usize
|
||||||
|
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
|
||||||
|
// fn get_b_g1(
|
||||||
|
// &mut self,
|
||||||
|
// num_inputs: usize,
|
||||||
|
// num_aux: usize
|
||||||
|
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
|
||||||
|
// fn get_b_g2(
|
||||||
|
// &mut self,
|
||||||
|
// num_inputs: usize,
|
||||||
|
// num_aux: usize
|
||||||
|
// ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<'a, E: Engine> ParameterSource<E> for &'a Parameters<E> {
|
||||||
|
// type G1Builder = (Arc<Vec<E::G1Affine>>, usize);
|
||||||
|
// type G2Builder = (Arc<Vec<E::G2Affine>>, usize);
|
||||||
|
|
||||||
|
// fn get_vk(
|
||||||
|
// &mut self,
|
||||||
|
// _: usize
|
||||||
|
// ) -> Result<VerifyingKey<E>, SynthesisError>
|
||||||
|
// {
|
||||||
|
// Ok(self.vk.clone())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn get_h(
|
||||||
|
// &mut self,
|
||||||
|
// _: usize
|
||||||
|
// ) -> Result<Self::G1Builder, SynthesisError>
|
||||||
|
// {
|
||||||
|
// Ok((self.h.clone(), 0))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn get_l(
|
||||||
|
// &mut self,
|
||||||
|
// _: usize
|
||||||
|
// ) -> Result<Self::G1Builder, SynthesisError>
|
||||||
|
// {
|
||||||
|
// Ok((self.l.clone(), 0))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn get_a(
|
||||||
|
// &mut self,
|
||||||
|
// num_inputs: usize,
|
||||||
|
// _: usize
|
||||||
|
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
|
||||||
|
// {
|
||||||
|
// Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs)))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn get_b_g1(
|
||||||
|
// &mut self,
|
||||||
|
// num_inputs: usize,
|
||||||
|
// _: usize
|
||||||
|
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
|
||||||
|
// {
|
||||||
|
// Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs)))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn get_b_g2(
|
||||||
|
// &mut self,
|
||||||
|
// num_inputs: usize,
|
||||||
|
// _: usize
|
||||||
|
// ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>
|
||||||
|
// {
|
||||||
|
// Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs)))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[cfg(test)]
|
||||||
|
// mod test_with_bls12_381 {
|
||||||
|
// use super::*;
|
||||||
|
// use {Circuit, SynthesisError, ConstraintSystem};
|
||||||
|
|
||||||
|
// use rand::{Rand, thread_rng};
|
||||||
|
// use ff::{Field};
|
||||||
|
// use pairing::bls12_381::{Bls12, Fr};
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn serialization() {
|
||||||
|
// struct MySillyCircuit<E: Engine> {
|
||||||
|
// a: Option<E::Fr>,
|
||||||
|
// b: Option<E::Fr>
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<E: Engine> Circuit<E> for MySillyCircuit<E> {
|
||||||
|
// fn synthesize<CS: ConstraintSystem<E>>(
|
||||||
|
// self,
|
||||||
|
// cs: &mut CS
|
||||||
|
// ) -> Result<(), SynthesisError>
|
||||||
|
// {
|
||||||
|
// let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
|
||||||
|
// let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
|
||||||
|
// let c = cs.alloc_input(|| "c", || {
|
||||||
|
// let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
// let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
|
||||||
|
// a.mul_assign(&b);
|
||||||
|
// Ok(a)
|
||||||
|
// })?;
|
||||||
|
|
||||||
|
// cs.enforce(
|
||||||
|
// || "a*b=c",
|
||||||
|
// |lc| lc + a,
|
||||||
|
// |lc| lc + b,
|
||||||
|
// |lc| lc + c
|
||||||
|
// );
|
||||||
|
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let rng = &mut thread_rng();
|
||||||
|
|
||||||
|
// let params = generate_random_parameters::<Bls12, _, _>(
|
||||||
|
// MySillyCircuit { a: None, b: None },
|
||||||
|
// rng
|
||||||
|
// ).unwrap();
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let mut v = vec![];
|
||||||
|
|
||||||
|
// params.write(&mut v).unwrap();
|
||||||
|
// assert_eq!(v.len(), 2136);
|
||||||
|
|
||||||
|
// let de_params = Parameters::read(&v[..], true).unwrap();
|
||||||
|
// assert!(params == de_params);
|
||||||
|
|
||||||
|
// let de_params = Parameters::read(&v[..], false).unwrap();
|
||||||
|
// assert!(params == de_params);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let pvk = prepare_verifying_key::<Bls12>(¶ms.vk);
|
||||||
|
|
||||||
|
// for _ in 0..100 {
|
||||||
|
// let a = Fr::rand(rng);
|
||||||
|
// let b = Fr::rand(rng);
|
||||||
|
// let mut c = a;
|
||||||
|
// c.mul_assign(&b);
|
||||||
|
|
||||||
|
// let proof = create_random_proof(
|
||||||
|
// MySillyCircuit {
|
||||||
|
// a: Some(a),
|
||||||
|
// b: Some(b)
|
||||||
|
// },
|
||||||
|
// ¶ms,
|
||||||
|
// rng
|
||||||
|
// ).unwrap();
|
||||||
|
|
||||||
|
// let mut v = vec![];
|
||||||
|
// proof.write(&mut v).unwrap();
|
||||||
|
|
||||||
|
// assert_eq!(v.len(), 192);
|
||||||
|
|
||||||
|
// let de_proof = Proof::read(&v[..]).unwrap();
|
||||||
|
// assert!(proof == de_proof);
|
||||||
|
|
||||||
|
// assert!(verify_proof(&pvk, &proof, &[c]).unwrap());
|
||||||
|
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
329
src/gm17/tests/mod.rs
Normal file
329
src/gm17/tests/mod.rs
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
use pairing::{
|
||||||
|
Engine
|
||||||
|
};
|
||||||
|
|
||||||
|
use ff:: {
|
||||||
|
Field,
|
||||||
|
PrimeField,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::tests::dummy_engine::*;
|
||||||
|
use super::super::tests::XORDemo;
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use ::{
|
||||||
|
Circuit,
|
||||||
|
ConstraintSystem,
|
||||||
|
SynthesisError
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
generate_parameters,
|
||||||
|
// prepare_verifying_key,
|
||||||
|
// create_proof,
|
||||||
|
// verify_proof
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gm17_xordemo() {
|
||||||
|
let g1 = Fr::one();
|
||||||
|
let g2 = Fr::one();
|
||||||
|
let alpha = Fr::from_str("48577").unwrap();
|
||||||
|
let beta = Fr::from_str("22580").unwrap();
|
||||||
|
let gamma = Fr::from_str("53332").unwrap();
|
||||||
|
// let delta = Fr::from_str("5481").unwrap();
|
||||||
|
let tau = Fr::from_str("3673").unwrap();
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
let c = XORDemo::<DummyEngine> {
|
||||||
|
a: None,
|
||||||
|
b: None,
|
||||||
|
_marker: PhantomData
|
||||||
|
};
|
||||||
|
|
||||||
|
generate_parameters(
|
||||||
|
c,
|
||||||
|
g1,
|
||||||
|
g2,
|
||||||
|
alpha,
|
||||||
|
beta,
|
||||||
|
gamma,
|
||||||
|
tau
|
||||||
|
).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// // This will synthesize the constraint system:
|
||||||
|
// //
|
||||||
|
// // public inputs: a_0 = 1, a_1 = c
|
||||||
|
// // aux inputs: a_2 = a, a_3 = b
|
||||||
|
// // constraints:
|
||||||
|
// // (a_0 - a_2) * (a_2) = 0
|
||||||
|
// // (a_0 - a_3) * (a_3) = 0
|
||||||
|
// // (a_2 + a_2) * (a_3) = (a_2 + a_3 - a_1)
|
||||||
|
// // (a_0) * 0 = 0
|
||||||
|
// // (a_1) * 0 = 0
|
||||||
|
|
||||||
|
// // The evaluation domain is 8. The H query should
|
||||||
|
// // have 7 elements (it's a quotient polynomial)
|
||||||
|
// assert_eq!(7, params.h.len());
|
||||||
|
|
||||||
|
// let mut root_of_unity = Fr::root_of_unity();
|
||||||
|
|
||||||
|
// // We expect this to be a 2^10 root of unity
|
||||||
|
// assert_eq!(Fr::one(), root_of_unity.pow(&[1 << 10]));
|
||||||
|
|
||||||
|
// // Let's turn it into a 2^3 root of unity.
|
||||||
|
// root_of_unity = root_of_unity.pow(&[1 << 7]);
|
||||||
|
// assert_eq!(Fr::one(), root_of_unity.pow(&[1 << 3]));
|
||||||
|
// assert_eq!(Fr::from_str("20201").unwrap(), root_of_unity);
|
||||||
|
|
||||||
|
// // Let's compute all the points in our evaluation domain.
|
||||||
|
// let mut points = Vec::with_capacity(8);
|
||||||
|
// for i in 0..8 {
|
||||||
|
// points.push(root_of_unity.pow(&[i]));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Let's compute t(tau) = (tau - p_0)(tau - p_1)...
|
||||||
|
// // = tau^8 - 1
|
||||||
|
// let mut t_at_tau = tau.pow(&[8]);
|
||||||
|
// t_at_tau.sub_assign(&Fr::one());
|
||||||
|
// {
|
||||||
|
// let mut tmp = Fr::one();
|
||||||
|
// for p in &points {
|
||||||
|
// let mut term = tau;
|
||||||
|
// term.sub_assign(p);
|
||||||
|
// tmp.mul_assign(&term);
|
||||||
|
// }
|
||||||
|
// assert_eq!(tmp, t_at_tau);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // We expect our H query to be 7 elements of the form...
|
||||||
|
// // {tau^i t(tau) / delta}
|
||||||
|
// let delta_inverse = delta.inverse().unwrap();
|
||||||
|
// let gamma_inverse = gamma.inverse().unwrap();
|
||||||
|
// {
|
||||||
|
// let mut coeff = delta_inverse;
|
||||||
|
// coeff.mul_assign(&t_at_tau);
|
||||||
|
|
||||||
|
// let mut cur = Fr::one();
|
||||||
|
// for h in params.h.iter() {
|
||||||
|
// let mut tmp = cur;
|
||||||
|
// tmp.mul_assign(&coeff);
|
||||||
|
|
||||||
|
// assert_eq!(*h, tmp);
|
||||||
|
|
||||||
|
// cur.mul_assign(&tau);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // The density of the IC query is 2 (2 inputs)
|
||||||
|
// assert_eq!(2, params.vk.ic.len());
|
||||||
|
|
||||||
|
// // The density of the L query is 2 (2 aux variables)
|
||||||
|
// assert_eq!(2, params.l.len());
|
||||||
|
|
||||||
|
// // The density of the A query is 4 (each variable is in at least one A term)
|
||||||
|
// assert_eq!(4, params.a.len());
|
||||||
|
|
||||||
|
// // The density of the B query is 2 (two variables are in at least one B term)
|
||||||
|
// assert_eq!(2, params.b_g1.len());
|
||||||
|
// assert_eq!(2, params.b_g2.len());
|
||||||
|
|
||||||
|
// /*
|
||||||
|
// Lagrange interpolation polynomials in our evaluation domain:
|
||||||
|
|
||||||
|
// ,-------------------------------. ,-------------------------------. ,-------------------------------.
|
||||||
|
// | A TERM | | B TERM | | C TERM |
|
||||||
|
// `-------------------------------. `-------------------------------' `-------------------------------'
|
||||||
|
// | a_0 | a_1 | a_2 | a_3 | | a_0 | a_1 | a_2 | a_3 | | a_0 | a_1 | a_2 | a_3 |
|
||||||
|
// | 1 | 0 | 64512 | 0 | | 0 | 0 | 1 | 0 | | 0 | 0 | 0 | 0 |
|
||||||
|
// | 1 | 0 | 0 | 64512 | | 0 | 0 | 0 | 1 | | 0 | 0 | 0 | 0 |
|
||||||
|
// | 0 | 0 | 2 | 0 | | 0 | 0 | 0 | 1 | | 0 | 64512 | 1 | 1 |
|
||||||
|
// | 1 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 |
|
||||||
|
// | 0 | 1 | 0 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 |
|
||||||
|
// `-------'-------'-------'-------' `-------'-------'-------'-------' `-------'-------'-------'-------'
|
||||||
|
|
||||||
|
// Example for u_0:
|
||||||
|
|
||||||
|
// sage: r = 64513
|
||||||
|
// sage: Fr = GF(r)
|
||||||
|
// sage: omega = (Fr(5)^63)^(2^7)
|
||||||
|
// sage: tau = Fr(3673)
|
||||||
|
// sage: R.<x> = PolynomialRing(Fr, 'x')
|
||||||
|
// sage: def eval(tau, c0, c1, c2, c3, c4):
|
||||||
|
// ....: p = R.lagrange_polynomial([(omega^0, c0), (omega^1, c1), (omega^2, c2), (omega^3, c3), (omega^4, c4), (omega^5, 0), (omega^6, 0), (omega^7, 0)])
|
||||||
|
// ....: return p.substitute(tau)
|
||||||
|
// sage: eval(tau, 1, 1, 0, 1, 0)
|
||||||
|
// 59158
|
||||||
|
// */
|
||||||
|
|
||||||
|
// let u_i = [59158, 48317, 21767, 10402].iter().map(|e| {
|
||||||
|
// Fr::from_str(&format!("{}", e)).unwrap()
|
||||||
|
// }).collect::<Vec<Fr>>();
|
||||||
|
// let v_i = [0, 0, 60619, 30791].iter().map(|e| {
|
||||||
|
// Fr::from_str(&format!("{}", e)).unwrap()
|
||||||
|
// }).collect::<Vec<Fr>>();
|
||||||
|
// let w_i = [0, 23320, 41193, 41193].iter().map(|e| {
|
||||||
|
// Fr::from_str(&format!("{}", e)).unwrap()
|
||||||
|
// }).collect::<Vec<Fr>>();
|
||||||
|
|
||||||
|
// for (u, a) in u_i.iter()
|
||||||
|
// .zip(¶ms.a[..])
|
||||||
|
// {
|
||||||
|
// assert_eq!(u, a);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (v, b) in v_i.iter()
|
||||||
|
// .filter(|&&e| e != Fr::zero())
|
||||||
|
// .zip(¶ms.b_g1[..])
|
||||||
|
// {
|
||||||
|
// assert_eq!(v, b);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (v, b) in v_i.iter()
|
||||||
|
// .filter(|&&e| e != Fr::zero())
|
||||||
|
// .zip(¶ms.b_g2[..])
|
||||||
|
// {
|
||||||
|
// assert_eq!(v, b);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for i in 0..4 {
|
||||||
|
// let mut tmp1 = beta;
|
||||||
|
// tmp1.mul_assign(&u_i[i]);
|
||||||
|
|
||||||
|
// let mut tmp2 = alpha;
|
||||||
|
// tmp2.mul_assign(&v_i[i]);
|
||||||
|
|
||||||
|
// tmp1.add_assign(&tmp2);
|
||||||
|
// tmp1.add_assign(&w_i[i]);
|
||||||
|
|
||||||
|
// if i < 2 {
|
||||||
|
// // Check the correctness of the IC query elements
|
||||||
|
// tmp1.mul_assign(&gamma_inverse);
|
||||||
|
|
||||||
|
// assert_eq!(tmp1, params.vk.ic[i]);
|
||||||
|
// } else {
|
||||||
|
// // Check the correctness of the L query elements
|
||||||
|
// tmp1.mul_assign(&delta_inverse);
|
||||||
|
|
||||||
|
// assert_eq!(tmp1, params.l[i - 2]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Check consistency of the other elements
|
||||||
|
// assert_eq!(alpha, params.vk.alpha_g1);
|
||||||
|
// assert_eq!(beta, params.vk.beta_g1);
|
||||||
|
// assert_eq!(beta, params.vk.beta_g2);
|
||||||
|
// assert_eq!(gamma, params.vk.gamma_g2);
|
||||||
|
// assert_eq!(delta, params.vk.delta_g1);
|
||||||
|
// assert_eq!(delta, params.vk.delta_g2);
|
||||||
|
|
||||||
|
// let pvk = prepare_verifying_key(¶ms.vk);
|
||||||
|
|
||||||
|
// let r = Fr::from_str("27134").unwrap();
|
||||||
|
// let s = Fr::from_str("17146").unwrap();
|
||||||
|
|
||||||
|
// let proof = {
|
||||||
|
// let c = XORDemo {
|
||||||
|
// a: Some(true),
|
||||||
|
// b: Some(false),
|
||||||
|
// _marker: PhantomData
|
||||||
|
// };
|
||||||
|
|
||||||
|
// create_proof(
|
||||||
|
// c,
|
||||||
|
// ¶ms,
|
||||||
|
// r,
|
||||||
|
// s
|
||||||
|
// ).unwrap()
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // A(x) =
|
||||||
|
// // a_0 * (44865*x^7 + 56449*x^6 + 44865*x^5 + 8064*x^4 + 3520*x^3 + 56449*x^2 + 3520*x + 40321) +
|
||||||
|
// // a_1 * (8064*x^7 + 56449*x^6 + 8064*x^5 + 56449*x^4 + 8064*x^3 + 56449*x^2 + 8064*x + 56449) +
|
||||||
|
// // a_2 * (16983*x^7 + 24192*x^6 + 63658*x^5 + 56449*x^4 + 16983*x^3 + 24192*x^2 + 63658*x + 56449) +
|
||||||
|
// // a_3 * (5539*x^7 + 27797*x^6 + 6045*x^5 + 56449*x^4 + 58974*x^3 + 36716*x^2 + 58468*x + 8064) +
|
||||||
|
// {
|
||||||
|
// // proof A = alpha + A(tau) + delta * r
|
||||||
|
// let mut expected_a = delta;
|
||||||
|
// expected_a.mul_assign(&r);
|
||||||
|
// expected_a.add_assign(&alpha);
|
||||||
|
// expected_a.add_assign(&u_i[0]); // a_0 = 1
|
||||||
|
// expected_a.add_assign(&u_i[1]); // a_1 = 1
|
||||||
|
// expected_a.add_assign(&u_i[2]); // a_2 = 1
|
||||||
|
// // a_3 = 0
|
||||||
|
// assert_eq!(proof.a, expected_a);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // B(x) =
|
||||||
|
// // a_0 * (0) +
|
||||||
|
// // a_1 * (0) +
|
||||||
|
// // a_2 * (56449*x^7 + 56449*x^6 + 56449*x^5 + 56449*x^4 + 56449*x^3 + 56449*x^2 + 56449*x + 56449) +
|
||||||
|
// // a_3 * (31177*x^7 + 44780*x^6 + 21752*x^5 + 42255*x^3 + 35861*x^2 + 33842*x + 48385)
|
||||||
|
// {
|
||||||
|
// // proof B = beta + B(tau) + delta * s
|
||||||
|
// let mut expected_b = delta;
|
||||||
|
// expected_b.mul_assign(&s);
|
||||||
|
// expected_b.add_assign(&beta);
|
||||||
|
// expected_b.add_assign(&v_i[0]); // a_0 = 1
|
||||||
|
// expected_b.add_assign(&v_i[1]); // a_1 = 1
|
||||||
|
// expected_b.add_assign(&v_i[2]); // a_2 = 1
|
||||||
|
// // a_3 = 0
|
||||||
|
// assert_eq!(proof.b, expected_b);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // C(x) =
|
||||||
|
// // a_0 * (0) +
|
||||||
|
// // a_1 * (27797*x^7 + 56449*x^6 + 36716*x^5 + 8064*x^4 + 27797*x^3 + 56449*x^2 + 36716*x + 8064) +
|
||||||
|
// // a_2 * (36716*x^7 + 8064*x^6 + 27797*x^5 + 56449*x^4 + 36716*x^3 + 8064*x^2 + 27797*x + 56449) +
|
||||||
|
// // a_3 * (36716*x^7 + 8064*x^6 + 27797*x^5 + 56449*x^4 + 36716*x^3 + 8064*x^2 + 27797*x + 56449)
|
||||||
|
// //
|
||||||
|
// // If A * B = C at each point in the domain, then the following polynomial...
|
||||||
|
// // P(x) = A(x) * B(x) - C(x)
|
||||||
|
// // = 49752*x^14 + 13914*x^13 + 29243*x^12 + 27227*x^11 + 62362*x^10 + 35703*x^9 + 4032*x^8 + 14761*x^6 + 50599*x^5 + 35270*x^4 + 37286*x^3 + 2151*x^2 + 28810*x + 60481
|
||||||
|
// //
|
||||||
|
// // ... should be divisible by t(x), producing the quotient polynomial:
|
||||||
|
// // h(x) = P(x) / t(x)
|
||||||
|
// // = 49752*x^6 + 13914*x^5 + 29243*x^4 + 27227*x^3 + 62362*x^2 + 35703*x + 4032
|
||||||
|
// {
|
||||||
|
// let mut expected_c = Fr::zero();
|
||||||
|
|
||||||
|
// // A * s
|
||||||
|
// let mut tmp = proof.a;
|
||||||
|
// tmp.mul_assign(&s);
|
||||||
|
// expected_c.add_assign(&tmp);
|
||||||
|
|
||||||
|
// // B * r
|
||||||
|
// let mut tmp = proof.b;
|
||||||
|
// tmp.mul_assign(&r);
|
||||||
|
// expected_c.add_assign(&tmp);
|
||||||
|
|
||||||
|
// // delta * r * s
|
||||||
|
// let mut tmp = delta;
|
||||||
|
// tmp.mul_assign(&r);
|
||||||
|
// tmp.mul_assign(&s);
|
||||||
|
// expected_c.sub_assign(&tmp);
|
||||||
|
|
||||||
|
// // L query answer
|
||||||
|
// // a_2 = 1, a_3 = 0
|
||||||
|
// expected_c.add_assign(¶ms.l[0]);
|
||||||
|
|
||||||
|
// // H query answer
|
||||||
|
// for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739].iter().enumerate() {
|
||||||
|
// let coeff = Fr::from_str(&format!("{}", coeff)).unwrap();
|
||||||
|
|
||||||
|
// let mut tmp = params.h[i];
|
||||||
|
// tmp.mul_assign(&coeff);
|
||||||
|
// expected_c.add_assign(&tmp);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// assert_eq!(expected_c, proof.c);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// assert!(verify_proof(
|
||||||
|
// &pvk,
|
||||||
|
// &proof,
|
||||||
|
// &[Fr::one()]
|
||||||
|
// ).unwrap());
|
||||||
|
}
|
@ -7,8 +7,8 @@ use ff:: {
|
|||||||
PrimeField,
|
PrimeField,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod dummy_engine;
|
use super::super::tests::dummy_engine::*;
|
||||||
use self::dummy_engine::*;
|
use super::super::tests::XORDemo;
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
@ -25,79 +25,6 @@ use super::{
|
|||||||
verify_proof
|
verify_proof
|
||||||
};
|
};
|
||||||
|
|
||||||
struct XORDemo<E: Engine> {
|
|
||||||
a: Option<bool>,
|
|
||||||
b: Option<bool>,
|
|
||||||
_marker: PhantomData<E>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine> Circuit<E> for XORDemo<E> {
|
|
||||||
fn synthesize<CS: ConstraintSystem<E>>(
|
|
||||||
self,
|
|
||||||
cs: &mut CS
|
|
||||||
) -> Result<(), SynthesisError>
|
|
||||||
{
|
|
||||||
let a_var = cs.alloc(|| "a", || {
|
|
||||||
if self.a.is_some() {
|
|
||||||
if self.a.unwrap() {
|
|
||||||
Ok(E::Fr::one())
|
|
||||||
} else {
|
|
||||||
Ok(E::Fr::zero())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(SynthesisError::AssignmentMissing)
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "a_boolean_constraint",
|
|
||||||
|lc| lc + CS::one() - a_var,
|
|
||||||
|lc| lc + a_var,
|
|
||||||
|lc| lc
|
|
||||||
);
|
|
||||||
|
|
||||||
let b_var = cs.alloc(|| "b", || {
|
|
||||||
if self.b.is_some() {
|
|
||||||
if self.b.unwrap() {
|
|
||||||
Ok(E::Fr::one())
|
|
||||||
} else {
|
|
||||||
Ok(E::Fr::zero())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(SynthesisError::AssignmentMissing)
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "b_boolean_constraint",
|
|
||||||
|lc| lc + CS::one() - b_var,
|
|
||||||
|lc| lc + b_var,
|
|
||||||
|lc| lc
|
|
||||||
);
|
|
||||||
|
|
||||||
let c_var = cs.alloc_input(|| "c", || {
|
|
||||||
if self.a.is_some() && self.b.is_some() {
|
|
||||||
if self.a.unwrap() ^ self.b.unwrap() {
|
|
||||||
Ok(E::Fr::one())
|
|
||||||
} else {
|
|
||||||
Ok(E::Fr::zero())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(SynthesisError::AssignmentMissing)
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "c_xor_constraint",
|
|
||||||
|lc| lc + a_var + a_var,
|
|
||||||
|lc| lc + b_var,
|
|
||||||
|lc| lc + a_var + b_var - c_var
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_xordemo() {
|
fn test_xordemo() {
|
||||||
let g1 = Fr::one();
|
let g1 = Fr::one();
|
||||||
|
@ -14,6 +14,10 @@ pub mod multicore;
|
|||||||
mod multiexp;
|
mod multiexp;
|
||||||
pub mod domain;
|
pub mod domain;
|
||||||
pub mod groth16;
|
pub mod groth16;
|
||||||
|
pub mod gm17;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
use pairing::{Engine};
|
use pairing::{Engine};
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
|
93
src/tests/mod.rs
Normal file
93
src/tests/mod.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use pairing::{
|
||||||
|
Engine
|
||||||
|
};
|
||||||
|
|
||||||
|
use ff:: {
|
||||||
|
Field,
|
||||||
|
PrimeField,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod dummy_engine;
|
||||||
|
use self::dummy_engine::*;
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use ::{
|
||||||
|
Circuit,
|
||||||
|
ConstraintSystem,
|
||||||
|
SynthesisError
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) struct XORDemo<E: Engine> {
|
||||||
|
pub(crate) a: Option<bool>,
|
||||||
|
pub(crate) b: Option<bool>,
|
||||||
|
pub(crate) _marker: PhantomData<E>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> Circuit<E> for XORDemo<E> {
|
||||||
|
fn synthesize<CS: ConstraintSystem<E>>(
|
||||||
|
self,
|
||||||
|
cs: &mut CS
|
||||||
|
) -> Result<(), SynthesisError>
|
||||||
|
{
|
||||||
|
let a_var = cs.alloc(|| "a", || {
|
||||||
|
if self.a.is_some() {
|
||||||
|
if self.a.unwrap() {
|
||||||
|
Ok(E::Fr::one())
|
||||||
|
} else {
|
||||||
|
Ok(E::Fr::zero())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(SynthesisError::AssignmentMissing)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
cs.enforce(
|
||||||
|
|| "a_boolean_constraint",
|
||||||
|
|lc| lc + CS::one() - a_var,
|
||||||
|
|lc| lc + a_var,
|
||||||
|
|lc| lc
|
||||||
|
);
|
||||||
|
|
||||||
|
let b_var = cs.alloc(|| "b", || {
|
||||||
|
if self.b.is_some() {
|
||||||
|
if self.b.unwrap() {
|
||||||
|
Ok(E::Fr::one())
|
||||||
|
} else {
|
||||||
|
Ok(E::Fr::zero())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(SynthesisError::AssignmentMissing)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
cs.enforce(
|
||||||
|
|| "b_boolean_constraint",
|
||||||
|
|lc| lc + CS::one() - b_var,
|
||||||
|
|lc| lc + b_var,
|
||||||
|
|lc| lc
|
||||||
|
);
|
||||||
|
|
||||||
|
let c_var = cs.alloc_input(|| "c", || {
|
||||||
|
if self.a.is_some() && self.b.is_some() {
|
||||||
|
if self.a.unwrap() ^ self.b.unwrap() {
|
||||||
|
Ok(E::Fr::one())
|
||||||
|
} else {
|
||||||
|
Ok(E::Fr::zero())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(SynthesisError::AssignmentMissing)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
cs.enforce(
|
||||||
|
|| "c_xor_constraint",
|
||||||
|
|lc| lc + a_var + a_var,
|
||||||
|
|lc| lc + b_var,
|
||||||
|
|lc| lc + a_var + b_var - c_var
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user