From b8d4b0cea487547f6ddaddb3a0cf488b0d014aca Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Thu, 6 Jun 2019 14:24:21 +0300 Subject: [PATCH] permutation argument works as itself, but not for verifier --- src/sonic/helped/batch.rs | 4 + src/sonic/helped/helper.rs | 13 + src/sonic/helped/prover.rs | 1 + src/sonic/helped/verifier.rs | 4 + src/sonic/tests/sonics.rs | 283 +++++++++++++++----- src/sonic/unhelped/mod.rs | 2 +- src/sonic/unhelped/permutation_argument.rs | 37 +-- src/sonic/unhelped/permutation_structure.rs | 97 +++---- src/sonic/unhelped/s2_proof.rs | 73 +++-- src/sonic/unhelped/verifier.rs | 226 +++++++++++++++- 10 files changed, 566 insertions(+), 174 deletions(-) diff --git a/src/sonic/helped/batch.rs b/src/sonic/helped/batch.rs index ef7f15d..6160e23 100644 --- a/src/sonic/helped/batch.rs +++ b/src/sonic/helped/batch.rs @@ -104,6 +104,7 @@ impl Batch { } } + /// 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 Batch { 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); diff --git a/src/sonic/helped/helper.rs b/src/sonic/helped/helper.rs index 72e83af..6007123 100644 --- a/src/sonic/helped/helper.rs +++ b/src/sonic/helped/helper.rs @@ -26,6 +26,9 @@ pub struct Aggregate { 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, S: SynthesisDriver>( @@ -80,6 +83,8 @@ pub fn create_aggregate_on_srs_using_information, 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, S: Sy // Open C at w let w: E::Fr = transcript.get_challenge_scalar(); + let w = E::Fr::one(); + let value = compute_value::(&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, S: Sy c_openings, // Then we have to finally open C opening, + + z: z, + + w: w } } \ No newline at end of file diff --git a/src/sonic/helped/prover.rs b/src/sonic/helped/prover.rs index 7ece0c2..eec3e1e 100644 --- a/src/sonic/helped/prover.rs +++ b/src/sonic/helped/prover.rs @@ -32,6 +32,7 @@ pub fn create_advice_on_information_and_srs, 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) = { diff --git a/src/sonic/helped/verifier.rs b/src/sonic/helped/verifier.rs index da150e7..dc76461 100644 --- a/src/sonic/helped/verifier.rs +++ b/src/sonic/helped/verifier.rs @@ -66,10 +66,14 @@ impl, S: SynthesisDriver, R: Rng> MultiVerifier::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::>(); + let samples: usize = 100; + + let xl = rng.gen(); + let xr = rng.gen(); + let image = mimc::(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::(&AdaptorCircuit(circuit.clone()), &srs).unwrap(); + println!("done in {:?}", start.elapsed()); + + println!("creating advice"); + let start = Instant::now(); + let advice = create_advice_on_srs::(&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::(&AdaptorCircuit(circuit.clone()), &proofs, &srs); + println!("done in {:?}", start.elapsed()); + + { + let rng = thread_rng(); + let mut verifier = MultiVerifier::::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::::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::::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 Circuit for MyCircuit { + fn synthesize>(&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::(&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::(&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::(circuit.clone()).expect("Must get circuit info"); // println!("{:?}", info); - // println!("creating proof"); - // let start = Instant::now(); - // let proof = create_proof_on_srs::(&AdaptorCircuit(circuit.clone()), &srs).unwrap(); - // println!("done in {:?}", start.elapsed()); + println!("creating proof"); + let start = Instant::now(); + let proof = create_proof_on_srs::(&AdaptorCircuit(circuit.clone()), &srs).unwrap(); + println!("done in {:?}", start.elapsed()); - // println!("creating advice"); - // let start = Instant::now(); - // let advice = create_advice_on_srs::(&AdaptorCircuit(circuit.clone()), &proof, &srs).unwrap(); - // println!("done in {:?}", start.elapsed()); + println!("creating advice"); + let start = Instant::now(); + let advice = create_advice_on_srs::(&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::(&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::(&AdaptorCircuit(circuit.clone()), &proofs, &srs); + println!("done in {:?}", start.elapsed()); - // { - // let rng = thread_rng(); - // let mut verifier = MultiVerifier::::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::::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::::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::::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::::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::::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::::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()); + } } } diff --git a/src/sonic/unhelped/mod.rs b/src/sonic/unhelped/mod.rs index 0efebdb..9dd7a67 100644 --- a/src/sonic/unhelped/mod.rs +++ b/src/sonic/unhelped/mod.rs @@ -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; \ No newline at end of file diff --git a/src/sonic/unhelped/permutation_argument.rs b/src/sonic/unhelped/permutation_argument.rs index 2662009..7438a72 100644 --- a/src/sonic/unhelped/permutation_argument.rs +++ b/src/sonic/unhelped/permutation_argument.rs @@ -31,27 +31,27 @@ pub struct PermutationArgument { #[derive(Clone)] pub struct PermutationProof { - 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 { - j: usize, - s_opening: E::G1Affine, - s_zy: E::Fr +pub struct PermutationArgumentProof { + pub j: usize, + pub s_opening: E::G1Affine, + pub s_zy: E::Fr } fn permute(coeffs: &[F], permutation: & [usize]) -> Vec{ assert_eq!(coeffs.len(), permutation.len()); let mut result: Vec = 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 PermutationArgument { wellformed_challenges: & Vec, y: E::Fr, z: E::Fr, - specialized_srs: &SpecializedSRS, + _specialized_srs: &SpecializedSRS, srs: &SRS - ) -> Proof { + ) -> PermutationArgumentProof { // 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 PermutationArgument { let valid = GrandProductArgument::verify_ab_commitment(n, &randomness, - &a_commitments, + & a_commitments, & b_commitments, &grand_product_openings, y, @@ -375,7 +375,7 @@ impl PermutationArgument { 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 PermutationArgument { pub fn verify( s_commitments: &Vec, - proof: &Proof, + proof: &PermutationArgumentProof, z: E::Fr, srs: &SRS ) -> 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); diff --git a/src/sonic/unhelped/permutation_structure.rs b/src/sonic/unhelped/permutation_structure.rs index cfe5bff..4f7b6bc 100644 --- a/src/sonic/unhelped/permutation_structure.rs +++ b/src/sonic/unhelped/permutation_structure.rs @@ -80,9 +80,7 @@ impl PermutationStructure { s2_eval.evaluate(x, y, &srs) } - pub fn create_permutation_arguments(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS) - // -> PermutationProof - { + fn create_permutation_vectors(&self) -> (Vec>, Vec>) { // 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 PermutationStructure { 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 PermutationStructure { 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 PermutationStructure { 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 PermutationStructure { 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 PermutationStructure { } } + (non_permuted_coeffs, permutations) + } + + pub fn create_permutation_special_reference(&self, srs: &SRS) -> SpecializedSRS + { + 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(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS) + -> (Vec<(E::G1Affine, E::G1Affine)>, Vec, PermutationProof, PermutationArgumentProof, 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 PermutationStructure { 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 PermutationStructure { let valid = PermutationArgument::verify(&s_commitments, &proof, z, &srs); assert!(valid, "permutation argument must be valid"); + + (commitments, challenges, opening, proof, z_prime, m) } } diff --git a/src/sonic/unhelped/s2_proof.rs b/src/sonic/unhelped/s2_proof.rs index a046e63..6cbaf9b 100644 --- a/src/sonic/unhelped/s2_proof.rs +++ b/src/sonic/unhelped/s2_proof.rs @@ -14,10 +14,10 @@ pub struct S2Eval { #[derive(Clone)] pub struct S2Proof { 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 S2Eval { @@ -48,7 +48,7 @@ impl S2Eval { 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 S2Eval { 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 S2Eval { 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 S2Eval { // e(D,hαx)e(D−y−1z,hα) = e(O,h)e(g−d,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 S2Eval { 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::::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); + } } \ No newline at end of file diff --git a/src/sonic/unhelped/verifier.rs b/src/sonic/unhelped/verifier.rs index 6962ab5..23f9425 100644 --- a/src/sonic/unhelped/verifier.rs +++ b/src/sonic/unhelped/verifier.rs @@ -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, S: SynthesisDriver, R: Rng> { circuit: C, + s1_special_reference: SpecializedSRS, + s2_special_reference: E::G1Affine, pub(crate) batch: Batch, k_map: Vec, n: usize, @@ -31,26 +38,118 @@ pub struct SuccinctMultiVerifier, S: SynthesisDriver, R impl, S: SynthesisDriver, R: Rng> SuccinctMultiVerifier { // This constructor consumes randomness source cause it's later used internally pub fn new(circuit: C, srs: &SRS, rng: R) -> Result { - 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, SxyAdvice)], + // aggregate: &Aggregate, + // ) + // { + // let mut transcript = Transcript::new(&[]); + // let mut y_values: Vec = 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, SxyAdvice)], aggregate: &Aggregate, - szw: E::Fr + permutation_argument_proof: &PermutationArgumentProof, + permutation_proof: &PermutationProof, + s2_proof: &S2Proof, + num_permutation_polynomials: usize, + srs: &SRS, + z_prime: E::Fr, // TODO, temporary before incorporation to the transcript + permutation_argument_commitments: & Vec<(E::G1Affine, E::G1Affine)>, + s_prime_challenges: Vec ) { let mut transcript = Transcript::new(&[]); @@ -67,16 +166,119 @@ impl, 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(C−yz,hα) = e(O,h)e(g−c,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(D−y−1z,hα) = e(O,h)e(g−d,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::>(); + + // 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::>(); + + 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();