From 3d65dcbb6b8647214cf48ea244c7238064dc0cf4 Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Thu, 6 Jun 2019 17:12:02 +0300 Subject: [PATCH] huge verbosity, but problem is pinned --- src/sonic/tests/sonics.rs | 46 +++++- src/sonic/unhelped/permutation_argument.rs | 11 +- src/sonic/unhelped/permutation_structure.rs | 166 +++++++++++++++++++- 3 files changed, 207 insertions(+), 16 deletions(-) diff --git a/src/sonic/tests/sonics.rs b/src/sonic/tests/sonics.rs index 633eef1..7e610d7 100644 --- a/src/sonic/tests/sonics.rs +++ b/src/sonic/tests/sonics.rs @@ -31,7 +31,7 @@ use crate::{ SynthesisError }; -const MIMC_ROUNDS: usize = 322; +const MIMC_ROUNDS: usize = 2; fn mimc( mut xl: E::Fr, @@ -477,7 +477,8 @@ fn test_succinct_sonic_mimc() { let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); // Generate the MiMC round constants - let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::>(); + // let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::>(); + let constants = (0..MIMC_ROUNDS).map(|_| Fr::one()).collect::>(); let samples: usize = 100; let xl = rng.gen(); @@ -486,7 +487,7 @@ fn test_succinct_sonic_mimc() { // Create an instance of our circuit (with the // witness) - let circuit = MiMCDemoNoInputs { + let circuit = MiMCDemoNoInputs:: { xl: Some(xl), xr: Some(xr), image: Some(image), @@ -520,17 +521,26 @@ fn test_succinct_sonic_mimc() { 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); + + 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::(&AdaptorCircuit(circuit.clone())); let perm_structure = create_permutation_structure::(&AdaptorCircuit(circuit.clone())); - // 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); @@ -600,9 +610,29 @@ fn test_succinct_sonic_mimc() { 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 (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); + let n = perm_structure.n; + 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]); + + let mut s_1 = s1_naive; + s_1.mul_assign(&z_inv_n_plus_1); + s_1.mul_assign(&y_n); + + 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); + + let mut verifier = SuccinctMultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); println!("verifying 100 proofs with advice"); let start = Instant::now(); diff --git a/src/sonic/unhelped/permutation_argument.rs b/src/sonic/unhelped/permutation_argument.rs index 7438a72..21b81ab 100644 --- a/src/sonic/unhelped/permutation_argument.rs +++ b/src/sonic/unhelped/permutation_argument.rs @@ -146,14 +146,19 @@ impl PermutationArgument { for (c, p) in self.non_permuted_coefficients.iter().zip(self.permutations.iter()) { let mut non_permuted = c.clone(); + // these are terms of s coefficients in each of the permutations, + // permuted by the corresponding permutation let permuted = permute(&non_permuted[..], &p[..]); + // distribute powers of Y to non-permuted coefficients mut_distribute_consequitive_powers(&mut non_permuted[..], y, y); + // and commit to S' let s_prime = multiexp(srs.g_positive_x_alpha[0..n].iter(), non_permuted.iter()).into_affine(); - let mut permuted_at_y = permute(&non_permuted[..], &p[..]); + // no we can permute pre-distributed powers of Y + let permuted_at_y = permute(&non_permuted[..], &p[..]); drop(non_permuted); - + // and commit to S let s = multiexp(srs.g_positive_x_alpha[0..n].iter(), permuted_at_y.iter()).into_affine(); result.push((s, s_prime)); @@ -260,6 +265,8 @@ impl PermutationArgument { let s_polynomial = s_polynomial.unwrap(); // evaluate at z let s_zy = evaluate_at_consequitive_powers(& s_polynomial[..], z, z); + println!("In permutation argument S(z, y) = {}", s_zy); + let mut s_zy_neg = s_zy; s_zy_neg.negate(); diff --git a/src/sonic/unhelped/permutation_structure.rs b/src/sonic/unhelped/permutation_structure.rs index 4f7b6bc..f7b2c09 100644 --- a/src/sonic/unhelped/permutation_structure.rs +++ b/src/sonic/unhelped/permutation_structure.rs @@ -74,6 +74,75 @@ impl PermutationStructure { S2Eval::calculate_commitment_element(self.n, srs) } + pub fn print_constraints(n:usize, q: usize, coeffs: &Vec>, permutations: &Vec>) { + 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>, permutations: &Vec>) { + 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>, permutations: &Vec>) { + 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) -> S2Proof { let s2_eval = S2Eval::new(self.n); @@ -107,6 +176,7 @@ impl PermutationStructure { Coeff::Zero => { }, Coeff::One => { + println!("A({}), coeff = 1 for place {} in permutation {}", gate_index, place, i); not_empty[i] = true; place_coeff_into[array_position] = one; place_permutation_into[array_position] = *place; @@ -198,6 +268,11 @@ impl PermutationStructure { // 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] { @@ -209,6 +284,15 @@ impl PermutationStructure { 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 for i in 0..m { @@ -253,7 +337,7 @@ impl PermutationStructure { } 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) + -> (Vec<(E::G1Affine, E::G1Affine)>, Vec, PermutationProof, PermutationArgumentProof, E::Fr, usize, E::Fr) { // we have to form non-permuted coefficients, as well as permutation structures; let n = self.n; @@ -270,6 +354,24 @@ impl PermutationStructure { &srs ); + // evaluate S naively + + 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); + } + } + + println!("naive s eval = {}", s_contrib); + let mut argument = PermutationArgument::new(non_permuted_coeffs, permutations); let challenges = (0..m).map(|_| E::Fr::rand(rng)).collect::>(); @@ -320,7 +422,7 @@ impl PermutationStructure { assert!(valid, "permutation argument must be valid"); - (commitments, challenges, opening, proof, z_prime, m) + (commitments, challenges, opening, proof, z_prime, m, s_contrib) } } @@ -337,7 +439,7 @@ fn test_simple_succinct_sonic() { impl Circuit for MyCircuit { fn synthesize>(&self, cs: &mut CS) -> Result<(), SynthesisError> { - let (a, b, _) = cs.multiply(|| { + let (a, b, c) = cs.multiply(|| { Ok(( E::Fr::from_str("10").unwrap(), E::Fr::from_str("20").unwrap(), @@ -346,10 +448,24 @@ fn test_simple_succinct_sonic() { })?; cs.enforce_zero(LinearCombination::zero() + (Coeff::Full(E::Fr::from_str("2").unwrap()), a) - b); + cs.enforce_zero(LinearCombination::zero() + (Coeff::Full(E::Fr::from_str("20").unwrap()), a) - c); + cs.enforce_zero(LinearCombination::zero() + (Coeff::Full(E::Fr::from_str("10").unwrap()), b) - c); - let multiplier = cs.alloc_input(|| Ok(E::Fr::from_str("20").unwrap()))?; + // let multiplier = cs.alloc_input(|| Ok(E::Fr::from_str("20").unwrap()))?; - cs.enforce_zero(LinearCombination::from(b) - multiplier); + // 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(()) } @@ -374,8 +490,46 @@ fn test_simple_succinct_sonic() { use crate::sonic::sonic::Permutation3; use crate::sonic::unhelped::permutation_structure::*; + let x: Fr = rng.gen(); + let y: Fr = rng.gen(); + + let x = Fr::one(); + let mut y = Fr::one(); + y.double(); + let perm_structure = create_permutation_structure::(&MyCircuit); - perm_structure.create_permutation_arguments(Fr::one(), Fr::one(), rng, &srs); + perm_structure.create_permutation_arguments(x, y, rng, &srs); + let s2 = S2Eval::new(perm_structure.n); + let s2 = s2.evaluate(x, y, &srs); + let mut s2_value = s2.c_value; + s2_value.add_assign(&s2.d_value); + + let mut expected_s2_value = Fr::zero(); + let y_inv = y.inverse().unwrap(); + let mut p1 = y; + p1.add_assign(&y_inv); + p1.mul_assign(&x); + expected_s2_value.add_assign(&p1); + + let mut t0 = y; + t0.square(); + + let mut t1 = y_inv; + t1.square(); + + let mut p2 = t0; + p2.add_assign(&t1); + p2.mul_assign(&x); + p2.mul_assign(&x); + + expected_s2_value.add_assign(&p2); + + println!("s2 value = {}", s2_value); + println!("expected s2 value = {}", expected_s2_value); + + assert!(expected_s2_value == s2_value); + + println!("N = {}, Q = {}", perm_structure.n, perm_structure.q); }