diff --git a/src/sonic/unhelped/grand_product_argument.rs b/src/sonic/unhelped/grand_product_argument.rs index 234edc4..dad9505 100644 --- a/src/sonic/unhelped/grand_product_argument.rs +++ b/src/sonic/unhelped/grand_product_argument.rs @@ -112,6 +112,24 @@ impl GrandProductArgument { ).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::G1Affine, E::G1Affine) { + assert_eq!(a.len(), b.len()); + + let n = a.len(); + + let a = multiexp( + srs.g_positive_x_alpha[0..n].iter(), + a.iter()).into_affine(); + + + let b = multiexp( + srs.g_positive_x_alpha[0..n].iter(), + b.iter()).into_affine(); + + (a, b) + } + pub fn open_commitments_for_grand_product(&self, y: E::Fr, z: E::Fr, srs: &SRS) -> Vec<(E::Fr, E::G1Affine)> { let n = self.n; @@ -288,7 +306,6 @@ impl GrandProductArgument { c } - // Argument is based on an approach of main SONIC construction, but with a custom S(X,Y) polynomial of a simple form pub fn make_argument(self, a_zy: & Vec, challenges: & Vec, y: E::Fr, z: E::Fr, srs: &SRS) -> GrandProductProof { assert_eq!(a_zy.len(), self.a_polynomials.len()); diff --git a/src/sonic/unhelped/permutation_argument.rs b/src/sonic/unhelped/permutation_argument.rs index 0dacc35..96c6039 100644 --- a/src/sonic/unhelped/permutation_argument.rs +++ b/src/sonic/unhelped/permutation_argument.rs @@ -8,6 +8,8 @@ use std::marker::PhantomData; use crate::sonic::srs::SRS; use crate::sonic::util::*; +use super::wellformed_argument::{WellformednessArgument, WellformednessProof}; +use super::grand_product_argument::{GrandProductArgument, GrandProductProof}; #[derive(Clone)] pub struct SpecializedSRS { @@ -22,6 +24,7 @@ pub struct SpecializedSRS { pub struct PermutationArgument { non_permuted_coefficients: Vec>, permuted_coefficients: Vec>, + permuted_at_y_coefficients: Vec>, permutations: Vec>, n: usize } @@ -33,12 +36,20 @@ pub struct PermutationProof { f_opening: E::G1Affine, } +#[derive(Clone)] +pub struct Proof { + j: usize, + s_opening: E::G1Affine, + 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() { - result[*j] = coeffs[i]; + result[*j - 1] = coeffs[i]; } result } @@ -58,6 +69,7 @@ impl PermutationArgument { PermutationArgument { non_permuted_coefficients: coefficients, permuted_coefficients: vec![vec![]], + permuted_at_y_coefficients: vec![vec![]], permutations: permutations, n: n } @@ -128,6 +140,7 @@ impl PermutationArgument { let n = self.non_permuted_coefficients[0].len(); let mut permuted_coefficients = vec![]; + let mut permuted_at_y_coefficients = vec![]; for (c, p) in self.non_permuted_coefficients.iter().zip(self.permutations.iter()) { let mut non_permuted = c.clone(); @@ -144,14 +157,22 @@ impl PermutationArgument { result.push((s, s_prime)); permuted_coefficients.push(permuted); + permuted_at_y_coefficients.push(permuted_at_y); } self.permuted_coefficients = permuted_coefficients; + self.permuted_at_y_coefficients = permuted_at_y_coefficients; result } - pub fn open_commitments_to_s(&self, challenges: &Vec, y: E::Fr, z_prime: E::Fr, srs: &SRS) -> PermutationProof { + pub fn open_commitments_to_s_prime( + &self, + challenges: &Vec, + y: E::Fr, + z_prime: E::Fr, + srs: &SRS + ) -> PermutationProof { let n = self.non_permuted_coefficients[0].len(); let mut yz = y; @@ -168,7 +189,7 @@ impl PermutationArgument { } else { let mut poly = p.clone(); mul_polynomial_by_scalar(&mut poly[..], *r); - + polynomial = Some(poly); } } @@ -178,7 +199,7 @@ impl PermutationArgument { let mut v_neg = v; v_neg.negate(); - let e = polynomial_commitment_opening( + let f = polynomial_commitment_opening( 0, n, Some(v_neg).iter().chain_ext(polynomial.iter()), @@ -188,7 +209,7 @@ impl PermutationArgument { mut_distribute_consequitive_powers(&mut polynomial[..], y, y); - let f = polynomial_commitment_opening( + let e = polynomial_commitment_opening( 0, n, Some(v_neg).iter().chain_ext(polynomial.iter()), @@ -203,268 +224,164 @@ impl PermutationArgument { } } - // // Make a commitment for the begining of the protocol, returns commitment and `v` scalar - // pub fn commit_to_individual_c_polynomials(&self, srs: &SRS) -> Vec<(E::G1Affine, E::Fr)> { - - // let mut results = vec![]; - - // let n = self.c_polynomials[0].len(); - - // for (p, v) in self.c_polynomials.iter().zip(self.v_elements.iter()) { - // let c = multiexp( - // srs.g_positive_x_alpha[0..n].iter(), - // p.iter() - // ).into_affine(); - - // results.push((c, *v)); - // } - - // results - // } - - // // Argument is based on an approach of main SONIC construction, but with a custom S(X,Y) polynomial of a simple form - // pub fn commit_to_t_polynomial(&mut self, challenges: & Vec, y: E::Fr, srs: &SRS) -> E::G1Affine { - // assert_eq!(challenges.len(), self.a_polynomials.len()); - - // let n = self.n; - - // let mut t_polynomial: Option> = None; - - // for (((a, c), v), challenge) in self.a_polynomials.iter() - // .zip(self.c_polynomials.iter()) - // .zip(self.v_elements.iter()) - // .zip(challenges.iter()) - // { - // let mut a_xy = a.clone(); - // let mut c_xy = c.clone(); - // let v = *v; - - // assert_eq!(a_xy.len(), 2*n + 1); - // assert_eq!(c_xy.len(), 2*n + 1); - - // // make a T polynomial - - // let r: Vec = { - // // p_a(X,Y)*Y - // let mut tmp = y; - // tmp.square(); - // mut_distribute_consequitive_powers(&mut a_xy[..], tmp, y); - - // // add extra terms - // //v*(XY)^{n+1}*Y + X^{n+2} + X^{n+1}Y − X^{2n+2}*Y - - // // n+1 term v*(XY)^{n+1}*Y + X^{n+1}Y - // let tmp = y.pow(&[(n+2) as u64]); - // let mut x_n_plus_one_term = v; - // x_n_plus_one_term.mul_assign(&tmp); - // x_n_plus_one_term.add_assign(&y); - // a_xy[n].add_assign(&x_n_plus_one_term); - - // // n+2 term - // a_xy[n+1].add_assign(&E::Fr::one()); - - // // 2n+2 term - // let mut tmp = y; - // tmp.negate(); - - // a_xy.push(tmp); - - // assert_eq!(a_xy.len(), 2*n + 2); - - // let mut r = vec![E::Fr::zero(); 2*n + 3]; - // r.extend(a_xy); - - // r - // }; - - // let r_prime: Vec = { - // let mut c_prime: Vec = c_xy.iter().rev().map(|el| *el).collect(); - // c_prime.push(E::Fr::one()); - // c_prime.push(E::Fr::zero()); - - // assert_eq!(c_prime.len(), 2*n + 3); - - // c_prime - // }; - - // // multiply polynomials with powers [-2n-2, -1] and [1, 2n+2], - // // expect result to be [-2n+1, 2n+1] - // let mut t: Vec = multiply_polynomials::(r, r_prime); - - // assert_eq!(t.len(), 6*n + 7); - - // // drain first powers due to the padding and last element due to requirement of being zero - // for (i, el) in t[0..(2*n+3)].iter().enumerate() { - // assert_eq!(*el, E::Fr::zero(), "{}", format!("Element {} is non-zero", i)); - // } - - // t.drain(0..(2*n+3)); - // let last = t.pop(); - // assert_eq!(last.unwrap(), E::Fr::zero(), "last element should be zero"); - - // assert_eq!(t.len(), 4*n + 3); - - // let mut val = { - // let mut tmp = y; - // tmp.square(); - // evaluate_at_consequitive_powers(&c_xy, tmp, y) - // }; - - // val.add_assign(&E::Fr::one()); - - // // subtract at constant term - // assert_eq!(t[2*n+1], val); - - // t[2*n+1].sub_assign(&val); - - // if t_polynomial.is_some() { - // if let Some(t_poly) = t_polynomial.as_mut() { - // mul_add_polynomials(&mut t_poly[..], &t, *challenge); - // } - // } else { - // mul_polynomial_by_scalar(&mut t, *challenge); - // t_polynomial = Some(t); - // } - // } - - // let t_polynomial = t_polynomial.unwrap(); - - // let c = multiexp(srs.g_negative_x_alpha[0..(2*n+1)].iter().rev() - // .chain_ext(srs.g_positive_x_alpha[0..(2*n+1)].iter()), - // t_polynomial[0..(2*n+1)].iter() - // .chain_ext(t_polynomial[(2*n+2)..].iter())).into_affine(); - - // self.t_polynomial = Some(t_polynomial); - - // c - // } - - - // // Argument is based on an approach of main SONIC construction, but with a custom S(X,Y) polynomial of a simple form - // pub fn make_argument(self, a_zy: & Vec, challenges: & Vec, y: E::Fr, z: E::Fr, srs: &SRS) -> GrandProductProof { - // assert_eq!(a_zy.len(), self.a_polynomials.len()); - // assert_eq!(challenges.len(), self.a_polynomials.len()); - - // let n = self.n; - - // let c_polynomials = self.c_polynomials; - // let mut e_polynomial: Option> = None; - // let mut f_polynomial: Option> = None; - - // let mut yz = y; - // yz.mul_assign(&z); - - // let z_inv = z.inverse().unwrap(); - - // for (((a, c), challenge), v) in a_zy.iter() - // .zip(c_polynomials.into_iter()) - // .zip(challenges.iter()) - // .zip(self.v_elements.iter()) - // { - // // cj = ((aj + vj(yz)n+1)y + zn+2 + zn+1y − z2n+2y)z−1 - // let mut c_zy = yz.pow([(n + 1) as u64]); - // c_zy.mul_assign(v); - // c_zy.add_assign(a); - // c_zy.mul_assign(&y); - - // let mut z_n_plus_1 = z.pow([(n + 1) as u64]); - - // let mut z_n_plus_2 = z_n_plus_1; - // z_n_plus_2.mul_assign(&z); - - // let mut z_2n_plus_2 = z_n_plus_1; - // z_2n_plus_2.square(); - // z_2n_plus_2.mul_assign(&y); - - // z_n_plus_1.mul_assign(&y); - - // c_zy.add_assign(&z_n_plus_1); - // c_zy.add_assign(&z_n_plus_2); - // c_zy.sub_assign(&z_2n_plus_2); - - // c_zy.mul_assign(&z_inv); - - // let mut rc = c_zy; - // rc.mul_assign(challenge); - - // let mut ry = y; - // ry.mul_assign(challenge); - - // if e_polynomial.is_some() && f_polynomial.is_some() { - // if let Some(e_poly) = e_polynomial.as_mut() { - // if let Some(f_poly) = f_polynomial.as_mut() { - // mul_add_polynomials(&mut e_poly[..], &c, rc); - // mul_add_polynomials(&mut f_poly[..], &c, ry); - // } - // } - // } else { - // let mut e = c.clone(); - // let mut f = c; - // mul_polynomial_by_scalar(&mut e, rc); - // mul_polynomial_by_scalar(&mut f, ry); - // e_polynomial = Some(e); - // f_polynomial = Some(f); - // } - // } - - // let e_polynomial = e_polynomial.unwrap(); - // let f_polynomial = f_polynomial.unwrap(); - - // // evaluate e at z^-1 - - // let mut e_val = evaluate_at_consequitive_powers(&e_polynomial, z_inv, z_inv); - // e_val.negate(); - - // // evaluate f at y - - // let mut f_val = evaluate_at_consequitive_powers(&f_polynomial, y, y); - // f_val.negate(); - - // let e_opening = polynomial_commitment_opening( - // 0, - // 2*n + 1, - // Some(e_val).iter().chain_ext(e_polynomial.iter()), - // z_inv, - // srs); - - // let f_opening = polynomial_commitment_opening( - // 0, - // 2*n + 1, - // Some(f_val).iter().chain_ext(f_polynomial.iter()), - // y, - // srs); - - // e_val.negate(); - // f_val.negate(); - - // let mut t_poly = self.t_polynomial.unwrap(); - // assert_eq!(t_poly.len(), 4*n + 3); - - // // largest negative power of t is -2n-1 - // let t_zy = { - // let tmp = z_inv.pow([(2*n+1) as u64]); - // evaluate_at_consequitive_powers(&t_poly, tmp, z) - // }; - - // t_poly[2*n + 1].sub_assign(&t_zy); - - // let t_opening = polynomial_commitment_opening( - // 2*n + 1, - // 2*n + 1, - // t_poly.iter(), - // z, - // srs); - - // GrandProductProof { - // t_opening: t_opening, - // e_zinv: e_val, - // e_opening: e_opening, - // f_y: f_val, - // f_opening: f_opening, - // } - // } - - pub fn verify_s_prime_commitment(n: usize, + // Argument a permutation argument. Current implementation consumes, cause extra arguments are required + pub fn make_argument(self, + beta: E::Fr, + gamma: E::Fr, + grand_product_challenges: & Vec, + wellformed_challenges: & Vec, + y: E::Fr, + z: E::Fr, + specialized_srs: &SpecializedSRS, + srs: &SRS + ) -> Proof { + // 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 + + let n = self.n; + let j = self.non_permuted_coefficients.len(); + assert_eq!(j, grand_product_challenges.len()); + assert_eq!(2*j, wellformed_challenges.len()); + + let mut s_polynomial: Option> = None; + + for c in self.permuted_at_y_coefficients.iter() + { + if s_polynomial.is_some() { + if let Some(poly) = s_polynomial.as_mut() { + add_polynomials(&mut poly[..], & c[..]); + } + } else { + s_polynomial = Some(c.clone()); + } + } + let mut s_polynomial = s_polynomial.unwrap(); + // evaluate at z + let s_zy = evaluate_at_consequitive_powers(& s_polynomial[..], z, z); + + let mut s_zy_neg = s_zy; + s_zy_neg.negate(); + + let s_zy_opening = polynomial_commitment_opening( + 0, + n, + Some(s_zy_neg).iter().chain_ext(s_polynomial.iter()), + z, + &srs + ); + + // Sj(P4j)^β (P1j)^γ is equal to the product of the coefficients of Sj′(P3j)^β (P1j)^γ + + let p_1_values = vec![E::Fr::one(); n]; + let p_3_values: Vec = (1..=n).map(|el| { + let mut repr = <::Fr as PrimeField>::Repr::default(); + repr.as_mut()[0] = el as u64; + let fe = E::Fr::from_repr(repr).unwrap(); + + fe + }).collect(); + + let mut grand_products = vec![]; + + for (i, ((non_permuted, permuted), permutation)) in self.non_permuted_coefficients.into_iter() + .zip(self.permuted_coefficients.into_iter()) + .zip(self.permutations.into_iter()).enumerate() + + { + // \prod si+βσi+γ = \prod s'i + β*i + γ + let mut s_j_combination = non_permuted; + { + let p_4_values: Vec = permutation.into_iter().map(|el| { + let mut repr = <::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_j_combination[..], & p_4_values[..], beta); + mul_add_polynomials(&mut s_j_combination[..], & p_1_values[..], gamma); + } + + let mut s_prime_j_combination = permuted; + { + mul_add_polynomials(&mut s_prime_j_combination[..], & p_3_values[..], beta); + mul_add_polynomials(&mut s_prime_j_combination[..], & p_1_values[..], gamma); + } + + grand_products.push((s_j_combination, s_prime_j_combination)); + } + + let mut a_commitments = vec![]; + let mut b_commitments = vec![]; + + for (a, b) in grand_products.iter() { + let (c_a, c_b) = GrandProductArgument::commit_for_individual_products(& a[..], & b[..], &srs); + a_commitments.push(c_a); + b_commitments.push(c_b); + } + + { + let mut all_polys = vec![]; + for p in grand_products.iter() { + let (a, b) = p; + all_polys.push(a.clone()); + all_polys.push(b.clone()); + } + + let wellformed_argument = WellformednessArgument::new(all_polys); + let commitments = wellformed_argument.commit(&srs); + let proof = wellformed_argument.make_argument(wellformed_challenges.clone(), &srs); + let valid = WellformednessArgument::verify(n, &wellformed_challenges, &commitments, &proof, &srs); + + assert!(valid, "wellformedness argument must be valid"); + } + + let mut grand_product_argument = GrandProductArgument::new(grand_products); + let c_commitments = grand_product_argument.commit_to_individual_c_polynomials(&srs); + let t_commitment = grand_product_argument.commit_to_t_polynomial(&grand_product_challenges, y, &srs); + let grand_product_openings = grand_product_argument.open_commitments_for_grand_product(y, z, &srs); + let a_zy: Vec = grand_product_openings.iter().map(|el| el.0.clone()).collect(); + let proof = grand_product_argument.make_argument(&a_zy, &grand_product_challenges, y, z, &srs); + + { + use rand::{XorShiftRng, SeedableRng, Rand, Rng}; + let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let randomness = (0..j).map(|_| E::Fr::rand(rng)).collect::>(); + + let valid = GrandProductArgument::verify_ab_commitment(n, + &randomness, + &a_commitments, + & b_commitments, + &grand_product_openings, + y, + z, + &srs); + assert!(valid, "ab part of grand product argument must be valid"); + + let randomness = (0..3).map(|_| E::Fr::rand(rng)).collect::>(); + let valid = GrandProductArgument::verify(n, + &randomness, + &a_zy, + &grand_product_challenges, + t_commitment, + &c_commitments, + &proof, + y, + z, + &srs); + + assert!(valid, "grand product argument must be valid"); + } + + Proof { + j: j, + s_opening: s_zy_opening, + s_zy: s_zy + } + } + + pub fn verify_s_prime_commitment( + n: usize, randomness: & Vec, challenges: & Vec, commitments: &Vec, @@ -477,6 +394,82 @@ impl PermutationArgument { assert_eq!(randomness.len(), 2); assert_eq!(challenges.len(), commitments.len()); + // 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_prep = srs.h_positive_x[0]; + // h_prep.negate(); + // let h_prep = h_prep.prepare(); + + // let value = proof.v_zy; + // let g_v = g.mul(value.into_repr()); + + // { + + // let mut minus_z_prime = z_prime; + // minus_z_prime.negate(); + + // let e_z = proof.e_opening.mul(minus_z_prime.into_repr()); + + // let mut h_alpha_term = e_z; + + // h_alpha_term.add_assign(&g_v); + + // let h_alpha_x_term = proof.e_opening; + + // let s_r = multiexp( + // commitments.iter(), + // challenges.iter() + // ).into_affine(); + + // let h_term = s_r; + + // let valid = E::final_exponentiation(&E::miller_loop(&[ + // (&h_alpha_x_term.prepare(), &h_alpha_x_precomp), + // (&h_alpha_term.into_affine().prepare(), &h_alpha_precomp), + // (&h_term.prepare(), &h_prep), + // ])).unwrap() == E::Fqk::one(); + + // if !valid { + // return false; + // } + // } + // { + // let mut minus_yz = z_prime; + // minus_yz.mul_assign(&y); + // minus_yz.negate(); + + // let f_yz = proof.f_opening.mul(minus_yz.into_repr()); + + // let p2_r = multiexp( + // specialized_srs.p_2.iter(), + // challenges.iter() + // ).into_affine(); + + // let mut h_alpha_term = f_yz; + + // h_alpha_term.add_assign(&g_v); + + // let h_alpha_x_term = proof.f_opening; + + // let h_term = p2_r; + + // let valid = E::final_exponentiation(&E::miller_loop(&[ + // (&h_alpha_x_term.prepare(), &h_alpha_x_precomp), + // (&h_alpha_term.into_affine().prepare(), &h_alpha_precomp), + // (&h_term.prepare(), &h_prep), + // ])).unwrap() == E::Fqk::one(); + + // if !valid { + // return false; + // } + // } + + // true + // e(E,hαx)e(E−z′,hα) = e(􏰗Mj=1Sj′rj,h)e(g−v,hα) // e(F,hαx)e(F−yz′,hα) = e(􏰗Mj=1P2jrj,h)e(g−v,hα) @@ -545,217 +538,129 @@ impl PermutationArgument { ])).unwrap() == E::Fqk::one() } - // pub fn verify( - // n: usize, - // randomness: & Vec, - // a_zy: & Vec, - // challenges: &Vec, - // t_commitment: E::G1Affine, - // commitments: &Vec<(E::G1Affine, E::Fr)>, - // proof: &GrandProductProof, - // y: E::Fr, - // z: E::Fr, - // srs: &SRS - // ) -> bool { - // assert_eq!(randomness.len(), 3); - // assert_eq!(a_zy.len(), challenges.len()); - // assert_eq!(commitments.len(), challenges.len()); + pub fn verify( + s_commitments: &Vec, + proof: &Proof, + z: E::Fr, + srs: &SRS + ) -> bool { - // 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(); + let h_alpha_precomp = srs.h_positive_x_alpha[0].prepare(); - // let h_alpha_precomp = srs.h_positive_x_alpha[0].prepare(); + let mut h_prep = srs.h_positive_x[0]; + h_prep.negate(); + let h_prep = h_prep.prepare(); - // let mut h_prep = srs.h_positive_x[0]; - // h_prep.negate(); - // let h_prep = h_prep.prepare(); + let mut minus_z = z; + minus_z.negate(); - // // first re-calculate cj and t(z,y) + let opening_z = proof.s_opening.mul(minus_z.into_repr()); - // let mut yz = y; - // yz.mul_assign(&z); + let mut h_alpha_term = opening_z; + let g_s = g.mul(proof.s_zy.into_repr()); - // let z_inv = z.inverse().unwrap(); + h_alpha_term.add_assign(&g_s); - // let mut t_zy = E::Fr::zero(); - // t_zy.add_assign(&proof.e_zinv); - // t_zy.sub_assign(&proof.f_y); + let h_alpha_x_term = proof.s_opening; - // let mut commitments_points = vec![]; - // let mut rc_vec = vec![]; - // let mut ry_vec = vec![]; + let mut s = E::G1::zero(); + for p in s_commitments { + s.add_assign_mixed(&p); + } - // for ((r, commitment), a) in challenges.iter() - // .zip(commitments.iter()) - // .zip(a_zy.iter()) { - // let (c, v) = commitment; - // commitments_points.push(c.clone()); - - // // cj = ((aj + vj(yz)n+1)y + zn+2 + zn+1y − z2n+2y)z−1 - // let mut c_zy = yz.pow([(n + 1) as u64]); - // c_zy.mul_assign(v); - // c_zy.add_assign(a); - // c_zy.mul_assign(&y); + let h_term = s.into_affine(); - // let mut z_n_plus_1 = z.pow([(n + 1) as u64]); - - // let mut z_n_plus_2 = z_n_plus_1; - // z_n_plus_2.mul_assign(&z); - - // let mut z_2n_plus_2 = z_n_plus_1; - // z_2n_plus_2.square(); - // z_2n_plus_2.mul_assign(&y); - - // z_n_plus_1.mul_assign(&y); - - // c_zy.add_assign(&z_n_plus_1); - // c_zy.add_assign(&z_n_plus_2); - // c_zy.sub_assign(&z_2n_plus_2); - - // c_zy.mul_assign(&z_inv); - - // let mut rc = c_zy; - // rc.mul_assign(&r); - // rc_vec.push(rc); - - // let mut ry = y; - // ry.mul_assign(&r); - // ry_vec.push(ry); - - // let mut val = rc; - // val.sub_assign(r); - // t_zy.add_assign(&val); - // } - - // let c_rc = multiexp( - // commitments_points.iter(), - // rc_vec.iter(), - // ).into_affine(); - - // let c_ry = multiexp( - // commitments_points.iter(), - // ry_vec.iter(), - // ).into_affine(); - - // let mut minus_y = y; - // minus_y.negate(); - - // let mut f_y = proof.f_opening.mul(minus_y.into_repr()); - // let g_f = g.mul(proof.f_y.into_repr()); - // f_y.add_assign(&g_f); - - // let mut minus_z = z; - // minus_z.negate(); - - // let mut t_z = proof.t_opening.mul(minus_z.into_repr()); - // let g_tzy = g.mul(t_zy.into_repr()); - // t_z.add_assign(&g_tzy); - - // let mut minus_z_inv = z_inv; - // minus_z_inv.negate(); - - // let mut e_z_inv = proof.e_opening.mul(minus_z_inv.into_repr()); - // let g_e = g.mul(proof.e_zinv.into_repr()); - // e_z_inv.add_assign(&g_e); - - // let h_alpha_term = multiexp( - // vec![e_z_inv.into_affine(), f_y.into_affine(), t_z.into_affine()].iter(), - // randomness.iter(), - // ).into_affine(); - - // let h_alpha_x_term = multiexp( - // Some(proof.e_opening).iter() - // .chain_ext(Some(proof.f_opening).iter()) - // .chain_ext(Some(proof.t_opening).iter()), - // randomness.iter(), - // ).into_affine(); - - - // let h_term = multiexp( - // Some(c_rc).iter() - // .chain_ext(Some(c_ry).iter()) - // .chain_ext(Some(t_commitment).iter()), - // randomness.iter(), - // ).into_affine(); - - // E::final_exponentiation(&E::miller_loop(&[ - // (&h_alpha_x_term.prepare(), &h_alpha_x_precomp), - // (&h_alpha_term.prepare(), &h_alpha_precomp), - // (&h_term.prepare(), &h_prep), - // ])).unwrap() == E::Fqk::one() - - // } + E::final_exponentiation(&E::miller_loop(&[ + (&h_alpha_x_term.prepare(), &h_alpha_x_precomp), + (&h_alpha_term.into_affine().prepare(), &h_alpha_precomp), + (&h_term.prepare(), &h_prep), + ])).unwrap() == E::Fqk::one() + } } -// #[test] -// fn test_grand_product_argument() { -// use pairing::bls12_381::{Fr, G1Affine, G1, Bls12}; -// use rand::{XorShiftRng, SeedableRng, Rand, Rng}; -// use crate::sonic::srs::SRS; +#[test] +fn test_permutation_argument() { + use pairing::bls12_381::{Fr, G1Affine, G1, Bls12}; + use rand::{XorShiftRng, SeedableRng, Rand, Rng}; + use crate::sonic::srs::SRS; -// let srs_x = Fr::from_str("23923").unwrap(); -// let srs_alpha = Fr::from_str("23728792").unwrap(); -// let srs = SRS::::dummy(830564, srs_x, srs_alpha); + let srs_x = Fr::from_str("23923").unwrap(); + let srs_alpha = Fr::from_str("23728792").unwrap(); + let srs = SRS::::dummy(830564, srs_x, srs_alpha); -// let n: usize = 1 << 8; -// let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); -// let coeffs = (0..n).map(|_| Fr::rand(rng)).collect::>(); -// let mut permutation = coeffs.clone(); -// rng.shuffle(&mut permutation); + let n: usize = 1 << 1; + let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + // let coeffs = (0..n).map(|_| Fr::rand(rng)).collect::>(); + // let mut permutation = (0..n).collect::>(); + // rng.shuffle(&mut permutation); -// let a_commitment = multiexp(srs.g_positive_x_alpha[0..n].iter(), coeffs.iter()).into_affine(); -// let b_commitment = multiexp(srs.g_positive_x_alpha[0..n].iter(), permutation.iter()).into_affine(); + let coeffs = vec![Fr::from_str("3").unwrap(), Fr::from_str("4").unwrap()]; + let permutation = vec![2, 1]; -// let mut argument = GrandProductArgument::new(vec![(coeffs, permutation)]); + let coeffs = vec![coeffs]; + let permutations = vec![permutation]; -// let commitments_and_v_values = argument.commit_to_individual_c_polynomials(&srs); + let specialized_srs = PermutationArgument::make_specialized_srs(&coeffs, &permutations, &srs); -// assert_eq!(commitments_and_v_values.len(), 1); + let mut argument = PermutationArgument::new(coeffs, permutations); -// let y : Fr = rng.gen(); + let y : Fr = rng.gen(); + let y : Fr = Fr::one(); + let y : Fr = Fr::from_str("2").unwrap(); -// let challenges = (0..1).map(|_| Fr::rand(rng)).collect::>(); + // let challenges = (0..1).map(|_| Fr::rand(rng)).collect::>(); -// let t_commitment = argument.commit_to_t_polynomial(&challenges, y, &srs); + let challenges = vec![Fr::one()]; -// let z : Fr = rng.gen(); + 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() { + s_commitments.push(s); + s_prime_commitments.push(s_prime); + } -// let grand_product_openings = argument.open_commitments_for_grand_product(y, z, &srs); + let z_prime : Fr = rng.gen(); + let z_prime : Fr = Fr::one(); -// let randomness = (0..1).map(|_| Fr::rand(rng)).collect::>(); + let opening = argument.open_commitments_to_s_prime(&challenges, y, z_prime, &srs); -// let valid = GrandProductArgument::verify_ab_commitment(n, -// &randomness, -// &vec![a_commitment], -// &vec![b_commitment], -// &grand_product_openings, -// y, -// z, -// &srs); + let randomness = (0..2).map(|_| Fr::rand(rng)).collect::>(); -// assert!(valid, "grand product commitments should be valid"); + let valid = PermutationArgument::verify_s_prime_commitment(n, + &randomness, + &challenges, + &s_prime_commitments, + &opening, + y, + z_prime, + &specialized_srs, + &srs); -// let a_zy: Vec = grand_product_openings.iter().map(|el| el.0.clone()).collect(); + assert!(valid, "s' commitment must be valid"); -// let proof = argument.make_argument(&a_zy, &challenges, y, z, &srs); + let beta : Fr = rng.gen(); + let gamma : Fr = rng.gen(); -// let randomness = (0..3).map(|_| Fr::rand(rng)).collect::>(); + let grand_product_challenges = (0..1).map(|_| Fr::rand(rng)).collect::>(); + let wellformed_challenges = (0..2).map(|_| Fr::rand(rng)).collect::>(); -// let valid = GrandProductArgument::verify( -// n, -// &randomness, -// &a_zy, -// &challenges, -// t_commitment, -// &commitments_and_v_values, -// &proof, -// y, -// z, -// &srs); + let z : Fr = rng.gen(); -// assert!(valid, "t commitment should be valid"); -// } + let proof = argument.make_argument( + beta, + gamma, + & grand_product_challenges, + & wellformed_challenges, + y, z, + &specialized_srs, &srs); + + let valid = PermutationArgument::verify(&s_commitments, &proof, z, &srs); + + assert!(valid, "permutation argument must be valid"); +} diff --git a/src/sonic/unhelped/wellformed_argument.rs b/src/sonic/unhelped/wellformed_argument.rs index 4eb38a0..5e707f1 100644 --- a/src/sonic/unhelped/wellformed_argument.rs +++ b/src/sonic/unhelped/wellformed_argument.rs @@ -52,6 +52,7 @@ impl WellformednessArgument { } pub fn make_argument(self, challenges: Vec, srs: &SRS) -> WellformednessProof { + assert_eq!(challenges.len(), self.polynomials.len()); let mut polynomials = self.polynomials; let mut challenges = challenges; @@ -165,7 +166,7 @@ fn test_argument_soundness() { let srs_alpha = Fr::from_str("23728792").unwrap(); let srs = SRS::::dummy(830564, srs_x, srs_alpha); - let n: usize = 1 << 16; + let n: usize = 1 << 8; let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); let coeffs = (0..n).map(|_| Fr::rand(rng)).collect::>();