permutation argument works as itself, but not for verifier

This commit is contained in:
Alex Vlasov 2019-06-06 14:24:21 +03:00
parent 95b91fc0b0
commit b8d4b0cea4
10 changed files with 566 additions and 174 deletions

@ -104,6 +104,7 @@ impl<E: Engine> Batch<E> {
}
}
/// add `(r*P) to the h^(alpha*x) terms, add -(r*point)*P to h^(alpha) terms
pub fn add_opening(&mut self, p: E::G1Affine, mut r: E::Fr, point: E::Fr) {
self.alpha_x.push((p, r));
r.mul_assign(&point);
@ -111,14 +112,17 @@ impl<E: Engine> Batch<E> {
self.alpha.push((p, r));
}
/// add (r*P) to -h^(x) terms
pub fn add_commitment(&mut self, p: E::G1Affine, r: E::Fr) {
self.neg_h.push((p, r));
}
/// add (r*P) to -h^(d-n) terms
pub fn add_commitment_max_n(&mut self, p: E::G1Affine, r: E::Fr) {
self.neg_x_n_minus_d.push((p, r));
}
/// add (r*point) to g terms for later pairing with h^(alpha)
pub fn add_opening_value(&mut self, mut r: E::Fr, point: E::Fr) {
r.mul_assign(&point);
self.value.add_assign(&r);

@ -26,6 +26,9 @@ pub struct Aggregate<E: Engine> {
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>(
@ -80,6 +83,8 @@ 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::one();
// Compute s(z, Y)
let (s_poly_negative, s_poly_positive) = {
let mut tmp = SyEval::new(z, n, q);
@ -101,8 +106,12 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
// Open C at w
let w: E::Fr = transcript.get_challenge_scalar();
let w = E::Fr::one();
let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative);
println!("In helper s(z, w) = {}", value);
let opening = {
let mut value = value;
value.negate();
@ -275,5 +284,9 @@ pub fn create_aggregate_on_srs_using_information<E: Engine, C: Circuit<E>, S: Sy
c_openings,
// Then we have to finally open C
opening,
z: z,
w: w
}
}

@ -32,6 +32,7 @@ pub fn create_advice_on_information_and_srs<E: Engine, C: Circuit<E>, S: Synthes
transcript.commit_point(&proof.t);
z = transcript.get_challenge_scalar();
}
let z_inv = z.inverse().ok_or(SynthesisError::DivisionByZero)?;
let (s_poly_negative, s_poly_positive) = {

@ -66,10 +66,14 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> MultiVerifier<E, C, 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 w = E::Fr::one();
let szw = {
let mut tmp = SxEval::new(w, self.n);
S::synthesize(&mut tmp, &self.circuit).unwrap(); // TODO

@ -351,6 +351,112 @@ fn test_sonic_mimc() {
}
}
#[test]
fn test_sonic_mimc_in_permutation_driver() {
use crate::pairing::ff::{Field, PrimeField};
use crate::pairing::{Engine, CurveAffine, CurveProjective};
use crate::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::sonic::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::sonic::Permutation3;
println!("creating proof");
let start = Instant::now();
let proof = create_proof_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating advice");
let start = Instant::now();
let advice = create_advice_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proof, &srs).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating aggregate for {} proofs", samples);
let start = Instant::now();
let proofs: Vec<_> = (0..samples).map(|_| (proof.clone(), advice.clone())).collect();
let aggregate = create_aggregate_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proofs, &srs);
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 rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying {} proofs without advice", samples);
let start = Instant::now();
{
for _ in 0..samples {
verifier.add_proof(&proof, &[], |_, _| None);
}
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
{
let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with advice");
let start = Instant::now();
{
for (ref proof, ref advice) in &proofs {
verifier.add_proof_with_advice(proof, &[], advice);
}
verifier.add_aggregate(&proofs, &aggregate);
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
}
}
#[test]
fn test_succinct_sonic_mimc() {
use crate::pairing::ff::{Field, PrimeField};
@ -390,79 +496,136 @@ fn test_succinct_sonic_mimc() {
use crate::sonic::sonic::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_for_succinct_sonic};
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::unhelped::permutation_structure::*;
use crate::sonic::unhelped::SuccinctMultiVerifier;
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()))?;
let dummy = cs.alloc_input(|| Ok(E::Fr::from_str("200").unwrap()))?;
cs.enforce_zero(LinearCombination::from(b) - multiplier);
cs.enforce_zero(LinearCombination::from(c) - dummy);
Ok(())
}
}
let perm_structure = create_permutation_structure::<Bls12, _>(&AdaptorCircuit(circuit.clone()));
perm_structure.create_permutation_arguments(Fr::one(), Fr::one(), rng, &srs);
println!("N = {}, Q = {}", perm_structure.n, perm_structure.q);
return;
// let perm_structure = create_permutation_structure::<Bls12, _>(&MyCircuit);
let s1_srs = perm_structure.create_permutation_special_reference(&srs);
let s2_srs = perm_structure.calculate_s2_commitment_value(&srs);
// let info = get_circuit_parameters_for_succinct_sonic::<Bls12, _>(circuit.clone()).expect("Must get circuit info");
// println!("{:?}", info);
// println!("creating proof");
// let start = Instant::now();
// let proof = create_proof_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
// println!("done in {:?}", start.elapsed());
println!("creating proof");
let start = Instant::now();
let proof = create_proof_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("done in {:?}", start.elapsed());
// println!("creating advice");
// let start = Instant::now();
// let advice = create_advice_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proof, &srs).unwrap();
// println!("done in {:?}", start.elapsed());
println!("creating advice");
let start = Instant::now();
let advice = create_advice_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proof, &srs).unwrap();
println!("done in {:?}", start.elapsed());
// println!("creating aggregate for {} proofs", samples);
// let start = Instant::now();
// let proofs: Vec<_> = (0..samples).map(|_| (proof.clone(), advice.clone())).collect();
// let aggregate = create_aggregate_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proofs, &srs);
// println!("done in {:?}", start.elapsed());
println!("creating aggregate for {} proofs", samples);
let start = Instant::now();
let proofs: Vec<_> = (0..samples).map(|_| (proof.clone(), advice.clone())).collect();
let aggregate = create_aggregate_on_srs::<Bls12, _, Permutation3>(&AdaptorCircuit(circuit.clone()), &proofs, &srs);
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 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 rng = thread_rng();
// let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
// println!("verifying {} proofs without advice", samples);
// let start = Instant::now();
// {
// for _ in 0..samples {
// verifier.add_proof(&proof, &[], |_, _| None);
// }
// assert_eq!(verifier.check_all(), true); // TODO
// }
// println!("done in {:?}", start.elapsed());
// }
// {
// let rng = thread_rng();
// let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
// println!("verifying 100 proofs with advice");
// let start = Instant::now();
// {
// for (ref proof, ref advice) in &proofs {
// verifier.add_proof_with_advice(proof, &[], advice);
// }
// verifier.add_aggregate(&proofs, &aggregate);
// assert_eq!(verifier.check_all(), true); // TODO
// }
// println!("done in {:?}", start.elapsed());
// }
{
let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying {} proofs without advice", samples);
let start = Instant::now();
{
for _ in 0..samples {
verifier.add_proof(&proof, &[], |_, _| None);
}
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
{
let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with advice non-succinct");
let start = Instant::now();
{
for (ref proof, ref advice) in &proofs {
verifier.add_proof_with_advice(proof, &[], advice);
}
verifier.add_aggregate(&proofs, &aggregate);
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
{
use rand::{XorShiftRng, SeedableRng, Rand, Rng};
let mut rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let (perm_commitments, s_prime_challenges, perm_proof, perm_arg_proof, z_prime, num_poly) = 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);
let mut verifier = SuccinctMultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with advice");
let start = Instant::now();
{
for (ref proof, ref advice) in &proofs {
verifier.add_proof_with_advice(proof, &[], advice);
}
verifier.add_aggregate(
&proofs,
&aggregate,
&perm_arg_proof,
&perm_proof,
&s2_proof,
num_poly,
&srs,
z_prime,
&perm_commitments,
s_prime_challenges
);
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
}
}

@ -14,5 +14,5 @@ pub mod permutation_structure;
// pub mod padding;
pub use self::wellformed_argument::{WellformednessArgument, WellformednessProof};
pub use self::permutation_argument::{PermutationArgument, PermutationProof, Proof};
pub use self::permutation_argument::{PermutationArgument, PermutationProof, PermutationArgumentProof};
pub use self::verifier::SuccinctMultiVerifier;

@ -31,27 +31,27 @@ pub struct PermutationArgument<E: Engine> {
#[derive(Clone)]
pub struct PermutationProof<E: Engine> {
v_zy: E::Fr,
e_opening: E::G1Affine,
f_opening: E::G1Affine,
pub v_zy: E::Fr,
pub e_opening: E::G1Affine,
pub f_opening: E::G1Affine,
}
#[derive(Clone)]
pub struct Proof<E: Engine> {
j: usize,
s_opening: E::G1Affine,
s_zy: E::Fr
pub struct PermutationArgumentProof<E: Engine> {
pub j: usize,
pub s_opening: E::G1Affine,
pub s_zy: E::Fr
}
fn permute<F: Field>(coeffs: &[F], permutation: & [usize]) -> Vec<F>{
assert_eq!(coeffs.len(), permutation.len());
let mut result: Vec<F> = vec![F::zero(); coeffs.len()];
for (i, j) in permutation.iter().enumerate() {
if *j < 1 {
// if permutation information is missing coefficient itself must be zero!
assert!(coeffs[i].is_zero());
continue;
}
// if *j < 1 {
// // if permutation information is missing coefficient itself must be zero!
// assert!(coeffs[i].is_zero());
// continue;
// }
result[*j - 1] = coeffs[i];
}
result
@ -234,9 +234,9 @@ impl<E: Engine> PermutationArgument<E> {
wellformed_challenges: & Vec<E::Fr>,
y: E::Fr,
z: E::Fr,
specialized_srs: &SpecializedSRS<E>,
_specialized_srs: &SpecializedSRS<E>,
srs: &SRS<E>
) -> Proof<E> {
) -> PermutationArgumentProof<E> {
// 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
@ -352,7 +352,7 @@ impl<E: Engine> PermutationArgument<E> {
let valid = GrandProductArgument::verify_ab_commitment(n,
&randomness,
&a_commitments,
& a_commitments,
& b_commitments,
&grand_product_openings,
y,
@ -375,7 +375,7 @@ impl<E: Engine> PermutationArgument<E> {
assert!(valid, "grand product argument must be valid");
}
Proof {
PermutationArgumentProof {
j: j,
s_opening: s_zy_opening,
s_zy: s_zy
@ -542,7 +542,7 @@ impl<E: Engine> PermutationArgument<E> {
pub fn verify(
s_commitments: &Vec<E::G1Affine>,
proof: &Proof<E>,
proof: &PermutationArgumentProof<E>,
z: E::Fr,
srs: &SRS<E>
) -> bool {
@ -651,7 +651,8 @@ fn test_permutation_argument() {
gamma,
& grand_product_challenges,
& wellformed_challenges,
y, z,
y,
z,
&specialized_srs, &srs);
let valid = PermutationArgument::verify(&s_commitments, &proof, z, &srs);

@ -80,9 +80,7 @@ impl<E: Engine> PermutationStructure<E> {
s2_eval.evaluate(x, y, &srs)
}
pub fn create_permutation_arguments<R: Rng>(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS<E>)
// -> PermutationProof<E>
{
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];
@ -91,7 +89,7 @@ impl<E: Engine> PermutationStructure<E> {
let one = E::Fr::one();
let mut minus_one = E::Fr::one();
minus_one.negate();
// println!("A");
let mut not_empty = [false; M];
// go other the permutations
for (gate_index, info) in self.a.iter().enumerate() {
@ -107,41 +105,27 @@ impl<E: Engine> PermutationStructure<E> {
let place_permutation_into = &mut permutations[i];
match coeff {
Coeff::Zero => {
// println!("Variable A({}) coefficient 0 at constraint {} in poly {}", gate_index+1, place, i);
// println!("Coeff 0 will be for Y^{} for X^{} for permutation {} ", place, x_power, i);
},
Coeff::One => {
not_empty[i] = true;
place_coeff_into[array_position] = one;
place_permutation_into[array_position] = *place;
// println!("Variable A({}) coefficient 1 at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term 1*X^{}*Y^{} in poly {}", x_power, place,i);
// println!("Coeff 1 will be at for Y^{} for X^{} for permutation {} ", place, x_power, i);
},
Coeff::NegativeOne => {
not_empty[i] = true;
place_coeff_into[array_position] = minus_one;
place_permutation_into[array_position] = *place;
// println!("Variable A({}) coefficient -1 at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term -1*X^{}*Y^{} in poly {}", x_power, place,i);
// println!("Coeff -1 will be at for Y^{} for X^{} for permutation {} ", place, x_power, i);
},
Coeff::Full(value) => {
not_empty[i] = true;
place_coeff_into[array_position] = *value;
place_permutation_into[array_position] = *place;
// println!("Variable A({}) coefficient * at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term k*X^{}*Y^{} in poly {}", x_power, place,i);
// println!("Coeff {} will be at for Y^{} for X^{} for permutation {} ", value, place, x_power, i);
}
}
} else {
// println!("Empty coeff for X^{} in permutation {}", gate_index, i);
}
}
}
// println!("B");
for (gate_index, info) in self.b.iter().enumerate() {
let offset = n + 1;
for i in 0..M {
@ -154,41 +138,27 @@ impl<E: Engine> PermutationStructure<E> {
let place_permutation_into = &mut permutations[i];
match coeff {
Coeff::Zero => {
// println!("Coeff 0 will be for Y^{} for X^{} for permutation {} ", place, x_power, i);
// println!("Variable B({}) coefficient 0 at constraint {} in poly {}", gate_index+1, place, i);
},
Coeff::One => {
not_empty[i] = true;
place_coeff_into[array_position] = one;
place_permutation_into[array_position] = *place;
// println!("Coeff 1 will be at for Y^{} for X^{} for permutation {} ", place, x_power, i);
// println!("Variable B({}) coefficient 1 at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term 1*X^{}*Y^{} in poly {}", x_power, place,i);
},
Coeff::NegativeOne => {
not_empty[i] = true;
place_coeff_into[array_position] = minus_one;
place_permutation_into[array_position] = *place;
// println!("Coeff -1 will be at for Y^{} for X^{} for permutation {} ", place, x_power, i);
// println!("Variable B({}) coefficient -1 at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term -1*X^{}*Y^{} in poly {}", x_power, place,i);
},
Coeff::Full(value) => {
not_empty[i] = true;
place_coeff_into[array_position] = *value;
place_permutation_into[array_position] = *place;
// println!("Coeff {} will be at for Y^{} for X^{} for permutation {} ", value, place, x_power, i);
// println!("Variable B({}) coefficient * at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term k*X^{}*Y^{} in poly {}", x_power, place,i);
}
}
} else {
// println!("Empty coeff for X^{} in permutation {}", gate_index, i);
}
}
}
// println!("C");
for (gate_index, info) in self.c.iter().enumerate() {
let offset = 2*n + 1;
for i in 0..M {
@ -202,55 +172,29 @@ impl<E: Engine> PermutationStructure<E> {
let place_permutation_into = &mut permutations[i];
match coeff {
Coeff::Zero => {
// println!("Coeff 0 will be for Y^{} for X^{} for permutation {} ", place, x_power, i);
// println!("Variable C({}) coefficient 0 at constraint {} in poly {}", gate_index+1, place, i);
},
Coeff::One => {
not_empty[i] = true;
place_coeff_into[array_position] = one;
place_permutation_into[array_position] = *place;
// println!("Coeff 1 will be at for Y^{} for X^{} for permutation {} ", place, x_power, i);
// println!("Variable C({}) coefficient 1 at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term 1*X^{}*Y^{} in poly {}", x_power, place,i);
},
Coeff::NegativeOne => {
not_empty[i] = true;
place_coeff_into[array_position] = minus_one;
place_permutation_into[array_position] = *place;
// println!("Coeff -1 will be at for Y^{} for X^{} for permutation {} ", place, x_power, i);
// println!("Variable C({}) coefficient -1 at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term -1*X^{}*Y^{} in poly {}", x_power, place,i);
},
Coeff::Full(value) => {
not_empty[i] = true;
place_coeff_into[array_position] = *value;
place_permutation_into[array_position] = *place;
// println!("Coeff {} will be at for Y^{} for X^{} for permutation {} ", value, place, x_power, i);
// println!("Variable C({}) coefficient * at constraint {} in poly {}", gate_index+1, place, i);
// println!("Term k*X^{}*Y^{} in poly {}", x_power, place,i);
}
}
} else {
// println!("Empty coeff for X^{} in permutation {}", gate_index, i);
}
}
}
// need to fill arrays with non-zero indexes just to have full permutation, even while it's just zero coefficient
// permutations[0][2] = 5;
// permutations[0][5] = 6;
// permutations[0][6] = 7;
// permutations[1][0] = 1;
// permutations[1][1] = 3;
// permutations[1][2] = 5;
// permutations[1][5] = 6;
// permutations[1][6] = 7;
println!("Not empty = {:?}", not_empty);
// TODO: fix
let mut m = M;
@ -292,14 +236,34 @@ impl<E: Engine> PermutationStructure<E> {
}
}
(non_permuted_coeffs, permutations)
}
pub fn create_permutation_special_reference(&self, srs: &SRS<E>) -> SpecializedSRS<E>
{
let (non_permuted_coeffs, permutations) = self.create_permutation_vectors();
let specialized_srs = PermutationArgument::make_specialized_srs(
&non_permuted_coeffs,
&permutations,
&srs
);
specialized_srs
}
pub fn create_permutation_arguments<R: Rng>(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS<E>)
-> (Vec<(E::G1Affine, E::G1Affine)>, Vec<E::Fr>, PermutationProof<E>, PermutationArgumentProof<E>, E::Fr, usize)
{
// we have to form non-permuted coefficients, as well as permutation structures;
let n = self.n;
let (non_permuted_coeffs, permutations) = self.create_permutation_vectors();
let m = non_permuted_coeffs.len();
println!("Will need {} permutation polynomials", m);
// println!("Nonpermuted 0 (coeffs for X^1, X^2, ...) = {:?}", non_permuted_coeffs[0]);
// println!("Permutation 0 (power of Y for X^1, X^2, ...) = {:?}", permutations[0]);
// println!("Nonpermuted 1 (coeffs for X^1, X^2, ...)= {:?}", non_permuted_coeffs[1]);
// println!("Permutation 1 (power of Y for X^1, X^2, ...) = {:?}", permutations[1]);
let specialized_srs = PermutationArgument::make_specialized_srs(
&non_permuted_coeffs,
&permutations,
@ -312,12 +276,13 @@ impl<E: Engine> PermutationStructure<E> {
let commitments = argument.commit(y, &srs);
let mut s_commitments = vec![];
let mut s_prime_commitments = vec![];
for (s, s_prime) in commitments.into_iter() {
for (s, s_prime) in commitments.clone().into_iter() {
s_commitments.push(s);
// println!("S' = {}", s_prime);
s_prime_commitments.push(s_prime);
}
let z_prime : E::Fr = rng.gen();
let opening = argument.open_commitments_to_s_prime(&challenges, y, z_prime, &srs);
@ -354,6 +319,8 @@ impl<E: Engine> PermutationStructure<E> {
let valid = PermutationArgument::verify(&s_commitments, &proof, z, &srs);
assert!(valid, "permutation argument must be valid");
(commitments, challenges, opening, proof, z_prime, m)
}
}

@ -14,10 +14,10 @@ pub struct S2Eval<E: Engine> {
#[derive(Clone)]
pub struct S2Proof<E: Engine> {
o: E::G1Affine,
c_value: E::Fr,
d_value: E::Fr,
c_opening: E::G1Affine,
d_opening: E::G1Affine
pub c_value: E::Fr,
pub d_value: E::Fr,
pub c_opening: E::G1Affine,
pub d_opening: E::G1Affine
}
impl<E: Engine> S2Eval<E> {
@ -48,7 +48,7 @@ impl<E: Engine> S2Eval<E> {
let (c, c_opening) = {
let mut point = y;
point.mul_assign(&x);
let val = evaluate_at_consequitive_powers(&poly[1..], E::Fr::one(), point);
let val = evaluate_at_consequitive_powers(&poly[1..], point, point);
poly[0] = val;
poly[0].negate();
let opening = polynomial_commitment_opening(0, self.n, poly.iter(), point, &srs);
@ -59,7 +59,7 @@ impl<E: Engine> S2Eval<E> {
let (d, d_opening) = {
let mut point = y.inverse().unwrap();
point.mul_assign(&x);
let val = evaluate_at_consequitive_powers(&poly[1..], E::Fr::one(), point);
let val = evaluate_at_consequitive_powers(&poly[1..], point, point);
poly[0] = val;
poly[0].negate();
let opening = polynomial_commitment_opening(0, self.n, poly.iter(), point, &srs);
@ -87,17 +87,19 @@ impl<E: Engine> S2Eval<E> {
h_prep.negate();
let h_prep = h_prep.prepare();
let mut c_minus_xy = proof.c_value;
let mut xy = x;
xy.mul_assign(&y);
let mut minus_xy = x;
minus_xy.mul_assign(&y);
minus_xy.negate();
c_minus_xy.sub_assign(&xy);
let mut h_alpha_term = proof.c_opening.mul(minus_xy.into_repr());
let g_in_c = E::G1Affine::one().mul(proof.c_value);
h_alpha_term.add_assign(&g_in_c);
let c_in_c_minus_xy = proof.c_opening.mul(c_minus_xy.into_repr()).into_affine();
let h_alpha_term = h_alpha_term.into_affine();
let valid = E::final_exponentiation(&E::miller_loop(&[
(&proof.c_opening.prepare(), &alpha_x_precomp),
(&c_in_c_minus_xy.prepare(), &alpha_precomp),
(&h_alpha_term.prepare(), &alpha_precomp),
(&proof.o.prepare(), &h_prep),
])).unwrap() == E::Fqk::one();
@ -107,17 +109,19 @@ impl<E: Engine> S2Eval<E> {
// e(D,hαx)e(Dy1z,hα) = e(O,h)e(gd,hα)
let mut d_minus_x_y_inv = proof.d_value;
let mut x_y_inv = x;
x_y_inv.mul_assign(&y.inverse().unwrap());
let mut minus_x_y_inv = x;
minus_x_y_inv.mul_assign(&y.inverse().unwrap());
minus_x_y_inv.negate();
d_minus_x_y_inv.sub_assign(&x_y_inv);
let mut h_alpha_term = proof.d_opening.mul(minus_x_y_inv.into_repr());
let g_in_d = E::G1Affine::one().mul(proof.d_value);
h_alpha_term.add_assign(&g_in_d);
let d_in_d_minus_x_y_inv = proof.d_opening.mul(d_minus_x_y_inv.into_repr()).into_affine();
let h_alpha_term = h_alpha_term.into_affine();
let valid = E::final_exponentiation(&E::miller_loop(&[
(&proof.d_opening.prepare(), &alpha_x_precomp),
(&d_in_d_minus_x_y_inv.prepare(), &alpha_precomp),
(&h_alpha_term.prepare(), &alpha_precomp),
(&proof.o.prepare(), &h_prep),
])).unwrap() == E::Fqk::one();
@ -127,4 +131,37 @@ impl<E: Engine> S2Eval<E> {
true
}
}
#[test]
fn test_s2_proof() {
use crate::pairing::ff::{Field, PrimeField};
use crate::pairing::{Engine, CurveAffine, CurveProjective};
use crate::pairing::bls12_381::{Bls12, Fr};
use std::time::{Instant};
use crate::sonic::srs::SRS;
use crate::sonic::cs::{Circuit, ConstraintSystem, LinearCombination};
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());
{
use rand::{XorShiftRng, SeedableRng, Rand, Rng};
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let x: Fr = rng.gen();
let y: Fr = rng.gen();
let proof = S2Eval::new(1024);
let proof = proof.evaluate(x, y, &srs);
let valid = S2Eval::verify(x, y, &proof, &srs);
assert!(valid);
}
}

@ -18,8 +18,15 @@ use crate::sonic::cs::{Circuit, Variable, Coeff};
use crate::sonic::srs::SRS;
use crate::sonic::sonic::Preprocess;
use super::s2_proof::{S2Proof, S2Eval};
use super::permutation_structure::create_permutation_structure;
use super::permutation_argument::SpecializedSRS;
use super::permutation_argument::{PermutationArgumentProof, PermutationProof, PermutationArgument};
pub struct SuccinctMultiVerifier<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> {
circuit: C,
s1_special_reference: SpecializedSRS<E>,
s2_special_reference: E::G1Affine,
pub(crate) batch: Batch<E>,
k_map: Vec<usize>,
n: usize,
@ -31,26 +38,118 @@ pub struct SuccinctMultiVerifier<E: Engine, C: Circuit<E>, S: SynthesisDriver, R
impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier<E, C, S, R> {
// This constructor consumes randomness source cause it's later used internally
pub fn new(circuit: C, srs: &SRS<E>, rng: R) -> Result<Self, SynthesisError> {
let mut preprocess = Preprocess::new();
let (n, q, k_map) = {
let mut preprocess = Preprocess::new();
S::synthesize(&mut preprocess, &circuit)?;
(preprocess.n, preprocess.q, preprocess.k_map)
};
// also calculate special reference for s1
let permutation_structure = create_permutation_structure(&circuit);
let s2_special_reference = permutation_structure.calculate_s2_commitment_value(&srs);
let s1_special_reference = permutation_structure.create_permutation_special_reference(&srs);
S::synthesize(&mut preprocess, &circuit)?;
Ok(SuccinctMultiVerifier {
circuit,
batch: Batch::new(srs, preprocess.n),
k_map: preprocess.k_map,
n: preprocess.n,
q: preprocess.q,
s1_special_reference,
s2_special_reference,
batch: Batch::new(srs, n),
k_map: k_map,
n: n,
q: q,
randomness_source: rng,
_marker: PhantomData
})
}
// 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(
&mut self,
proofs: &[(Proof<E>, SxyAdvice<E>)],
aggregate: &Aggregate<E>,
szw: E::Fr
permutation_argument_proof: &PermutationArgumentProof<E>,
permutation_proof: &PermutationProof<E>,
s2_proof: &S2Proof<E>,
num_permutation_polynomials: usize,
srs: &SRS<E>,
z_prime: E::Fr, // TODO, temporary before incorporation to the transcript
permutation_argument_commitments: & Vec<(E::G1Affine, E::G1Affine)>,
s_prime_challenges: Vec<E::Fr>
)
{
let mut transcript = Transcript::new(&[]);
@ -67,16 +166,119 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier
let z: E::Fr = transcript.get_challenge_scalar();
// let z = E::Fr::one();
println!("Verifier z = {}", z);
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
let w = E::Fr::one();
// tmp.finalize(z)
// };
println!("Verifier w = {}", w);
println!("N = {}", self.n);
let szw = {
// prover will supply s1 and s2, need to calculate
// s(z, w) = X^-(N+1) * Y^N * s1 - X^N * s2
let x_n = z.pow(&[self.n as u64]);
let mut x_n_plus_1 = x_n;
x_n_plus_1.mul_assign(&z);
let x_n_plus_1_inv = x_n_plus_1.inverse().unwrap();
let y_n = w.pow(&[self.n as u64]);
// simultaneously add components to the batch verifier
// this is s2 contribution itself
let mut s2_part = s2_proof.c_value;
s2_part.add_assign(&s2_proof.d_value);
println!("S2 = {}", s2_part);
s2_part.mul_assign(&x_n);
// add terms for S2 for verification
// {
// let random: E::Fr = self.randomness_source.gen();
// // e(C,hαx)e(Cyz,hα) = e(O,h)e(gc,hα) that is
// // e(C,hαx)e(C^yz,hα)*e(O,-h)e(g^c,hα) = 1
// let mut xy = z;
// xy.mul_assign(&w);
// self.batch.add_opening(s2_proof.c_opening, random, xy);
// self.batch.add_opening_value(random, s2_proof.c_value);
// self.batch.add_commitment(self.s2_special_reference, random);
// }
// {
// let random: E::Fr = self.randomness_source.gen();
// // e(D,hαx)e(Dy1z,hα) = e(O,h)e(gd,hα) that is
// // e(D,hαx)e(D^y-1z,hα)*e(O,-h)e(g^d,hα) = 1
// let mut y_inv_by_x = z;
// y_inv_by_x.mul_assign(&w.inverse().unwrap());
// self.batch.add_opening(s2_proof.d_opening, random, y_inv_by_x);
// self.batch.add_opening_value(random, s2_proof.d_value);
// self.batch.add_commitment(self.s2_special_reference, random);
// }
// now work with s1 part
let mut s1_part = permutation_argument_proof.s_zy;
println!("S1 = {}", s1_part);
s1_part.mul_assign(&x_n_plus_1_inv);
s1_part.mul_assign(&y_n);
// TODO: this one should be from transcipt
// let s_prime_challenges = (0..num_permutation_polynomials).map(|_| E::Fr::rand(&mut self.randomness_source)).collect::<Vec<_>>();
// s and s' commitments of permutation argument
let mut s_commitments = vec![];
let mut s_prime_commitments = vec![];
for (s, s_prime) in permutation_argument_commitments.iter() {
s_commitments.push(*s);
s_prime_commitments.push(*s_prime);
}
let randomness = (0..2).map(|_| E::Fr::rand(&mut self.randomness_source)).collect::<Vec<_>>();
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!("Succinct s(z, w) = {}", szw);
{
let random: E::Fr = self.randomness_source.gen();