TODO: reformulate permutation argument

This commit is contained in:
Alex Vlasov 2019-06-11 15:43:27 +03:00
parent eaaff874fc
commit ae9716a428
9 changed files with 820 additions and 642 deletions

@ -106,6 +106,8 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative); let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative);
println!("Helper s(z, w) = {}", value);
let opening = { let opening = {
let mut value = value; let mut value = value;
value.negate(); value.negate();
@ -117,20 +119,6 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
w, w,
&srs &srs
) )
// let poly = kate_divison(
// s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
// w,
// );
// let negative_poly = poly[0..n].iter().rev();
// let positive_poly = poly[n..].iter();
// multiexp(
// srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
// srs.g_positive_x[0..positive_poly.len()].iter()
// ),
// negative_poly.chain_ext(positive_poly)
// ).into_affine()
}; };
// Let's open up C to every y. // Let's open up C to every y.
@ -143,22 +131,6 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
value.add_assign(&positive_powers_contrib); value.add_assign(&positive_powers_contrib);
value.add_assign(&negative_powers_contrib); value.add_assign(&negative_powers_contrib);
// let mut tmp = yinv;
// for &coeff in poly_negative {
// let mut coeff = coeff;
// coeff.mul_assign(&tmp);
// value.add_assign(&coeff);
// tmp.mul_assign(&yinv);
// }
// let mut tmp = *y;
// for &coeff in poly_positive {
// let mut coeff = coeff;
// coeff.mul_assign(&tmp);
// value.add_assign(&coeff);
// tmp.mul_assign(&y);
// }
value value
} }
@ -180,20 +152,6 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
*y, *y,
&srs &srs
) )
// let poly = kate_divison(
// s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
// *y,
// );
// let negative_poly = poly[0..n].iter().rev();
// let positive_poly = poly[n..].iter();
// multiexp(
// srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
// srs.g_positive_x[0..positive_poly.len()].iter()
// ),
// negative_poly.chain_ext(positive_poly)
// ).into_affine()
}; };
c_openings.push((opening, value)); c_openings.push((opening, value));
@ -229,15 +187,6 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
mul_add_polynomials(& mut poly_negative[..], &s_poly_negative[..], r); mul_add_polynomials(& mut poly_negative[..], &s_poly_negative[..], r);
mul_add_polynomials(& mut poly_positive[..], &s_poly_positive[..], r); mul_add_polynomials(& mut poly_positive[..], &s_poly_positive[..], r);
// for (mut coeff, target) in s_poly_negative.into_iter().zip(poly_negative.iter_mut()) {
// coeff.mul_assign(&r);
// target.add_assign(&coeff);
// }
// for (mut coeff, target) in s_poly_positive.into_iter().zip(poly_positive.iter_mut()) {
// coeff.mul_assign(&r);
// target.add_assign(&coeff);
// }
} }
println!("Re-evaluation of {} S polynomials taken {:?}", y_values.len(), start.elapsed()); println!("Re-evaluation of {} S polynomials taken {:?}", y_values.len(), start.elapsed());
@ -254,19 +203,6 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
&srs &srs
) )
// let poly = kate_divison(
// poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(poly_positive.iter()),
// z,
// );
// let negative_poly = poly[0..n].iter().rev();
// let positive_poly = poly[n..].iter();
// multiexp(
// srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
// srs.g_positive_x[0..positive_poly.len()].iter()
// ),
// negative_poly.chain_ext(positive_poly)
// ).into_affine()
}; };
Aggregate { Aggregate {

@ -498,47 +498,13 @@ fn test_succinct_sonic_mimc() {
use crate::sonic::sonic::AdaptorCircuit; use crate::sonic::sonic::AdaptorCircuit;
use crate::sonic::helped::prover::{create_advice_on_srs, create_proof_on_srs}; use crate::sonic::helped::prover::{create_advice_on_srs, create_proof_on_srs};
use crate::sonic::helped::{get_circuit_parameters_for_succinct_sonic, MultiVerifier}; use crate::sonic::helped::{get_circuit_parameters_for_succinct_sonic, MultiVerifier};
use crate::sonic::helped::helper::{create_aggregate_on_srs};
use crate::sonic::sonic::Permutation3; use crate::sonic::sonic::Permutation3;
use crate::sonic::unhelped::permutation_structure::*; use crate::sonic::unhelped::permutation_structure::*;
use crate::sonic::unhelped::SuccinctMultiVerifier; use crate::sonic::unhelped::SuccinctMultiVerifier;
use crate::sonic::unhelped::{create_aggregate_on_srs};
use crate::sonic::cs::{Circuit, ConstraintSystem, LinearCombination, Coeff}; use crate::sonic::cs::{Circuit, ConstraintSystem, LinearCombination, Coeff};
struct MyCircuit;
impl<E: Engine> Circuit<E> for MyCircuit {
fn synthesize<CS: ConstraintSystem<E>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
let (a, b, c) = 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::zero() + (Coeff::Full(E::Fr::from_str("2").unwrap()), a) - b);
let multiplier = cs.alloc_input(|| Ok(E::Fr::from_str("20").unwrap()))?;
cs.enforce_zero(LinearCombination::from(b) - multiplier);
let (a1, b1, _) = cs.multiply(|| {
Ok((
E::Fr::from_str("5").unwrap(),
E::Fr::from_str("5").unwrap(),
E::Fr::from_str("25").unwrap(),
))
})?;
cs.enforce_zero(LinearCombination::zero() + (Coeff::Full(E::Fr::from_str("2").unwrap()), b1) - a);
cs.enforce_zero(LinearCombination::zero() + (Coeff::Full(E::Fr::from_str("4").unwrap()), a1) - b);
cs.enforce_zero(LinearCombination::zero() + (Coeff::Full(E::Fr::from_str("40").unwrap()), b1) - c);
Ok(())
}
}
// let perm_structure = create_permutation_structure::<Bls12, _>(&AdaptorCircuit(circuit.clone())); // let perm_structure = create_permutation_structure::<Bls12, _>(&AdaptorCircuit(circuit.clone()));
let perm_structure = create_permutation_structure::<Bls12, _>(&AdaptorCircuit(circuit.clone())); let perm_structure = create_permutation_structure::<Bls12, _>(&AdaptorCircuit(circuit.clone()));
let s1_srs = perm_structure.create_permutation_special_reference(&srs); let s1_srs = perm_structure.create_permutation_special_reference(&srs);
@ -560,84 +526,49 @@ fn test_succinct_sonic_mimc() {
println!("creating aggregate for {} proofs", samples); println!("creating aggregate for {} proofs", samples);
let start = Instant::now(); let start = Instant::now();
let proofs: Vec<_> = (0..samples).map(|_| (proof.clone(), advice.clone())).collect(); let proofs: Vec<_> = (0..samples).map(|_| (proof.clone(), advice.clone())).collect();
let aggregate = create_aggregate_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proofs, &srs); let aggregate = create_aggregate_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proofs, &srs, &s1_srs);
println!("done in {:?}", start.elapsed()); println!("done in {:?}", start.elapsed());
{
let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
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());
}
{ let _ = crate::sonic::helped::helper::create_aggregate_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proofs, &srs);
let rng = thread_rng(); // {
let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); // let rng = thread_rng();
println!("verifying {} proofs without advice", samples); // let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
let start = Instant::now(); // println!("verifying 1 proof without advice");
{ // let start = Instant::now();
for _ in 0..samples { // {
verifier.add_proof(&proof, &[], |_, _| None); // for _ in 0..1 {
} // verifier.add_proof(&proof, &[], |_, _| None);
assert_eq!(verifier.check_all(), true); // TODO // }
} // assert_eq!(verifier.check_all(), true); // TODO
println!("done in {:?}", start.elapsed()); // }
} // println!("done in {:?}", start.elapsed());
// }
{ // {
let rng = thread_rng(); // let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); // let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with advice non-succinct"); // println!("verifying {} proofs without advice", samples);
let start = Instant::now(); // let start = Instant::now();
{ // {
for (ref proof, ref advice) in &proofs { // for _ in 0..samples {
verifier.add_proof_with_advice(proof, &[], advice); // verifier.add_proof(&proof, &[], |_, _| None);
} // }
verifier.add_aggregate(&proofs, &aggregate); // assert_eq!(verifier.check_all(), true); // TODO
assert_eq!(verifier.check_all(), true); // TODO // }
} // println!("done in {:?}", start.elapsed());
println!("done in {:?}", start.elapsed()); // }
}
{ {
use rand::{XorShiftRng, SeedableRng, Rand, Rng}; use rand::{XorShiftRng, SeedableRng, Rand, Rng};
let mut rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); let mut rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let start = Instant::now(); let start = Instant::now();
let (perm_commitments, s_prime_challenges, perm_proof, perm_arg_proof, z_prime, num_poly, s1_naive) = perm_structure.create_permutation_arguments(aggregate.w, aggregate.z, &mut rng, &srs);
let s2_proof = perm_structure.calculate_s2_proof(aggregate.z, aggregate.w, &srs);
println!("Permutation argument done in {:?}", start.elapsed()); // let aggregate =
// let (perm_commitments, s_prime_challenges, perm_proof, perm_arg_proof, z_prime, num_poly, s1_naive) = perm_structure.create_permutation_arguments(aggregate.w, aggregate.z, &mut rng, &srs);
// let n = perm_structure.n; // let s2_proof = perm_structure.calculate_s2_proof(aggregate.z, aggregate.w, &srs);
// let z = aggregate.z;
// let y = aggregate.w;
// let z_inv = z.inverse().unwrap();
// let z_inv_n_plus_1 = z_inv.pow([(n+1) as u64]);
// let z_n = z.pow([n as u64]);
// let y_n = y.pow([n as u64]);
// println!("S_1 naive = {}", s1_naive);
// let mut s_1 = s1_naive;
// s_1.mul_assign(&z_inv_n_plus_1);
// s_1.mul_assign(&y_n);
// println!("S_1 multiplied = {}", s_1);
// let mut s_2 = s2_proof.c_value;
// s_2.add_assign(&s2_proof.d_value);
// s_2.mul_assign(&z_n);
// s_1.sub_assign(&s_2);
// println!("S naive = {}", s_1);
// println!("Permutation argument done in {:?}", start.elapsed());
let mut verifier = SuccinctMultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); let mut verifier = SuccinctMultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with succinct advice"); println!("verifying 100 proofs with succinct advice");
@ -649,14 +580,8 @@ fn test_succinct_sonic_mimc() {
verifier.add_aggregate( verifier.add_aggregate(
&proofs, &proofs,
&aggregate, &aggregate,
&perm_arg_proof,
&perm_proof,
&s2_proof,
num_poly,
&srs, &srs,
z_prime, &s1_srs
&perm_commitments,
s_prime_challenges
); );
assert_eq!(verifier.check_all(), true); // TODO assert_eq!(verifier.check_all(), true); // TODO
} }

@ -16,31 +16,46 @@ use crate::sonic::cs::{Circuit, Variable, Coeff};
use crate::sonic::srs::SRS; use crate::sonic::srs::SRS;
use crate::sonic::sonic::CountNandQ; use crate::sonic::sonic::CountNandQ;
use crate::sonic::sonic::M; use crate::sonic::sonic::M;
use super::s2_proof::{S2Eval, S2Proof};
use super::permutation_structure::create_permutation_structure;
use super::permutation_argument::PermutationArgument;
use super::permutation_argument::SignatureOfCorrectComputation;
use super::permutation_argument::SpecializedSRS;
#[derive(Clone)] #[derive(Clone)]
pub struct SuccinctAggregate<E: Engine> { pub struct SuccinctAggregate<E: Engine> {
pub permutations: [] pub signature: SignatureOfCorrectComputation<E>,
pub a: Vec<[Option<(Coeff<E>, usize)>; M]>, pub s2_proof: S2Proof<E>,
pub b: Vec<[Option<(Coeff<E>, usize)>; M]>, pub c: E::G1Affine,
pub c: Vec<[Option<(Coeff<E>, usize)>; M]>, // We have to open each of the S commitments to a random point `z`
pub s_opening: E::G1Affine,
// We have to open C to each constituent `y`
pub c_openings: Vec<(E::G1Affine, E::Fr)>,
// Then we have to finally open C
pub opening: E::G1Affine,
pub z: E::Fr,
pub w: E::Fr,
} }
pub fn create_aggregate<E: Engine, C: Circuit<E>, S: SynthesisDriver>( // pub fn create_aggregate<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
circuit: &C, // circuit: &C,
inputs: &[(Proof<E>, SxyAdvice<E>)], // inputs: &[(Proof<E>, SxyAdvice<E>)],
params: &Parameters<E>, // params: &Parameters<E>,
) -> SuccinctAggregate<E> // ) -> SuccinctAggregate<E>
{ // {
let n = params.vk.n; // let n = params.vk.n;
let q = params.vk.q; // let q = params.vk.q;
create_aggregate_on_srs_using_information::<E, C, S>(circuit, inputs, &params.srs, n, q) // create_aggregate_on_srs_using_information::<E, C, S>(circuit, inputs, &params.srs, n, q)
} // }
pub fn create_aggregate_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>( pub fn create_aggregate_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
circuit: &C, circuit: &C,
inputs: &[(Proof<E>, SxyAdvice<E>)], inputs: &[(Proof<E>, SxyAdvice<E>)],
srs: &SRS<E>, srs: &SRS<E>,
specialized_srs: &SpecializedSRS<E>
) -> SuccinctAggregate<E> ) -> SuccinctAggregate<E>
{ {
// TODO: precompute this? // TODO: precompute this?
@ -52,17 +67,19 @@ pub fn create_aggregate_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
(tmp.n, tmp.q) (tmp.n, tmp.q)
}; };
create_aggregate_on_srs_using_information::<E, C, S>(circuit, inputs, srs, n, q) create_aggregate_on_srs_using_information::<E, C, S>(circuit, inputs, srs, specialized_srs, n, q)
} }
pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: SynthesisDriver>( pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
circuit: &C, circuit: &C,
inputs: &[(Proof<E>, SxyAdvice<E>)], inputs: &[(Proof<E>, SxyAdvice<E>)],
srs: &SRS<E>, srs: &SRS<E>,
specialized_srs: &SpecializedSRS<E>,
n: usize, n: usize,
q: usize, q: usize,
) -> SuccinctAggregate<E> ) -> SuccinctAggregate<E>
{ {
// take few proofs that are to be evaluated at some y_i and make an aggregate from them
let mut transcript = Transcript::new(&[]); let mut transcript = Transcript::new(&[]);
let mut y_values: Vec<E::Fr> = Vec::with_capacity(inputs.len()); let mut y_values: Vec<E::Fr> = Vec::with_capacity(inputs.len());
for &(ref proof, ref sxyadvice) in inputs { for &(ref proof, ref sxyadvice) in inputs {
@ -77,22 +94,7 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
let z: E::Fr = transcript.get_challenge_scalar(); let z: E::Fr = transcript.get_challenge_scalar();
let t = { // Compute s(z, Y) for opening of the previous commitments at the same `z`
let mut tmp: PermutationSynthesizer<E, B> = PermutationSynthesizer::new(backend);
let one = tmp.alloc_input(|| Ok(E::Fr::one())).expect("should have no issues");
match (one, <PermutationSynthesizer<E, B> as ConstraintSystem<E>>::ONE) {
(Variable::A(1), Variable::A(1)) => {},
_ => panic!("one variable is incorrect")
}
circuit.synthesize(&mut tmp).expect("should synthesize");
tmp
};
// Compute s(z, Y)
let (s_poly_negative, s_poly_positive) = { let (s_poly_negative, s_poly_positive) = {
let mut tmp = SyEval::new(z, n, q); let mut tmp = SyEval::new(z, n, q);
S::synthesize(&mut tmp, circuit).unwrap(); // TODO S::synthesize(&mut tmp, circuit).unwrap(); // TODO
@ -113,8 +115,12 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
// Open C at w // Open C at w
let w: E::Fr = transcript.get_challenge_scalar(); let w: E::Fr = transcript.get_challenge_scalar();
println!("Aggregate: Z = {}, W = {}", z, w);
let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative); let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative);
println!("Aggregate: S(z,w) = {}", value);
let opening = { let opening = {
let mut value = value; let mut value = value;
value.negate(); value.negate();
@ -126,22 +132,30 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
w, w,
&srs &srs
) )
// let poly = kate_divison(
// s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
// w,
// );
// let negative_poly = poly[0..n].iter().rev();
// let positive_poly = poly[n..].iter();
// multiexp(
// srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
// srs.g_positive_x[0..positive_poly.len()].iter()
// ),
// negative_poly.chain_ext(positive_poly)
// ).into_affine()
}; };
// now we need signature of correct computation. For this purpose
// verifier already knows specialized SRS, so we can just commit to
// s1 and s2 parts of such signature to get `w` and later open at this point!
// Commit!
// TODO: Precompute!
// this will internally synthesize a circuit and structure of permutations
let s2_eval = S2Eval::new(n);
let s2_proof = s2_eval.evaluate(z, w, &srs);
let permutation_structure = create_permutation_structure(circuit);
let (non_permuted_coeffs, permutations) = permutation_structure.create_permutation_vectors();
let signature = PermutationArgument::make_signature(
non_permuted_coeffs,
permutations,
w,
z,
&srs,
&specialized_srs
);
// Let's open up C to every y. // Let's open up C to every y.
fn compute_value<E: Engine>(y: &E::Fr, poly_positive: &[E::Fr], poly_negative: &[E::Fr]) -> E::Fr { fn compute_value<E: Engine>(y: &E::Fr, poly_positive: &[E::Fr], poly_negative: &[E::Fr]) -> E::Fr {
let mut value = E::Fr::zero(); let mut value = E::Fr::zero();
@ -152,28 +166,14 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
value.add_assign(&positive_powers_contrib); value.add_assign(&positive_powers_contrib);
value.add_assign(&negative_powers_contrib); value.add_assign(&negative_powers_contrib);
// let mut tmp = yinv;
// for &coeff in poly_negative {
// let mut coeff = coeff;
// coeff.mul_assign(&tmp);
// value.add_assign(&coeff);
// tmp.mul_assign(&yinv);
// }
// let mut tmp = *y;
// for &coeff in poly_positive {
// let mut coeff = coeff;
// coeff.mul_assign(&tmp);
// value.add_assign(&coeff);
// tmp.mul_assign(&y);
// }
value value
} }
use std::time::Instant; use std::time::Instant;
let start = Instant::now(); let start = Instant::now();
// we still need to re-open previous commitments at the same new z
let mut c_openings = vec![]; let mut c_openings = vec![];
for y in &y_values { for y in &y_values {
let value = compute_value::<E>(y, &s_poly_positive, &s_poly_negative); let value = compute_value::<E>(y, &s_poly_positive, &s_poly_negative);
@ -189,20 +189,6 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
*y, *y,
&srs &srs
) )
// let poly = kate_divison(
// s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
// *y,
// );
// let negative_poly = poly[0..n].iter().rev();
// let positive_poly = poly[n..].iter();
// multiexp(
// srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
// srs.g_positive_x[0..positive_poly.len()].iter()
// ),
// negative_poly.chain_ext(positive_poly)
// ).into_affine()
}; };
c_openings.push((opening, value)); c_openings.push((opening, value));
@ -237,16 +223,6 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
mul_add_polynomials(& mut poly_negative[..], &s_poly_negative[..], r); mul_add_polynomials(& mut poly_negative[..], &s_poly_negative[..], r);
mul_add_polynomials(& mut poly_positive[..], &s_poly_positive[..], r); mul_add_polynomials(& mut poly_positive[..], &s_poly_positive[..], r);
// for (mut coeff, target) in s_poly_negative.into_iter().zip(poly_negative.iter_mut()) {
// coeff.mul_assign(&r);
// target.add_assign(&coeff);
// }
// for (mut coeff, target) in s_poly_positive.into_iter().zip(poly_positive.iter_mut()) {
// coeff.mul_assign(&r);
// target.add_assign(&coeff);
// }
} }
println!("Re-evaluation of {} S polynomials taken {:?}", y_values.len(), start.elapsed()); println!("Re-evaluation of {} S polynomials taken {:?}", y_values.len(), start.elapsed());
@ -262,30 +238,17 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
z, z,
&srs &srs
) )
// let poly = kate_divison(
// poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(poly_positive.iter()),
// z,
// );
// let negative_poly = poly[0..n].iter().rev();
// let positive_poly = poly[n..].iter();
// multiexp(
// srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
// srs.g_positive_x[0..positive_poly.len()].iter()
// ),
// negative_poly.chain_ext(positive_poly)
// ).into_affine()
}; };
Aggregate { SuccinctAggregate {
// Commitment to s(z, Y) signature,
s2_proof,
c, c,
// We have to open each of the S commitments to a random point `z`
s_opening, s_opening,
// We have to open C to each constituent `y`
c_openings, c_openings,
// Then we have to finally open C
opening, opening,
z: z,
w: w,
} }
} }

@ -49,6 +49,7 @@ impl<E: Engine> GrandProductArgument<E> {
z: E::Fr, z: E::Fr,
srs: &SRS<E>, srs: &SRS<E>,
) -> GrandProductSignature<E> { ) -> GrandProductSignature<E> {
println!("Making grand product argument for {} grand products", grand_products.len());
let mut a_commitments = vec![]; let mut a_commitments = vec![];
let mut b_commitments = vec![]; let mut b_commitments = vec![];
@ -68,7 +69,7 @@ impl<E: Engine> GrandProductArgument<E> {
let mut all_polys = vec![]; let mut all_polys = vec![];
let mut wellformed_challenges = vec![]; let mut wellformed_challenges = vec![];
for c in 0..(grand_products.len()*2) { for _ in 0..(grand_products.len()*2) {
let c = transcript.get_challenge_scalar(); let c = transcript.get_challenge_scalar();
wellformed_challenges.push(c); wellformed_challenges.push(c);
} }
@ -196,21 +197,21 @@ impl<E: Engine> GrandProductArgument<E> {
} }
} }
// Make a commitment to a polynomial in a form A*B^{x+1} = [a_1...a_{n}, 0, b_1...b_{n}] // // Make a commitment to a polynomial in a form A*B^{x+1} = [a_1...a_{n}, 0, b_1...b_{n}]
pub fn commit_for_grand_product(a: &[E::Fr], b: &[E::Fr], srs: &SRS<E>) -> E::G1Affine { // pub fn commit_for_grand_product(a: &[E::Fr], b: &[E::Fr], srs: &SRS<E>) -> E::G1Affine {
assert_eq!(a.len(), b.len()); // assert_eq!(a.len(), b.len());
let n = a.len(); // let n = a.len();
// multiexp(
// srs.g_positive_x_alpha[0..(2*n+1)].iter(),
// a.iter()
// .chain_ext(Some(E::Fr::zero()).iter())
// .chain_ext(b.iter())
// ).into_affine()
// }
multiexp(
srs.g_positive_x_alpha[0..(2*n+1)].iter(),
a.iter()
.chain_ext(Some(E::Fr::zero()).iter())
.chain_ext(b.iter())
).into_affine()
}
// Make a commitment to a polynomial in a form A*B^{x+1} = [a_1...a_{n}, 0, b_1...b_{n}]
pub fn commit_for_individual_products(a: &[E::Fr], b: &[E::Fr], srs: &SRS<E>) -> (E::G1Affine, E::G1Affine) { pub fn commit_for_individual_products(a: &[E::Fr], b: &[E::Fr], srs: &SRS<E>) -> (E::G1Affine, E::G1Affine) {
assert_eq!(a.len(), b.len()); assert_eq!(a.len(), b.len());
@ -536,11 +537,10 @@ impl<E: Engine> GrandProductArgument<E> {
y: E::Fr, y: E::Fr,
z: E::Fr, z: E::Fr,
srs: &SRS<E> srs: &SRS<E>
) -> bool { ) -> bool {
assert_eq!(randomness.len(), a_commitments.len()); assert_eq!(randomness.len(), a_commitments.len());
assert_eq!(openings.len(), a_commitments.len()); assert_eq!(openings.len(), a_commitments.len());
assert_eq!(b_commitments.len(), a_commitments.len()); assert_eq!(b_commitments.len(), a_commitments.len());
let d = srs.d;
// e(Dj,hαx)e(Dyz,hα) = e(Aj,h)e(Bj,hxn+1)e(gaj ,hα) // e(Dj,hαx)e(Dyz,hα) = e(Aj,h)e(Bj,hxn+1)e(gaj ,hα)
@ -625,8 +625,6 @@ impl<E: Engine> GrandProductArgument<E> {
assert_eq!(a_zy.len(), challenges.len()); assert_eq!(a_zy.len(), challenges.len());
assert_eq!(commitments.len(), challenges.len()); assert_eq!(commitments.len(), challenges.len());
let d = srs.d;
let g = srs.g_positive_x[0]; let g = srs.g_positive_x[0];
let h_alpha_x_precomp = srs.h_positive_x_alpha[1].prepare(); let h_alpha_x_precomp = srs.h_positive_x_alpha[1].prepare();

@ -9,10 +9,9 @@ mod grand_product_argument;
mod permutation_argument; mod permutation_argument;
mod verifier; mod verifier;
pub mod permutation_structure; pub mod permutation_structure;
// mod helper; mod aggregate;
// mod permutation;
// pub mod padding;
pub use self::wellformed_argument::{WellformednessArgument, WellformednessProof}; pub use self::wellformed_argument::{WellformednessArgument, WellformednessProof};
pub use self::permutation_argument::{PermutationArgument, PermutationProof, PermutationArgumentProof}; pub use self::permutation_argument::{PermutationArgument, PermutationProof, PermutationArgumentProof};
pub use self::verifier::SuccinctMultiVerifier; pub use self::verifier::SuccinctMultiVerifier;
pub use self::aggregate::*;

@ -15,10 +15,10 @@ use crate::sonic::transcript::{Transcript, TranscriptProtocol};
#[derive(Clone)] #[derive(Clone)]
pub struct SpecializedSRS<E: Engine> { pub struct SpecializedSRS<E: Engine> {
p_1: E::G1Affine, pub p_1: E::G1Affine,
p_2: Vec<E::G1Affine>, pub p_2: Vec<E::G1Affine>,
p_3: E::G1Affine, pub p_3: E::G1Affine,
p_4: Vec<E::G1Affine>, pub p_4: Vec<E::G1Affine>,
n: usize n: usize
} }
@ -26,8 +26,8 @@ pub struct SpecializedSRS<E: Engine> {
pub struct PermutationArgument<E: Engine> { pub struct PermutationArgument<E: Engine> {
non_permuted_coefficients: Vec<Vec<E::Fr>>, non_permuted_coefficients: Vec<Vec<E::Fr>>,
non_permuted_at_y_coefficients: Vec<Vec<E::Fr>>, non_permuted_at_y_coefficients: Vec<Vec<E::Fr>>,
permuted_coefficients: Vec<Vec<E::Fr>>,
permuted_at_y_coefficients: Vec<Vec<E::Fr>>, permuted_at_y_coefficients: Vec<Vec<E::Fr>>,
inverse_permuted_at_y_coefficients: Vec<Vec<E::Fr>>,
permutations: Vec<Vec<usize>>, permutations: Vec<Vec<usize>>,
n: usize n: usize
} }
@ -97,9 +97,10 @@ impl<E: Engine> PermutationArgument<E> {
PermutationArgument { PermutationArgument {
non_permuted_coefficients: coefficients, non_permuted_coefficients: coefficients,
non_permuted_at_y_coefficients: vec![vec![]], non_permuted_at_y_coefficients: vec![],
permuted_coefficients: vec![vec![]], // permuted_coefficients: vec![],
permuted_at_y_coefficients: vec![vec![]], permuted_at_y_coefficients: vec![],
inverse_permuted_at_y_coefficients: vec![],
permutations: permutations, permutations: permutations,
n: n n: n
} }
@ -148,7 +149,9 @@ impl<E: Engine> PermutationArgument<E> {
fe fe
}).collect(); }).collect();
let p4 = multiexp(srs.g_positive_x_alpha[0..n].iter(), values.iter()).into_affine(); let p4 = multiexp(srs.g_positive_x_alpha[0..n].iter(), values.iter()).into_affine();
p_4.push(p4); p_4.push(p4);
} }
} }
@ -164,71 +167,59 @@ impl<E: Engine> PermutationArgument<E> {
// commit to s and s' at y. Mutates the state // commit to s and s' at y. Mutates the state
pub fn commit(&mut self, y: E::Fr, srs: &SRS<E>) -> Vec<(E::G1Affine, E::G1Affine)> { pub fn commit(&mut self, y: E::Fr, srs: &SRS<E>) -> Vec<(E::G1Affine, E::G1Affine)> {
assert!(self.inverse_permuted_at_y_coefficients.len() == 0);
let mut result = vec![]; let mut result = vec![];
let n = self.non_permuted_coefficients[0].len(); let n = self.non_permuted_coefficients[0].len();
let mut non_permuted_at_y_coefficients = vec![]; let mut non_permuted_at_y_coefficients = vec![];
let mut permuted_coefficients = vec![]; // let mut permuted_coefficients = vec![];
let mut permuted_at_y_coefficients = vec![]; let mut permuted_at_y_coefficients = vec![];
let mut inverse_permuted_at_y_coefficients = vec![];
// naive algorithms // naive algorithms
// for every permutation poly // for every permutation poly
// -- go throught all variable_idx // -- go throught all variable_idx
// - take coeff from non-permuted coeffs[veriable_idx] // - take coeff from non-permuted coeffs[permutation[variable_idx]]
// - mul by Y^{permutation[variable_idx]} // - mul by Y^{permutation[variable_idx]}
// - mul by X^{variable_idx + 1} // - mul by X^{variable_idx + 1}
// let mut s_contrib = E::Fr::zero();
// for permutation_index in 0..m {
// for (variable_index, constraint_power) in permutations[permutation_index].iter().enumerate() {
// let y_power = y.pow([*constraint_power as u64]);
// let x_power = z.pow([(variable_index+1) as u64]);
// let coeff = non_permuted_coeffs[permutation_index][variable_index];
// let mut result = coeff;
// result.mul_assign(&x_power);
// result.mul_assign(&y_power);
// s_contrib.add_assign(&result);
// }
// }
// this part distributes powers of Y^{constraint} and Y^{variable} for different arguments
for (c, p) in self.non_permuted_coefficients.iter().zip(self.permutations.iter()) { for (c, p) in self.non_permuted_coefficients.iter().zip(self.permutations.iter()) {
// this one will have terms coeff[0] * Y^1
let mut non_permuted_at_y = c.clone(); let mut non_permuted_at_y = c.clone();
// permute to later have coeff[i] at spot K for distribution of powers and for argument
let permuted = permute(&non_permuted_at_y[..], &p[..]);
// here will be distributed powers for coeff[i] * Y^K
let mut permuted_at_y = permuted.clone();
// distribute powers of Y to non-permuted coefficients as coeff[0]*Y^1, coeff[0]*Y^2, ...
mut_distribute_consequitive_powers(&mut non_permuted_at_y[..], y, y); mut_distribute_consequitive_powers(&mut non_permuted_at_y[..], y, y);
// and commit to S'
let s_prime = multiexp(srs.g_positive_x_alpha[0..n].iter(), non_permuted_at_y.iter()).into_affine(); let s_prime = multiexp(srs.g_positive_x_alpha[0..n].iter(), non_permuted_at_y.iter()).into_affine();
// this construction has already moved coeff[i] to the corresponding constraint k, so term is coeff[i]*Y^{K} for place K // if we pretend that non_permuted_at_y[sigma[i]] = coeffs[sigma[i]] * Y^sigma[i],
mut_distribute_consequitive_powers(&mut permuted_at_y[..], y, y); // then inverse_permuted_at_y[i] = coeffs[sigma[i]] * Y^sigma[i]
let inverse_permuted_at_y = permute_inverse(&non_permuted_at_y[..], &p[..]);
// now there is a coefficient coeff[i]*Y^{K} for place K at place K, so we need to move it back to i // let mut t = vec![E::Fr::zero(); inverse_permuted_at_y.len()];
let permuted_at_y = permute_inverse(&permuted_at_y[..], &p[..]); // for i in 0..t.len() {
// let coeff = c[i];
// let sigma_i = p[i];
// let y_sigma_i = y.pow([sigma_i as u64]);
// t[i] = coeff;
// t[i].mul_assign(&y_sigma_i);
// }
// and commit to S // and commit to S
let s = multiexp(srs.g_positive_x_alpha[0..n].iter(), permuted_at_y.iter()).into_affine(); let s = multiexp(srs.g_positive_x_alpha[0..n].iter(), inverse_permuted_at_y.iter()).into_affine();
// let s = multiexp(srs.g_positive_x_alpha[0..n].iter(), t.iter()).into_affine();
result.push((s, s_prime)); result.push((s, s_prime));
non_permuted_at_y_coefficients.push(non_permuted_at_y); non_permuted_at_y_coefficients.push(non_permuted_at_y);
permuted_coefficients.push(permuted); // permuted_coefficients.push(permuted);
permuted_at_y_coefficients.push(permuted_at_y); // permuted_at_y_coefficients.push(t);
// permuted_at_y_coefficients.push(permuted_at_y);
inverse_permuted_at_y_coefficients.push(inverse_permuted_at_y);
} }
self.non_permuted_at_y_coefficients = non_permuted_at_y_coefficients; self.non_permuted_at_y_coefficients = non_permuted_at_y_coefficients;
self.permuted_coefficients = permuted_coefficients; // self.permuted_coefficients = permuted_coefficients;
self.permuted_at_y_coefficients = permuted_at_y_coefficients; self.permuted_at_y_coefficients = permuted_at_y_coefficients;
self.inverse_permuted_at_y_coefficients = inverse_permuted_at_y_coefficients;
result result
} }
@ -302,6 +293,7 @@ impl<E: Engine> PermutationArgument<E> {
_specialized_srs: &SpecializedSRS<E>, _specialized_srs: &SpecializedSRS<E>,
srs: &SRS<E> srs: &SRS<E>
) -> PermutationArgumentProof<E> { ) -> PermutationArgumentProof<E> {
panic!("");
// Sj(P4j)β(P1j)γ is equal to the product of the coefficients of Sj(P3j)β(P1j)γ // Sj(P4j)β(P1j)γ is equal to the product of the coefficients of Sj(P3j)β(P1j)γ
// also open s = \sum self.permuted_coefficients(X, y) at z // also open s = \sum self.permuted_coefficients(X, y) at z
@ -313,6 +305,7 @@ impl<E: Engine> PermutationArgument<E> {
let mut s_polynomial: Option<Vec<E::Fr>> = None; let mut s_polynomial: Option<Vec<E::Fr>> = None;
for c in self.permuted_at_y_coefficients.iter() for c in self.permuted_at_y_coefficients.iter()
// for c in self.inverse_permuted_at_y_coefficients.iter()
{ {
if s_polynomial.is_some() { if s_polynomial.is_some() {
if let Some(poly) = s_polynomial.as_mut() { if let Some(poly) = s_polynomial.as_mut() {
@ -326,6 +319,8 @@ impl<E: Engine> PermutationArgument<E> {
// evaluate at z // evaluate at z
let s_zy = evaluate_at_consequitive_powers(& s_polynomial[..], z, z); let s_zy = evaluate_at_consequitive_powers(& s_polynomial[..], z, z);
println!("S_zy = {}", s_zy);
let mut s_zy_neg = s_zy; let mut s_zy_neg = s_zy;
s_zy_neg.negate(); s_zy_neg.negate();
@ -350,32 +345,76 @@ impl<E: Engine> PermutationArgument<E> {
let mut grand_products = vec![]; let mut grand_products = vec![];
for (i, ((non_permuted, permuted), permutation)) in self.non_permuted_coefficients.into_iter() for (((non_permuted, inv_permuted), permutation), permuted) in self.non_permuted_at_y_coefficients.into_iter()
.zip(self.permuted_coefficients.into_iter()) .zip(self.inverse_permuted_at_y_coefficients.into_iter())
.zip(self.permutations.into_iter()).enumerate() .zip(self.permutations.into_iter())
.zip(self.permuted_at_y_coefficients.into_iter())
{ {
// \prod si+βσi+γ = \prod s'i + β*i + γ // in S combination at the place i there should be term coeff[sigma(i)] * Y^sigma(i), that we can take
let mut s_j_combination = non_permuted; // from non-permuted by inverse_permuting it
// let mut s_combination = permute_inverse(&non_permuted[..], &permutation);
let mut s_combination = inv_permuted;
{ {
let p_4_values: Vec<E::Fr> = permutation.into_iter().map(|el| { let p_4_values: Vec<E::Fr> = permutation.clone().into_iter().map(|el| {
let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default(); let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default();
repr.as_mut()[0] = el as u64; repr.as_mut()[0] = el as u64;
let fe = E::Fr::from_repr(repr).unwrap(); let fe = E::Fr::from_repr(repr).unwrap();
fe fe
}).collect(); }).collect();
mul_add_polynomials(&mut s_j_combination[..], & p_4_values[..], beta); mul_add_polynomials(&mut s_combination[..], & p_4_values[..], beta);
mul_add_polynomials(&mut s_j_combination[..], & p_1_values[..], gamma); mul_add_polynomials(&mut s_combination[..], & p_1_values[..], gamma);
} }
let mut s_prime_j_combination = permuted; let mut s_combination_may_be = permuted;
{ {
mul_add_polynomials(&mut s_prime_j_combination[..], & p_3_values[..], beta); let p_4_values: Vec<E::Fr> = permutation.clone().into_iter().map(|el| {
mul_add_polynomials(&mut s_prime_j_combination[..], & p_1_values[..], gamma); let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default();
repr.as_mut()[0] = el as u64;
let fe = E::Fr::from_repr(repr).unwrap();
fe
}).collect();
mul_add_polynomials(&mut s_combination_may_be[..], & p_4_values[..], beta);
mul_add_polynomials(&mut s_combination_may_be[..], & p_1_values[..], gamma);
} }
grand_products.push((s_j_combination, s_prime_j_combination)); // combination of coeff[i]*Y^i + beta * i + gamma
let mut s_prime_combination = non_permuted.clone();
{
mul_add_polynomials(&mut s_prime_combination[..], & p_3_values[..], beta);
mul_add_polynomials(&mut s_prime_combination[..], & p_1_values[..], gamma);
}
// Sanity check
let s_prime_product = s_prime_combination.iter().fold(E::Fr::one(), |mut sum, x|
{
sum.mul_assign(&x);
sum
});
let s_product = s_combination.iter().fold(E::Fr::one(), |mut sum, x|
{
sum.mul_assign(&x);
sum
});
let s_product_may_be = s_combination_may_be.iter().fold(E::Fr::one(), |mut sum, x|
{
sum.mul_assign(&x);
sum
});
println!("S = {}, S may be = {}, S' = {}", s_product, s_product_may_be, s_prime_product);
assert_eq!(s_product, s_prime_product, "product of coefficients must be the same");
grand_products.push((s_combination, s_prime_combination));
} }
let mut a_commitments = vec![]; let mut a_commitments = vec![];
@ -400,7 +439,7 @@ impl<E: Engine> PermutationArgument<E> {
let proof = wellformed_argument.make_argument(wellformed_challenges.clone(), &srs); let proof = wellformed_argument.make_argument(wellformed_challenges.clone(), &srs);
let valid = WellformednessArgument::verify(n, &wellformed_challenges, &commitments, &proof, &srs); let valid = WellformednessArgument::verify(n, &wellformed_challenges, &commitments, &proof, &srs);
assert!(valid, "wellformedness argument must be valid"); // assert!(valid, "wellformedness argument must be valid");
} }
let mut grand_product_argument = GrandProductArgument::new(grand_products); let mut grand_product_argument = GrandProductArgument::new(grand_products);
@ -416,7 +455,7 @@ impl<E: Engine> PermutationArgument<E> {
let randomness = (0..j).map(|_| E::Fr::rand(rng)).collect::<Vec<_>>(); let randomness = (0..j).map(|_| E::Fr::rand(rng)).collect::<Vec<_>>();
let valid = GrandProductArgument::verify_ab_commitment(n, let valid = GrandProductArgument::verify_ab_commitment(n,
&randomness, & randomness,
& a_commitments, & a_commitments,
& b_commitments, & b_commitments,
&grand_product_openings, &grand_product_openings,
@ -605,42 +644,42 @@ impl<E: Engine> PermutationArgument<E> {
let s_prime_commitments_opening = argument.open_commitments_to_s_prime(&challenges, y, z_prime, &srs); let s_prime_commitments_opening = argument.open_commitments_to_s_prime(&challenges, y, z_prime, &srs);
let (proof, grand_product_signature) = { let (proof, grand_product_signature, beta, gamma) = {
// TODO: create better way to get few distinct challenges from the transcript // TODO: create better way to get few distinct challenges from the transcript
let (proof, grand_product_signature) = argument.make_argument_with_transcript( let (proof, grand_product_signature, beta, gamma) = argument.make_argument_with_transcript(
&mut transcript, &mut transcript,
y, y,
z, z,
&srs &srs
); );
(proof, grand_product_signature) (proof, grand_product_signature, beta, gamma)
}; };
// TODO: sanity check for now, // TODO: sanity check for now,
// later eliminate a and b commitments // later eliminate a and b commitments
// for (j, (((a, b), s), s_prime)) in grand_product_signature.a_commitments.iter() for (j, (((a, b), s), s_prime)) in grand_product_signature.a_commitments.iter()
// .zip(grand_product_signature.b_commitments.iter()) .zip(grand_product_signature.b_commitments.iter())
// .zip(s_commitments.iter()) .zip(s_commitments.iter())
// .zip(s_prime_commitments.iter()) .zip(s_prime_commitments.iter())
// .enumerate() .enumerate()
// { {
// // Sj(P4j)β(P1j)γ // Sj(P4j)β(P1j)γ
// let mut lhs = s.into_projective(); let mut lhs = s.into_projective();
// lhs.add_assign(&specialized_srs.p_4[j].mul(beta.into_repr())); lhs.add_assign(&specialized_srs.p_4[j].mul(beta.into_repr()));
// lhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr())); lhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr()));
// assert!(lhs.into_affine() == *a); assert!(lhs.into_affine() == *a);
// // Sj(P3j)β(P1j)γ // Sj(P3j)β(P1j)γ
// let mut rhs = s_prime.into_projective(); let mut rhs = s_prime.into_projective();
// rhs.add_assign(&specialized_srs.p_3.mul(beta.into_repr())); rhs.add_assign(&specialized_srs.p_3.mul(beta.into_repr()));
// rhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr())); rhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr()));
// assert!(rhs.into_affine() == *b); assert!(rhs.into_affine() == *b);
// } }
SignatureOfCorrectComputation { SignatureOfCorrectComputation {
s_commitments, s_commitments,
@ -658,9 +697,11 @@ impl<E: Engine> PermutationArgument<E> {
y: E::Fr, y: E::Fr,
z: E::Fr, z: E::Fr,
srs: &SRS<E> srs: &SRS<E>
) -> (PermutationArgumentProof<E>, GrandProductSignature<E>) { ) -> (PermutationArgumentProof<E>, GrandProductSignature<E>, E::Fr, E::Fr) {
let beta: E::Fr = transcript.get_challenge_scalar(); let beta: E::Fr = transcript.get_challenge_scalar();
println!("Beta in prover = {}", beta);
let gamma: E::Fr = transcript.get_challenge_scalar(); let gamma: E::Fr = transcript.get_challenge_scalar();
println!("Gamma in prover = {}", gamma);
// Sj(P4j)β(P1j)γ is equal to the product of the coefficients of Sj(P3j)β(P1j)γ // Sj(P4j)β(P1j)γ is equal to the product of the coefficients of Sj(P3j)β(P1j)γ
// also open s = \sum self.permuted_coefficients(X, y) at z // also open s = \sum self.permuted_coefficients(X, y) at z
@ -670,7 +711,8 @@ impl<E: Engine> PermutationArgument<E> {
let mut s_polynomial: Option<Vec<E::Fr>> = None; let mut s_polynomial: Option<Vec<E::Fr>> = None;
for c in self.permuted_at_y_coefficients.iter() // for c in self.permuted_at_y_coefficients.iter()
for c in self.inverse_permuted_at_y_coefficients.iter()
{ {
if s_polynomial.is_some() { if s_polynomial.is_some() {
if let Some(poly) = s_polynomial.as_mut() { if let Some(poly) = s_polynomial.as_mut() {
@ -709,59 +751,54 @@ impl<E: Engine> PermutationArgument<E> {
let mut grand_products = vec![]; let mut grand_products = vec![];
// TODO: Check the validity! // TODO: Check the validity!
for ((non_permuted, inv_permuted), permutation) in self.non_permuted_at_y_coefficients.into_iter()
for ((non_permuted, permuted), permutation) in self.non_permuted_coefficients.into_iter() .zip(self.inverse_permuted_at_y_coefficients.into_iter())
.zip(self.permuted_coefficients.into_iter()) .zip(self.permutations.into_iter())
.zip(self.permutations.into_iter()) // .zip(self.permuted_at_y_coefficients.into_iter())
// for ((non_permuted, permuted), permutation) in self.non_permuted_at_y_coefficients.into_iter()
// .zip(self.permuted_at_y_coefficients.into_iter())
// .zip(self.permutations.into_iter())
{ {
// \prod si+βσi+γ = \prod s'i + β*i + γ // in S combination at the place i there should be term coeff[sigma(i)] * Y^sigma(i), that we can take
// from non-permuted by inverse_permuting it
// s combination is coeff[sigma(i)]*Y^{sigma(i)} + beta*sigma(i) + gamma // let mut s_combination = permute_inverse(&non_permuted[..], &permutation);
let mut s_j_combination = non_permuted; let mut s_combination = inv_permuted;
// let mut s_j_combination = permuted;
{ {
let p_4_values: Vec<E::Fr> = permutation.into_iter().map(|el| { let p_4_values: Vec<E::Fr> = permutation.into_iter().map(|el| {
let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default(); let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default();
repr.as_mut()[0] = el as u64; repr.as_mut()[0] = el as u64;
let fe = E::Fr::from_repr(repr).unwrap(); let fe = E::Fr::from_repr(repr).unwrap();
fe fe
}).collect(); }).collect();
mul_add_polynomials(&mut s_j_combination[..], & p_4_values[..], beta); mul_add_polynomials(&mut s_combination[..], & p_4_values[..], beta);
mul_add_polynomials(&mut s_j_combination[..], & p_1_values[..], gamma); mul_add_polynomials(&mut s_combination[..], & p_1_values[..], gamma);
} }
let mut s_prime_j_combination = permuted; // combination of coeff[i]*Y^i + beta * i + gamma
// let mut s_prime_j_combination = non_permuted; let mut s_prime_combination = non_permuted.clone();
// s' combination is coeff[i]*Y^{i} + beta*i + gamma
{ {
mul_add_polynomials(&mut s_prime_j_combination[..], & p_3_values[..], beta);
mul_add_polynomials(&mut s_prime_j_combination[..], & p_1_values[..], gamma); mul_add_polynomials(&mut s_prime_combination[..], & p_3_values[..], beta);
mul_add_polynomials(&mut s_prime_combination[..], & p_1_values[..], gamma);
} }
// Sanity check // Sanity check
let product = s_j_combination.iter().fold(E::Fr::one(), |mut sum, x| let s_prime_product = s_prime_combination.iter().fold(E::Fr::one(), |mut sum, x|
{
sum.mul_assign(&x);
sum
});
let product_prime = s_prime_j_combination.iter().fold(E::Fr::one(), |mut sum, x|
{ {
sum.mul_assign(&x); sum.mul_assign(&x);
sum sum
}); });
assert_eq!(product, product_prime); let s_product = s_combination.iter().fold(E::Fr::one(), |mut sum, x|
{
sum.mul_assign(&x);
grand_products.push((s_j_combination, s_prime_j_combination)); sum
});
assert_eq!(s_product, s_prime_product, "product of coefficients must be the same");
grand_products.push((s_combination, s_prime_combination));
} }
let grand_product_signature = GrandProductArgument::create_signature( let grand_product_signature = GrandProductArgument::create_signature(
@ -778,7 +815,7 @@ impl<E: Engine> PermutationArgument<E> {
s_zy: s_zy s_zy: s_zy
}; };
(proof, grand_product_signature) (proof, grand_product_signature, beta, gamma)
} }
} }
@ -791,7 +828,8 @@ fn test_permutation_argument() {
let srs_x = Fr::from_str("23923").unwrap(); let srs_x = Fr::from_str("23923").unwrap();
let srs_alpha = Fr::from_str("23728792").unwrap(); let srs_alpha = Fr::from_str("23728792").unwrap();
let srs = SRS::<Bls12>::dummy(830564, srs_x, srs_alpha); // let srs = SRS::<Bls12>::dummy(830564, srs_x, srs_alpha);
let srs = SRS::<Bls12>::new(1024, srs_x, srs_alpha);
let n: usize = 1 << 4; let n: usize = 1 << 4;
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);

@ -74,82 +74,13 @@ impl<E: Engine> PermutationStructure<E> {
S2Eval::calculate_commitment_element(self.n, srs) S2Eval::calculate_commitment_element(self.n, srs)
} }
pub fn print_constraints(n:usize, q: usize, coeffs: &Vec<Vec<E::Fr>>, permutations: &Vec<Vec<usize>>) {
let m = coeffs.len();
for constraint_idx in 1..=q {
println!("Constraint {}", constraint_idx);
let mut terms = vec![];
for p_idx in 0..m {
if let Some(variable_idx) = permutations[p_idx].iter().position(|&s| s == constraint_idx) {
let coeff = coeffs[p_idx][variable_idx];
terms.push((variable_idx, coeff));
}
}
for (var_idx, coeff) in terms.into_iter() {
if var_idx < n + 1 {
print!("{} * A({})", coeff, n - var_idx);
} else if var_idx < 2*n + 1 {
print!("{} * B({})", coeff, var_idx - n);
} else {
print!("{} * C({})", coeff, var_idx - 2*n);
}
print!("\n");
}
}
}
pub fn print_terms_per_variable(n:usize, q: usize, coeffs: &Vec<Vec<E::Fr>>, permutations: &Vec<Vec<usize>>) {
let m = coeffs.len();
let k = coeffs[0].len();
for var_idx in 0..k {
println!("Terms for X^{}", var_idx + 1);
for p_idx in 0..m {
println!("In permutation poly {}", p_idx);
let constraint_index = permutations[p_idx][var_idx];
if constraint_index == 0 {
continue;
}
let coeff = coeffs[p_idx][var_idx];
if var_idx < n + 1 {
print!("{} * A({}) * Y^{}", coeff, n - var_idx, constraint_index);
} else if var_idx < 2*n + 1 {
print!("{} * B({}) * Y^{}", coeff, var_idx - n, constraint_index);
} else {
print!("{} * C({}) * Y^{}", coeff, var_idx - 2*n, constraint_index);
}
print!("\n");
}
}
}
pub fn print_terms_in_permutations(n:usize, q: usize, coeffs: &Vec<Vec<E::Fr>>, permutations: &Vec<Vec<usize>>) {
let m = coeffs.len();
for p_idx in 0..m {
println!("Permutation polynomial {}", p_idx);
for (var_idx, constraint_idx) in permutations[p_idx].iter().enumerate() {
let coeff = coeffs[p_idx][var_idx];
if var_idx < n + 1 {
print!("{} * A({})", coeff, n - var_idx);
} else if var_idx < 2*n + 1 {
print!("{} * B({})", coeff, var_idx - n);
} else {
print!("{} * C({})", coeff, var_idx - 2*n);
}
print!("\n");
}
}
}
pub fn calculate_s2_proof(&self, x: E::Fr, y: E::Fr, srs: &SRS<E>) -> S2Proof<E> { pub fn calculate_s2_proof(&self, x: E::Fr, y: E::Fr, srs: &SRS<E>) -> S2Proof<E> {
let s2_eval = S2Eval::new(self.n); let s2_eval = S2Eval::new(self.n);
s2_eval.evaluate(x, y, &srs) s2_eval.evaluate(x, y, &srs)
} }
fn create_permutation_vectors(&self) -> (Vec<Vec<E::Fr>>, Vec<Vec<usize>>) { pub fn create_inverse_permutation_vectors(&self) -> (Vec<Vec<E::Fr>>, Vec<Vec<usize>>) {
// we have to form non-permuted coefficients, as well as permutation structures; // we have to form non-permuted coefficients, as well as permutation structures;
let n = self.n; let n = self.n;
let mut non_permuted_coeffs = vec![vec![E::Fr::zero(); 3*n+1]; M]; let mut non_permuted_coeffs = vec![vec![E::Fr::zero(); 3*n+1]; M];
@ -168,7 +99,6 @@ impl<E: Engine> PermutationStructure<E> {
if let Some((coeff, place)) = info[i].as_ref() { if let Some((coeff, place)) = info[i].as_ref() {
// place it // place it
assert!(*place != 0); assert!(*place != 0);
let x_power = offset - gate_index + 1;
let array_position = offset - gate_index; // special for A let array_position = offset - gate_index; // special for A
let place_coeff_into = &mut non_permuted_coeffs[i]; let place_coeff_into = &mut non_permuted_coeffs[i];
let place_permutation_into = &mut permutations[i]; let place_permutation_into = &mut permutations[i];
@ -201,7 +131,6 @@ impl<E: Engine> PermutationStructure<E> {
if let Some((coeff, place)) = info[i].as_ref() { if let Some((coeff, place)) = info[i].as_ref() {
// place it // place it
assert!(*place != 0); assert!(*place != 0);
let x_power = offset + gate_index + 1; // 1 indexed
let array_position = offset + gate_index; let array_position = offset + gate_index;
let place_coeff_into = &mut non_permuted_coeffs[i]; let place_coeff_into = &mut non_permuted_coeffs[i];
let place_permutation_into = &mut permutations[i]; let place_permutation_into = &mut permutations[i];
@ -235,7 +164,6 @@ impl<E: Engine> PermutationStructure<E> {
if let Some((coeff, place)) = info[i].as_ref() { if let Some((coeff, place)) = info[i].as_ref() {
// place it // place it
assert!(*place != 0); assert!(*place != 0);
let x_power = offset + gate_index + 1; // 1 indexed
let array_position = offset + gate_index; let array_position = offset + gate_index;
let place_coeff_into = &mut non_permuted_coeffs[i]; let place_coeff_into = &mut non_permuted_coeffs[i];
let place_permutation_into = &mut permutations[i]; let place_permutation_into = &mut permutations[i];
@ -262,6 +190,8 @@ impl<E: Engine> PermutationStructure<E> {
} }
} }
Self::print_constraints(n, self.q, &non_permuted_coeffs, &permutations);
// need to fill arrays with non-zero indexes just to have full permutation, even while it's just zero coefficient // need to fill arrays with non-zero indexes just to have full permutation, even while it's just zero coefficient
// TODO: fix // TODO: fix
@ -283,15 +213,6 @@ impl<E: Engine> PermutationStructure<E> {
assert!(m != 0); assert!(m != 0);
// Self::print_constraints(n, self.q, &non_permuted_coeffs, &permutations);
// Self::print_terms_per_variable(n, self.q, &non_permuted_coeffs, &permutations);
// Self::print_terms_in_permutations(n, self.q, &non_permuted_coeffs, &permutations);
// for i in 0..m {
// println!("Coeffs = {:?}", non_permuted_coeffs[i]);
// println!("Permutation = {:?}", permutations[i]);
// }
// find something faster, although it's still linear // find something faster, although it's still linear
for i in 0..m { for i in 0..m {
@ -322,6 +243,198 @@ impl<E: Engine> PermutationStructure<E> {
(non_permuted_coeffs, permutations) (non_permuted_coeffs, permutations)
} }
pub fn create_permutation_vectors(&self) -> (Vec<Vec<E::Fr>>, Vec<Vec<usize>>) {
// we have to form non-permuted coefficients, as well as permutation structures;
let n = self.n;
let mut non_permuted_coeffs = vec![vec![E::Fr::zero(); 3*n+1]; M];
let mut permutations = vec![vec![0usize; 3*n+1]; M];
let one = E::Fr::one();
let mut minus_one = E::Fr::one();
minus_one.negate();
let mut not_empty = [false; M];
// go other the permutations
for (gate_index, info) in self.a.iter().enumerate() {
let offset = n-1;
for i in 0..M {
// coefficients of A are placed at the offset = 0 from the beginning of the vector
if let Some((coeff, place)) = info[i].as_ref() {
// place it
assert!(*place != 0);
let array_position = offset - gate_index; // special for A
let coeff_position = *place - 1;
let place_coeff_into = &mut non_permuted_coeffs[i];
let place_permutation_into = &mut permutations[i];
match coeff {
Coeff::Zero => {
},
Coeff::One => {
not_empty[i] = true;
place_coeff_into[coeff_position] = one;
place_permutation_into[array_position] = *place;
},
Coeff::NegativeOne => {
not_empty[i] = true;
place_coeff_into[coeff_position] = minus_one;
place_permutation_into[array_position] = *place;
},
Coeff::Full(value) => {
not_empty[i] = true;
place_coeff_into[coeff_position] = *value;
place_permutation_into[array_position] = *place;
}
}
}
}
}
for (gate_index, info) in self.b.iter().enumerate() {
let offset = n + 1;
for i in 0..M {
if let Some((coeff, place)) = info[i].as_ref() {
// place it
assert!(*place != 0);
let array_position = offset + gate_index;
let coeff_position = *place - 1;
let place_coeff_into = &mut non_permuted_coeffs[i];
let place_permutation_into = &mut permutations[i];
match coeff {
Coeff::Zero => {
},
Coeff::One => {
not_empty[i] = true;
place_coeff_into[coeff_position] = one;
place_permutation_into[array_position] = *place;
},
Coeff::NegativeOne => {
not_empty[i] = true;
place_coeff_into[coeff_position] = minus_one;
place_permutation_into[array_position] = *place;
},
Coeff::Full(value) => {
not_empty[i] = true;
place_coeff_into[coeff_position] = *value;
place_permutation_into[array_position] = *place;
}
}
}
}
}
for (gate_index, info) in self.c.iter().enumerate() {
let offset = 2*n + 1;
for i in 0..M {
// coefficients of A are placed at the offset = 0 from the beginning of the vector
if let Some((coeff, place)) = info[i].as_ref() {
// place it
assert!(*place != 0);
let array_position = offset + gate_index;
let coeff_position = *place - 1;
let place_coeff_into = &mut non_permuted_coeffs[i];
let place_permutation_into = &mut permutations[i];
match coeff {
Coeff::Zero => {
},
Coeff::One => {
not_empty[i] = true;
place_coeff_into[coeff_position] = one;
place_permutation_into[array_position] = *place;
},
Coeff::NegativeOne => {
not_empty[i] = true;
place_coeff_into[coeff_position] = minus_one;
place_permutation_into[array_position] = *place;
},
Coeff::Full(value) => {
not_empty[i] = true;
place_coeff_into[coeff_position] = *value;
place_permutation_into[array_position] = *place;
}
}
}
}
}
// Self::print_constraints(n, self.q, &non_permuted_coeffs, &permutations);
// need to fill arrays with non-zero indexes just to have full permutation, even while it's just zero coefficient
// TODO: fix
let mut m = M;
// for i in (0..M).into_iter().rev() {
// // these are no constant terms
// assert!(non_permuted_coeffs[i][n].is_zero());
// assert!(permutations[i][n] == 0);
// }
for i in (0..M).into_iter().rev() {
if !not_empty[i] {
non_permuted_coeffs.pop();
permutations.pop();
m -= 1;
}
}
assert!(m != 0);
// find something faster, although it's still linear
for i in 0..m {
let mut fillers: Vec<usize> = (1..=(3*n+1)).map(|el| el).collect();
for (p, c) in permutations[i].iter_mut().zip(non_permuted_coeffs[i].iter()) {
if *p == 0 {
continue;
// assert!(c.is_zero());
} else {
fillers[*p - 1] = 0;
}
}
let mut fill_from = 0;
for p in permutations[i].iter_mut() {
if *p == 0 {
loop {
if fillers[fill_from] != 0 {
*p = fillers[fill_from];
fill_from += 1;
break;
} else {
fill_from += 1;
}
}
}
}
}
(non_permuted_coeffs, permutations)
}
pub fn print_constraints(n:usize, q: usize, coeffs: &Vec<Vec<E::Fr>>, permutations: &Vec<Vec<usize>>) {
let m = coeffs.len();
for constraint_idx in 1..=q {
println!("Constraint {} (term for Y^{})", constraint_idx, constraint_idx);
let mut terms = vec![];
for p_idx in 0..m {
if let Some(variable_idx) = permutations[p_idx].iter().position(|&s| s == constraint_idx) {
let coeff = coeffs[p_idx][variable_idx];
terms.push((variable_idx, coeff));
}
}
for (var_idx, coeff) in terms.into_iter() {
if var_idx < n + 1 {
print!("{} * A({})", coeff, n - var_idx);
} else if var_idx < 2*n + 1 {
print!("{} * B({})", coeff, var_idx - n);
} else {
print!("{} * C({})", coeff, var_idx - 2*n);
}
print!("\n");
}
}
}
pub fn create_permutation_special_reference(&self, srs: &SRS<E>) -> SpecializedSRS<E> pub fn create_permutation_special_reference(&self, srs: &SRS<E>) -> SpecializedSRS<E>
{ {
let (non_permuted_coeffs, permutations) = self.create_permutation_vectors(); let (non_permuted_coeffs, permutations) = self.create_permutation_vectors();
@ -335,9 +448,33 @@ impl<E: Engine> PermutationStructure<E> {
specialized_srs specialized_srs
} }
pub fn make_signature(&self, y: E::Fr, z: E::Fr, srs: &SRS<E>) { pub fn make_signature(&self, y: E::Fr, z: E::Fr, srs: &SRS<E>) -> SignatureOfCorrectComputation<E> {
let (non_permuted_coeffs, permutations) = self.create_permutation_vectors(); let (non_permuted_coeffs, permutations) = self.create_permutation_vectors();
let mut s_contrib = E::Fr::zero();
for permutation_index in 0..permutations.len() {
for (variable_index, sigma_i) in permutations[permutation_index].iter().enumerate() {
let y_power = y.pow([*sigma_i as u64]);
let x_power = z.pow([(variable_index+1) as u64]);
let coeff = non_permuted_coeffs[permutation_index][*sigma_i - 1];
let mut result = coeff;
result.mul_assign(&x_power);
result.mul_assign(&y_power);
s_contrib.add_assign(&result);
}
}
let z_n_plus_1_inv = z.pow([(self.n + 1) as u64]).inverse().unwrap();
let y_n = y.pow([self.n as u64]);
println!("Naive S contribution = {}", s_contrib);
s_contrib.mul_assign(&z_n_plus_1_inv);
s_contrib.mul_assign(&y_n);
println!("Naive S contribution scaled = {}", s_contrib);
let specialized_srs = PermutationArgument::make_specialized_srs( let specialized_srs = PermutationArgument::make_specialized_srs(
&non_permuted_coeffs, &non_permuted_coeffs,
&permutations, &permutations,
@ -352,6 +489,8 @@ impl<E: Engine> PermutationStructure<E> {
&srs, &srs,
&specialized_srs &specialized_srs
); );
signature
} }
pub fn create_permutation_arguments<R: Rng>(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS<E>) pub fn create_permutation_arguments<R: Rng>(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS<E>)
@ -376,10 +515,10 @@ impl<E: Engine> PermutationStructure<E> {
let mut s_contrib = E::Fr::zero(); let mut s_contrib = E::Fr::zero();
for permutation_index in 0..m { for permutation_index in 0..m {
for (variable_index, constraint_power) in permutations[permutation_index].iter().enumerate() { for (variable_index, sigma_i) in permutations[permutation_index].iter().enumerate() {
let y_power = y.pow([*constraint_power as u64]); let y_power = y.pow([*sigma_i as u64]);
let x_power = z.pow([(variable_index+1) as u64]); let x_power = z.pow([(variable_index+1) as u64]);
let coeff = non_permuted_coeffs[permutation_index][variable_index]; let coeff = non_permuted_coeffs[permutation_index][*sigma_i - 1];
let mut result = coeff; let mut result = coeff;
result.mul_assign(&x_power); result.mul_assign(&x_power);
@ -388,6 +527,8 @@ impl<E: Engine> PermutationStructure<E> {
} }
} }
println!("Naive S contribution = {}", s_contrib);
let mut argument = PermutationArgument::new(non_permuted_coeffs, permutations); let mut argument = PermutationArgument::new(non_permuted_coeffs, permutations);
let challenges = (0..m).map(|_| E::Fr::rand(rng)).collect::<Vec<_>>(); let challenges = (0..m).map(|_| E::Fr::rand(rng)).collect::<Vec<_>>();
@ -491,7 +632,8 @@ fn test_simple_succinct_sonic() {
let srs_alpha = Fr::from_str("23728792").unwrap(); let srs_alpha = Fr::from_str("23728792").unwrap();
println!("making srs"); println!("making srs");
let start = Instant::now(); let start = Instant::now();
let srs = SRS::<Bls12>::dummy(830564, srs_x, srs_alpha); // let srs = SRS::<Bls12>::dummy(830564, srs_x, srs_alpha);
let srs = SRS::<Bls12>::new(100, srs_x, srs_alpha);
println!("done in {:?}", start.elapsed()); println!("done in {:?}", start.elapsed());
{ {
@ -506,18 +648,52 @@ fn test_simple_succinct_sonic() {
use crate::sonic::sonic::Permutation3; use crate::sonic::sonic::Permutation3;
use crate::sonic::unhelped::permutation_structure::*; use crate::sonic::unhelped::permutation_structure::*;
let x: Fr = rng.gen(); // let z: Fr = rng.gen();
let y: Fr = rng.gen(); // let y: Fr = rng.gen();
let x = Fr::one(); let z: Fr = Fr::from_str("2").unwrap();
let mut y = Fr::one(); let y: Fr = Fr::one();
y.double();
let perm_structure = create_permutation_structure::<Bls12, _>(&MyCircuit); let perm_structure = create_permutation_structure::<Bls12, _>(&MyCircuit);
perm_structure.create_permutation_arguments(x, y, rng, &srs); let (non_permuted_coeffs, permutations) = perm_structure.create_permutation_vectors();
perm_structure.make_signature(x, y, &srs); println!("Non-permuted = {:?}", non_permuted_coeffs[0]);
println!("Permutation = {:?}", permutations[0]);
println!("N = {}, Q = {}", perm_structure.n, perm_structure.q);
let n = perm_structure.n;
let szy = {
let mut tmp = SxEval::<Bls12>::new(y, n);
Permutation3::synthesize(&mut tmp, &MyCircuit).unwrap(); // TODO
tmp.finalize(z)
};
let naive_s1 = {
let mut res = Fr::zero();
for j in 0..permutations.len() {
for i in 0..non_permuted_coeffs[j].len() {
let sigma_i = permutations[j][i];
let coeff_i = non_permuted_coeffs[j][i];
let coeff_sigma_i = non_permuted_coeffs[j][sigma_i - 1];
let y_power = y.pow([sigma_i as u64]);
let x_power = z.pow([(i+1) as u64]);
// let mut result = coeff_sigma_i;
let mut result = coeff_i;
result.mul_assign(&y_power);
result.mul_assign(&x_power);
res.add_assign(&result);
}
}
res
};
println!("Naive s1 = {}", naive_s1);
// perm_structure.create_permutation_arguments(y, z, rng, &srs);
let signature = perm_structure.make_signature(y, z, &srs);
let s2 = S2Eval::new(perm_structure.n); let s2 = S2Eval::new(perm_structure.n);
let s2 = s2.evaluate(x, y, &srs); let s2 = s2.evaluate(z, y, &srs);
let mut s2_value = s2.c_value; let mut s2_value = s2.c_value;
s2_value.add_assign(&s2.d_value); s2_value.add_assign(&s2.d_value);
@ -525,7 +701,7 @@ fn test_simple_succinct_sonic() {
let y_inv = y.inverse().unwrap(); let y_inv = y.inverse().unwrap();
let mut p1 = y; let mut p1 = y;
p1.add_assign(&y_inv); p1.add_assign(&y_inv);
p1.mul_assign(&x); p1.mul_assign(&z);
expected_s2_value.add_assign(&p1); expected_s2_value.add_assign(&p1);
let mut t0 = y; let mut t0 = y;
@ -536,13 +712,33 @@ fn test_simple_succinct_sonic() {
let mut p2 = t0; let mut p2 = t0;
p2.add_assign(&t1); p2.add_assign(&t1);
p2.mul_assign(&x); p2.mul_assign(&z);
p2.mul_assign(&x); p2.mul_assign(&z);
expected_s2_value.add_assign(&p2); expected_s2_value.add_assign(&p2);
let z_n = z.pow([n as u64]);
let z_n_plus_1_inv = z.pow([(n + 1) as u64]).inverse().unwrap();
let y_n = y.pow([n as u64]);
assert!(expected_s2_value == s2_value); assert!(expected_s2_value == s2_value);
println!("N = {}, Q = {}", perm_structure.n, perm_structure.q); s2_value.mul_assign(&z_n);
let mut s1 = signature.perm_argument_proof.s_zy;
println!("S1 = {}", s1);
s1.mul_assign(&z_n_plus_1_inv);
s1.mul_assign(&y_n);
s1.sub_assign(&s2_value);
let mut naive_s1 = naive_s1;
naive_s1.mul_assign(&z_n_plus_1_inv);
naive_s1.mul_assign(&y_n);
naive_s1.sub_assign(&s2_value);
println!("S1(?) = {}", naive_s1);
assert_eq!(s1, szy);
} }
} }

@ -19,9 +19,14 @@ use crate::sonic::srs::SRS;
use crate::sonic::sonic::Preprocess; use crate::sonic::sonic::Preprocess;
use super::s2_proof::{S2Proof, S2Eval}; use super::s2_proof::{S2Proof, S2Eval};
use super::aggregate::SuccinctAggregate;
use super::permutation_structure::create_permutation_structure; use super::permutation_structure::create_permutation_structure;
use super::permutation_argument::SpecializedSRS; use super::permutation_argument::{
use super::permutation_argument::{PermutationArgumentProof, PermutationProof, PermutationArgument}; PermutationArgumentProof,
PermutationProof,
PermutationArgument,
SpecializedSRS
};
pub struct SuccinctMultiVerifier<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> { pub struct SuccinctMultiVerifier<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> {
circuit: C, circuit: C,
@ -51,7 +56,6 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier
let s2_special_reference = permutation_structure.calculate_s2_commitment_value(&srs); let s2_special_reference = permutation_structure.calculate_s2_commitment_value(&srs);
let s1_special_reference = permutation_structure.create_permutation_special_reference(&srs); let s1_special_reference = permutation_structure.create_permutation_special_reference(&srs);
Ok(SuccinctMultiVerifier { Ok(SuccinctMultiVerifier {
circuit, circuit,
s1_special_reference, s1_special_reference,
@ -65,91 +69,12 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier
}) })
} }
// pub fn add_non_succinct_aggregate(
// &mut self,
// proofs: &[(Proof<E>, SxyAdvice<E>)],
// aggregate: &Aggregate<E>,
// )
// {
// let mut transcript = Transcript::new(&[]);
// let mut y_values: Vec<E::Fr> = Vec::with_capacity(proofs.len());
// for &(ref proof, ref sxyadvice) in proofs {
// {
// let mut transcript = Transcript::new(&[]);
// transcript.commit_point(&proof.r);
// y_values.push(transcript.get_challenge_scalar());
// }
// transcript.commit_point(&sxyadvice.s);
// }
// let z: E::Fr = transcript.get_challenge_scalar();
// let z = E::Fr::one();
// transcript.commit_point(&aggregate.c);
// let w: E::Fr = transcript.get_challenge_scalar();
// let szw = {
// let mut tmp = SxEval::new(w, self.n);
// S::synthesize(&mut tmp, &self.circuit).unwrap(); // TODO
// tmp.finalize(z)
// };
// println!("Nonsuccinct S(z,w) = {}", szw);
// // {
// // let random: E::Fr = self.randomness_source.gen();
// // self.batch.add_opening(aggregate.opening, random, w);
// // self.batch.add_commitment(aggregate.c, random);
// // self.batch.add_opening_value(szw, random);
// // }
// for ((opening, value), &y) in aggregate.c_openings.iter().zip(y_values.iter()) {
// let random: E::Fr = self.randomness_source.gen();
// self.batch.add_opening(*opening, random, y);
// self.batch.add_commitment(aggregate.c, random);
// self.batch.add_opening_value(*value, random);
// }
// let random: E::Fr = self.randomness_source.gen();
// let mut expected_value = E::Fr::zero();
// for ((_, advice), c_opening) in proofs.iter().zip(aggregate.c_openings.iter()) {
// let mut r: E::Fr = transcript.get_challenge_scalar();
// // expected value of the later opening
// {
// let mut tmp = c_opening.1;
// tmp.mul_assign(&r);
// expected_value.add_assign(&tmp);
// }
// r.mul_assign(&random);
// self.batch.add_commitment(advice.s, r);
// }
// self.batch.add_opening_value(expected_value, random);
// self.batch.add_opening(aggregate.s_opening, random, z);
// }
pub fn add_aggregate( pub fn add_aggregate(
&mut self, &mut self,
proofs: &[(Proof<E>, SxyAdvice<E>)], proofs: &[(Proof<E>, SxyAdvice<E>)],
aggregate: &Aggregate<E>, aggregate: &SuccinctAggregate<E>,
permutation_argument_proof: &PermutationArgumentProof<E>,
permutation_proof: &PermutationProof<E>,
s2_proof: &S2Proof<E>,
num_permutation_polynomials: usize,
srs: &SRS<E>, srs: &SRS<E>,
z_prime: E::Fr, // TODO, temporary before incorporation to the transcript specialized_srs: &SpecializedSRS<E>
permutation_argument_commitments: & Vec<(E::G1Affine, E::G1Affine)>,
s_prime_challenges: Vec<E::Fr>
) )
{ {
let mut transcript = Transcript::new(&[]); let mut transcript = Transcript::new(&[]);
@ -170,6 +95,8 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier
let w: E::Fr = transcript.get_challenge_scalar(); let w: E::Fr = transcript.get_challenge_scalar();
println!("Verifier: Z = {}, W = {}", z, w);
let szw = { let szw = {
// prover will supply s1 and s2, need to calculate // prover will supply s1 and s2, need to calculate
// s(z, w) = X^-(N+1) * Y^N * s1 - X^N * s2 // s(z, w) = X^-(N+1) * Y^N * s1 - X^N * s2
@ -184,6 +111,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier
// simultaneously add components to the batch verifier // simultaneously add components to the batch verifier
// this is s2 contribution itself // this is s2 contribution itself
let s2_proof = &aggregate.s2_proof;
let mut s2_part = s2_proof.c_value; let mut s2_part = s2_proof.c_value;
s2_part.add_assign(&s2_proof.d_value); s2_part.add_assign(&s2_proof.d_value);
s2_part.mul_assign(&x_n); s2_part.mul_assign(&x_n);
@ -222,50 +150,244 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier
// now work with s1 part // now work with s1 part
let mut s1_part = permutation_argument_proof.s_zy; let mut s1_part = aggregate.signature.perm_argument_proof.s_zy;
s1_part.mul_assign(&x_n_plus_1_inv); s1_part.mul_assign(&x_n_plus_1_inv);
s1_part.mul_assign(&y_n); s1_part.mul_assign(&y_n);
// TODO: this one should be from transcipt let mut szw = s1_part;
// let s_prime_challenges = (0..num_permutation_polynomials).map(|_| E::Fr::rand(&mut self.randomness_source)).collect::<Vec<_>>(); szw.sub_assign(&s2_part);
// s and s' commitments of permutation argument // verify commitments for s' and s
let mut s_commitments = vec![];
let mut s_prime_commitments = vec![]; {
for (s, s_prime) in permutation_argument_commitments.iter() { let mut transcript = Transcript::new(&[]);
s_commitments.push(*s);
s_prime_commitments.push(*s_prime); // let s_commitments = &aggregate.signature.s_commitments;
// let s_prime_commitments = &aggregate.signature.s_prime_commitments;
let mut challenges = vec![];
for (s, s_prime) in aggregate.signature.s_commitments.iter()
.zip(aggregate.signature.s_prime_commitments.iter()) {
{
let mut transcript = Transcript::new(&[]);
transcript.commit_point(s);
transcript.commit_point(s_prime);
let challenge = transcript.get_challenge_scalar();
challenges.push(challenge);
}
transcript.commit_point(s);
transcript.commit_point(s_prime);
}
let z_prime: E::Fr = transcript.get_challenge_scalar();
// we expect M permutation proofs, add them all into verification
// using batching with random challenges and extra randomness for pairing equation
{
// e(E,hαx)e(Ez,hα) = e(􏰇Mj=1Sjrj,h)e(gv,hα)
let perm_proof = &aggregate.signature.perm_proof;
let s_r = multiexp(
aggregate.signature.s_prime_commitments.iter(),
challenges.iter()
).into_affine();
let p2_r = multiexp(
self.s1_special_reference.p_2.iter(),
challenges.iter()
).into_affine();
let value = perm_proof.v_zy;
let random: E::Fr = self.randomness_source.gen();
self.batch.add_opening(perm_proof.e_opening, random, z_prime);
self.batch.add_opening_value(random, value);
self.batch.add_commitment(s_r, random);
// e(F,hαx)e(Fyz,hα) = e(􏰇Mj=1P2jrj,h)e(gv,hα)
let mut y_z_prime = z_prime;
y_z_prime.mul_assign(&w);
let random: E::Fr = self.randomness_source.gen();
self.batch.add_opening(perm_proof.f_opening, random, y_z_prime);
self.batch.add_opening_value(random, value);
self.batch.add_commitment(p2_r, random);
}
// now we can actually take an opening of S commitments and
{
// e(I,hαx)e(Iz,hα) = e(􏰇Mj=1 Sj,h)e(gs,hα)
let value = aggregate.signature.perm_argument_proof.s_zy;
let mut s_commitment = E::G1::zero();
for s in aggregate.signature.s_commitments.iter() {
s_commitment.add_assign_mixed(s);
}
let random: E::Fr = self.randomness_source.gen();
self.batch.add_opening(aggregate.signature.perm_argument_proof.s_opening, random, z);
self.batch.add_opening_value(random, value);
self.batch.add_commitment(s_commitment.into_affine(), random);
}
// TODO: Add grand product argument!
// for each of the grand product arguments create a corresponding commitment
// from already known elements
let beta: E::Fr = transcript.get_challenge_scalar();
println!("Beta in verifier = {}", beta);
let gamma: E::Fr = transcript.get_challenge_scalar();
println!("Gamma in verifier = {}", gamma);
let mut a_commitments = vec![];
let mut b_commitments = vec![];
use crate::pairing::CurveAffine;
use crate::pairing::ff::PrimeField;
for (j, (s, s_prime)) in aggregate.signature.s_commitments.iter()
.zip(aggregate.signature.s_prime_commitments.iter())
.enumerate()
{
// Sj(P4j)β(P1j)γ
let mut a = s.into_projective();
a.add_assign(&self.s1_special_reference.p_4[j].mul(beta.into_repr()));
a.add_assign(&self.s1_special_reference.p_1.mul(gamma.into_repr()));
let a = a.into_affine();
// Sj(P3j)β(P1j)γ
let mut b = s_prime.into_projective();
b.add_assign(&self.s1_special_reference.p_3.mul(beta.into_repr()));
b.add_assign(&self.s1_special_reference.p_1.mul(gamma.into_repr()));
let b = b.into_affine();
// let a_original = aggregate.signature.grand_product_signature.a_commitments[j];
// let b_original = aggregate.signature.grand_product_signature.b_commitments[j];
// assert!(a == a_original);
// assert!(b == b_original);
a_commitments.push(a);
b_commitments.push(b);
}
// Now perform an actual check
{
let randomness: Vec<E::Fr> = (0..aggregate.signature.s_commitments.len()).map(|_| self.randomness_source.gen()).collect();
// e(Dj,hαx)e(Dyz,hα) = e(Aj,h)e(Bj,hxn+1)e(gaj ,hα)
let g = srs.g_positive_x[0];
let h_alpha_x_precomp = srs.h_positive_x_alpha[1].prepare();
let h_alpha_precomp = srs.h_positive_x_alpha[0].prepare();
let mut h_x_n_plus_one_precomp = srs.h_positive_x[self.n];
h_x_n_plus_one_precomp.negate();
let h_x_n_plus_one_precomp = h_x_n_plus_one_precomp.prepare();
let mut h_prep = srs.h_positive_x[0];
h_prep.negate();
let h_prep = h_prep.prepare();
let a = multiexp(
a_commitments.iter(),
randomness.iter(),
).into_affine();
let a = a.prepare();
let b = multiexp(
b_commitments.iter(),
randomness.iter(),
).into_affine();
let b = b.prepare();
let mut yz_neg = w;
yz_neg.mul_assign(&z);
yz_neg.negate();
let mut ops = vec![];
let mut value = E::Fr::zero();
for (el, r) in aggregate.signature.grand_product_signature.grand_product_openings.iter().zip(randomness.iter()) {
let (v, o) = el;
ops.push(o.clone());
let mut val = *v;
val.mul_assign(&r);
value.add_assign(&val);
}
let value = g.mul(value.into_repr()).into_affine().prepare();
let openings = multiexp(
ops.iter(),
randomness.iter(),
).into_affine();
let openings_zy = openings.mul(yz_neg.into_repr()).into_affine().prepare();
let openings = openings.prepare();
// e(Dj,hαx)e(Dyz,hα) = e(Aj,h)e(Bj,hxn+1)e(gaj ,hα)
let valid = E::final_exponentiation(&E::miller_loop(&[
(&openings, &h_alpha_x_precomp),
(&openings_zy, &h_alpha_precomp),
(&a, &h_prep),
(&b, &h_x_n_plus_one_precomp),
(&value, &h_alpha_precomp)
])).unwrap() == E::Fqk::one();
// TODO
// assert!(valid, "grand product arguments must be valid for individual commitments");
}
// TODO: sanity check for now,
// later eliminate a and b commitments
// for (j, (((a, b), s), s_prime)) in grand_product_signature.a_commitments.iter()
// .zip(grand_product_signature.b_commitments.iter())
// .zip(s_commitments.iter())
// .zip(s_prime_commitments.iter())
// .enumerate()
// {
// // Sj(P4j)β(P1j)γ
// let mut lhs = s.into_projective();
// lhs.add_assign(&specialized_srs.p_4[j].mul(beta.into_repr()));
// lhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr()));
// assert!(lhs.into_affine() == *a);
// // Sj(P3j)β(P1j)γ
// let mut rhs = s_prime.into_projective();
// rhs.add_assign(&specialized_srs.p_3.mul(beta.into_repr()));
// rhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr()));
// assert!(rhs.into_affine() == *b);
// }
} }
let randomness = (0..2).map(|_| E::Fr::rand(&mut self.randomness_source)).collect::<Vec<_>>(); szw
let valid = PermutationArgument::verify_s_prime_commitment(self.n,
&randomness,
&s_prime_challenges,
&s_prime_commitments,
permutation_proof,
w,
z_prime,
&self.s1_special_reference,
&srs);
assert!(valid);
// TODO: move all these to the transcripts
let beta : E::Fr = self.randomness_source.gen();
let gamma : E::Fr = self.randomness_source.gen();
let valid = PermutationArgument::verify(&s_commitments, &permutation_argument_proof, z, &srs);
assert!(valid);
let mut s = s1_part;
s.sub_assign(&s2_part);
s
}; };
println!("Verifier: S(z,w) = {}", szw);
{ {
let random: E::Fr = self.randomness_source.gen(); let random: E::Fr = self.randomness_source.gen();

@ -34,8 +34,9 @@ impl<E: Engine> WellformednessArgument<E> {
srs: &SRS<E> srs: &SRS<E>
) -> WellformednessSignature<E> { ) -> WellformednessSignature<E> {
let j = all_polys.len(); let j = all_polys.len();
let mut transcript = Transcript::new(&[]); println!("Making wellformedness argument for {} polys", j);
let wellformed_argument = WellformednessArgument::new(all_polys); let wellformed_argument = WellformednessArgument::new(all_polys);
// TODO: remove commitments
let commitments = wellformed_argument.commit(&srs); let commitments = wellformed_argument.commit(&srs);
// let mut wellformed_challenges = vec![]; // let mut wellformed_challenges = vec![];
// for c in commitments.iter() { // for c in commitments.iter() {