temporary commit
This commit is contained in:
parent
2173354b1f
commit
a0aaf7a6e4
BIN
src/sonic/S_poly.pdf
Normal file
BIN
src/sonic/S_poly.pdf
Normal file
Binary file not shown.
@ -51,52 +51,3 @@ pub fn verify_aggregate<E: Engine, C: Circuit<E> + Clone, R: Rng>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn my_fun_circuit_test() {
|
|
||||||
// use pairing::ff::PrimeField;
|
|
||||||
// use pairing::bls12_381::{Bls12, Fr};
|
|
||||||
// use super::*;
|
|
||||||
// use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};
|
|
||||||
|
|
||||||
// struct MyCircuit;
|
|
||||||
|
|
||||||
// impl<E: Engine> Circuit<E> for MyCircuit {
|
|
||||||
// fn synthesize<CS: ConstraintSystem<E>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
|
|
||||||
// let (a, b, _) = cs.multiply(|| {
|
|
||||||
// Ok((
|
|
||||||
// E::Fr::from_str("10").unwrap(),
|
|
||||||
// E::Fr::from_str("20").unwrap(),
|
|
||||||
// E::Fr::from_str("200").unwrap(),
|
|
||||||
// ))
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// cs.enforce_zero(LinearCombination::from(a) + a - b);
|
|
||||||
|
|
||||||
// //let multiplier = cs.alloc_input(|| Ok(E::Fr::from_str("20").unwrap()))?;
|
|
||||||
|
|
||||||
// //cs.enforce_zero(LinearCombination::from(b) - multiplier);
|
|
||||||
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let srs = SRS::<Bls12>::new(
|
|
||||||
// 20,
|
|
||||||
// Fr::from_str("22222").unwrap(),
|
|
||||||
// Fr::from_str("33333333").unwrap(),
|
|
||||||
// );
|
|
||||||
// let proof = create_proof_on_srs::<Bls12, _, Basic>(&MyCircuit, &srs).unwrap();
|
|
||||||
|
|
||||||
// use std::time::{Instant};
|
|
||||||
// let start = Instant::now();
|
|
||||||
// let mut batch = MultiVerifier::<Bls12, _, Basic>::new(MyCircuit, &srs).unwrap();
|
|
||||||
|
|
||||||
// for _ in 0..1 {
|
|
||||||
// batch.add_proof(&proof, &[/*Fr::from_str("20").unwrap()*/], |_, _| None);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// assert!(batch.check_all());
|
|
||||||
|
|
||||||
// let elapsed = start.elapsed();
|
|
||||||
// println!("time to verify: {:?}", elapsed);
|
|
||||||
// }
|
|
||||||
|
@ -74,11 +74,11 @@ impl<E: Engine> SxEval<E> {
|
|||||||
|
|
||||||
let mut acc = E::Fr::zero();
|
let mut acc = E::Fr::zero();
|
||||||
|
|
||||||
let mut tmp = x_inv;
|
let tmp = x_inv;
|
||||||
acc.add_assign(&evaluate_at_consequitive_powers(& self.u[..], tmp, tmp));
|
acc.add_assign(&evaluate_at_consequitive_powers(& self.u[..], tmp, tmp));
|
||||||
let mut tmp = x;
|
let tmp = x;
|
||||||
acc.add_assign(&evaluate_at_consequitive_powers(& self.v[..], tmp, tmp));
|
acc.add_assign(&evaluate_at_consequitive_powers(& self.v[..], tmp, tmp));
|
||||||
let mut tmp = x.pow(&[(self.v.len()+1) as u64]);
|
let tmp = x.pow(&[(self.v.len()+1) as u64]);
|
||||||
acc.add_assign(&evaluate_at_consequitive_powers(& self.w[..], tmp, x));
|
acc.add_assign(&evaluate_at_consequitive_powers(& self.w[..], tmp, x));
|
||||||
|
|
||||||
// let mut tmp = x_inv;
|
// let mut tmp = x_inv;
|
||||||
|
@ -240,7 +240,6 @@ pub fn create_proof_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
|
|||||||
rx1.push(E::Fr::zero());
|
rx1.push(E::Fr::zero());
|
||||||
rx1.extend(wires.a);
|
rx1.extend(wires.a);
|
||||||
|
|
||||||
|
|
||||||
let mut rxy = rx1.clone();
|
let mut rxy = rx1.clone();
|
||||||
|
|
||||||
let y_inv = y.inverse().ok_or(SynthesisError::DivisionByZero)?;
|
let y_inv = y.inverse().ok_or(SynthesisError::DivisionByZero)?;
|
||||||
|
@ -540,3 +540,101 @@ fn test_high_level_sonic_api() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_constraints_info() {
|
||||||
|
use pairing::bn256::{Bn256};
|
||||||
|
use std::time::{Instant};
|
||||||
|
use crate::sonic::unhelped::padding::{constraints_info};
|
||||||
|
{
|
||||||
|
// This may not be cryptographically safe, use
|
||||||
|
// `OsRng` (for example) in production software.
|
||||||
|
let mut rng = &mut thread_rng();
|
||||||
|
|
||||||
|
// Generate the MiMC round constants
|
||||||
|
let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let xl = rng.gen();
|
||||||
|
let xr = rng.gen();
|
||||||
|
let image = mimc::<Bn256>(xl, xr, &constants);
|
||||||
|
|
||||||
|
// Create an instance of our circuit (with the
|
||||||
|
// witness)
|
||||||
|
let circuit = MiMCDemo {
|
||||||
|
xl: Some(xl),
|
||||||
|
xr: Some(xr),
|
||||||
|
constants: &constants
|
||||||
|
};
|
||||||
|
|
||||||
|
constraints_info::<Bn256, _>(circuit.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_padding_using_mimc() {
|
||||||
|
use pairing::ff::{Field, PrimeField};
|
||||||
|
use pairing::{Engine, CurveAffine, CurveProjective};
|
||||||
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
|
use std::time::{Instant};
|
||||||
|
use crate::sonic::srs::SRS;
|
||||||
|
|
||||||
|
let srs_x = Fr::from_str("23923").unwrap();
|
||||||
|
let srs_alpha = Fr::from_str("23728792").unwrap();
|
||||||
|
println!("making srs");
|
||||||
|
let start = Instant::now();
|
||||||
|
let srs = SRS::<Bls12>::dummy(830564, srs_x, srs_alpha);
|
||||||
|
println!("done in {:?}", start.elapsed());
|
||||||
|
|
||||||
|
{
|
||||||
|
// This may not be cryptographically safe, use
|
||||||
|
// `OsRng` (for example) in production software.
|
||||||
|
let rng = &mut thread_rng();
|
||||||
|
|
||||||
|
// Generate the MiMC round constants
|
||||||
|
let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::<Vec<_>>();
|
||||||
|
let samples: usize = 100;
|
||||||
|
|
||||||
|
let xl = rng.gen();
|
||||||
|
let xr = rng.gen();
|
||||||
|
let image = mimc::<Bls12>(xl, xr, &constants);
|
||||||
|
|
||||||
|
// Create an instance of our circuit (with the
|
||||||
|
// witness)
|
||||||
|
let circuit = MiMCDemoNoInputs {
|
||||||
|
xl: Some(xl),
|
||||||
|
xr: Some(xr),
|
||||||
|
image: Some(image),
|
||||||
|
constants: &constants
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::sonic::cs::Basic;
|
||||||
|
use crate::sonic::sonic::AdaptorCircuit;
|
||||||
|
use crate::sonic::helped::prover::{create_advice_on_srs, create_proof_on_srs};
|
||||||
|
use crate::sonic::helped::{MultiVerifier, get_circuit_parameters};
|
||||||
|
use crate::sonic::helped::helper::{create_aggregate_on_srs};
|
||||||
|
use crate::sonic::unhelped::padding::Padding;
|
||||||
|
|
||||||
|
let info = get_circuit_parameters::<Bls12, _>(circuit.clone()).expect("Must get circuit info");
|
||||||
|
println!("{:?}", info);
|
||||||
|
|
||||||
|
println!("creating proof");
|
||||||
|
let start = Instant::now();
|
||||||
|
let proof = create_proof_on_srs::<Bls12, _, Padding>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
|
||||||
|
println!("done in {:?}", start.elapsed());
|
||||||
|
|
||||||
|
{
|
||||||
|
let rng = thread_rng();
|
||||||
|
let mut verifier = MultiVerifier::<Bls12, _, Padding, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
|
||||||
|
println!("K map = {:?}", verifier.get_k_map());
|
||||||
|
println!("verifying 1 proof without advice");
|
||||||
|
let start = Instant::now();
|
||||||
|
{
|
||||||
|
for _ in 0..1 {
|
||||||
|
verifier.add_proof(&proof, &[], |_, _| None);
|
||||||
|
}
|
||||||
|
assert_eq!(verifier.check_all(), true); // TODO
|
||||||
|
}
|
||||||
|
println!("done in {:?}", start.elapsed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,5 +7,6 @@ mod s2_proof;
|
|||||||
mod wellformed_argument;
|
mod wellformed_argument;
|
||||||
mod grand_product_argument;
|
mod grand_product_argument;
|
||||||
mod permutation_argument;
|
mod permutation_argument;
|
||||||
|
pub mod padding;
|
||||||
|
|
||||||
pub use self::wellformed_argument::{WellformednessArgument, WellformednessProof};
|
pub use self::wellformed_argument::{WellformednessArgument, WellformednessProof};
|
686
src/sonic/unhelped/padding.rs
Normal file
686
src/sonic/unhelped/padding.rs
Normal file
@ -0,0 +1,686 @@
|
|||||||
|
use pairing::ff::{Field};
|
||||||
|
use pairing::{Engine, CurveProjective};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::sonic::cs::{Backend};
|
||||||
|
use crate::sonic::cs::{Coeff, Variable, LinearCombination};
|
||||||
|
use crate::sonic::util::*;
|
||||||
|
use crate::sonic::util::*;
|
||||||
|
use crate::sonic::cs::{SynthesisDriver};
|
||||||
|
use crate::Circuit as BellmanCircuit;
|
||||||
|
use crate::sonic::sonic::AdaptorCircuit;
|
||||||
|
use crate::sonic::cs::Circuit;
|
||||||
|
use crate::sonic::cs::ConstraintSystem;
|
||||||
|
use crate::sonic::cs::Nonassigning;
|
||||||
|
use crate::SynthesisError;
|
||||||
|
|
||||||
|
/*
|
||||||
|
s_1(X, Y) = \sum\limits_{i=1}^N u_i(Y) X^{N + 1 - i}
|
||||||
|
+ \sum\limits_{i=1}^N v_i(Y) X^{N + 1 + i}
|
||||||
|
+ \sum\limits_{i=1}^N w_i(Y) X^{2N + 1 + i}
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
u_i(Y) = \sum\limits_{q=1}^Q Y^{q} u_{i,q}
|
||||||
|
v_i(Y) = \sum\limits_{q=1}^Q Y^{q} v_{i,q}
|
||||||
|
w_i(Y) = \sum\limits_{q=1}^Q Y^{q} w_{i,q}
|
||||||
|
|
||||||
|
s_1(X, Y) = \sum\limits_{i=1}^(3N + 1) [u_{N + 1 - i}(Y), v_{i - N - 1}(Y), w_{i - 2N - 1}(Y)] X^{i}
|
||||||
|
|
||||||
|
where [] means concatenation
|
||||||
|
|
||||||
|
if we open up both sums a little it would look like
|
||||||
|
|
||||||
|
// q = 1,
|
||||||
|
Y * ( X * u_{N, 1} + X^{N + 1} * v_{1, 1} + X^{2N + 1} * w{1, 1}) = Y * (k_0 * X + k_1 * X^{N + 1} + k_2 * X^{2N + 1})
|
||||||
|
and for permutation where should exist another term over Y that would have the same structure, but with coefficients permuted, e.g.
|
||||||
|
Y^{p_1} * (k_1 * X + k_2 * X^{N + 1} + k_0 * X^{2N + 1}) and Y^{p_2} * (k_2 * X + k_0 * X^{N + 1} + k_1 * X^{2N + 1})
|
||||||
|
that would result in a sum
|
||||||
|
|
||||||
|
X * (k_0 * Y + k_1 * Y^{p_1} + k_2 * Y^{p_2})
|
||||||
|
+ X^{N + 1} * (k_1 * Y + k_2 * Y^{p_1} + k_0 * Y^{p_2})
|
||||||
|
+ X^{2N + 1} * (k_2 * Y + k_0 * Y^{p_1} + k_1 * Y^{p_2})
|
||||||
|
|
||||||
|
and permutations would look like
|
||||||
|
[k_0, k_1, k_2]
|
||||||
|
[1 , p_1, p_2]
|
||||||
|
|
||||||
|
[k_0, k_1, k_2]
|
||||||
|
[p_2, 1 , p_1]
|
||||||
|
|
||||||
|
[k_0, k_1, k_2]
|
||||||
|
[p_1, p_2, 1 ]
|
||||||
|
|
||||||
|
that would naively mean that k_0 should appear in constraint number 1 for variable number 1
|
||||||
|
constraint number p_1 for variable number N + 1
|
||||||
|
constraint number p_2 for variable number 2N + 1
|
||||||
|
|
||||||
|
restructuring strategy:
|
||||||
|
|
||||||
|
where u_{i, q} is a coefficient in a linear constraint for an A type variable number i
|
||||||
|
that corresponds to the qth multiplication gate
|
||||||
|
|
||||||
|
to make s_1 representable as a permutation we first must synthesize all the normal constraints,
|
||||||
|
then make what would look like a cyclic shift + expansion
|
||||||
|
|
||||||
|
- imagine that there were originally N variables
|
||||||
|
- variable A(i) in linear constraint number q had a coefficient of u{i, q}
|
||||||
|
- add a variable B(i+n) that would have a number
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub struct Debugging<E> {
|
||||||
|
constraint_num: usize,
|
||||||
|
u: Vec<String>,
|
||||||
|
v: Vec<String>,
|
||||||
|
w: Vec<String>,
|
||||||
|
_marker: std::marker::PhantomData<E>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Engine> Backend<E> for &'a mut Debugging<E> {
|
||||||
|
fn new_linear_constraint(&mut self) {
|
||||||
|
self.constraint_num += 1;
|
||||||
|
self.u.push("".to_string());
|
||||||
|
self.v.push("".to_string());
|
||||||
|
self.w.push("".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_coefficient(&mut self, var: Variable, coeff: Coeff<E>) {
|
||||||
|
let one = E::Fr::one();
|
||||||
|
let mut minus_one = one;
|
||||||
|
minus_one.negate();
|
||||||
|
match var {
|
||||||
|
Variable::A(index) => {
|
||||||
|
let acc = &mut self.u[self.constraint_num - 1];
|
||||||
|
match coeff {
|
||||||
|
Coeff::Zero => { },
|
||||||
|
Coeff::One => {
|
||||||
|
acc.push_str(&format!(" + A{}", index));
|
||||||
|
},
|
||||||
|
Coeff::NegativeOne => {
|
||||||
|
acc.push_str(&format!(" - A{}", index));
|
||||||
|
},
|
||||||
|
Coeff::Full(val) => {
|
||||||
|
if val == one {
|
||||||
|
acc.push_str(&format!(" + A{}", index));
|
||||||
|
} else if val == minus_one {
|
||||||
|
acc.push_str(&format!(" - A{}", index));
|
||||||
|
} else {
|
||||||
|
acc.push_str(&format!(" + {}*A{}", val, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::B(index) => {
|
||||||
|
let acc = &mut self.v[self.constraint_num - 1];
|
||||||
|
match coeff {
|
||||||
|
Coeff::Zero => { },
|
||||||
|
Coeff::One => {
|
||||||
|
acc.push_str(&format!(" + B{}", index));
|
||||||
|
},
|
||||||
|
Coeff::NegativeOne => {
|
||||||
|
acc.push_str(&format!(" - B{}", index));
|
||||||
|
},
|
||||||
|
Coeff::Full(val) => {
|
||||||
|
if val == one {
|
||||||
|
acc.push_str(&format!(" + B{}", index));
|
||||||
|
} else if val == minus_one {
|
||||||
|
acc.push_str(&format!(" - B{}", index));
|
||||||
|
} else {
|
||||||
|
acc.push_str(&format!(" + {}*B{}", val, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::C(index) => {
|
||||||
|
let acc = &mut self.w[self.constraint_num - 1];
|
||||||
|
match coeff {
|
||||||
|
Coeff::Zero => { },
|
||||||
|
Coeff::One => {
|
||||||
|
acc.push_str(&format!(" + C{}", index));
|
||||||
|
},
|
||||||
|
Coeff::NegativeOne => {
|
||||||
|
acc.push_str(&format!(" - C{}", index));
|
||||||
|
},
|
||||||
|
Coeff::Full(val) => {
|
||||||
|
if val == one {
|
||||||
|
acc.push_str(&format!(" + C{}", index));
|
||||||
|
} else if val == minus_one {
|
||||||
|
acc.push_str(&format!(" - C{}", index));
|
||||||
|
} else {
|
||||||
|
acc.push_str(&format!(" + {}*C{}", val, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Padding;
|
||||||
|
|
||||||
|
impl SynthesisDriver for Padding {
|
||||||
|
fn synthesize<E: Engine, C: Circuit<E>, B: Backend<E>>(backend: B, circuit: &C) -> Result<(), SynthesisError> {
|
||||||
|
struct Synthesizer<E: Engine, B: Backend<E>> {
|
||||||
|
backend: B,
|
||||||
|
current_variable: Option<usize>,
|
||||||
|
_marker: PhantomData<E>,
|
||||||
|
q: usize,
|
||||||
|
n: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, B: Backend<E>>Synthesizer<E, B> {
|
||||||
|
fn purge_current_var(&mut self) {
|
||||||
|
match self.current_variable.take() {
|
||||||
|
Some(index) => {
|
||||||
|
let var_a = Variable::A(index);
|
||||||
|
let var_b = Variable::B(index);
|
||||||
|
let var_c = Variable::C(index);
|
||||||
|
|
||||||
|
let mut product = None;
|
||||||
|
|
||||||
|
let value_a = self.backend.get_var(var_a);
|
||||||
|
|
||||||
|
self.backend.set_var(var_b, || {
|
||||||
|
let value_b = E::Fr::one();
|
||||||
|
product = Some(value_a.ok_or(SynthesisError::AssignmentMissing)?);
|
||||||
|
product.as_mut().map(|product| product.mul_assign(&value_b));
|
||||||
|
|
||||||
|
Ok(value_b)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.backend.set_var(var_c, || {
|
||||||
|
product.ok_or(SynthesisError::AssignmentMissing)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.current_variable = None;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_one(&mut self) -> Variable {
|
||||||
|
self.n += 1;
|
||||||
|
let index = self.n;
|
||||||
|
assert_eq!(index, 1);
|
||||||
|
self.backend.new_multiplication_gate();
|
||||||
|
|
||||||
|
let var_a = Variable::A(1);
|
||||||
|
let var_b = Variable::B(1);
|
||||||
|
let var_c = Variable::C(1);
|
||||||
|
|
||||||
|
self.backend.set_var(var_a, || {
|
||||||
|
Ok(E::Fr::one())
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.backend.set_var(var_b, || {
|
||||||
|
Ok(E::Fr::one())
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.backend.set_var(var_c, || {
|
||||||
|
Ok(E::Fr::one())
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.q += 1;
|
||||||
|
self.backend.new_linear_constraint();
|
||||||
|
self.backend.insert_coefficient(var_a, Coeff::One);
|
||||||
|
self.backend.insert_coefficient(var_b, Coeff::One);
|
||||||
|
self.backend.insert_coefficient(var_c, Coeff::NegativeOne);
|
||||||
|
self.backend.new_k_power(self.q);
|
||||||
|
|
||||||
|
var_a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, B: Backend<E>> ConstraintSystem<E> for Synthesizer<E, B> {
|
||||||
|
const ONE: Variable = Variable::A(1);
|
||||||
|
|
||||||
|
fn alloc<F>(&mut self, value: F) -> Result<Variable, SynthesisError>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<E::Fr, SynthesisError>
|
||||||
|
{
|
||||||
|
match self.current_variable.take() {
|
||||||
|
Some(index) => {
|
||||||
|
let var_a = Variable::A(index);
|
||||||
|
let var_b = Variable::B(index);
|
||||||
|
let var_c = Variable::C(index);
|
||||||
|
|
||||||
|
let mut product = None;
|
||||||
|
|
||||||
|
let value_a = self.backend.get_var(var_a);
|
||||||
|
|
||||||
|
self.backend.set_var(var_b, || {
|
||||||
|
let value_b = value()?;
|
||||||
|
product = Some(value_a.ok_or(SynthesisError::AssignmentMissing)?);
|
||||||
|
product.as_mut().map(|product| product.mul_assign(&value_b));
|
||||||
|
|
||||||
|
Ok(value_b)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.backend.set_var(var_c, || {
|
||||||
|
product.ok_or(SynthesisError::AssignmentMissing)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.current_variable = None;
|
||||||
|
|
||||||
|
Ok(var_b)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.n += 1;
|
||||||
|
let index = self.n;
|
||||||
|
self.backend.new_multiplication_gate();
|
||||||
|
|
||||||
|
let var_a = Variable::A(index);
|
||||||
|
|
||||||
|
self.backend.set_var(var_a, value)?;
|
||||||
|
|
||||||
|
self.current_variable = Some(index);
|
||||||
|
|
||||||
|
Ok(var_a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: allocate input without spawning extra constraints
|
||||||
|
fn alloc_input<F>(&mut self, value: F) -> Result<Variable, SynthesisError>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<E::Fr, SynthesisError>
|
||||||
|
{
|
||||||
|
// self.purge_current_var();
|
||||||
|
// self.n += 1;
|
||||||
|
// self.backend.new_multiplication_gate();
|
||||||
|
|
||||||
|
// let index = self.n;
|
||||||
|
|
||||||
|
// let var = Variable::A::(index);
|
||||||
|
|
||||||
|
// self.q += 1;
|
||||||
|
// self.backend.new_k_power(self.q);
|
||||||
|
// self.backend.self.backend.insert_coefficient(new_var, Coeff::One);
|
||||||
|
|
||||||
|
// it's always going to be
|
||||||
|
let input_var = self.alloc(value)?;
|
||||||
|
|
||||||
|
self.enforce_zero(LinearCombination::zero() + input_var);
|
||||||
|
self.backend.new_k_power(self.q-2);
|
||||||
|
self.backend.new_k_power(self.q-1);
|
||||||
|
self.backend.new_k_power(self.q);
|
||||||
|
|
||||||
|
Ok(input_var)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_zero(&mut self, lc: LinearCombination<E>)
|
||||||
|
{
|
||||||
|
self.q += 1;
|
||||||
|
self.backend.new_linear_constraint();
|
||||||
|
|
||||||
|
for (var, coeff) in lc.as_ref() {
|
||||||
|
self.backend.insert_coefficient(*var, *coeff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we need to "rotate" a linear constraint by allocating more dummy variables, so ensuring
|
||||||
|
// that if for some q (index of LC) there is a coefficient C in front of a variable A(i) (that will result in a term ~ C*Y^{q}*X^{i})
|
||||||
|
// then there will be some other q' where there is a coefficient C in front of the variable B(i)
|
||||||
|
// (that will result in a term ~ C*Y^{q'}*X^{i+N}) and another q'' with C in front of C(i)
|
||||||
|
// (that will result in a term ~ C*Y^{q''}*X^{i+2N}), so S polynomial is indeed a permutation
|
||||||
|
|
||||||
|
// allocate at max 1 variable to later work with whole gates directly
|
||||||
|
|
||||||
|
self.purge_current_var();
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
// A -> B, B -> C, C -> A
|
||||||
|
{
|
||||||
|
self.q += 1;
|
||||||
|
self.backend.new_linear_constraint();
|
||||||
|
|
||||||
|
let mut allocation_map = HashMap::with_capacity(lc.as_ref().len());
|
||||||
|
let mut expected_new_index = self.n + 1;
|
||||||
|
|
||||||
|
// determine size of the map
|
||||||
|
for (var, _) in lc.as_ref() {
|
||||||
|
match var {
|
||||||
|
Variable::A(index) => {
|
||||||
|
if allocation_map.get(index).is_none() && *index != 1 {
|
||||||
|
allocation_map.insert(*index, expected_new_index);
|
||||||
|
expected_new_index += 1;
|
||||||
|
println!("A{} -> B{}", index, expected_new_index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Variable::B(index) => {
|
||||||
|
if allocation_map.get(index).is_none() && *index != 2 {
|
||||||
|
allocation_map.insert(*index, expected_new_index);
|
||||||
|
expected_new_index += 1;
|
||||||
|
println!("B{} -> C{}", index, expected_new_index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Variable::C(index) => {
|
||||||
|
if allocation_map.get(index).is_none() && *index != 3 {
|
||||||
|
allocation_map.insert(*index, expected_new_index);
|
||||||
|
expected_new_index += 1;
|
||||||
|
println!("C{} -> A{}", index, expected_new_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..allocation_map.len() {
|
||||||
|
self.backend.new_multiplication_gate();
|
||||||
|
self.n += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, new_index) in allocation_map.iter() {
|
||||||
|
let var_a = Variable::A(*new_index);
|
||||||
|
let var_b = Variable::B(*new_index);
|
||||||
|
let var_c = Variable::C(*new_index);
|
||||||
|
|
||||||
|
// A -> B, B -> C, C -> A
|
||||||
|
let b_val = self.backend.get_var(Variable::A(*index));
|
||||||
|
let c_val = self.backend.get_var(Variable::B(*index));
|
||||||
|
let a_val = self.backend.get_var(Variable::C(*index));
|
||||||
|
|
||||||
|
self.backend.set_var(var_a, || {
|
||||||
|
let value = a_val.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.backend.set_var(var_b, || {
|
||||||
|
let value = b_val.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.backend.set_var(var_c, || {
|
||||||
|
let value = c_val.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// A -> B, B -> C, C -> A
|
||||||
|
for (var, coeff) in lc.as_ref() {
|
||||||
|
let new_var = match var {
|
||||||
|
Variable::A(index) => {
|
||||||
|
let var = if *index == 1 {
|
||||||
|
Variable::B(2)
|
||||||
|
} else {
|
||||||
|
let new_index = allocation_map.get(index).unwrap();
|
||||||
|
Variable::B(*new_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
var
|
||||||
|
},
|
||||||
|
Variable::B(index) => {
|
||||||
|
let var = if *index == 2 {
|
||||||
|
Variable::C(3)
|
||||||
|
} else {
|
||||||
|
let new_index = allocation_map.get(index).unwrap();
|
||||||
|
Variable::C(*new_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
var
|
||||||
|
},
|
||||||
|
Variable::C(index) => {
|
||||||
|
let var = if *index == 3 {
|
||||||
|
Variable::A(1)
|
||||||
|
} else {
|
||||||
|
let new_index = allocation_map.get(index).unwrap();
|
||||||
|
Variable::A(*new_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
var
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.backend.insert_coefficient(new_var, *coeff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A -> C, B -> A, C -> B
|
||||||
|
{
|
||||||
|
self.q += 1;
|
||||||
|
self.backend.new_linear_constraint();
|
||||||
|
|
||||||
|
let mut allocation_map = HashMap::with_capacity(lc.as_ref().len());
|
||||||
|
let mut expected_new_index = self.n + 1;
|
||||||
|
|
||||||
|
// determine size of the map
|
||||||
|
for (var, _) in lc.as_ref() {
|
||||||
|
match var {
|
||||||
|
Variable::A(index) => {
|
||||||
|
if allocation_map.get(index).is_none() && *index != 1 {
|
||||||
|
allocation_map.insert(*index, expected_new_index);
|
||||||
|
expected_new_index += 1;
|
||||||
|
println!("A{} -> C{}", index, expected_new_index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Variable::B(index) => {
|
||||||
|
if allocation_map.get(index).is_none() && *index != 2 {
|
||||||
|
allocation_map.insert(*index, expected_new_index);
|
||||||
|
expected_new_index += 1;
|
||||||
|
println!("B{} -> A{}", index, expected_new_index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Variable::C(index) => {
|
||||||
|
if allocation_map.get(index).is_none() && *index != 3 {
|
||||||
|
allocation_map.insert(*index, expected_new_index);
|
||||||
|
expected_new_index += 1;
|
||||||
|
println!("C{} -> B{}", index, expected_new_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..allocation_map.len() {
|
||||||
|
self.backend.new_multiplication_gate();
|
||||||
|
self.n += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A -> C, B -> A, C -> B
|
||||||
|
for (index, new_index) in allocation_map.iter() {
|
||||||
|
let var_a = Variable::A(*new_index);
|
||||||
|
let var_b = Variable::B(*new_index);
|
||||||
|
let var_c = Variable::C(*new_index);
|
||||||
|
|
||||||
|
let b_val = self.backend.get_var(Variable::C(*index));
|
||||||
|
let c_val = self.backend.get_var(Variable::A(*index));
|
||||||
|
let a_val = self.backend.get_var(Variable::B(*index));
|
||||||
|
|
||||||
|
self.backend.set_var(var_a, || {
|
||||||
|
let value = a_val.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.backend.set_var(var_b, || {
|
||||||
|
let value = b_val.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
|
||||||
|
self.backend.set_var(var_c, || {
|
||||||
|
let value = c_val.ok_or(SynthesisError::AssignmentMissing)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}).expect("should exist by now");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A -> C, B -> A, C -> B
|
||||||
|
for (var, coeff) in lc.as_ref() {
|
||||||
|
let new_var = match var {
|
||||||
|
Variable::A(index) => {
|
||||||
|
let var = if *index == 1 {
|
||||||
|
Variable::C(3)
|
||||||
|
} else {
|
||||||
|
let new_index = allocation_map.get(index).unwrap();
|
||||||
|
Variable::C(*new_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
var
|
||||||
|
},
|
||||||
|
Variable::B(index) => {
|
||||||
|
let var = if *index == 2 {
|
||||||
|
Variable::A(1)
|
||||||
|
} else {
|
||||||
|
let new_index = allocation_map.get(index).unwrap();
|
||||||
|
Variable::A(*new_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
var
|
||||||
|
},
|
||||||
|
Variable::C(index) => {
|
||||||
|
let var = if *index == 3 {
|
||||||
|
Variable::B(2)
|
||||||
|
} else {
|
||||||
|
let new_index = allocation_map.get(index).unwrap();
|
||||||
|
Variable::B(*new_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
var
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.backend.insert_coefficient(new_var, *coeff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multiply<F>(&mut self, values: F) -> Result<(Variable, Variable, Variable), SynthesisError>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<(E::Fr, E::Fr, E::Fr), SynthesisError>
|
||||||
|
{
|
||||||
|
self.n += 1;
|
||||||
|
let index = self.n;
|
||||||
|
self.backend.new_multiplication_gate();
|
||||||
|
|
||||||
|
let a = Variable::A(index);
|
||||||
|
let b = Variable::B(index);
|
||||||
|
let c = Variable::C(index);
|
||||||
|
|
||||||
|
let mut b_val = None;
|
||||||
|
let mut c_val = None;
|
||||||
|
|
||||||
|
self.backend.set_var(a, || {
|
||||||
|
let (a, b, c) = values()?;
|
||||||
|
|
||||||
|
b_val = Some(b);
|
||||||
|
c_val = Some(c);
|
||||||
|
|
||||||
|
Ok(a)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.backend.set_var(b, || {
|
||||||
|
b_val.ok_or(SynthesisError::AssignmentMissing)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.backend.set_var(c, || {
|
||||||
|
c_val.ok_or(SynthesisError::AssignmentMissing)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok((a, b, c))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_value(&self, var: Variable) -> Result<E::Fr, ()> {
|
||||||
|
self.backend.get_var(var).ok_or(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tmp: Synthesizer<E, B> = Synthesizer {
|
||||||
|
backend: backend,
|
||||||
|
current_variable: None,
|
||||||
|
_marker: PhantomData,
|
||||||
|
q: 0,
|
||||||
|
n: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let one = tmp.alloc_input(|| Ok(E::Fr::one())).expect("should have no issues");
|
||||||
|
|
||||||
|
match (one, <Synthesizer<E, B> as ConstraintSystem<E>>::ONE) {
|
||||||
|
(Variable::A(1), Variable::A(1)) => {},
|
||||||
|
_ => panic!("one variable is incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
circuit.synthesize(&mut tmp)?;
|
||||||
|
|
||||||
|
println!("Done synthesizing, N = {}, Q = {}", tmp.n, tmp.q);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constraints_info<E: Engine, C: BellmanCircuit<E> + Clone>(
|
||||||
|
circuit: C,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let adapted_circuit = AdaptorCircuit(circuit);
|
||||||
|
|
||||||
|
create_constraints_info::<_, _, Nonassigning>(&adapted_circuit)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constraints_padding_info<E: Engine, C: BellmanCircuit<E> + Clone>(
|
||||||
|
circuit: C,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let adapted_circuit = AdaptorCircuit(circuit);
|
||||||
|
|
||||||
|
create_constraints_info::<_, _, Padding>(&adapted_circuit)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_constraints_info<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
|
||||||
|
circuit: &C,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let mut backend = Debugging::<E> {
|
||||||
|
constraint_num: 0,
|
||||||
|
u: vec![],
|
||||||
|
v: vec![],
|
||||||
|
w: vec![],
|
||||||
|
_marker: std::marker::PhantomData
|
||||||
|
};
|
||||||
|
|
||||||
|
S::synthesize(&mut backend, circuit).unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
for (i, ((u, v), w)) in backend.u.iter()
|
||||||
|
.zip(backend.v.iter())
|
||||||
|
.zip(backend.w.iter())
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
println!("Constraint {}: 0 = {}{}{}", i, u, v, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn my_fun_circuit_test() {
|
||||||
|
use pairing::ff::PrimeField;
|
||||||
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
|
|
||||||
|
struct MyCircuit;
|
||||||
|
|
||||||
|
impl<E: Engine> Circuit<E> for MyCircuit {
|
||||||
|
fn synthesize<CS: ConstraintSystem<E>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
|
||||||
|
let (a, b, _) = cs.multiply(|| {
|
||||||
|
Ok((
|
||||||
|
E::Fr::from_str("10").unwrap(),
|
||||||
|
E::Fr::from_str("20").unwrap(),
|
||||||
|
E::Fr::from_str("200").unwrap(),
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
cs.enforce_zero(LinearCombination::from(a) + a - b);
|
||||||
|
|
||||||
|
let multiplier = cs.alloc_input(|| Ok(E::Fr::from_str("20").unwrap()))?;
|
||||||
|
|
||||||
|
cs.enforce_zero(LinearCombination::from(b) - multiplier);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create_constraints_info::<Bls12, _, Nonassigning>(&MyCircuit);
|
||||||
|
println!("---------------");
|
||||||
|
create_constraints_info::<Bls12, _, Padding>(&MyCircuit);
|
||||||
|
}
|
@ -43,8 +43,6 @@ pub struct Proof<E: Engine> {
|
|||||||
s_zy: E::Fr
|
s_zy: E::Fr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn permute<F: Field>(coeffs: &[F], permutation: & [usize]) -> Vec<F>{
|
fn permute<F: Field>(coeffs: &[F], permutation: & [usize]) -> Vec<F>{
|
||||||
assert_eq!(coeffs.len(), permutation.len());
|
assert_eq!(coeffs.len(), permutation.len());
|
||||||
let mut result: Vec<F> = vec![F::zero(); coeffs.len()];
|
let mut result: Vec<F> = vec![F::zero(); coeffs.len()];
|
||||||
|
@ -123,12 +123,12 @@ pub fn polynomial_commitment_opening<
|
|||||||
) -> E::G1Affine
|
) -> E::G1Affine
|
||||||
where I::IntoIter: DoubleEndedIterator + ExactSizeIterator,
|
where I::IntoIter: DoubleEndedIterator + ExactSizeIterator,
|
||||||
{
|
{
|
||||||
let poly = parallel_kate_divison::<E, _>(polynomial_coefficients, point);
|
// let poly = parallel_kate_divison::<E, _>(polynomial_coefficients, point);
|
||||||
|
|
||||||
// let poly = kate_divison(
|
let poly = kate_divison(
|
||||||
// polynomial_coefficients,
|
polynomial_coefficients,
|
||||||
// point,
|
point,
|
||||||
// );
|
);
|
||||||
|
|
||||||
let negative_poly = poly[0..largest_negative_power].iter().rev();
|
let negative_poly = poly[0..largest_negative_power].iter().rev();
|
||||||
let positive_poly = poly[largest_negative_power..].iter();
|
let positive_poly = poly[largest_negative_power..].iter();
|
||||||
|
Loading…
Reference in New Issue
Block a user