From f93f0db4d15b8e7dc00be9d18d682bae25d119df Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 18:04:47 +0000 Subject: [PATCH 001/242] Add chunked Lagrange_basis_evaluations --- kimchi/src/lagrange_basis_evaluations.rs | 124 +++++++++++++++++------ kimchi/src/prover.rs | 14 +-- 2 files changed, 103 insertions(+), 35 deletions(-) diff --git a/kimchi/src/lagrange_basis_evaluations.rs b/kimchi/src/lagrange_basis_evaluations.rs index 157fb5af2a..a2393b610b 100644 --- a/kimchi/src/lagrange_basis_evaluations.rs +++ b/kimchi/src/lagrange_basis_evaluations.rs @@ -5,39 +5,49 @@ use rayon::prelude::*; /// The evaluations of all normalized lagrange basis polynomials at a given /// point. Can be used to evaluate an `Evaluations` form polynomial at that point. pub struct LagrangeBasisEvaluations { - pub evals: Vec, + evals: Vec>, } impl LagrangeBasisEvaluations { /// Given the evaluations form of a polynomial, directly evaluate that polynomial at a point. - pub fn evaluate>(&self, p: &Evaluations) -> F { - assert_eq!(p.evals.len() % self.evals.len(), 0); - let stride = p.evals.len() / self.evals.len(); + pub fn evaluate>(&self, p: &Evaluations) -> Vec { + assert_eq!(p.evals.len() % self.evals[0].len(), 0); + let stride = p.evals.len() / self.evals[0].len(); let p_evals = &p.evals; (&self.evals) .into_par_iter() - .enumerate() - .map(|(i, e)| p_evals[stride * i] * e) - .sum() + .map(|evals| { + evals + .into_par_iter() + .enumerate() + .map(|(i, e)| p_evals[stride * i] * e) + .sum() + }) + .collect() } /// Given the evaluations form of a polynomial, directly evaluate that polynomial at a point, /// assuming that the given evaluations are either 0 or 1 at every point of the domain. - pub fn evaluate_boolean>(&self, p: &Evaluations) -> F { - assert_eq!(p.evals.len() % self.evals.len(), 0); - let stride = p.evals.len() / self.evals.len(); - let mut result = F::zero(); - for (i, e) in self.evals.iter().enumerate() { - if !p.evals[stride * i].is_zero() { - result += e; - } - } - result + pub fn evaluate_boolean>(&self, p: &Evaluations) -> Vec { + assert_eq!(p.evals.len() % self.evals[0].len(), 0); + let stride = p.evals.len() / self.evals[0].len(); + self.evals + .iter() + .map(|evals| { + let mut result = F::zero(); + for (i, e) in evals.iter().enumerate() { + if !p.evals[stride * i].is_zero() { + result += e; + } + } + result + }) + .collect() } /// Compute all evaluations of the normalized lagrange basis polynomials of the /// given domain at the given point. Runs in time O(domain size). - pub fn new(domain: D, x: F) -> LagrangeBasisEvaluations { + fn new_with_segment_size_1(domain: D, x: F) -> LagrangeBasisEvaluations { let n = domain.size(); // We want to compute for all i // s_i = 1 / t_i @@ -98,7 +108,38 @@ impl LagrangeBasisEvaluations { // Denominators now contains the desired result. LagrangeBasisEvaluations { - evals: denominators, + evals: vec![denominators], + } + } + + /// Compute all evaluations of the normalized lagrange basis polynomials of the + /// given domain at the given point. Runs in time O(domain size). + fn new_with_chunked_segments( + max_poly_size: usize, + domain: D, + x: F, + ) -> LagrangeBasisEvaluations { + let n = domain.size(); + let num_chunks = n / max_poly_size; + let mut evals = Vec::with_capacity(num_chunks); + let mut x_pow = F::one(); + for i in 0..num_chunks { + let mut chunked_evals = vec![F::zero(); n]; + for j in 0..max_poly_size { + chunked_evals[i * max_poly_size + j] = x_pow; + x_pow *= x; + } + domain.ifft_in_place(&mut chunked_evals); + evals.push(chunked_evals); + } + LagrangeBasisEvaluations { evals } + } + + pub fn new(max_poly_size: usize, domain: D, x: F) -> LagrangeBasisEvaluations { + if domain.size() == max_poly_size { + Self::new_with_segment_size_1(domain, x) + } else { + Self::new_with_chunked_segments(max_poly_size, domain, x) } } } @@ -118,19 +159,44 @@ mod tests { let domain = Radix2EvaluationDomain::new(n).unwrap(); let rng = &mut StdRng::from_seed([0u8; 32]); let x = Fp::rand(rng); - let evaluator = LagrangeBasisEvaluations::new(domain, x); + let evaluator = LagrangeBasisEvaluations::new(domain.size(), domain, x); let expected = (0..n).map(|i| { let mut lagrange_i = vec![Fp::zero(); n]; lagrange_i[i] = Fp::one(); - Evaluations::from_vec_and_domain(lagrange_i, domain) + vec![Evaluations::from_vec_and_domain(lagrange_i, domain) .interpolate() - .evaluate(&x) + .evaluate(&x)] }); - for (i, expected) in expected.enumerate() { - if evaluator.evals[i] != expected { - panic!("{}, {}: {} != {}", line!(), i, evaluator.evals[i], expected); + for (i, (expected, got)) in expected.zip(evaluator.evals).enumerate() { + for (j, (expected, got)) in expected.iter().zip(got.iter()).enumerate() { + if got != expected { + panic!("{}, {}, {}: {} != {}", line!(), i, j, got, expected); + } + } + } + } + + #[test] + fn test_new_with_chunked_segments() { + let n = 1 << 4; + let domain = Radix2EvaluationDomain::new(n).unwrap(); + let rng = &mut StdRng::from_seed([0u8; 32]); + let x = Fp::rand(rng); + let evaluator = LagrangeBasisEvaluations::new(domain.size(), domain, x); + let evaluator_chunked = + LagrangeBasisEvaluations::new_with_chunked_segments(domain.size(), domain, x); + for (i, (evals, evals_chunked)) in evaluator + .evals + .iter() + .zip(evaluator_chunked.evals.iter()) + .enumerate() + { + for (j, (evals, evals_chunked)) in evals.iter().zip(evals_chunked.iter()).enumerate() { + if evals != evals_chunked { + panic!("{}, {}, {}: {} != {}", line!(), i, j, evals, evals_chunked); + } } } } @@ -151,10 +217,10 @@ mod tests { let x = Fp::rand(rng); - let evaluator = LagrangeBasisEvaluations::new(domain, x); + let evaluator = LagrangeBasisEvaluations::new(domain.size(), domain, x); let y = evaluator.evaluate(&evals); - let expected = evals.interpolate().evaluate(&x); + let expected = vec![evals.interpolate().evaluate(&x)]; assert_eq!(y, expected) } @@ -179,10 +245,10 @@ mod tests { let x = Fp::rand(rng); - let evaluator = LagrangeBasisEvaluations::new(domain, x); + let evaluator = LagrangeBasisEvaluations::new(domain.size(), domain, x); let y = evaluator.evaluate_boolean(&evals); - let expected = evals.interpolate().evaluate(&x); + let expected = vec![evals.interpolate().evaluate(&x)]; assert_eq!(y, expected) } } diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 9ff74d8f20..8c1d6f5a6b 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -907,19 +907,21 @@ where //~ //~ TODO: do we want to specify more on that? It seems unecessary except for the t polynomial (or if for some reason someone sets that to a low value) - let zeta_evals = LagrangeBasisEvaluations::new(index.cs.domain.d1, zeta); - let zeta_omega_evals = LagrangeBasisEvaluations::new(index.cs.domain.d1, zeta_omega); + let zeta_evals = + LagrangeBasisEvaluations::new(index.max_poly_size, index.cs.domain.d1, zeta); + let zeta_omega_evals = + LagrangeBasisEvaluations::new(index.max_poly_size, index.cs.domain.d1, zeta_omega); let chunked_evals_for_selector = |p: &Evaluations>| PointEvaluations { - zeta: vec![zeta_evals.evaluate_boolean(p)], - zeta_omega: vec![zeta_omega_evals.evaluate_boolean(p)], + zeta: zeta_evals.evaluate_boolean(p), + zeta_omega: zeta_omega_evals.evaluate_boolean(p), }; let chunked_evals_for_evaluations = |p: &Evaluations>| PointEvaluations { - zeta: vec![zeta_evals.evaluate(p)], - zeta_omega: vec![zeta_omega_evals.evaluate(p)], + zeta: zeta_evals.evaluate(p), + zeta_omega: zeta_omega_evals.evaluate(p), }; let chunked_evals = ProofEvaluations::>> { From 95ebf04675492b64c792b8ccfe929402af6b204f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 18:42:38 +0000 Subject: [PATCH 002/242] Carry public polynomials in the proof --- book/src/specs/kimchi.md | 6 ++-- kimchi/src/oracles.rs | 7 +---- kimchi/src/plonk_sponge.rs | 3 +- kimchi/src/proof.rs | 11 ++++++++ kimchi/src/prover.rs | 19 +++++-------- kimchi/src/verifier.rs | 56 ++++++++++---------------------------- 6 files changed, 38 insertions(+), 64 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 1852146616..e0e24f1c6e 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1954,6 +1954,8 @@ pub struct LookupEvaluations { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProofEvaluations { + /// public input polynomials + pub public: Evals, /// witness polynomials pub w: [Evals; COLUMNS], /// permutation polynomial @@ -2170,7 +2172,6 @@ The prover then follows the following steps to create the proof: 1. Squeeze the Fq-sponge and absorb the result with the Fr-Sponge. 1. Absorb the previous recursion challenges. 1. Compute evaluations for the previous recursion challenges. -1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. 1. Absorb all the polynomial evaluations in $\zeta$ and $\zeta\omega$: * the public polynomial @@ -2240,9 +2241,6 @@ We run the following algorithm: 1. Squeeze the Fq-sponge and absorb the result with the Fr-Sponge. 1. Absorb the previous recursion challenges. 1. Compute evaluations for the previous recursion challenges. -1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. - - NOTE: this works only in the case when the poly segment size is not smaller than that of the domain. 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. 1. Absorb all the polynomial evaluations in $\zeta$ and $\zeta\omega$: * the public polynomial diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index aaa91e186d..7d7c222547 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -20,8 +20,6 @@ where pub oracles: RandomOracles, /// the computed powers of alpha pub all_alphas: Alphas, - /// public polynomial evaluations - pub public_evals: [Vec; 2], /// zeta^n and (zeta * omega)^n pub powers_of_eval_points_for_chunks: PointEvaluations, /// recursion data @@ -50,7 +48,6 @@ pub mod caml { #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)] pub struct CamlOracles { pub o: CamlRandomOracles, - pub public_evals: (CamlF, CamlF), pub opening_prechallenges: Vec, pub digest_before_evaluations: CamlF, } @@ -78,10 +75,9 @@ pub mod caml { let oracles_result = proof.oracles::(&index, &p_comm, public_input)?; - let (mut sponge, combined_inner_product, public_evals, digest, oracles) = ( + let (mut sponge, combined_inner_product, digest, oracles) = ( oracles_result.fq_sponge, oracles_result.combined_inner_product, - oracles_result.public_evals, oracles_result.digest, oracles_result.oracles, ); @@ -97,7 +93,6 @@ pub mod caml { Ok(CamlOracles { o: oracles.into(), - public_evals: (public_evals[0][0].into(), public_evals[1][0].into()), opening_prechallenges, digest_before_evaluations: digest.into(), }) diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index da54379f4d..255d98e8db 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -60,6 +60,7 @@ impl FrSponge for DefaultFrSponge { self.last_squeezed = vec![]; let ProofEvaluations { + public, w, z, s, @@ -69,7 +70,7 @@ impl FrSponge for DefaultFrSponge { poseidon_selector, } = e; - let mut points = vec![z, generic_selector, poseidon_selector]; + let mut points = vec![public, z, generic_selector, poseidon_selector]; w.iter().for_each(|w_i| points.push(w_i)); coefficients.iter().for_each(|c_i| points.push(c_i)); s.iter().for_each(|s_i| points.push(s_i)); diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index d335a5bfed..235072cc13 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -61,6 +61,8 @@ pub struct LookupEvaluations { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProofEvaluations { + /// public input polynomials + pub public: Evals, /// witness polynomials pub w: [Evals; COLUMNS], /// permutation polynomial @@ -198,6 +200,7 @@ impl LookupEvaluations { impl ProofEvaluations { pub fn map Eval2>(self, f: &FN) -> ProofEvaluations { let ProofEvaluations { + public, w, z, s, @@ -207,6 +210,7 @@ impl ProofEvaluations { poseidon_selector, } = self; ProofEvaluations { + public: f(public), w: w.map(f), z: f(z), s: s.map(f), @@ -219,6 +223,7 @@ impl ProofEvaluations { pub fn map_ref Eval2>(&self, f: &FN) -> ProofEvaluations { let ProofEvaluations { + public, w: [w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14], z, s: [s0, s1, s2, s3, s4, s5], @@ -228,6 +233,7 @@ impl ProofEvaluations { poseidon_selector, } = self; ProofEvaluations { + public: f(public), w: [ f(w0), f(w1), @@ -289,6 +295,7 @@ impl ProofEvaluations { ProofEvaluations { generic_selector: array::from_fn(|i| &evals[i].generic_selector), poseidon_selector: array::from_fn(|i| &evals[i].poseidon_selector), + public: array::from_fn(|i| &evals[i].public), z: array::from_fn(|i| &evals[i].z), w: array::from_fn(|j| array::from_fn(|i| &evals[i].w[j])), s: array::from_fn(|j| array::from_fn(|i| &evals[i].s[j])), @@ -373,6 +380,7 @@ impl ProofEvaluations> { zeta_omega: next, }; ProofEvaluations { + public: pt(F::zero(), F::zero()), w: array::from_fn(|i| pt(curr[i], next[i])), z: pt(F::zero(), F::zero()), s: array::from_fn(|_| pt(F::zero(), F::zero())), @@ -523,6 +531,7 @@ pub mod caml { #[allow(clippy::type_complexity)] #[derive(Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)] pub struct CamlProofEvaluations { + pub public: PointEvaluations>, pub w: ( PointEvaluations>, PointEvaluations>, @@ -698,6 +707,7 @@ pub mod caml { ); Self { + public: pe.public.map(&|x| x.into_iter().map(Into::into).collect()), w, coefficients, z: pe.z.map(&|x| x.into_iter().map(Into::into).collect()), @@ -793,6 +803,7 @@ pub mod caml { ]; Self { + public: cpe.public.map(&|x| x.into_iter().map(Into::into).collect()), w, coefficients, z: cpe.z.map(&|x| x.into_iter().map(Into::into).collect()), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 8c1d6f5a6b..b33e6e977b 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -925,6 +925,13 @@ where }; let chunked_evals = ProofEvaluations::>> { + public: { + let chunked = public_poly.to_chunked_polynomial(index.max_poly_size); + PointEvaluations { + zeta: chunked.evaluate_chunks(zeta), + zeta_omega: chunked.evaluate_chunks(zeta_omega), + } + }, s: array::from_fn(|i| { chunked_evals_for_evaluations( &index.column_evaluations.permutation_coefficients8[i], @@ -1055,16 +1062,6 @@ where }) .collect::>(); - //~ 1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. - let public_evals = if public_poly.is_zero() { - [vec![G::ScalarField::zero()], vec![G::ScalarField::zero()]] - } else { - [ - vec![public_poly.evaluate(&zeta)], - vec![public_poly.evaluate(&zeta_omega)], - ] - }; - //~ 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. fr_sponge.absorb(&ft_eval1); @@ -1075,8 +1072,6 @@ where //~~ * poseidon selector //~~ * the 15 register/witness //~~ * 6 sigmas evaluations (the last one is not evaluated) - fr_sponge.absorb_multiple(&public_evals[0]); - fr_sponge.absorb_multiple(&public_evals[1]); fr_sponge.absorb_evaluations(&chunked_evals); //~ 1. Sample $v'$ with the Fr-Sponge diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index c58fb2a50e..f92198fd3c 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -287,36 +287,6 @@ where ark_ff::fields::batch_inversion::(&mut zeta_minus_x); - //~ 1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. - //~ - //~ NOTE: this works only in the case when the poly segment size is not smaller than that of the domain. - let public_evals = if public_input.is_empty() { - [vec![G::ScalarField::zero()], vec![G::ScalarField::zero()]] - } else { - [ - vec![ - (public_input - .iter() - .zip(zeta_minus_x.iter()) - .zip(index.domain.elements()) - .map(|((p, l), w)| -*l * p * w) - .fold(G::ScalarField::zero(), |x, y| x + y)) - * (zeta1 - G::ScalarField::one()) - * index.domain.size_inv, - ], - vec![ - (public_input - .iter() - .zip(zeta_minus_x[public_input.len()..].iter()) - .zip(index.domain.elements()) - .map(|((p, l), w)| -*l * p * w) - .fold(G::ScalarField::zero(), |x, y| x + y)) - * index.domain.size_inv - * (zetaw.pow([n]) - G::ScalarField::one()), - ], - ] - }; - //~ 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. fr_sponge.absorb(&self.ft_eval1); @@ -327,8 +297,6 @@ where //~~ * poseidon selector //~~ * the 15 register/witness //~~ * 6 sigmas evaluations (the last one is not evaluated) - fr_sponge.absorb_multiple(&public_evals[0]); - fr_sponge.absorb_multiple(&public_evals[1]); fr_sponge.absorb_evaluations(&self.evals); //~ 1. Sample $v'$ with the Fr-Sponge. @@ -372,11 +340,7 @@ where .map(|(w, s)| (beta * s.zeta) + w.zeta + gamma) .fold(init, |x, y| x * y); - ft_eval0 -= if public_evals[0].is_empty() { - G::ScalarField::zero() - } else { - public_evals[0][0] - }; + ft_eval0 -= self.evals.public.zeta[0]; ft_eval0 -= evals .w @@ -422,7 +386,13 @@ where #[allow(clippy::type_complexity)] let mut es: Vec<(Vec>, Option)> = polys.iter().map(|(_, e)| (e.clone(), None)).collect(); - es.push((public_evals.to_vec(), None)); + es.push(( + vec![ + self.evals.public.zeta.clone(), + self.evals.public.zeta_omega.clone(), + ], + None, + )); es.push((vec![ft_eval0, ft_eval1], None)); for col in [ Column::Z, @@ -468,7 +438,6 @@ where digest, oracles, all_alphas, - public_evals, powers_of_eval_points_for_chunks, polys, zeta1, @@ -487,6 +456,7 @@ where G::BaseField: PrimeField, { let ProofEvaluations { + public, w, z, s, @@ -504,6 +474,8 @@ where } }; + check_eval_len(public)?; + for w_i in w { check_eval_len(w_i)?; } @@ -603,7 +575,6 @@ where fq_sponge, oracles, all_alphas, - public_evals, powers_of_eval_points_for_chunks, polys, zeta1: zeta_to_domain_size, @@ -704,7 +675,10 @@ where //~~ * public input commitment evaluations.push(Evaluation { commitment: public_comm, - evaluations: public_evals.to_vec(), + evaluations: vec![ + proof.evals.public.zeta.clone(), + proof.evals.public.zeta_omega.clone(), + ], degree_bound: None, }); From 0fc74c31cb673bd229546bdfe65caef5246a2725 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 19:30:37 +0000 Subject: [PATCH 003/242] Add parameters to IncorrectEvaluationsLength --- kimchi/src/error.rs | 4 ++-- kimchi/src/verifier.rs | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 10c77d8e18..5cd5b5c0c6 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -44,8 +44,8 @@ pub enum VerifyError { #[error("the previous challenges have an unexpected length (expected {0}, got {1})")] IncorrectPrevChallengesLength(usize, usize), - #[error("proof malformed: an evaluation was of the incorrect size (all evaluations are expected to be of length 1)")] - IncorrectEvaluationsLength, + #[error("proof malformed: an evaluation was of the incorrect size (expected {0}, got {1})")] + IncorrectEvaluationsLength(usize, usize), #[error("the opening proof failed to verify")] OpenProof, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index f92198fd3c..0c345b4ad2 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -455,6 +455,8 @@ where G: KimchiCurve, G::BaseField: PrimeField, { + let expected_size = 1; + let ProofEvaluations { public, w, @@ -467,10 +469,18 @@ where } = &proof.evals; let check_eval_len = |eval: &PointEvaluations>| -> Result<()> { - if eval.zeta.len().is_one() && eval.zeta_omega.len().is_one() { - Ok(()) + if eval.zeta.len() != expected_size { + Err(VerifyError::IncorrectEvaluationsLength( + expected_size, + eval.zeta.len(), + )) + } else if eval.zeta_omega.len() != expected_size { + Err(VerifyError::IncorrectEvaluationsLength( + expected_size, + eval.zeta_omega.len(), + )) } else { - Err(VerifyError::IncorrectEvaluationsLength) + Ok(()) } }; From 4f8e4da315b57fb2a1fa18dbeb9b37ce30513549 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 19:32:15 +0000 Subject: [PATCH 004/242] Pass the expected length of evaluations as a parameter --- kimchi/src/verifier.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 0c345b4ad2..bedaec9103 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -448,15 +448,11 @@ where } /// Enforce the length of evaluations inside [`Proof`]. -/// Atm, the length of evaluations(both `zeta` and `zeta_omega`) SHOULD be 1. -/// The length value is prone to future change. -fn check_proof_evals_len(proof: &ProverProof) -> Result<()> +fn check_proof_evals_len(proof: &ProverProof, expected_size: usize) -> Result<()> where G: KimchiCurve, G::BaseField: PrimeField, { - let expected_size = 1; - let ProofEvaluations { public, w, @@ -550,7 +546,7 @@ where } //~ 1. Check the length of evaluations inside the proof. - check_proof_evals_len(proof)?; + check_proof_evals_len(proof, 1)?; //~ 1. Commit to the negated public input polynomial. let public_comm = { From fadb1ff9d76abbf2fb80538e438903328b2ddedb Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 19:37:09 +0000 Subject: [PATCH 005/242] Compute chunk_size for proof evals length --- kimchi/src/verifier.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index bedaec9103..2f8804faa7 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -546,7 +546,8 @@ where } //~ 1. Check the length of evaluations inside the proof. - check_proof_evals_len(proof, 1)?; + let chunk_size = verifier_index.domain.size() / verifier_index.max_poly_size; + check_proof_evals_len(proof, chunk_size)?; //~ 1. Commit to the negated public input polynomial. let public_comm = { From 42abaf1dec5b05770ca05ed383d8fa6dc00d58ec Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 22:11:44 +0000 Subject: [PATCH 006/242] Compute correct size of t_comm --- book/src/specs/kimchi.md | 2 +- kimchi/src/error.rs | 4 ++-- kimchi/src/prover.rs | 7 +++++-- kimchi/src/verifier.rs | 12 +++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index e0e24f1c6e..e3ed63a2fc 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2233,7 +2233,7 @@ We run the following algorithm: 1. Absorb the commitment to the permutation trace with the Fq-Sponge. 1. Sample $\alpha'$ with the Fq-Sponge. 1. Derive $\alpha$ from $\alpha'$ using the endomorphism (TODO: details). -1. Enforce that the length of the $t$ commitment is of size `PERMUTS`. +1. Enforce that the length of the $t$ commitment is of size 7. 1. Absorb the commitment to the quotient polynomial $t$ into the argument. 1. Sample $\zeta'$ with the Fq-Sponge. 1. Derive $\zeta$ from $\zeta'$ using the endomorphism (TODO: specify). diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 5cd5b5c0c6..cfa0b6ad3f 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -35,8 +35,8 @@ pub enum ProverError { /// Errors that can arise when verifying a proof #[derive(Error, Debug, Clone, Copy)] pub enum VerifyError { - #[error("the commitment to {0} is of an unexpected size")] - IncorrectCommitmentLength(&'static str), + #[error("the commitment to {0} is of an unexpected size (expected {1}, got {2})")] + IncorrectCommitmentLength(&'static str, usize, usize), #[error("the public input is of an unexpected size (expected {0})")] IncorrectPubicInputLength(usize), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index b33e6e977b..22f771ebce 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -814,13 +814,16 @@ where let t_comm = { let mut t_comm = index.srs.commit("ient_poly, None, rng); - let expected_t_size = PERMUTS; - let dummies = expected_t_size - t_comm.commitment.unshifted.len(); + let expected_t_size = 7; + let dummies = expected_t_size * (index.cs.domain.d1.size() / index.max_poly_size) + - t_comm.commitment.unshifted.len(); + // Add `dummies` many hiding commitments to the 0 polynomial, since if the // number of commitments in `t_comm` is less than the max size, it means that // the higher degree coefficients of `t` are 0. for _ in 0..dummies { let w = ::rand(rng); + t_comm .commitment .unshifted diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 2f8804faa7..63fdea0719 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -119,6 +119,8 @@ where let n = index.domain.size; let (_, endo_r) = G::endos(); + let chunk_size = index.domain.size() / index.max_poly_size; + //~ 1. Setup the Fq-Sponge. let mut fq_sponge = EFqSponge::new(G::OtherCurve::sponge_params()); @@ -212,9 +214,13 @@ where //~ 1. Derive $\alpha$ from $\alpha'$ using the endomorphism (TODO: details). let alpha = alpha_chal.to_field(endo_r); - //~ 1. Enforce that the length of the $t$ commitment is of size `PERMUTS`. - if self.commitments.t_comm.unshifted.len() != PERMUTS { - return Err(VerifyError::IncorrectCommitmentLength("t")); + //~ 1. Enforce that the length of the $t$ commitment is of size 7. + if self.commitments.t_comm.unshifted.len() != chunk_size * 7 { + return Err(VerifyError::IncorrectCommitmentLength( + "t", + chunk_size * 7, + self.commitments.t_comm.unshifted.len(), + )); } //~ 1. Absorb the commitment to the quotient polynomial $t$ into the argument. From 0c1ef4d7ede7dd4ad31e3b876b46bbf16a7b6fbe Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 22:18:35 +0000 Subject: [PATCH 007/242] Add more info to verifier errors --- kimchi/src/error.rs | 6 ++++-- kimchi/src/verifier.rs | 26 ++++++++++++++------------ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index cfa0b6ad3f..2c787cc072 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -44,8 +44,10 @@ pub enum VerifyError { #[error("the previous challenges have an unexpected length (expected {0}, got {1})")] IncorrectPrevChallengesLength(usize, usize), - #[error("proof malformed: an evaluation was of the incorrect size (expected {0}, got {1})")] - IncorrectEvaluationsLength(usize, usize), + #[error( + "proof malformed: an evaluation for {2} was of the incorrect size (expected {0}, got {1})" + )] + IncorrectEvaluationsLength(usize, usize, &'static str), #[error("the opening proof failed to verify")] OpenProof, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 63fdea0719..2fad72ffef 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -470,33 +470,35 @@ where poseidon_selector, } = &proof.evals; - let check_eval_len = |eval: &PointEvaluations>| -> Result<()> { + let check_eval_len = |eval: &PointEvaluations>, str: &'static str| -> Result<()> { if eval.zeta.len() != expected_size { Err(VerifyError::IncorrectEvaluationsLength( expected_size, eval.zeta.len(), + str, )) } else if eval.zeta_omega.len() != expected_size { Err(VerifyError::IncorrectEvaluationsLength( expected_size, eval.zeta_omega.len(), + str, )) } else { Ok(()) } }; - check_eval_len(public)?; + check_eval_len(public, "public input")?; for w_i in w { - check_eval_len(w_i)?; + check_eval_len(w_i, "witness")?; } - check_eval_len(z)?; + check_eval_len(z, "permutation accumulator")?; for s_i in s { - check_eval_len(s_i)?; + check_eval_len(s_i, "permutation shifts")?; } for coeff in coefficients { - check_eval_len(coeff)?; + check_eval_len(coeff, "coefficients")?; } if let Some(LookupEvaluations { sorted, @@ -506,16 +508,16 @@ where }) = lookup { for sorted_i in sorted { - check_eval_len(sorted_i)?; + check_eval_len(sorted_i, "lookup sorted")?; } - check_eval_len(aggreg)?; - check_eval_len(table)?; + check_eval_len(aggreg, "lookup aggregation")?; + check_eval_len(table, "lookup table")?; if let Some(runtime) = &runtime { - check_eval_len(runtime)?; + check_eval_len(runtime, "runtime lookup table")?; } } - check_eval_len(generic_selector)?; - check_eval_len(poseidon_selector)?; + check_eval_len(generic_selector, "generic selector")?; + check_eval_len(poseidon_selector, "poseidon selector")?; Ok(()) } From caae0aa99c0c71c554428a7824f72214a2758e59 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 22:56:15 +0000 Subject: [PATCH 008/242] Explicitly pass the expected number of chunks --- kimchi/src/prover.rs | 22 ++++++++++------- poly-commitment/src/commitment.rs | 8 +++--- poly-commitment/src/tests/batch_15_wires.rs | 2 +- poly-commitment/src/tests/commitment.rs | 2 +- utils/src/chunked_polynomial.rs | 6 ++++- utils/src/dense_polynomial.rs | 27 ++++++++++----------- 6 files changed, 37 insertions(+), 30 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 22f771ebce..081146b6bc 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -170,6 +170,8 @@ where let (_, endo_r) = G::endos(); + let num_chunks = d1_size / index.max_poly_size; + // TODO: rng should be passed as arg let rng = &mut rand::rngs::OsRng; @@ -852,7 +854,7 @@ where .aggreg_coeffs .as_ref() .unwrap() - .to_chunked_polynomial(index.max_poly_size); + .to_chunked_polynomial(num_chunks, index.max_poly_size); //~~ * the sorted polynomials let sorted = lookup_context @@ -860,11 +862,11 @@ where .as_ref() .unwrap() .iter() - .map(|c| c.to_chunked_polynomial(index.max_poly_size)); + .map(|c| c.to_chunked_polynomial(num_chunks, index.max_poly_size)); //~~ * the table polynonial let joint_table = lookup_context.joint_lookup_table.as_ref().unwrap(); - let joint_table = joint_table.to_chunked_polynomial(index.max_poly_size); + let joint_table = joint_table.to_chunked_polynomial(num_chunks, index.max_poly_size); lookup_context.eval = Some(LookupEvaluations { aggreg: PointEvaluations { @@ -882,7 +884,8 @@ where zeta_omega: joint_table.evaluate_chunks(zeta_omega), }, runtime: lookup_context.runtime_table.as_ref().map(|runtime_table| { - let runtime_table = runtime_table.to_chunked_polynomial(index.max_poly_size); + let runtime_table = + runtime_table.to_chunked_polynomial(num_chunks, index.max_poly_size); PointEvaluations { zeta: runtime_table.evaluate_chunks(zeta), zeta_omega: runtime_table.evaluate_chunks(zeta_omega), @@ -929,7 +932,7 @@ where let chunked_evals = ProofEvaluations::>> { public: { - let chunked = public_poly.to_chunked_polynomial(index.max_poly_size); + let chunked = public_poly.to_chunked_polynomial(num_chunks, index.max_poly_size); PointEvaluations { zeta: chunked.evaluate_chunks(zeta), zeta_omega: chunked.evaluate_chunks(zeta_omega), @@ -944,7 +947,8 @@ where chunked_evals_for_evaluations(&index.column_evaluations.coefficients8[i]) }), w: array::from_fn(|i| { - let chunked = witness_poly[i].to_chunked_polynomial(index.max_poly_size); + let chunked = + witness_poly[i].to_chunked_polynomial(num_chunks, index.max_poly_size); PointEvaluations { zeta: chunked.evaluate_chunks(zeta), zeta_omega: chunked.evaluate_chunks(zeta_omega), @@ -952,7 +956,7 @@ where }), z: { - let chunked = z_poly.to_chunked_polynomial(index.max_poly_size); + let chunked = z_poly.to_chunked_polynomial(num_chunks, index.max_poly_size); PointEvaluations { zeta: chunked.evaluate_chunks(zeta), zeta_omega: chunked.evaluate_chunks(zeta_omega), @@ -1006,12 +1010,12 @@ where drop(env); // see https://o1-labs.github.io/mina-book/crypto/plonk/maller_15.html#the-prover-side - f.to_chunked_polynomial(index.max_poly_size) + f.to_chunked_polynomial(num_chunks, index.max_poly_size) .linearize(zeta_to_srs_len) }; let t_chunked = quotient_poly - .to_chunked_polynomial(index.max_poly_size) + .to_chunked_polynomial(7 * num_chunks, index.max_poly_size) .linearize(zeta_to_srs_len); &f_chunked - &t_chunked.scale(zeta_to_domain_size - G::ScalarField::one()) diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 4ac2efc6e5..5333443c0b 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -1018,10 +1018,10 @@ mod tests { // evaluate the polynomials at these two points let poly1_chunked_evals = vec![ poly1 - .to_chunked_polynomial(srs.g.len()) + .to_chunked_polynomial(1, srs.g.len()) .evaluate_chunks(elm[0]), poly1 - .to_chunked_polynomial(srs.g.len()) + .to_chunked_polynomial(1, srs.g.len()) .evaluate_chunks(elm[1]), ]; @@ -1034,10 +1034,10 @@ mod tests { let poly2_chunked_evals = vec![ poly2 - .to_chunked_polynomial(srs.g.len()) + .to_chunked_polynomial(1, srs.g.len()) .evaluate_chunks(elm[0]), poly2 - .to_chunked_polynomial(srs.g.len()) + .to_chunked_polynomial(1, srs.g.len()) .evaluate_chunks(elm[1]), ]; diff --git a/poly-commitment/src/tests/batch_15_wires.rs b/poly-commitment/src/tests/batch_15_wires.rs index 8137ac55d6..51549f36d6 100644 --- a/poly-commitment/src/tests/batch_15_wires.rs +++ b/poly-commitment/src/tests/batch_15_wires.rs @@ -81,7 +81,7 @@ where ( srs.commit(&a[i].clone(), bounds[i], rng), x.iter() - .map(|xx| a[i].to_chunked_polynomial(size).evaluate_chunks(*xx)) + .map(|xx| a[i].to_chunked_polynomial(1, size).evaluate_chunks(*xx)) .collect::>(), bounds[i], ) diff --git a/poly-commitment/src/tests/commitment.rs b/poly-commitment/src/tests/commitment.rs index 85b86c6eae..18f8ee7d91 100644 --- a/poly-commitment/src/tests/commitment.rs +++ b/poly-commitment/src/tests/commitment.rs @@ -141,7 +141,7 @@ fn test_randomised(mut rng: &mut RNG) { let mut chunked_evals = vec![]; for point in eval_points.clone() { chunked_evals.push( - poly.to_chunked_polynomial(srs.g.len()) + poly.to_chunked_polynomial(1, srs.g.len()) .evaluate_chunks(point), ); } diff --git a/utils/src/chunked_polynomial.rs b/utils/src/chunked_polynomial.rs index c8d09c42b3..6f79de09ea 100644 --- a/utils/src/chunked_polynomial.rs +++ b/utils/src/chunked_polynomial.rs @@ -64,6 +64,7 @@ mod tests { let one = Fp::one(); let zeta = one + one; let zeta_n = zeta.square(); + let num_chunks = 4; let res = (one + zeta) * (one + zeta_n + zeta_n * zeta.square() + zeta_n * zeta.square() * zeta.square()); @@ -71,7 +72,10 @@ mod tests { let coeffs = [one, one, one, one, one, one, one, one]; let f = DensePolynomial::from_coefficients_slice(&coeffs); - let eval = f.to_chunked_polynomial(2).linearize(zeta_n).evaluate(&zeta); + let eval = f + .to_chunked_polynomial(num_chunks, 2) + .linearize(zeta_n) + .evaluate(&zeta); assert!(eval == res); } diff --git a/utils/src/dense_polynomial.rs b/utils/src/dense_polynomial.rs index fdb2b9e4a3..72560f1057 100644 --- a/utils/src/dense_polynomial.rs +++ b/utils/src/dense_polynomial.rs @@ -22,8 +22,8 @@ pub trait ExtendedDensePolynomial { fn eval_polynomial(coeffs: &[F], x: F) -> F; /// Convert a polynomial into chunks. - /// Implementors must ensure that the result contains at least 1 chunk. - fn to_chunked_polynomial(&self, size: usize) -> ChunkedPolynomial; + /// Implementors must ensure that the result contains exactly num_chunks. + fn to_chunked_polynomial(&self, num_chunks: usize, size: usize) -> ChunkedPolynomial; } impl ExtendedDensePolynomial for DensePolynomial { @@ -46,20 +46,17 @@ impl ExtendedDensePolynomial for DensePolynomial { DensePolynomial::from_coefficients_slice(coeffs).evaluate(&x) } - fn to_chunked_polynomial(&self, chunk_size: usize) -> ChunkedPolynomial { - // Ensure that there is always at least 1 polynomial in the resulting chunked polynomial. - if self.coeffs.is_empty() { - return ChunkedPolynomial { - polys: vec![DensePolynomial::from_coefficients_vec(vec![])], - size: chunk_size, - }; - } - - let mut chunk_polys: Vec> = vec![]; + fn to_chunked_polynomial(&self, num_chunks: usize, chunk_size: usize) -> ChunkedPolynomial { + let mut chunk_polys: Vec> = Vec::with_capacity(num_chunks); for chunk in self.coeffs.chunks(chunk_size) { chunk_polys.push(DensePolynomial::from_coefficients_slice(chunk)); } + // Pad unused chunks with zeros. + for _ in chunk_polys.len()..num_chunks { + chunk_polys.push(DensePolynomial::from_coefficients_vec(vec![])); + } + ChunkedPolynomial { polys: chunk_polys, size: chunk_size, @@ -83,12 +80,14 @@ mod tests { let one = Fp::one(); let two = one + one; let three = two + one; + let num_chunks = 4; // 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 let coeffs = [one, one, one, one, one, one, one, one]; let f = DensePolynomial::from_coefficients_slice(&coeffs); - let evals = f.to_chunked_polynomial(2).evaluate_chunks(two); - for eval in evals.into_iter().take(4) { + let evals = f.to_chunked_polynomial(num_chunks, 2).evaluate_chunks(two); + assert_eq!(evals.len(), num_chunks); + for eval in evals.into_iter().take(num_chunks) { assert!(eval == three); } } From 73b8acb3d7c4fb95c2f5e2eccbe4814a23a58217 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 27 Feb 2023 23:14:52 +0000 Subject: [PATCH 009/242] Allow for zeroed segments --- poly-commitment/src/evaluation_proof.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 7c030787cc..6774bc5403 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -165,8 +165,8 @@ impl SRS { assert!(omegas.shifted.is_none()); } for j in 0..omegas.unshifted.len() { - let segment = &p_i.coeffs - [offset..std::cmp::min(offset + self.g.len(), p_i.coeffs.len())]; + let segment = &p_i.coeffs[std::cmp::min(offset, p_i.coeffs.len()) + ..std::cmp::min(offset + self.g.len(), p_i.coeffs.len())]; // always mixing in the unshifted segments plnm.add_unshifted(scale, segment); From 35bbdaf3218fafb67d111d45a227ab848f25c2e5 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 01:40:28 +0000 Subject: [PATCH 010/242] Fixup chunked commitment as verifier for empty public input --- kimchi/src/verifier.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 2fad72ffef..90485d11f1 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -570,19 +570,23 @@ where .get(&verifier_index.domain.size()) .expect("pre-computed committed lagrange bases not found"); let com: Vec<_> = lgr_comm.iter().take(verifier_index.public).collect(); - let elm: Vec<_> = public_input.iter().map(|s| -*s).collect(); - let public_comm = PolyComm::::multi_scalar_mul(&com, &elm); - verifier_index - .srs() - .mask_custom( - public_comm, - &PolyComm { - unshifted: vec![G::ScalarField::one(); 1], - shifted: None, - }, - ) - .unwrap() - .commitment + if public_input.len() == 0 { + PolyComm::new(vec![verifier_index.srs().h; chunk_size], None) + } else { + let elm: Vec<_> = public_input.iter().map(|s| -*s).collect(); + let public_comm = PolyComm::::multi_scalar_mul(&com, &elm); + verifier_index + .srs() + .mask_custom( + public_comm, + &PolyComm { + unshifted: vec![G::ScalarField::one(); 1], + shifted: None, + }, + ) + .unwrap() + .commitment + } }; //~ 1. Run the [Fiat-Shamir argument](#fiat-shamir-argument). From a520addb3325d5b42db5b930a96c21c54b0b65f5 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 01:45:12 +0000 Subject: [PATCH 011/242] Generate the correct number of chunks for public input --- kimchi/src/prover.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 081146b6bc..216224b645 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1123,7 +1123,11 @@ where //~~ * the 15 registers/witness columns //~~ * the 6 sigmas //~~ * optionally, the runtime table - polynomials.push((coefficients_form(&public_poly), None, fixed_hiding(1))); + polynomials.push(( + coefficients_form(&public_poly), + None, + fixed_hiding(num_chunks), + )); polynomials.push((coefficients_form(&ft), None, blinding_ft)); polynomials.push((coefficients_form(&z_poly), None, z_comm.blinders)); polynomials.push(( From 4b6a86113a237217aa6e270781d9dae18e310346 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 05:15:18 +0000 Subject: [PATCH 012/242] Handle chunking in evaluations for the opening proof --- poly-commitment/src/evaluation_proof.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 6774bc5403..ab6ba331c2 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -5,7 +5,7 @@ use ark_ff::{FftField, Field, One, PrimeField, UniformRand, Zero}; use ark_poly::{univariate::DensePolynomial, UVPolynomial}; use ark_poly::{EvaluationDomain, Evaluations}; use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; -use o1_utils::math; +use o1_utils::{math, ExtendedDensePolynomial}; use rand_core::{CryptoRng, RngCore}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -151,9 +151,12 @@ impl SRS { .for_each(|(i, x)| { *x += scale * evals[i * stride]; }); - assert_eq!(omegas.unshifted.len(), 1); - omega += &(omegas.unshifted[0] * scale); - scale *= &polyscale; + for j in 0..omegas.unshifted.len() { + omega += &(omegas.unshifted[j] * scale); + scale *= &polyscale; + } + // We assume here that we have no shifted segment. + // TODO: Remove shifted } DensePolynomialOrEvaluations::DensePolynomial(p_i) => { @@ -195,8 +198,12 @@ impl SRS { let mut plnm = plnm.to_dense_polynomial(); if !plnm_evals_part.is_empty() { let n = plnm_evals_part.len(); + let max_poly_size = self.g.len(); + let num_chunks = n / max_poly_size; plnm += &Evaluations::from_vec_and_domain(plnm_evals_part, D::new(n).unwrap()) - .interpolate(); + .interpolate() + .to_chunked_polynomial(num_chunks, max_poly_size) + .linearize(polyscale); } (plnm, omega) From bde771ed0328f67074129487c81e85ff1a2e251f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 05:17:28 +0000 Subject: [PATCH 013/242] Use the correct blinders in the prover --- kimchi/src/prover.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 216224b645..604aee6a89 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1133,12 +1133,12 @@ where polynomials.push(( evaluations_form(&index.column_evaluations.generic_selector4), None, - fixed_hiding(1), + fixed_hiding(num_chunks), )); polynomials.push(( evaluations_form(&index.column_evaluations.poseidon_selector8), None, - fixed_hiding(1), + fixed_hiding(num_chunks), )); polynomials.extend( witness_poly @@ -1152,13 +1152,13 @@ where .column_evaluations .coefficients8 .iter() - .map(|coefficientm| (evaluations_form(coefficientm), None, non_hiding(1))) + .map(|coefficientm| (evaluations_form(coefficientm), None, non_hiding(num_chunks))) .collect::>(), ); polynomials.extend( index.column_evaluations.permutation_coefficients8[0..PERMUTS - 1] .iter() - .map(|w| (evaluations_form(w), None, non_hiding(1))) + .map(|w| (evaluations_form(w), None, non_hiding(num_chunks))) .collect::>(), ); @@ -1186,14 +1186,19 @@ where let runtime_comm = lookup_context.runtime_table_comm.as_ref().unwrap(); let joint_combiner = lookup_context.joint_combiner.as_ref().unwrap(); - let blinding = runtime_comm.blinders.unshifted[0]; + let unshifted = runtime_comm + .blinders + .unshifted + .iter() + .map(|blinding| *joint_combiner * blinding) + .collect(); PolyComm { - unshifted: vec![*joint_combiner * blinding], + unshifted, shifted: None, } } else { - non_hiding(1) + non_hiding(num_chunks) }; let joint_lookup_table = lookup_context.joint_lookup_table.as_ref().unwrap(); From 49174e7755eb177b21be50219b9baea423d67287 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 15:45:30 +0000 Subject: [PATCH 014/242] Add explicit num_chunks to commit_non_hiding and friends --- book/src/specs/kimchi.md | 1 - kimchi/src/prover.rs | 33 +++++---------------- kimchi/src/tests/recursion.rs | 2 +- poly-commitment/src/commitment.rs | 25 ++++++++++++---- poly-commitment/src/tests/batch_15_wires.rs | 4 ++- poly-commitment/src/tests/commitment.rs | 4 ++- 6 files changed, 33 insertions(+), 36 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index e3ed63a2fc..bb983c29e9 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2135,7 +2135,6 @@ The prover then follows the following steps to create the proof: and by then dividing the resulting polynomial with the vanishing polynomial $Z_H$. TODO: specify the split of the permutation polynomial into perm and bnd? 1. commit (hiding) to the quotient polynomial $t$ - TODO: specify the dummies 1. Absorb the the commitment of the quotient polynomial with the Fq-Sponge. 1. Sample $\zeta'$ with the Fq-Sponge. 1. Derive $\zeta$ from $\zeta'$ using the endomorphism (TODO: specify) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 604aee6a89..92c269d2ba 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -32,7 +32,6 @@ use crate::{ }, prover_index::ProverIndex, }; -use ark_ec::ProjectiveCurve; use ark_ff::{FftField, Field, One, PrimeField, UniformRand, Zero}; use ark_poly::{ univariate::DensePolynomial, EvaluationDomain, Evaluations, Polynomial, @@ -235,7 +234,7 @@ where .interpolate(); //~ 1. Commit (non-hiding) to the negated public input polynomial. - let public_comm = index.srs.commit_non_hiding(&public_poly, None); + let public_comm = index.srs.commit_non_hiding(&public_poly, num_chunks, None); let public_comm = { index .srs @@ -360,7 +359,10 @@ where // commit the runtime polynomial // (and save it to the proof) - let runtime_table_comm = index.srs.commit(&runtime_table_contribution, None, rng); + let runtime_table_comm = + index + .srs + .commit(&runtime_table_contribution, num_chunks, None, rng); // absorb the commitment absorb_commitment(&mut fq_sponge, &runtime_table_comm.commitment); @@ -564,7 +566,7 @@ where let z_poly = index.perm_aggreg(&witness, &beta, &gamma, rng)?; //~ 1. Commit (hidding) to the permutation aggregation polynomial $z$. - let z_comm = index.srs.commit(&z_poly, None, rng); + let z_comm = index.srs.commit(&z_poly, num_chunks, None, rng); //~ 1. Absorb the permutation aggregation polynomial $z$ with the Fq-Sponge. absorb_commitment(&mut fq_sponge, &z_comm.commitment); @@ -812,28 +814,7 @@ where }; //~ 1. commit (hiding) to the quotient polynomial $t$ - //~ TODO: specify the dummies - let t_comm = { - let mut t_comm = index.srs.commit("ient_poly, None, rng); - - let expected_t_size = 7; - let dummies = expected_t_size * (index.cs.domain.d1.size() / index.max_poly_size) - - t_comm.commitment.unshifted.len(); - - // Add `dummies` many hiding commitments to the 0 polynomial, since if the - // number of commitments in `t_comm` is less than the max size, it means that - // the higher degree coefficients of `t` are 0. - for _ in 0..dummies { - let w = ::rand(rng); - - t_comm - .commitment - .unshifted - .push(index.srs.h.mul(w).into_affine()); - t_comm.blinders.unshifted.push(w); - } - t_comm - }; + let t_comm = { index.srs.commit("ient_poly, 7 * num_chunks, None, rng) }; //~ 1. Absorb the the commitment of the quotient polynomial with the Fq-Sponge. absorb_commitment(&mut fq_sponge, &t_comm.commitment); diff --git a/kimchi/src/tests/recursion.rs b/kimchi/src/tests/recursion.rs index 7936bb738e..c74b293ca1 100644 --- a/kimchi/src/tests/recursion.rs +++ b/kimchi/src/tests/recursion.rs @@ -43,7 +43,7 @@ fn test_recursion() { let comm = { let coeffs = b_poly_coefficients(&chals); let b = DensePolynomial::from_coefficients_vec(coeffs); - index.srs.commit_non_hiding(&b, None) + index.srs.commit_non_hiding(&b, 1, None) }; RecursionChallenge::new(chals, comm) }; diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 5333443c0b..d6c1199e4b 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -522,10 +522,11 @@ impl SRS { pub fn commit( &self, plnm: &DensePolynomial, + num_chunks: usize, max: Option, rng: &mut (impl RngCore + CryptoRng), ) -> BlindedCommitment { - self.mask(self.commit_non_hiding(plnm, max), rng) + self.mask(self.commit_non_hiding(plnm, num_chunks, max), rng) } /// Turns a non-hiding polynomial commitment into a hidding polynomial commitment. Transforms each given `` into `( + wH, w)` with a random `w` per commitment. @@ -560,6 +561,7 @@ impl SRS { /// This function commits a polynomial using the SRS' basis of size `n`. /// - `plnm`: polynomial to commit to with max size of sections + /// - `num_chunks`: the number of unshifted commitments to be included in the output polynomial commitment /// - `max`: maximal degree of the polynomial (not inclusive), if none, no degree bound /// The function returns an unbounded commitment vector (which splits the commitment into several commitments of size at most `n`), /// as well as an optional bounded commitment (if `max` is set). @@ -567,6 +569,7 @@ impl SRS { pub fn commit_non_hiding( &self, plnm: &DensePolynomial, + num_chunks: usize, max: Option, ) -> PolyComm { let is_zero = plnm.is_zero(); @@ -587,6 +590,10 @@ impl SRS { }); } + for _ in unshifted.len()..num_chunks { + unshifted.push(G::zero()); + } + // committing only last chunk shifted to the right edge of SRS let shifted = match max { None => None, @@ -903,12 +910,14 @@ mod tests { let mut srs = SRS::::create(n); srs.add_lagrange_basis(domain); + let num_chunks = domain.size() / srs.g.len(); + let expected_lagrange_commitments: Vec<_> = (0..n) .map(|i| { let mut e = vec![Fp::zero(); n]; e[i] = Fp::one(); let p = Evaluations::>::from_vec_and_domain(e, domain).interpolate(); - srs.commit_non_hiding(&p, None) + srs.commit_non_hiding(&p, num_chunks, None) }) .collect(); @@ -929,12 +938,14 @@ mod tests { let mut srs = SRS::::create(n / 2); srs.add_lagrange_basis(domain); + let num_chunks = domain.size() / srs.g.len(); + let expected_lagrange_commitments: Vec<_> = (0..n) .map(|i| { let mut e = vec![Fp::zero(); n]; e[i] = Fp::one(); let p = Evaluations::>::from_vec_and_domain(e, domain).interpolate(); - srs.commit_non_hiding(&p, None) + srs.commit_non_hiding(&p, num_chunks, None) }) .collect(); @@ -955,12 +966,14 @@ mod tests { let mut srs = SRS::::create(n / 2 + 1); srs.add_lagrange_basis(domain); + let num_chunks = (domain.size() + srs.g.len() - 1) / srs.g.len(); + let expected_lagrange_commitments: Vec<_> = (0..n) .map(|i| { let mut e = vec![Fp::zero(); n]; e[i] = Fp::one(); let p = Evaluations::>::from_vec_and_domain(e, domain).interpolate(); - srs.commit_non_hiding(&p, Some(64)) + srs.commit_non_hiding(&p, num_chunks, Some(64)) }) .collect(); @@ -985,9 +998,9 @@ mod tests { let rng = &mut StdRng::from_seed([0u8; 32]); // commit the two polynomials (and upperbound the second one) - let commitment = srs.commit(&poly1, None, rng); + let commitment = srs.commit(&poly1, 1, None, rng); let upperbound = poly2.degree() + 1; - let bounded_commitment = srs.commit(&poly2, Some(upperbound), rng); + let bounded_commitment = srs.commit(&poly2, 1, Some(upperbound), rng); // create an aggregated opening proof let (u, v) = (Fp::rand(rng), Fp::rand(rng)); diff --git a/poly-commitment/src/tests/batch_15_wires.rs b/poly-commitment/src/tests/batch_15_wires.rs index 51549f36d6..1969c78168 100644 --- a/poly-commitment/src/tests/batch_15_wires.rs +++ b/poly-commitment/src/tests/batch_15_wires.rs @@ -29,6 +29,8 @@ where let size = 1 << 7; let srs = SRS::::create(size); + let num_chunks = 1; + let group_map = ::Map::setup(); let sponge = DefaultFqSponge::::new( @@ -79,7 +81,7 @@ where let comm = (0..a.len()) .map(|i| { ( - srs.commit(&a[i].clone(), bounds[i], rng), + srs.commit(&a[i].clone(), num_chunks, bounds[i], rng), x.iter() .map(|xx| a[i].to_chunked_polynomial(1, size).evaluate_chunks(*xx)) .collect::>(), diff --git a/poly-commitment/src/tests/commitment.rs b/poly-commitment/src/tests/commitment.rs index 18f8ee7d91..fe2e9beb19 100644 --- a/poly-commitment/src/tests/commitment.rs +++ b/poly-commitment/src/tests/commitment.rs @@ -101,6 +101,8 @@ fn test_randomised(mut rng: &mut RNG) { // create an SRS optimized for polynomials of degree 2^7 - 1 let srs = SRS::::create(1 << 7); + let num_chunks = 1; + // TODO: move to bench let mut time_commit = Duration::new(0, 0); let mut time_open = Duration::new(0, 0); @@ -135,7 +137,7 @@ fn test_randomised(mut rng: &mut RNG) { let BlindedCommitment { commitment: chunked_commitment, blinders: chunked_blinding, - } = srs.commit(&poly, bound, &mut rng); + } = srs.commit(&poly, num_chunks, bound, &mut rng); time_commit += timer.elapsed(); let mut chunked_evals = vec![]; From bd1161b1ab19128916b558fa6cda12bfe13b0f97 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 16:00:49 +0000 Subject: [PATCH 015/242] Check-in debugging helper --- poly-commitment/src/evaluation_proof.rs | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index ab6ba331c2..e6dcfb5433 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -352,6 +352,55 @@ impl SRS { sg: g0, } } + + /// This function is a debugging helper. + #[allow(clippy::too_many_arguments)] + #[allow(clippy::type_complexity)] + #[allow(clippy::many_single_char_names)] + pub fn prover_polynomials_to_verifier_evaluations>( + &self, + plnms: &[( + DensePolynomialOrEvaluations, + Option, + PolyComm, + )], // vector of polynomial with optional degree bound and commitment randomness + elm: &[G::ScalarField], // vector of evaluation points + ) -> Vec> + where + G::BaseField: PrimeField, + { + plnms + .iter() + .enumerate() + .map(|(i, (poly_or_evals, degree_bound, blinders))| { + let poly = match poly_or_evals { + DensePolynomialOrEvaluations::DensePolynomial(poly) => (*poly).clone(), + DensePolynomialOrEvaluations::Evaluations(evals, _) => { + (*evals).clone().interpolate() + } + }; + let chunked_polynomial = + poly.to_chunked_polynomial(blinders.unshifted.len(), self.g.len()); + let chunked_commitment = + { self.commit_non_hiding(&poly, blinders.unshifted.len(), None) }; + let masked_commitment = match self.mask_custom(chunked_commitment, blinders) { + Ok(comm) => comm, + Err(err) => panic!("Error at index {}: {}", i, err), + }; + let chunked_evals = elm + .iter() + .map(|elm| chunked_polynomial.evaluate_chunks(*elm)) + .collect(); + Evaluation { + commitment: masked_commitment.commitment, + + evaluations: chunked_evals, + + degree_bound: degree_bound.clone(), + } + }) + .collect() + } } #[serde_as] From 0233db765bc00b9a6776eeabad0321c1a9c02a65 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 17:08:56 +0000 Subject: [PATCH 016/242] Fix stupid typo --- kimchi/src/lagrange_basis_evaluations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/lagrange_basis_evaluations.rs b/kimchi/src/lagrange_basis_evaluations.rs index a2393b610b..08a94dd816 100644 --- a/kimchi/src/lagrange_basis_evaluations.rs +++ b/kimchi/src/lagrange_basis_evaluations.rs @@ -122,8 +122,8 @@ impl LagrangeBasisEvaluations { let n = domain.size(); let num_chunks = n / max_poly_size; let mut evals = Vec::with_capacity(num_chunks); - let mut x_pow = F::one(); for i in 0..num_chunks { + let mut x_pow = F::one(); let mut chunked_evals = vec![F::zero(); n]; for j in 0..max_poly_size { chunked_evals[i * max_poly_size + j] = x_pow; From 367ee30823bffdabd953207277f869ab6976415c Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 17:23:17 +0000 Subject: [PATCH 017/242] Fixup blinders for public input in verifier --- kimchi/src/verifier.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 90485d11f1..8f42e505ca 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -578,11 +578,8 @@ where verifier_index .srs() .mask_custom( - public_comm, - &PolyComm { - unshifted: vec![G::ScalarField::one(); 1], - shifted: None, - }, + public_comm.clone(), + &public_comm.map(|_| G::ScalarField::one()), ) .unwrap() .commitment From 18722368f6db488139782caa811bb08b42fd8ae5 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 17:50:14 +0000 Subject: [PATCH 018/242] Use all evaluations of the public input in the verifier --- kimchi/src/verifier.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 8f42e505ca..570add95fa 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -22,8 +22,9 @@ use crate::{ }; use ark_ec::AffineCurve; use ark_ff::{Field, One, PrimeField, Zero}; -use ark_poly::{EvaluationDomain, Polynomial}; +use ark_poly::{univariate::DensePolynomial, EvaluationDomain, Polynomial}; use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; +use o1_utils::ExtendedDensePolynomial; use poly_commitment::commitment::{ absorb_commitment, combined_inner_product, BatchEvaluationProof, Evaluation, PolyComm, }; @@ -346,7 +347,10 @@ where .map(|(w, s)| (beta * s.zeta) + w.zeta + gamma) .fold(init, |x, y| x * y); - ft_eval0 -= self.evals.public.zeta[0]; + ft_eval0 -= DensePolynomial::eval_polynomial( + &self.evals.public.zeta, + powers_of_eval_points_for_chunks.zeta, + ); ft_eval0 -= evals .w From db78ae0b8cb89b3fb959c90ef3f38e5c441bd1ec Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 18:18:59 +0000 Subject: [PATCH 019/242] Clippy --- poly-commitment/src/evaluation_proof.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index e6dcfb5433..552e6becc2 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -385,7 +385,7 @@ impl SRS { { self.commit_non_hiding(&poly, blinders.unshifted.len(), None) }; let masked_commitment = match self.mask_custom(chunked_commitment, blinders) { Ok(comm) => comm, - Err(err) => panic!("Error at index {}: {}", i, err), + Err(err) => panic!("Error at index {i}: {err}"), }; let chunked_evals = elm .iter() @@ -396,7 +396,7 @@ impl SRS { evaluations: chunked_evals, - degree_bound: degree_bound.clone(), + degree_bound: *degree_bound, } }) .collect() From 03ac01d1e2e9e1691f810b90f6aefa2bab991994 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 22:03:44 +0000 Subject: [PATCH 020/242] Clippy --- kimchi/src/verifier.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 570add95fa..8a9f894f06 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -574,7 +574,7 @@ where .get(&verifier_index.domain.size()) .expect("pre-computed committed lagrange bases not found"); let com: Vec<_> = lgr_comm.iter().take(verifier_index.public).collect(); - if public_input.len() == 0 { + if public_input.is_empty() { PolyComm::new(vec![verifier_index.srs().h; chunk_size], None) } else { let elm: Vec<_> = public_input.iter().map(|s| -*s).collect(); From b3cc0d82c4bd419aba60f7383e13d068144fb706 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 18:16:12 +0000 Subject: [PATCH 021/242] Remove all checks that SRS size == domain size --- kimchi/src/error.rs | 3 --- kimchi/src/prover.rs | 4 ---- kimchi/src/prover_index.rs | 10 ---------- kimchi/src/verifier.rs | 5 ----- poly-commitment/src/evaluation_proof.rs | 3 --- 5 files changed, 25 deletions(-) diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 2c787cc072..017943f980 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -22,9 +22,6 @@ pub enum ProverError { #[error("the lookup failed to find a match in the table")] ValueNotInTable, - #[error("SRS size is smaller than the domain size required by the circuit")] - SRSTooSmall, - #[error("the runtime tables provided did not match the index's configuration")] RuntimeTablesInconsistent, diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 92c269d2ba..b5bd001c4d 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -161,11 +161,7 @@ where prev_challenges: Vec>, blinders: Option<[Option>; COLUMNS]>, ) -> Result { - // make sure that the SRS is not smaller than the domain size let d1_size = index.cs.domain.d1.size(); - if index.srs.max_degree() < d1_size { - return Err(ProverError::SRSTooSmall); - } let (_, endo_r) = G::endos(); diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 2bef36cc4b..ee7d279648 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -56,22 +56,12 @@ pub struct ProverIndex { impl ProverIndex { /// this function compiles the index from constraints - /// - /// # Panics - /// - /// Will panic if `polynomial segment size` is bigger than `circuit`. pub fn create( mut cs: ConstraintSystem, endo_q: G::ScalarField, srs: Arc>, ) -> Self { let max_poly_size = srs.g.len(); - if cs.public > 0 { - assert!( - max_poly_size >= cs.domain.d1.size(), - "polynomial segment size has to be not smaller than that of the circuit!" - ); - } cs.endo = endo_q; // pre-compute the linearization diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 8a9f894f06..5b42fe1bde 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -888,11 +888,6 @@ where if verifier_index.srs().g.len() != srs.g.len() { return Err(VerifyError::DifferentSRS); } - - // also make sure that the SRS is not smaller than the domain size - if verifier_index.srs().max_degree() < verifier_index.domain.size() { - return Err(VerifyError::SRSTooSmall); - } } //~ 1. Validate each proof separately following the [partial verification](#partial-verification) steps. diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 552e6becc2..fa61b710e5 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -117,8 +117,6 @@ impl SRS { let mut plnm_evals_part = { // For now just check that all the evaluation polynomials are the same degree so that we // can do just a single FFT. - // Furthermore we check they have size less than the SRS size so we don't have to do chunking. - // If/when we change this, we can add more complicated code to handle different degrees. let degree = plnms .iter() .fold(None, |acc, (p, _, _)| match p { @@ -131,7 +129,6 @@ impl SRS { } }) .unwrap_or(0); - assert!(degree <= padded_length); vec![G::ScalarField::zero(); degree] }; // let mut plnm_chunks: Vec<(G::ScalarField, OptShiftedPolynomial<_>)> = vec![]; From 6d354f42b8e36c537c4599124c24ee2b3afe8a9b Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 28 Feb 2023 18:28:37 +0000 Subject: [PATCH 022/242] Add override_srs_size to TestFramework --- kimchi/src/prover_index.rs | 6 ++++-- kimchi/src/tests/framework.rs | 8 ++++++++ kimchi/src/tests/not.rs | 11 +++++++++-- kimchi/src/tests/range_check.rs | 1 + 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index ee7d279648..73fc436cfb 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -142,6 +142,7 @@ pub mod testing { lookup_tables: Vec>, runtime_tables: Option>>, disable_gates_checks: bool, + override_srs_size: Option, ) -> ProverIndex where G::BaseField: PrimeField, @@ -156,7 +157,8 @@ pub mod testing { .disable_gates_checks(disable_gates_checks) .build() .unwrap(); - let mut srs = SRS::::create(cs.domain.d1.size()); + let srs_size = override_srs_size.unwrap_or_else(|| cs.domain.d1.size()); + let mut srs = SRS::::create(srs_size); srs.add_lagrange_basis(cs.domain.d1); let srs = Arc::new(srs); @@ -172,6 +174,6 @@ pub mod testing { G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, { - new_index_for_test_with_lookups::(gates, public, 0, vec![], None, false) + new_index_for_test_with_lookups::(gates, public, 0, vec![], None, false, None) } } diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index f637ddc8d3..ad617d5ad0 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -36,6 +36,7 @@ pub(crate) struct TestFramework { recursion: Vec>, num_prev_challenges: usize, disable_gates_checks: bool, + override_srs_size: Option, prover_index: Option>, verifier_index: Option>, @@ -94,6 +95,12 @@ where self } + #[must_use] + pub(crate) fn override_srs_size(mut self, size: usize) -> Self { + self.override_srs_size = Some(size); + self + } + /// creates the indexes #[must_use] pub(crate) fn setup(mut self) -> TestRunner { @@ -109,6 +116,7 @@ where lookup_tables, runtime_tables_setup, self.disable_gates_checks, + self.override_srs_size, ); println!( "- time to create prover index: {:?}s", diff --git a/kimchi/src/tests/not.rs b/kimchi/src/tests/not.rs index 92e3d15918..056c7e8494 100644 --- a/kimchi/src/tests/not.rs +++ b/kimchi/src/tests/not.rs @@ -412,8 +412,15 @@ fn test_bad_not_gnrc() { }) ); witness[0][1] += PallasField::one(); - let index = - new_index_for_test_with_lookups(cs.gates, 1, 0, vec![xor::lookup_table()], None, false); + let index = new_index_for_test_with_lookups( + cs.gates, + 1, + 0, + vec![xor::lookup_table()], + None, + false, + None, + ); assert_eq!( index.cs.gates[1].verify::(1, &witness, &index, &[]), Err(("generic: incorrect gate").to_string()) diff --git a/kimchi/src/tests/range_check.rs b/kimchi/src/tests/range_check.rs index c9188de577..6705bf5cec 100644 --- a/kimchi/src/tests/range_check.rs +++ b/kimchi/src/tests/range_check.rs @@ -67,6 +67,7 @@ fn create_test_prover_index(public_size: usize, compact: bool) -> ProverIndex Date: Tue, 28 Feb 2023 22:02:28 +0000 Subject: [PATCH 023/242] Add chunked test --- kimchi/src/tests/chunked.rs | 115 ++++++++++++++++++++++++++++++++++++ kimchi/src/tests/mod.rs | 1 + 2 files changed, 116 insertions(+) create mode 100644 kimchi/src/tests/chunked.rs diff --git a/kimchi/src/tests/chunked.rs b/kimchi/src/tests/chunked.rs new file mode 100644 index 0000000000..9db6998f40 --- /dev/null +++ b/kimchi/src/tests/chunked.rs @@ -0,0 +1,115 @@ +use super::framework::TestFramework; +use crate::circuits::polynomials::generic::GenericGateSpec; +use crate::circuits::{ + gate::CircuitGate, + wires::{Wire, COLUMNS}, +}; +use ark_ff::{UniformRand, Zero}; +use itertools::iterate; +use mina_curves::pasta::{Fp, Vesta, VestaParameters}; +use mina_poseidon::{ + constants::PlonkSpongeConstantsKimchi, + sponge::{DefaultFqSponge, DefaultFrSponge}, +}; +use std::array; + +type SpongeParams = PlonkSpongeConstantsKimchi; +type BaseSponge = DefaultFqSponge; +type ScalarSponge = DefaultFrSponge; + +fn test_generic_gate_with_srs_override( + circuit_size_log_2: usize, + override_srs_size: Option, +) { + let public = vec![Fp::from(1u8); 5]; + let circuit_size = (1 << circuit_size_log_2) - 5; + + let mut gates_row = iterate(0, |&i| i + 1); + let mut gates = Vec::with_capacity(circuit_size); + let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); circuit_size]); + + let rng = &mut rand::rngs::OsRng; + + // public input + for p in public.iter() { + let r = gates_row.next().unwrap(); + witness[0][r] = *p; + gates.push(CircuitGate::create_generic_gadget( + Wire::for_row(r), + GenericGateSpec::Pub, + None, + )); + } + + for _ in public.len()..circuit_size { + let r = gates_row.next().unwrap(); + + // First gate + let g1 = GenericGateSpec::Add { + left_coeff: None, + right_coeff: Some(3u32.into()), + output_coeff: None, + }; + let g1_l = ::rand(rng); + let g1_r = ::rand(rng); + let g1_o = g1_l + g1_r * Fp::from(3u32); + witness[0][r] = g1_l; + witness[1][r] = g1_r; + witness[2][r] = g1_o; + + // Second gate + let g2 = GenericGateSpec::Mul { + output_coeff: None, + mul_coeff: Some(2u32.into()), + }; + let g2_l = ::rand(rng); + let g2_r = ::rand(rng); + let g2_o = g2_l * g2_r * Fp::from(2u32); + witness[3][r] = g2_l; + witness[4][r] = g2_r; + witness[5][r] = g2_o; + gates.push(CircuitGate::create_generic_gadget( + Wire::for_row(r), + g1, + Some(g2), + )); + } + + // create and verify proof based on the witness + let framework = TestFramework::::default() + .gates(gates) + .witness(witness) + .public_inputs(public); + let framework = if let Some(srs_size) = override_srs_size { + framework.override_srs_size(srs_size) + } else { + framework + }; + framework + .setup() + .prove_and_verify::() + .unwrap(); +} + +// Disabled, too slow +/*#[test] +fn test_2_to_20_chunked_generic_gate_pub() { + test_generic_gate_with_srs_override(20, Some(1 << 16)) +}*/ + +// Disabled, too slow +/*#[test] +fn test_2_to_18_chunked_generic_gate_pub() { + test_generic_gate_with_srs_override(18, Some(1 << 16)) +}*/ + +#[test] +fn test_2_to_17_chunked_generic_gate_pub() { + test_generic_gate_with_srs_override(17, Some(1 << 16)) +} + +// Disabled; redundant, just for comparison +/*#[test] +fn test_2_to_16_unchunked_generic_gate_pub() { + test_generic_gate_with_srs_override(16, None) +}*/ diff --git a/kimchi/src/tests/mod.rs b/kimchi/src/tests/mod.rs index f102cfa78f..ec35f9635f 100644 --- a/kimchi/src/tests/mod.rs +++ b/kimchi/src/tests/mod.rs @@ -1,4 +1,5 @@ mod and; +mod chunked; mod ec; mod endomul; mod endomul_scalar; From 028e2be7748f2e6bdc89ad0b517ced7cab143522 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 13:34:58 +0000 Subject: [PATCH 024/242] Replace specialized last_4_rows functions with last_n_rows alternatives --- .../circuits/domain_constant_evaluation.rs | 4 +- kimchi/src/circuits/expr.rs | 8 ++-- .../src/circuits/polynomials/permutation.rs | 41 ++++++++++++------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/kimchi/src/circuits/domain_constant_evaluation.rs b/kimchi/src/circuits/domain_constant_evaluation.rs index 15cbb5ff92..8590719388 100644 --- a/kimchi/src/circuits/domain_constant_evaluation.rs +++ b/kimchi/src/circuits/domain_constant_evaluation.rs @@ -10,7 +10,7 @@ use ark_poly::{univariate::DensePolynomial as DP, Evaluations as E, Radix2Evalua use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use super::polynomials::permutation::vanishes_on_last_4_rows; +use super::polynomials::permutation::vanishes_on_last_n_rows; #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] @@ -46,7 +46,7 @@ impl DomainConstantEvaluations { E::>::from_vec_and_domain(vec![F::one(); domain.d8.size()], domain.d8); let vanishes_on_last_4_rows = - vanishes_on_last_4_rows(domain.d1).evaluate_over_domain(domain.d8); + vanishes_on_last_n_rows(domain.d1, 4).evaluate_over_domain(domain.d8); assert!(domain.d1.size > ZK_ROWS); diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 9f084f6903..f8bda59c10 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -7,7 +7,7 @@ use crate::{ index::LookupSelectors, lookups::{LookupPattern, LookupPatterns}, }, - polynomials::permutation::eval_vanishes_on_last_4_rows, + polynomials::permutation::eval_vanishes_on_last_n_rows, wires::COLUMNS, }, proof::{PointEvaluations, ProofEvaluations}, @@ -718,7 +718,7 @@ impl PolishToken { } EndoCoefficient => stack.push(c.endo_coefficient), Mds { row, col } => stack.push(c.mds[*row][*col]), - VanishesOnLast4Rows => stack.push(eval_vanishes_on_last_4_rows(d, pt)), + VanishesOnLast4Rows => stack.push(eval_vanishes_on_last_n_rows(d, 4, pt)), UnnormalizedLagrangeBasis(i) => { stack.push(unnormalized_lagrange_basis(&d, *i, &pt)) } @@ -1538,7 +1538,7 @@ impl Expr> { let y = (*y).evaluate_(d, pt, evals, c)?; Ok(x - y) } - VanishesOnLast4Rows => Ok(eval_vanishes_on_last_4_rows(d, pt)), + VanishesOnLast4Rows => Ok(eval_vanishes_on_last_n_rows(d, 4, pt)), UnnormalizedLagrangeBasis(i) => Ok(unnormalized_lagrange_basis(&d, *i, &pt)), Cell(v) => v.evaluate(evals), Cache(_, e) => e.evaluate_(d, pt, evals, c), @@ -1597,7 +1597,7 @@ impl Expr { let y = (*y).evaluate(d, pt, evals)?; Ok(x - y) } - VanishesOnLast4Rows => Ok(eval_vanishes_on_last_4_rows(d, pt)), + VanishesOnLast4Rows => Ok(eval_vanishes_on_last_n_rows(d, 4, pt)), UnnormalizedLagrangeBasis(i) => Ok(unnormalized_lagrange_basis(&d, *i, &pt)), Cell(v) => v.evaluate(evals), Cache(_, e) => e.evaluate(d, pt, evals), diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 8ca2057b3d..32068d6c0d 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -64,26 +64,37 @@ use std::array; /// Number of constraints produced by the argument. pub const CONSTRAINTS: u32 = 3; pub const ZK_ROWS: u64 = 3; + /// Evaluates the polynomial -/// (x - w^{n - 4}) (x - w^{n - 3}) * (x - w^{n - 2}) * (x - w^{n - 1}) -pub fn eval_vanishes_on_last_4_rows(domain: D, x: F) -> F { - let w4 = domain.group_gen.pow([domain.size - (ZK_ROWS + 1)]); - let w3 = domain.group_gen * w4; - let w2 = domain.group_gen * w3; - let w1 = domain.group_gen * w2; - (x - w1) * (x - w2) * (x - w3) * (x - w4) +/// (x - w^{n - i}) * (x - w^{n - i - 1}) * ... * (x - w^{n - 1}) +pub fn eval_vanishes_on_last_n_rows(domain: D, i: u64, x: F) -> F { + if i == 0 { + return F::one(); + } + let mut term = domain.group_gen.pow([domain.size - i]); + let mut acc = x - term; + for _ in 0..i - 1 { + term *= domain.group_gen; + acc *= x - term; + } + acc } /// The polynomial -/// (x - w^{n - 4}) (x - w^{n - 3}) * (x - w^{n - 2}) * (x - w^{n - 1}) -pub fn vanishes_on_last_4_rows(domain: D) -> DensePolynomial { +/// (x - w^{n - i}) * (x - w^{n - i - 1}) * ... * (x - w^{n - 1}) +pub fn vanishes_on_last_n_rows(domain: D, i: u64) -> DensePolynomial { + let constant = |a: F| DensePolynomial::from_coefficients_slice(&[a]); + if i == 0 { + return constant(F::one()); + } let x = DensePolynomial::from_coefficients_slice(&[F::zero(), F::one()]); - let c = |a: F| DensePolynomial::from_coefficients_slice(&[a]); - let w4 = domain.group_gen.pow([domain.size - (ZK_ROWS + 1)]); - let w3 = domain.group_gen * w4; - let w2 = domain.group_gen * w3; - let w1 = domain.group_gen * w2; - &(&(&x - &c(w1)) * &(&x - &c(w2))) * &(&(&x - &c(w3)) * &(&x - &c(w4))) + let mut term = domain.group_gen.pow([domain.size - i]); + let mut acc = &x - &constant(term); + for _ in 0..i - 1 { + term *= domain.group_gen; + acc = &acc * &(&x - &constant(term)); + } + acc } /// Returns the end of the circuit, which is used for introducing zero-knowledge in the permutation polynomial From 0528df85ede5ab454fd7734d18d8579bc3aaf813 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 14:11:05 +0000 Subject: [PATCH 025/242] Add zk_rows to constraint system --- book/src/specs/kimchi.md | 2 +- kimchi/src/circuits/constraints.rs | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index bb983c29e9..6389a75429 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1601,7 +1601,7 @@ The compilation steps to create the common index are as follow: 1. If the circuit is less than 2 gates, abort. 2. Create a domain for the circuit. That is, compute the smallest subgroup of the field that - has order greater or equal to `n + ZK_ROWS` elements. + has order greater or equal to `n + zk_rows` elements. 3. Pad the circuit: add zero gates to reach the domain size. 4. sample the `PERMUTS` shifts. diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 238e725bc1..1bb2d86d5e 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -148,6 +148,8 @@ pub struct ConstraintSystem { #[serde(bound = "CircuitGate: Serialize + DeserializeOwned")] pub gates: Vec>, + pub zk_rows: u64, + /// flags for optional features pub feature_flags: FeatureFlags, @@ -680,14 +682,16 @@ impl Builder { num_lookups }; + let zk_rows = ZK_ROWS; + //~ 2. Create a domain for the circuit. That is, //~ compute the smallest subgroup of the field that - //~ has order greater or equal to `n + ZK_ROWS` elements. + //~ has order greater or equal to `n + zk_rows` elements. let domain_size_lower_bound = - std::cmp::max(gates.len(), num_lookups + 1) + ZK_ROWS as usize; + std::cmp::max(gates.len(), num_lookups + 1) + zk_rows as usize; let domain = EvaluationDomains::::create(domain_size_lower_bound)?; - assert!(domain.d1.size > ZK_ROWS); + assert!(domain.d1.size > zk_rows); //~ 3. Pad the circuit: add zero gates to reach the domain size. let d1_size = domain.d1.size(); @@ -748,6 +752,7 @@ impl Builder { gates, shift: shifts.shifts, endo, + zk_rows, //fr_sponge_params: self.sponge_params, lookup_constraint_system, feature_flags, From d80c159d357c855c2f3e4b54ed4c68bf2d2e591a Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 14:17:02 +0000 Subject: [PATCH 026/242] Rename vanishes_on_last_4_rows, use the given zk_rows for precomputation --- kimchi/src/circuits/constraints.rs | 5 +++-- .../src/circuits/domain_constant_evaluation.rs | 18 ++++++++---------- kimchi/src/circuits/expr.rs | 15 +++++++++------ kimchi/src/prover.rs | 5 ++++- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 1bb2d86d5e..02ecd2ab45 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -254,8 +254,9 @@ impl ConstraintSystem { } pub fn precomputations(&self) -> &Arc> { - self.precomputations - .get_or_init(|| Arc::new(DomainConstantEvaluations::create(self.domain).unwrap())) + self.precomputations.get_or_init(|| { + Arc::new(DomainConstantEvaluations::create(self.domain, self.zk_rows).unwrap()) + }) } pub fn set_precomputations(&self, precomputations: Arc>) { diff --git a/kimchi/src/circuits/domain_constant_evaluation.rs b/kimchi/src/circuits/domain_constant_evaluation.rs index 8590719388..6996223342 100644 --- a/kimchi/src/circuits/domain_constant_evaluation.rs +++ b/kimchi/src/circuits/domain_constant_evaluation.rs @@ -1,8 +1,6 @@ //! This contains the [DomainConstantEvaluations] which is used to provide precomputations to a [ConstraintSystem](super::constraints::ConstraintSystem). use crate::circuits::domains::EvaluationDomains; -use crate::circuits::polynomials::permutation::zk_polynomial; -use crate::circuits::polynomials::permutation::ZK_ROWS; use ark_ff::FftField; use ark_poly::EvaluationDomain; use ark_poly::UVPolynomial; @@ -26,9 +24,9 @@ pub struct DomainConstantEvaluations { /// 0-th Lagrange evaluated over domain.d8 #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub constant_1_d8: E>, - /// the polynomial that vanishes on the last four rows + /// the polynomial that vanishes on the zero-knowledge rows and the row before #[serde_as(as = "o1_utils::serialization::SerdeAs")] - pub vanishes_on_last_4_rows: E>, + pub vanishes_on_zero_knowledge_and_previous_rows: E>, /// zero-knowledge polynomial over domain.d8 #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub zkpl: E>, @@ -37,7 +35,7 @@ pub struct DomainConstantEvaluations { } impl DomainConstantEvaluations { - pub fn create(domain: EvaluationDomains) -> Option { + pub fn create(domain: EvaluationDomains, zk_rows: u64) -> Option { let poly_x_d1 = DP::from_coefficients_slice(&[F::zero(), F::one()]) .evaluate_over_domain_by_ref(domain.d8); let constant_1_d4 = @@ -45,20 +43,20 @@ impl DomainConstantEvaluations { let constant_1_d8 = E::>::from_vec_and_domain(vec![F::one(); domain.d8.size()], domain.d8); - let vanishes_on_last_4_rows = - vanishes_on_last_n_rows(domain.d1, 4).evaluate_over_domain(domain.d8); + let vanishes_on_zero_knowledge_and_previous_rows = + vanishes_on_last_n_rows(domain.d1, zk_rows + 1).evaluate_over_domain(domain.d8); - assert!(domain.d1.size > ZK_ROWS); + assert!(domain.d1.size > zk_rows); // x^3 - x^2(w1+w2+w3) + x(w1w2+w1w3+w2w3) - w1w2w3 - let zkpm = zk_polynomial(domain.d1); + let zkpm = vanishes_on_last_n_rows(domain.d1, zk_rows); let zkpl = zkpm.evaluate_over_domain_by_ref(domain.d8); Some(DomainConstantEvaluations { poly_x_d1, constant_1_d4, constant_1_d8, - vanishes_on_last_4_rows, + vanishes_on_zero_knowledge_and_previous_rows, zkpl, zkpm, }) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index f8bda59c10..240a35ca5c 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -96,8 +96,8 @@ pub struct Environment<'a, F: FftField> { pub witness: &'a [Evaluations>; COLUMNS], /// The coefficient column polynomials pub coefficient: &'a [Evaluations>; COLUMNS], - /// The polynomial which vanishes on the last 4 elements of the domain. - pub vanishes_on_last_4_rows: &'a Evaluations>, + /// The polynomial that vanishes on the zero-knowledge rows and the row before. + pub vanishes_on_zero_knowledge_and_previous_rows: &'a Evaluations>, /// The permutation aggregation polynomial. pub z: &'a Evaluations>, /// The index selector polynomials. @@ -1733,7 +1733,7 @@ impl Expr { Expr::VanishesOnLast4Rows => EvalResult::SubEvals { domain: Domain::D8, shift: 0, - evals: env.vanishes_on_last_4_rows, + evals: env.vanishes_on_zero_knowledge_and_previous_rows, }, Expr::Constant(x) => EvalResult::Constant(*x), Expr::UnnormalizedLagrangeBasis(i) => EvalResult::Evals { @@ -2429,7 +2429,7 @@ where Constant(x) => x.ocaml(), Cell(v) => format!("cell({})", v.ocaml()), UnnormalizedLagrangeBasis(i) => format!("unnormalized_lagrange_basis({})", *i), - VanishesOnLast4Rows => "vanishes_on_last_4_rows".to_string(), + VanishesOnLast4Rows => "vanishes_on_zero_knowledge_and_previous_rows".to_string(), BinOp(Op2::Add, x, y) => format!("({} + {})", x.ocaml(cache), y.ocaml(cache)), BinOp(Op2::Mul, x, y) => format!("({} * {})", x.ocaml(cache), y.ocaml(cache)), BinOp(Op2::Sub, x, y) => format!("({} - {})", x.ocaml(cache), y.ocaml(cache)), @@ -2501,7 +2501,7 @@ where Constant(x) => x.text(), Cell(v) => v.text(), UnnormalizedLagrangeBasis(i) => format!("unnormalized_lagrange_basis({})", *i), - VanishesOnLast4Rows => "vanishes_on_last_4_rows".to_string(), + VanishesOnLast4Rows => "vanishes_on_zero_knowledge_and_previous_rows".to_string(), BinOp(Op2::Add, x, y) => format!("({} + {})", x.text(cache), y.text(cache)), BinOp(Op2::Mul, x, y) => format!("({} * {})", x.text(cache), y.text(cache)), BinOp(Op2::Sub, x, y) => format!("({} - {})", x.text(cache), y.text(cache)), @@ -2900,7 +2900,10 @@ pub mod test { }, witness: &domain_evals.d8.this.w, coefficient: &index.column_evaluations.coefficients8, - vanishes_on_last_4_rows: &index.cs.precomputations().vanishes_on_last_4_rows, + vanishes_on_zero_knowledge_and_previous_rows: &index + .cs + .precomputations() + .vanishes_on_zero_knowledge_and_previous_rows, z: &domain_evals.d8.this.z, l0_1: l0_1(index.cs.domain.d1), domain: index.cs.domain, diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index b5bd001c4d..7e3c4f3dcb 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -666,7 +666,10 @@ where }, witness: &lagrange.d8.this.w, coefficient: &index.column_evaluations.coefficients8, - vanishes_on_last_4_rows: &index.cs.precomputations().vanishes_on_last_4_rows, + vanishes_on_zero_knowledge_and_previous_rows: &index + .cs + .precomputations() + .vanishes_on_zero_knowledge_and_previous_rows, z: &lagrange.d8.this.z, l0_1: l0_1(index.cs.domain.d1), domain: index.cs.domain, From 68ac0fef8809ec37a5710beaaa33e592f47371d6 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 14:49:52 +0000 Subject: [PATCH 027/242] Pass around zk_rows explicitly in expr --- kimchi/src/circuits/expr.rs | 101 +++++++++++------- kimchi/src/circuits/gate.rs | 1 + kimchi/src/circuits/lookup/constraints.rs | 4 +- kimchi/src/circuits/polynomials/endosclmul.rs | 1 + kimchi/src/circuits/polynomials/turshi.rs | 1 + kimchi/src/prover.rs | 1 + kimchi/src/verifier.rs | 8 ++ 7 files changed, 75 insertions(+), 42 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 240a35ca5c..806430b483 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -67,6 +67,8 @@ pub struct Constants { pub endo_coefficient: F, /// The MDS matrix pub mds: &'static Vec>, + /// The number of zero-knowledge rows + pub zk_rows: u64, } /// The polynomials specific to the lookup argument. @@ -461,7 +463,7 @@ impl FeatureFlag { /// variables /// /// - `Cell(v)` for `v : Variable` -/// - VanishesOnLast4Rows +/// - VanishesOnZeroKnowledgeAndPreviousRows /// - UnnormalizedLagrangeBasis(i) for `i : i32` /// /// This represents a PLONK "custom constraint", which enforces that @@ -474,7 +476,7 @@ pub enum Expr { Double(Box>), Square(Box>), BinOp(Op2, Box>, Box>), - VanishesOnLast4Rows, + VanishesOnZeroKnowledgeAndPreviousRows, /// UnnormalizedLagrangeBasis(i) is /// (x^n - 1) / (x - omega^i) UnnormalizedLagrangeBasis(i32), @@ -488,9 +490,10 @@ impl + PartialEq + Clone> Expr { fn apply_feature_flags_inner(&self, features: &FeatureFlags) -> (Expr, bool) { use Expr::*; match self { - Constant(_) | Cell(_) | VanishesOnLast4Rows | UnnormalizedLagrangeBasis(_) => { - (self.clone(), false) - } + Constant(_) + | Cell(_) + | VanishesOnZeroKnowledgeAndPreviousRows + | UnnormalizedLagrangeBasis(_) => (self.clone(), false), Double(c) => { let (c_reduced, reduce_further) = c.apply_feature_flags_inner(features); if reduce_further && c_reduced.is_zero() { @@ -645,7 +648,7 @@ pub enum PolishToken { Add, Mul, Sub, - VanishesOnLast4Rows, + VanishesOnZeroKnowledgeAndPreviousRows, UnnormalizedLagrangeBasis(i32), Store, Load(usize), @@ -718,7 +721,9 @@ impl PolishToken { } EndoCoefficient => stack.push(c.endo_coefficient), Mds { row, col } => stack.push(c.mds[*row][*col]), - VanishesOnLast4Rows => stack.push(eval_vanishes_on_last_n_rows(d, 4, pt)), + VanishesOnZeroKnowledgeAndPreviousRows => { + stack.push(eval_vanishes_on_last_n_rows(d, c.zk_rows + 1, pt)) + } UnnormalizedLagrangeBasis(i) => { stack.push(unnormalized_lagrange_basis(&d, *i, &pt)) } @@ -791,22 +796,24 @@ impl Expr { Expr::Constant(c) } - fn degree(&self, d1_size: u64) -> u64 { + fn degree(&self, d1_size: u64, zk_rows: u64) -> u64 { use Expr::*; match self { - Double(x) => x.degree(d1_size), + Double(x) => x.degree(d1_size, zk_rows), Constant(_) => 0, - VanishesOnLast4Rows => 4, + VanishesOnZeroKnowledgeAndPreviousRows => zk_rows + 1, UnnormalizedLagrangeBasis(_) => d1_size, Cell(_) => d1_size, - Square(x) => 2 * x.degree(d1_size), - BinOp(Op2::Mul, x, y) => (*x).degree(d1_size) + (*y).degree(d1_size), + Square(x) => 2 * x.degree(d1_size, zk_rows), + BinOp(Op2::Mul, x, y) => (*x).degree(d1_size, zk_rows) + (*y).degree(d1_size, zk_rows), BinOp(Op2::Add, x, y) | BinOp(Op2::Sub, x, y) => { - std::cmp::max((*x).degree(d1_size), (*y).degree(d1_size)) + std::cmp::max((*x).degree(d1_size, zk_rows), (*y).degree(d1_size, zk_rows)) + } + Pow(e, d) => d * e.degree(d1_size, zk_rows), + Cache(_, e) => e.degree(d1_size, zk_rows), + IfFeature(_, e1, e2) => { + std::cmp::max(e1.degree(d1_size, zk_rows), e2.degree(d1_size, zk_rows)) } - Pow(e, d) => d * e.degree(d1_size), - Cache(_, e) => e.degree(d1_size), - IfFeature(_, e1, e2) => std::cmp::max(e1.degree(d1_size), e2.degree(d1_size)), } } } @@ -1414,8 +1421,8 @@ impl Expr> { c.to_polish_(res); } Expr::Cell(v) => res.push(PolishToken::Cell(*v)), - Expr::VanishesOnLast4Rows => { - res.push(PolishToken::VanishesOnLast4Rows); + Expr::VanishesOnZeroKnowledgeAndPreviousRows => { + res.push(PolishToken::VanishesOnZeroKnowledgeAndPreviousRows); } Expr::UnnormalizedLagrangeBasis(i) => { res.push(PolishToken::UnnormalizedLagrangeBasis(*i)); @@ -1484,7 +1491,7 @@ impl Expr> { Square(x) => x.evaluate_constants_(c).square(), Constant(x) => Constant(x.value(c)), Cell(v) => Cell(*v), - VanishesOnLast4Rows => VanishesOnLast4Rows, + VanishesOnZeroKnowledgeAndPreviousRows => VanishesOnZeroKnowledgeAndPreviousRows, UnnormalizedLagrangeBasis(i) => UnnormalizedLagrangeBasis(*i), BinOp(Op2::Add, x, y) => x.evaluate_constants_(c) + y.evaluate_constants_(c), BinOp(Op2::Mul, x, y) => x.evaluate_constants_(c) * y.evaluate_constants_(c), @@ -1538,7 +1545,9 @@ impl Expr> { let y = (*y).evaluate_(d, pt, evals, c)?; Ok(x - y) } - VanishesOnLast4Rows => Ok(eval_vanishes_on_last_n_rows(d, 4, pt)), + VanishesOnZeroKnowledgeAndPreviousRows => { + Ok(eval_vanishes_on_last_n_rows(d, c.zk_rows + 1, pt)) + } UnnormalizedLagrangeBasis(i) => Ok(unnormalized_lagrange_basis(&d, *i, &pt)), Cell(v) => v.evaluate(evals), Cache(_, e) => e.evaluate_(d, pt, evals, c), @@ -1574,38 +1583,41 @@ impl Expr { &self, d: D, pt: F, + zk_rows: u64, evals: &ProofEvaluations>, ) -> Result { use Expr::*; match self { Constant(x) => Ok(*x), - Pow(x, p) => Ok(x.evaluate(d, pt, evals)?.pow([*p])), - Double(x) => x.evaluate(d, pt, evals).map(|x| x.double()), - Square(x) => x.evaluate(d, pt, evals).map(|x| x.square()), + Pow(x, p) => Ok(x.evaluate(d, pt, zk_rows, evals)?.pow([*p])), + Double(x) => x.evaluate(d, pt, zk_rows, evals).map(|x| x.double()), + Square(x) => x.evaluate(d, pt, zk_rows, evals).map(|x| x.square()), BinOp(Op2::Mul, x, y) => { - let x = (*x).evaluate(d, pt, evals)?; - let y = (*y).evaluate(d, pt, evals)?; + let x = (*x).evaluate(d, pt, zk_rows, evals)?; + let y = (*y).evaluate(d, pt, zk_rows, evals)?; Ok(x * y) } BinOp(Op2::Add, x, y) => { - let x = (*x).evaluate(d, pt, evals)?; - let y = (*y).evaluate(d, pt, evals)?; + let x = (*x).evaluate(d, pt, zk_rows, evals)?; + let y = (*y).evaluate(d, pt, zk_rows, evals)?; Ok(x + y) } BinOp(Op2::Sub, x, y) => { - let x = (*x).evaluate(d, pt, evals)?; - let y = (*y).evaluate(d, pt, evals)?; + let x = (*x).evaluate(d, pt, zk_rows, evals)?; + let y = (*y).evaluate(d, pt, zk_rows, evals)?; Ok(x - y) } - VanishesOnLast4Rows => Ok(eval_vanishes_on_last_n_rows(d, 4, pt)), + VanishesOnZeroKnowledgeAndPreviousRows => { + Ok(eval_vanishes_on_last_n_rows(d, zk_rows + 1, pt)) + } UnnormalizedLagrangeBasis(i) => Ok(unnormalized_lagrange_basis(&d, *i, &pt)), Cell(v) => v.evaluate(evals), - Cache(_, e) => e.evaluate(d, pt, evals), + Cache(_, e) => e.evaluate(d, pt, zk_rows, evals), IfFeature(feature, e1, e2) => { if feature.is_enabled() { - e1.evaluate(d, pt, evals) + e1.evaluate(d, pt, zk_rows, evals) } else { - e2.evaluate(d, pt, evals) + e2.evaluate(d, pt, zk_rows, evals) } } } @@ -1614,7 +1626,7 @@ impl Expr { /// Compute the polynomial corresponding to this expression, in evaluation form. pub fn evaluations(&self, env: &Environment<'_, F>) -> Evaluations> { let d1_size = env.domain.d1.size; - let deg = self.degree(d1_size); + let deg = self.degree(d1_size, env.constants.zk_rows); let d = if deg <= d1_size { Domain::D1 } else if deg <= 4 * d1_size { @@ -1730,7 +1742,7 @@ impl Expr { } } } - Expr::VanishesOnLast4Rows => EvalResult::SubEvals { + Expr::VanishesOnZeroKnowledgeAndPreviousRows => EvalResult::SubEvals { domain: Domain::D8, shift: 0, evals: env.vanishes_on_zero_knowledge_and_previous_rows, @@ -1930,7 +1942,7 @@ impl + Clone + One + Zero + PartialEq> Expr { Cell(v) => evaluated.contains(&v.col), Double(x) => x.is_constant(evaluated), BinOp(_, x, y) => x.is_constant(evaluated) && y.is_constant(evaluated), - VanishesOnLast4Rows => true, + VanishesOnZeroKnowledgeAndPreviousRows => true, UnnormalizedLagrangeBasis(_) => true, Cache(_, x) => x.is_constant(evaluated), IfFeature(_, e1, e2) => e1.is_constant(evaluated) && e2.is_constant(evaluated), @@ -1976,7 +1988,9 @@ impl + Clone + One + Zero + PartialEq> Expr { } Cache(_, e) => e.monomials(ev), UnnormalizedLagrangeBasis(i) => constant(UnnormalizedLagrangeBasis(*i)), - VanishesOnLast4Rows => constant(VanishesOnLast4Rows), + VanishesOnZeroKnowledgeAndPreviousRows => { + constant(VanishesOnZeroKnowledgeAndPreviousRows) + } Constant(c) => constant(Constant(c.clone())), Cell(var) => sing(vec![*var], Constant(F::one())), BinOp(Op2::Add, e1, e2) => { @@ -2429,7 +2443,9 @@ where Constant(x) => x.ocaml(), Cell(v) => format!("cell({})", v.ocaml()), UnnormalizedLagrangeBasis(i) => format!("unnormalized_lagrange_basis({})", *i), - VanishesOnLast4Rows => "vanishes_on_zero_knowledge_and_previous_rows".to_string(), + VanishesOnZeroKnowledgeAndPreviousRows => { + "vanishes_on_zero_knowledge_and_previous_rows".to_string() + } BinOp(Op2::Add, x, y) => format!("({} + {})", x.ocaml(cache), y.ocaml(cache)), BinOp(Op2::Mul, x, y) => format!("({} * {})", x.ocaml(cache), y.ocaml(cache)), BinOp(Op2::Sub, x, y) => format!("({} - {})", x.ocaml(cache), y.ocaml(cache)), @@ -2478,7 +2494,9 @@ where Constant(x) => x.latex(), Cell(v) => v.latex(), UnnormalizedLagrangeBasis(i) => format!("unnormalized\\_lagrange\\_basis({})", *i), - VanishesOnLast4Rows => "vanishes\\_on\\_last\\_4\\_rows".to_string(), + VanishesOnZeroKnowledgeAndPreviousRows => { + "vanishes\\_on\\_zero\\_knowledge\\_and\\_previous\\_row".to_string() + } BinOp(Op2::Add, x, y) => format!("({} + {})", x.latex(cache), y.latex(cache)), BinOp(Op2::Mul, x, y) => format!("({} \\cdot {})", x.latex(cache), y.latex(cache)), BinOp(Op2::Sub, x, y) => format!("({} - {})", x.latex(cache), y.latex(cache)), @@ -2501,7 +2519,9 @@ where Constant(x) => x.text(), Cell(v) => v.text(), UnnormalizedLagrangeBasis(i) => format!("unnormalized_lagrange_basis({})", *i), - VanishesOnLast4Rows => "vanishes_on_zero_knowledge_and_previous_rows".to_string(), + VanishesOnZeroKnowledgeAndPreviousRows => { + "vanishes_on_zero_knowledge_and_previous_rows".to_string() + } BinOp(Op2::Add, x, y) => format!("({} + {})", x.text(cache), y.text(cache)), BinOp(Op2::Mul, x, y) => format!("({} * {})", x.text(cache), y.text(cache)), BinOp(Op2::Sub, x, y) => format!("({} - {})", x.text(cache), y.text(cache)), @@ -2897,6 +2917,7 @@ pub mod test { joint_combiner: None, endo_coefficient: one, mds: &Vesta::sponge_params().mds, + zk_rows: 3, }, witness: &domain_evals.d8.this.w, coefficient: &index.column_evaluations.coefficients8, diff --git a/kimchi/src/circuits/gate.rs b/kimchi/src/circuits/gate.rs index f2a247851f..b3ec44543c 100644 --- a/kimchi/src/circuits/gate.rs +++ b/kimchi/src/circuits/gate.rs @@ -251,6 +251,7 @@ impl CircuitGate { joint_combiner: Some(F::one()), endo_coefficient: cs.endo, mds: &G::sponge_params().mds, + zk_rows: cs.zk_rows, }; // Create the argument environment for the constraints over field elements let env = ArgumentEnv::::create(argument_witness, self.coeffs.clone(), constants); diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index 22e394d4b8..9132272053 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -602,9 +602,9 @@ pub fn constraints( let final_lookup_row: i32 = -(ZK_ROWS as i32) - 1; let mut res = vec![ - // the accumulator except for the last 4 rows + // the accumulator except for the last zk_rows+1 rows // (contains the zk-rows and the last value of the accumulator) - E::VanishesOnLast4Rows * aggreg_equation, + E::VanishesOnZeroKnowledgeAndPreviousRows * aggreg_equation, // the initial value of the accumulator E::UnnormalizedLagrangeBasis(0) * (E::cell(Column::LookupAggreg, Curr) - E::one()), // Check that the final value of the accumulator is 1 diff --git a/kimchi/src/circuits/polynomials/endosclmul.rs b/kimchi/src/circuits/polynomials/endosclmul.rs index 8ddf04b95f..07fd31e6a5 100644 --- a/kimchi/src/circuits/polynomials/endosclmul.rs +++ b/kimchi/src/circuits/polynomials/endosclmul.rs @@ -145,6 +145,7 @@ impl CircuitGate { joint_combiner: None, mds: &G::sponge_params().mds, endo_coefficient: cs.endo, + zk_rows: 3, }; let evals: ProofEvaluations> = diff --git a/kimchi/src/circuits/polynomials/turshi.rs b/kimchi/src/circuits/polynomials/turshi.rs index 41a5e6de85..0671da2436 100644 --- a/kimchi/src/circuits/polynomials/turshi.rs +++ b/kimchi/src/circuits/polynomials/turshi.rs @@ -225,6 +225,7 @@ impl CircuitGate { joint_combiner: None, endo_coefficient: cs.endo, mds: &G::sponge_params().mds, + zk_rows: 3, }; let pt = F::rand(rng); diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 7e3c4f3dcb..b45814770f 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -663,6 +663,7 @@ where joint_combiner: lookup_context.joint_combiner, endo_coefficient: index.cs.endo, mds, + zk_rows: index.cs.zk_rows, }, witness: &lagrange.d8.this.w, coefficient: &index.column_evaluations.coefficients8, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index d81a8c9c83..4ee1b0d131 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -122,6 +122,9 @@ where let chunk_size = index.domain.size() / index.max_poly_size; + // TODO + let zk_rows = 3; + //~ 1. Setup the Fq-Sponge. let mut fq_sponge = EFqSponge::new(G::OtherCurve::sponge_params()); @@ -375,6 +378,7 @@ where joint_combiner: joint_combiner.as_ref().map(|j| j.1), endo_coefficient: index.endo, mds: &G::sponge_params().mds, + zk_rows, }; ft_eval0 -= PolishToken::evaluate( @@ -563,6 +567,9 @@ where //~ Essentially, this steps verifies that $f(\zeta) = t(\zeta) * Z_H(\zeta)$. //~ + // TODO + let zk_rows = 3; + if proof.prev_challenges.len() != verifier_index.prev_challenges { return Err(VerifyError::IncorrectPrevChallengesLength( verifier_index.prev_challenges, @@ -665,6 +672,7 @@ where joint_combiner: oracles.joint_combiner.as_ref().map(|j| j.1), endo_coefficient: verifier_index.endo, mds: &G::sponge_params().mds, + zk_rows, }; for (col, tokens) in &verifier_index.linearization.index_terms { From 09ae11ead16efa20451f6960663f865ff20e1fc4 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 14:56:55 +0000 Subject: [PATCH 028/242] Carry zk_rows in the verifier index --- book/src/specs/kimchi.md | 2 ++ kimchi/src/verifier.rs | 6 ++---- kimchi/src/verifier_index.rs | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 6389a75429..f87e46ab1e 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1750,6 +1750,8 @@ pub struct VerifierIndex { pub domain: D, /// maximal size of polynomial section pub max_poly_size: usize, + /// the number of randomized rows to achieve zero knowledge + pub zk_rows: u64, /// polynomial commitment keys #[serde(skip)] pub srs: OnceCell>>, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 4ee1b0d131..1529799ddd 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -122,8 +122,7 @@ where let chunk_size = index.domain.size() / index.max_poly_size; - // TODO - let zk_rows = 3; + let zk_rows = index.zk_rows; //~ 1. Setup the Fq-Sponge. let mut fq_sponge = EFqSponge::new(G::OtherCurve::sponge_params()); @@ -567,8 +566,7 @@ where //~ Essentially, this steps verifies that $f(\zeta) = t(\zeta) * Z_H(\zeta)$. //~ - // TODO - let zk_rows = 3; + let zk_rows = verifier_index.zk_rows; if proof.prev_challenges.len() != verifier_index.prev_challenges { return Err(VerifyError::IncorrectPrevChallengesLength( diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 1163885f0d..8c99ca7ef7 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -62,6 +62,8 @@ pub struct VerifierIndex { pub domain: D, /// maximal size of polynomial section pub max_poly_size: usize, + /// the number of randomized rows to achieve zero knowledge + pub zk_rows: u64, /// polynomial commitment keys #[serde(skip)] pub srs: OnceCell>>, @@ -200,6 +202,7 @@ impl ProverIndex { VerifierIndex { domain, max_poly_size: self.max_poly_size, + zk_rows: self.cs.zk_rows, powers_of_alpha: self.powers_of_alpha.clone(), public: self.cs.public, prev_challenges: self.cs.prev_challenges, @@ -394,6 +397,7 @@ impl VerifierIndex { let VerifierIndex { domain: _, max_poly_size: _, + zk_rows: _, srs: _, public: _, prev_challenges: _, From 0042ca21596bb17fd9b6dd90a976228ec8f7f130 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 15:00:33 +0000 Subject: [PATCH 029/242] Fixup constant zk_rows: 3 --- kimchi/src/circuits/polynomials/endosclmul.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/polynomials/endosclmul.rs b/kimchi/src/circuits/polynomials/endosclmul.rs index 07fd31e6a5..5834a2a4df 100644 --- a/kimchi/src/circuits/polynomials/endosclmul.rs +++ b/kimchi/src/circuits/polynomials/endosclmul.rs @@ -145,7 +145,7 @@ impl CircuitGate { joint_combiner: None, mds: &G::sponge_params().mds, endo_coefficient: cs.endo, - zk_rows: 3, + zk_rows: cs.zk_rows, }; let evals: ProofEvaluations> = From ffdf4e23bc3e4c33138c28dd2a96127217336e48 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 15:36:10 +0000 Subject: [PATCH 030/242] Remove ZK_ROWS from lookup constraints --- kimchi/src/alphas.rs | 7 ++++-- kimchi/src/circuits/lookup/constraints.rs | 26 ++++++++++++----------- kimchi/src/linearization.rs | 11 ++++++---- kimchi/src/prover.rs | 17 +++++++++++++-- kimchi/src/prover_index.rs | 3 ++- 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/kimchi/src/alphas.rs b/kimchi/src/alphas.rs index 0eaa047114..2dbef2aaf3 100644 --- a/kimchi/src/alphas.rs +++ b/kimchi/src/alphas.rs @@ -323,8 +323,11 @@ mod tests { fn get_alphas_for_spec() { let gates = vec![CircuitGate::::zero(Wire::for_row(0)); 2]; let index = new_index_for_test::(gates, 0); - let (_linearization, powers_of_alpha) = - expr_linearization::(Some(&index.cs.feature_flags), true); + let (_linearization, powers_of_alpha) = expr_linearization::( + Some(&index.cs.feature_flags), + true, + index.cs.zk_rows as usize, + ); // make sure this is present in the specification let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let spec_path = Path::new(&manifest_dir) diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index 9132272053..ef11bc9588 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -23,9 +23,6 @@ use super::runtime_tables; /// Number of constraints produced by the argument. pub const CONSTRAINTS: u32 = 7; -/// The number of random values to append to columns for zero-knowledge. -pub const ZK_ROWS: usize = 3; - /// Pad with zeroes and then add 3 random elements in the last two /// rows for zero knowledge. /// @@ -35,13 +32,14 @@ pub const ZK_ROWS: usize = 3; pub fn zk_patch( mut e: Vec, d: D, + zk_rows: usize, rng: &mut R, ) -> Evaluations> { let n = d.size(); let k = e.len(); - assert!(k <= n - ZK_ROWS); - e.extend((0..((n - ZK_ROWS) - k)).map(|_| F::zero())); - e.extend((0..ZK_ROWS).map(|_| F::rand(rng))); + assert!(k <= n - zk_rows); + e.extend((0..((n - zk_rows) - k)).map(|_| F::zero())); + e.extend((0..zk_rows).map(|_| F::rand(rng))); Evaluations::>::from_vec_and_domain(e, d) } @@ -93,6 +91,7 @@ pub fn sorted( joint_combiner: F, table_id_combiner: F, lookup_info: &LookupInfo, + zk_rows: usize, ) -> Result>, ProverError> { // We pad the lookups so that it is as if we lookup exactly // `max_lookups_per_row` in every row. @@ -100,7 +99,7 @@ pub fn sorted( let n = d1.size(); let mut counts: HashMap<&F, usize> = HashMap::new(); - let lookup_rows = n - ZK_ROWS - 1; + let lookup_rows = n - zk_rows - 1; let by_row = lookup_info.by_row(gates); let max_lookups_per_row = lookup_info.max_per_row; @@ -238,13 +237,14 @@ pub fn aggregation( sorted: &[Evaluations>], rng: &mut R, lookup_info: &LookupInfo, + zk_rows: usize, ) -> Result>, ProverError> where R: Rng + ?Sized, F: PrimeField, { let n = d1.size(); - let lookup_rows = n - ZK_ROWS - 1; + let lookup_rows = n - zk_rows - 1; let beta1: F = F::one() + beta; let gammabeta1 = gamma * beta1; let mut lookup_aggreg = vec![F::one()]; @@ -316,11 +316,11 @@ where lookup_aggreg[i + 1] *= prev; }); - let res = zk_patch(lookup_aggreg, d1, rng); + let res = zk_patch(lookup_aggreg, d1, zk_rows, rng); // check that the final evaluation is equal to 1 if cfg!(debug_assertions) { - let final_val = res.evals[d1.size() - (ZK_ROWS + 1)]; + let final_val = res.evals[d1.size() - (zk_rows + 1)]; if final_val != F::one() { panic!("aggregation incorrect: {final_val}"); } @@ -370,6 +370,7 @@ impl LookupConfiguration { pub fn constraints( configuration: &LookupConfiguration, generate_feature_flags: bool, + zk_rows: usize, ) -> Vec> { // Something important to keep in mind is that the last 2 rows of // all columns will have random values in them to maintain zero-knowledge. @@ -599,7 +600,7 @@ pub fn constraints( let aggreg_equation = E::cell(Column::LookupAggreg, Next) * denominator - E::cell(Column::LookupAggreg, Curr) * numerator; - let final_lookup_row: i32 = -(ZK_ROWS as i32) - 1; + let final_lookup_row: i32 = -(zk_rows as i32) - 1; let mut res = vec![ // the accumulator except for the last zk_rows+1 rows @@ -679,12 +680,13 @@ pub fn verify, TABLE: Fn() -> I>( table_id_combiner: &F, sorted: &[Evaluations>], lookup_info: &LookupInfo, + zk_rows: usize, ) { sorted .iter() .for_each(|s| assert_eq!(d1.size, s.domain().size)); let n = d1.size(); - let lookup_rows = n - ZK_ROWS - 1; + let lookup_rows = n - zk_rows - 1; // Check that the (desnakified) sorted table is // 1. Sorted diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 76e33efa96..f2b0a9c663 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -37,6 +37,7 @@ use ark_ff::{FftField, PrimeField, SquareRootField, Zero}; pub fn constraints_expr( feature_flags: Option<&FeatureFlags>, generic: bool, + zk_rows: usize, ) -> (Expr>, Alphas) { // register powers of alpha so that we don't reuse them across mutually inclusive constraints let mut powers_of_alpha = Alphas::::default(); @@ -158,7 +159,8 @@ pub fn constraints_expr( if feature_flags.lookup_features.patterns != LookupPatterns::default() { let lookup_configuration = LookupConfiguration::new(LookupInfo::create(feature_flags.lookup_features)); - let constraints = lookup::constraints::constraints(&lookup_configuration, false); + let constraints = + lookup::constraints::constraints(&lookup_configuration, false, zk_rows); // note: the number of constraints depends on the lookup configuration, // specifically the presence of runtime tables. @@ -184,7 +186,7 @@ pub fn constraints_expr( joint_lookup_used: true, }; let lookup_configuration = LookupConfiguration::new(LookupInfo::create(all_features)); - let constraints = lookup::constraints::constraints(&lookup_configuration, true); + let constraints = lookup::constraints::constraints(&lookup_configuration, true, zk_rows); // note: the number of constraints depends on the lookup configuration, // specifically the presence of runtime tables. @@ -215,7 +217,7 @@ pub fn constraints_expr( // flags. if cfg!(feature = "check_feature_flags") { if let Some(feature_flags) = feature_flags { - let (feature_flagged_expr, _) = constraints_expr(None, generic); + let (feature_flagged_expr, _) = constraints_expr(None, generic, zk_rows); let feature_flagged_expr = feature_flagged_expr.apply_feature_flags(feature_flags); assert_eq!(expr, feature_flagged_expr); } @@ -312,10 +314,11 @@ pub fn linearization_columns( pub fn expr_linearization( feature_flags: Option<&FeatureFlags>, generic: bool, + zk_rows: usize, ) -> (Linearization>>, Alphas) { let evaluated_cols = linearization_columns::(feature_flags); - let (expr, powers_of_alpha) = constraints_expr(feature_flags, generic); + let (expr, powers_of_alpha) = constraints_expr(feature_flags, generic, zk_rows); let linearization = expr .linearize(evaluated_cols) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index b45814770f..bc288698e5 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -476,13 +476,21 @@ where joint_combiner, table_id_combiner, &lcs.configuration.lookup_info, + index.cs.zk_rows as usize, )?; //~~ * Randomize the last `EVALS` rows in each of the sorted polynomials //~~ in order to add zero-knowledge to the protocol. let sorted: Vec<_> = sorted .into_iter() - .map(|chunk| lookup::constraints::zk_patch(chunk, index.cs.domain.d1, rng)) + .map(|chunk| { + lookup::constraints::zk_patch( + chunk, + index.cs.domain.d1, + index.cs.zk_rows as usize, + rng, + ) + }) .collect(); //~~ * Commit each of the sorted polynomials. @@ -537,6 +545,7 @@ where lookup_context.sorted.as_ref().unwrap(), rng, &lcs.configuration.lookup_info, + index.cs.zk_rows as usize, )?; //~~ * Commit to the aggregation polynomial. @@ -766,7 +775,11 @@ where // lookup { if let Some(lcs) = index.cs.lookup_constraint_system.as_ref() { - let constraints = lookup::constraints::constraints(&lcs.configuration, false); + let constraints = lookup::constraints::constraints( + &lcs.configuration, + false, + index.cs.zk_rows as usize, + ); let constraints_len = u32::try_from(constraints.len()) .expect("not expecting a large amount of constraints"); let lookup_alphas = diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 73fc436cfb..c6b91b4886 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -65,7 +65,8 @@ impl ProverIndex { cs.endo = endo_q; // pre-compute the linearization - let (linearization, powers_of_alpha) = expr_linearization(Some(&cs.feature_flags), true); + let (linearization, powers_of_alpha) = + expr_linearization(Some(&cs.feature_flags), true, cs.zk_rows as usize); let evaluated_column_coefficients = cs.evaluated_column_coefficients(); From ad24c951b73e9abe275fe7cee17ebb06d844282f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 15:41:02 +0000 Subject: [PATCH 031/242] Use vanishes_on_last_n_rows for zk polys --- .../src/circuits/polynomials/permutation.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 32068d6c0d..d4507cacf4 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -105,29 +105,14 @@ pub fn zk_w3(domain: D) -> F { /// Evaluates the polynomial /// (x - w^{n - 3}) * (x - w^{n - 2}) * (x - w^{n - 1}) pub fn eval_zk_polynomial(domain: D, x: F) -> F { - let w3 = zk_w3(domain); - let w2 = domain.group_gen * w3; - let w1 = domain.group_gen * w2; - (x - w1) * (x - w2) * (x - w3) + eval_vanishes_on_last_n_rows(domain, ZK_ROWS, x) } /// Computes the zero-knowledge polynomial for blinding the permutation polynomial: `(x-w^{n-k})(x-w^{n-k-1})...(x-w^n)`. /// Currently, we use k = 3 for 2 blinding factors, /// see pub fn zk_polynomial(domain: D) -> DensePolynomial { - let w3 = zk_w3(domain); - let w2 = domain.group_gen * w3; - let w1 = domain.group_gen * w2; - - // (x-w3)(x-w2)(x-w1) = - // x^3 - x^2(w1+w2+w3) + x(w1w2+w1w3+w2w3) - w1w2w3 - let w1w2 = w1 * w2; - DensePolynomial::from_coefficients_slice(&[ - -w1w2 * w3, // 1 - w1w2 + (w1 * w3) + (w3 * w2), // x - -w1 - w2 - w3, // x^2 - F::one(), // x^3 - ]) + vanishes_on_last_n_rows(domain, ZK_ROWS) } /// Shifts represent the shifts required in the permutation argument of PLONK. From 23928edb471fd37968c0f1554e2404f7f40d922f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 15:52:56 +0000 Subject: [PATCH 032/242] Remove zk_polynomial and eval_zk_polynomial --- kimchi/src/circuits/polynomials/permutation.rs | 13 ------------- kimchi/src/verifier_index.rs | 5 +++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index d4507cacf4..803a8574ed 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -102,19 +102,6 @@ pub fn zk_w3(domain: D) -> F { domain.group_gen.pow([domain.size - (ZK_ROWS)]) } -/// Evaluates the polynomial -/// (x - w^{n - 3}) * (x - w^{n - 2}) * (x - w^{n - 1}) -pub fn eval_zk_polynomial(domain: D, x: F) -> F { - eval_vanishes_on_last_n_rows(domain, ZK_ROWS, x) -} - -/// Computes the zero-knowledge polynomial for blinding the permutation polynomial: `(x-w^{n-k})(x-w^{n-k-1})...(x-w^n)`. -/// Currently, we use k = 3 for 2 blinding factors, -/// see -pub fn zk_polynomial(domain: D) -> DensePolynomial { - vanishes_on_last_n_rows(domain, ZK_ROWS) -} - /// Shifts represent the shifts required in the permutation argument of PLONK. /// It also caches the shifted powers of omega for optimization purposes. pub struct Shifts { diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 8c99ca7ef7..946e729986 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -6,7 +6,7 @@ use crate::{ circuits::{ expr::{Linearization, PolishToken}, lookup::{index::LookupSelectors, lookups::LookupInfo}, - polynomials::permutation::{zk_polynomial, zk_w3}, + polynomials::permutation::{vanishes_on_last_n_rows, zk_w3}, wires::{COLUMNS, PERMUTS}, }, curve::KimchiCurve, @@ -319,7 +319,8 @@ impl VerifierIndex { /// Gets zkpm from [`VerifierIndex`] lazily pub fn zkpm(&self) -> &DensePolynomial { - self.zkpm.get_or_init(|| zk_polynomial(self.domain)) + self.zkpm + .get_or_init(|| vanishes_on_last_n_rows(self.domain, self.zk_rows)) } /// Gets w from [`VerifierIndex`] lazily From 04bcffb038a14cdac032b06e71148f2039306601 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 6 Mar 2023 16:03:11 +0000 Subject: [PATCH 033/242] Remove final uses of ZK_ROWS --- book/src/specs/kimchi.md | 4 ++-- kimchi/src/circuits/constraints.rs | 15 ++++++++++----- kimchi/src/circuits/expr.rs | 10 ++++------ kimchi/src/circuits/lookup/index.rs | 10 +++++----- kimchi/src/circuits/polynomials/permutation.rs | 5 ++--- kimchi/src/prover.rs | 11 +++++------ kimchi/src/verifier_index.rs | 6 +++--- 7 files changed, 31 insertions(+), 30 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index f87e46ab1e..2ba6f602c8 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2070,10 +2070,10 @@ The prover then follows the following steps to create the proof: 1. Ensure we have room in the witness for the zero-knowledge rows. We currently expect the witness not to be of the same length as the domain, but instead be of the length of the (smaller) circuit. - If we cannot add `ZK_ROWS` rows to the columns of the witness before reaching + If we cannot add `zk_rows` rows to the columns of the witness before reaching the size of the domain, abort. 1. Pad the witness columns with Zero gates to make them the same length as the domain. - Then, randomize the last `ZK_ROWS` of each columns. + Then, randomize the last `zk_rows` of each columns. 1. Setup the Fq-Sponge. 1. Absorb the digest of the VerifierIndex. 1. Absorb the commitments of the previous challenges with the Fq-sponge. diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 02ecd2ab45..c6f63719e6 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -7,7 +7,7 @@ use crate::{ gate::{CircuitGate, GateType}, lookup::{index::LookupConstraintSystem, lookups::LookupFeatures, tables::LookupTable}, polynomial::{WitnessEvals, WitnessOverDomains, WitnessShifts}, - polynomials::permutation::{Shifts, ZK_ROWS}, + polynomials::permutation::Shifts, wires::*, }, curve::KimchiCurve, @@ -683,7 +683,7 @@ impl Builder { num_lookups }; - let zk_rows = ZK_ROWS; + let zk_rows = 3; //~ 2. Create a domain for the circuit. That is, //~ compute the smallest subgroup of the field that @@ -734,9 +734,14 @@ impl Builder { // // Lookup // ------ - let lookup_constraint_system = - LookupConstraintSystem::create(&gates, lookup_tables, runtime_tables, &domain) - .map_err(|e| SetupError::ConstraintSystem(e.to_string()))?; + let lookup_constraint_system = LookupConstraintSystem::create( + &gates, + lookup_tables, + runtime_tables, + &domain, + zk_rows as usize, + ) + .map_err(|e| SetupError::ConstraintSystem(e.to_string()))?; let sid = shifts.map[0].clone(); diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 806430b483..b62371ebde 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -2841,11 +2841,8 @@ pub mod test { use super::*; use crate::{ circuits::{ - constraints::ConstraintSystem, - expr::constraints::ExprOps, - gate::CircuitGate, - polynomials::{generic::GenericGateSpec, permutation::ZK_ROWS}, - wires::Wire, + constraints::ConstraintSystem, expr::constraints::ExprOps, gate::CircuitGate, + polynomials::generic::GenericGateSpec, wires::Wire, }, curve::KimchiCurve, prover_index::ProverIndex, @@ -2938,7 +2935,8 @@ pub mod test { #[test] fn test_unnormalized_lagrange_basis() { - let domain = EvaluationDomains::::create(2usize.pow(10) + ZK_ROWS as usize) + let zk_rows = 3; + let domain = EvaluationDomains::::create(2usize.pow(10) + zk_rows) .expect("failed to create evaluation domain"); let rng = &mut StdRng::from_seed([17u8; 32]); diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index a5e1734f63..3bb1634b62 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -7,7 +7,6 @@ use crate::circuits::{ lookups::{LookupInfo, LookupPattern}, tables::LookupTable, }, - polynomials::permutation::ZK_ROWS, }; use ark_ff::{FftField, PrimeField, SquareRootField}; use ark_poly::{ @@ -204,6 +203,7 @@ impl LookupConstraintSystem { lookup_tables: Vec>, runtime_tables: Option>>, domain: &EvaluationDomains, + zk_rows: usize, ) -> Result, LookupError> { //~ 1. If no lookup is used in the circuit, do not create a lookup index match LookupInfo::create_from_gates(gates, runtime_tables.is_some()) { @@ -212,10 +212,10 @@ impl LookupConstraintSystem { let d1_size = domain.d1.size(); // The maximum number of entries that can be provided across all tables. - // Since we do not assert the lookup constraint on the final `ZK_ROWS` rows, and + // Since we do not assert the lookup constraint on the final `zk_rows` rows, and // because the row before is used to assert that the lookup argument's final // product is 1, we cannot use those rows to store any values. - let max_num_entries = d1_size - (ZK_ROWS as usize) - 1; + let max_num_entries = d1_size - zk_rows - 1; //~ 2. Get the lookup selectors and lookup tables (TODO: how?) let (lookup_selectors, gate_lookup_tables) = @@ -257,8 +257,8 @@ impl LookupConstraintSystem { .take(d1_size - runtime_table_offset - runtime_len), ); - // although the last ZK_ROWS are fine - for e in evals.iter_mut().rev().take(ZK_ROWS as usize) { + // although the last zk_rows are fine + for e in evals.iter_mut().rev().take(zk_rows) { *e = F::zero(); } diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 803a8574ed..d7f995c2ab 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -63,7 +63,6 @@ use std::array; /// Number of constraints produced by the argument. pub const CONSTRAINTS: u32 = 3; -pub const ZK_ROWS: u64 = 3; /// Evaluates the polynomial /// (x - w^{n - i}) * (x - w^{n - i - 1}) * ... * (x - w^{n - 1}) @@ -98,8 +97,8 @@ pub fn vanishes_on_last_n_rows(domain: D, i: u64) -> DensePolyno } /// Returns the end of the circuit, which is used for introducing zero-knowledge in the permutation polynomial -pub fn zk_w3(domain: D) -> F { - domain.group_gen.pow([domain.size - (ZK_ROWS)]) +pub fn zk_w(domain: D, zk_rows: u64) -> F { + domain.group_gen.pow([domain.size - zk_rows]) } /// Shifts represent the shifts required in the permutation argument of PLONK. diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index bc288698e5..b58154e05e 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -13,7 +13,6 @@ use crate::{ foreign_field_add::circuitgates::ForeignFieldAdd, foreign_field_mul::{self, circuitgates::ForeignFieldMul}, generic, permutation, - permutation::ZK_ROWS, poseidon::Poseidon, range_check::circuitgates::{RangeCheck0, RangeCheck1}, rot::Rot64, @@ -180,19 +179,19 @@ where //~ 1. Ensure we have room in the witness for the zero-knowledge rows. //~ We currently expect the witness not to be of the same length as the domain, //~ but instead be of the length of the (smaller) circuit. - //~ If we cannot add `ZK_ROWS` rows to the columns of the witness before reaching + //~ If we cannot add `zk_rows` rows to the columns of the witness before reaching //~ the size of the domain, abort. let length_witness = witness[0].len(); let length_padding = d1_size .checked_sub(length_witness) .ok_or(ProverError::NoRoomForZkInWitness)?; - if length_padding < ZK_ROWS as usize { + if length_padding < index.cs.zk_rows as usize { return Err(ProverError::NoRoomForZkInWitness); } //~ 1. Pad the witness columns with Zero gates to make them the same length as the domain. - //~ Then, randomize the last `ZK_ROWS` of each columns. + //~ Then, randomize the last `zk_rows` of each columns. for w in &mut witness { if w.len() != length_witness { return Err(ProverError::WitnessCsInconsistent); @@ -202,7 +201,7 @@ where w.extend(std::iter::repeat(G::ScalarField::zero()).take(length_padding)); // zk-rows - for row in w.iter_mut().rev().take(ZK_ROWS as usize) { + for row in w.iter_mut().rev().take(index.cs.zk_rows as usize) { *row = ::rand(rng); } } @@ -339,7 +338,7 @@ where } // zero-knowledge - for e in evals.iter_mut().rev().take(ZK_ROWS as usize) { + for e in evals.iter_mut().rev().take(index.cs.zk_rows as usize) { *e = ::rand(rng); } diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 946e729986..9672d9a4ba 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -6,7 +6,7 @@ use crate::{ circuits::{ expr::{Linearization, PolishToken}, lookup::{index::LookupSelectors, lookups::LookupInfo}, - polynomials::permutation::{vanishes_on_last_n_rows, zk_w3}, + polynomials::permutation::{vanishes_on_last_n_rows, zk_w}, wires::{COLUMNS, PERMUTS}, }, curve::KimchiCurve, @@ -294,7 +294,7 @@ impl ProverIndex { }, w: { let cell = OnceCell::new(); - cell.set(zk_w3(self.cs.domain.d1)).unwrap(); + cell.set(zk_w(self.cs.domain.d1, self.cs.zk_rows)).unwrap(); cell }, endo: self.cs.endo, @@ -325,7 +325,7 @@ impl VerifierIndex { /// Gets w from [`VerifierIndex`] lazily pub fn w(&self) -> &G::ScalarField { - self.w.get_or_init(|| zk_w3(self.domain)) + self.w.get_or_init(|| zk_w(self.domain, self.zk_rows)) } /// Deserializes a [`VerifierIndex`] from a file, given a pointer to an SRS and an optional offset in the file. From 2d22c190149a41088200c76f19cd8da5dd5a66a2 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 7 Mar 2023 06:50:01 +0000 Subject: [PATCH 034/242] Generalize permutation over zk_rows --- book/src/specs/kimchi.md | 6 ++--- .../src/circuits/polynomials/permutation.rs | 27 +++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 2ba6f602c8..042d49336c 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -310,10 +310,10 @@ z_2 = &\ (w_0(g^i) + \sigma_0 \cdot beta + \gamma) \cdot \\ \end{align} $$ -If computed correctly, we should have $z(g^{n-3}) = 1$. +If computed correctly, we should have $z(g^{n-zk_rows}) = 1$. -Finally, randomize the last `EVAL_POINTS` evaluations $z(g^{n-2})$ and $z(g^{n-1})$, -in order to add zero-knowledge to the protocol. +Finally, randomize the last `zk_rows-1` evaluations in order to add zero-knowledge to +the protocol. ### Lookup diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index d7f995c2ab..10a69a50d6 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -196,6 +196,8 @@ impl> ProverIndex { let alpha1 = alphas.next().expect("missing power of alpha"); let alpha2 = alphas.next().expect("missing power of alpha"); + let zk_rows = self.cs.zk_rows as usize; + // constant gamma in evaluation form (in domain d8) let gamma = &self.cs.precomputations().constant_1_d8.scale(gamma); @@ -283,9 +285,9 @@ impl> ProverIndex { return Err(ProverError::Permutation("first division rest")); } - // accumulator end := (z(x) - 1) / (x - sid[n-3]) + // accumulator end := (z(x) - 1) / (x - sid[n-zk_rows]) let denominator = DensePolynomial::from_coefficients_slice(&[ - -self.cs.sid[self.cs.domain.d1.size() - 3], + -self.cs.sid[self.cs.domain.d1.size() - zk_rows], F::one(), ]); let (bnd2, res) = DenseOrSparsePolynomial::divide_with_q_and_r( @@ -391,6 +393,8 @@ impl> ProverIndex { ) -> Result, ProverError> { let n = self.cs.domain.d1.size(); + let zk_rows = self.cs.zk_rows as usize; + // only works if first element is 1 assert_eq!(self.cs.domain.d1.elements().next(), Some(F::one())); @@ -435,7 +439,7 @@ impl> ProverIndex { //~ \end{align} //~ $$ //~ - for j in 0..n - 3 { + for j in 0..n - zk_rows { z[j + 1] = witness .iter() .zip(self.column_evaluations.permutation_coefficients8.iter()) @@ -443,9 +447,9 @@ impl> ProverIndex { .fold(F::one(), |x, y| x * y); } - ark_ff::fields::batch_inversion::(&mut z[1..=n - 3]); + ark_ff::fields::batch_inversion::(&mut z[1..=n - zk_rows]); - for j in 0..n - 3 { + for j in 0..n - zk_rows { let x = z[j]; z[j + 1] *= witness .iter() @@ -454,16 +458,17 @@ impl> ProverIndex { .fold(x, |z, y| z * y); } - //~ If computed correctly, we should have $z(g^{n-3}) = 1$. + //~ If computed correctly, we should have $z(g^{n-zk_rows}) = 1$. //~ - if z[n - 3] != F::one() { + if z[n - zk_rows] != F::one() { return Err(ProverError::Permutation("final value")); }; - //~ Finally, randomize the last `EVAL_POINTS` evaluations $z(g^{n-2})$ and $z(g^{n-1})$, - //~ in order to add zero-knowledge to the protocol. - z[n - 2] = F::rand(rng); - z[n - 1] = F::rand(rng); + //~ Finally, randomize the last `zk_rows-1` evaluations in order to add zero-knowledge to + //~ the protocol. + for i in n-zk_rows+1..n { + z[i] = F::rand(rng); + } let res = Evaluations::>::from_vec_and_domain(z, self.cs.domain.d1).interpolate(); Ok(res) From c83802f813dbdec4587acb5fa3719d532009d718 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 10 Mar 2023 19:11:11 +0000 Subject: [PATCH 035/242] Fixup comments --- kimchi/src/circuits/polynomials/permutation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 10a69a50d6..0e72422f83 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -65,7 +65,7 @@ use std::array; pub const CONSTRAINTS: u32 = 3; /// Evaluates the polynomial -/// (x - w^{n - i}) * (x - w^{n - i - 1}) * ... * (x - w^{n - 1}) +/// (x - w^{n - i}) * (x - w^{n - i + 1}) * ... * (x - w^{n - 1}) pub fn eval_vanishes_on_last_n_rows(domain: D, i: u64, x: F) -> F { if i == 0 { return F::one(); @@ -80,7 +80,7 @@ pub fn eval_vanishes_on_last_n_rows(domain: D, i: u64, x: F) -> } /// The polynomial -/// (x - w^{n - i}) * (x - w^{n - i - 1}) * ... * (x - w^{n - 1}) +/// (x - w^{n - i}) * (x - w^{n - i + 1}) * ... * (x - w^{n - 1}) pub fn vanishes_on_last_n_rows(domain: D, i: u64) -> DensePolynomial { let constant = |a: F| DensePolynomial::from_coefficients_slice(&[a]); if i == 0 { From f39158dbbca765373235dac5ac4693312b046e78 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 10 Mar 2023 19:16:45 +0000 Subject: [PATCH 036/242] Tweak permutation argument to behave correctly under chunking --- book/src/specs/kimchi.md | 7 ++- .../circuits/domain_constant_evaluation.rs | 16 ++--- .../src/circuits/polynomials/permutation.rs | 60 +++++++++++++------ kimchi/src/verifier.rs | 23 +++++-- kimchi/src/verifier_index.rs | 20 ++++--- 5 files changed, 87 insertions(+), 39 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 042d49336c..2461928bbf 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -310,10 +310,11 @@ z_2 = &\ (w_0(g^i) + \sigma_0 \cdot beta + \gamma) \cdot \\ \end{align} $$ +We randomize the evaluations at `n - zk_rows + 1` and `n - zk_rows + 2` order to add +zero-knowledge to the protocol. + If computed correctly, we should have $z(g^{n-zk_rows}) = 1$. -Finally, randomize the last `zk_rows-1` evaluations in order to add zero-knowledge to -the protocol. ### Lookup @@ -1819,7 +1820,7 @@ pub struct VerifierIndex { pub shift: [G::ScalarField; PERMUTS], /// zero-knowledge polynomial #[serde(skip)] - pub zkpm: OnceCell>, + pub permutation_vanishing_polynomial_m: OnceCell>, // TODO(mimoo): isn't this redundant with domain.d1.group_gen ? /// domain offset for zero-knowledge #[serde(skip)] diff --git a/kimchi/src/circuits/domain_constant_evaluation.rs b/kimchi/src/circuits/domain_constant_evaluation.rs index 6996223342..6659f42d31 100644 --- a/kimchi/src/circuits/domain_constant_evaluation.rs +++ b/kimchi/src/circuits/domain_constant_evaluation.rs @@ -8,7 +8,7 @@ use ark_poly::{univariate::DensePolynomial as DP, Evaluations as E, Radix2Evalua use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use super::polynomials::permutation::vanishes_on_last_n_rows; +use super::polynomials::permutation::{permutation_vanishing_polynomial, vanishes_on_last_n_rows}; #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] @@ -29,9 +29,9 @@ pub struct DomainConstantEvaluations { pub vanishes_on_zero_knowledge_and_previous_rows: E>, /// zero-knowledge polynomial over domain.d8 #[serde_as(as = "o1_utils::serialization::SerdeAs")] - pub zkpl: E>, + pub permutation_vanishing_polynomial_l: E>, #[serde_as(as = "o1_utils::serialization::SerdeAs")] - pub zkpm: DP, + pub permutation_vanishing_polynomial_m: DP, } impl DomainConstantEvaluations { @@ -49,16 +49,18 @@ impl DomainConstantEvaluations { assert!(domain.d1.size > zk_rows); // x^3 - x^2(w1+w2+w3) + x(w1w2+w1w3+w2w3) - w1w2w3 - let zkpm = vanishes_on_last_n_rows(domain.d1, zk_rows); - let zkpl = zkpm.evaluate_over_domain_by_ref(domain.d8); + let permutation_vanishing_polynomial_m = + permutation_vanishing_polynomial(domain.d1, zk_rows); + let permutation_vanishing_polynomial_l = + permutation_vanishing_polynomial_m.evaluate_over_domain_by_ref(domain.d8); Some(DomainConstantEvaluations { poly_x_d1, constant_1_d4, constant_1_d8, vanishes_on_zero_knowledge_and_previous_rows, - zkpl, - zkpm, + permutation_vanishing_polynomial_l, + permutation_vanishing_polynomial_m, }) } } diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 0e72422f83..03d63b7da1 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -101,6 +101,26 @@ pub fn zk_w(domain: D, zk_rows: u64) -> F { domain.group_gen.pow([domain.size - zk_rows]) } +/// Evaluates the polynomial +/// (x - w^{n - zk_rows}) * (x - w^{n - zk_rows + 1}) * (x - w^{n - 1}) +pub fn eval_permutation_vanishing_polynomial(domain: D, zk_rows: u64, x: F) -> F { + let term = domain.group_gen.pow([domain.size - zk_rows]); + (x - term) * (x - term * domain.group_gen) * (x - domain.group_gen.pow([domain.size - 1])) +} + +/// The polynomial +/// (x - w^{n - zk_rows}) * (x - w^{n - zk_rows + 1}) * (x - w^{n - 1}) +pub fn permutation_vanishing_polynomial( + domain: D, + zk_rows: u64, +) -> DensePolynomial { + let constant = |a: F| DensePolynomial::from_coefficients_slice(&[a]); + let x = DensePolynomial::from_coefficients_slice(&[F::zero(), F::one()]); + let term = domain.group_gen.pow([domain.size - zk_rows]); + &(&(&x - &constant(term)) * &(&x - &constant(term * domain.group_gen))) + * &(&x - &constant(domain.group_gen.pow([domain.size - 1]))) +} + /// Shifts represent the shifts required in the permutation argument of PLONK. /// It also caches the shifted powers of omega for optimization purposes. pub struct Shifts { @@ -259,7 +279,8 @@ impl> ProverIndex { sigmas = &sigmas * &term; } - &(&shifts - &sigmas).scale(alpha0) * &self.cs.precomputations().zkpl + &(&shifts - &sigmas).scale(alpha0) + * &self.cs.precomputations().permutation_vanishing_polynomial_l }; //~ and `bnd`: @@ -319,7 +340,11 @@ impl> ProverIndex { //~ //~ $\text{scalar} \cdot \sigma_6(x)$ //~ - let zkpm_zeta = self.cs.precomputations().zkpm.evaluate(&zeta); + let zkpm_zeta = self + .cs + .precomputations() + .permutation_vanishing_polynomial_m + .evaluate(&zeta); let scalar = ConstraintSystem::::perm_scalars(e, beta, gamma, alphas, zkpm_zeta); let evals8 = &self.column_evaluations.permutation_coefficients8[PERMUTS - 1].evals; const STRIDE: usize = 8; @@ -439,7 +464,7 @@ impl> ProverIndex { //~ \end{align} //~ $$ //~ - for j in 0..n - zk_rows { + for j in 0..n - 1 { z[j + 1] = witness .iter() .zip(self.column_evaluations.permutation_coefficients8.iter()) @@ -447,15 +472,22 @@ impl> ProverIndex { .fold(F::one(), |x, y| x * y); } - ark_ff::fields::batch_inversion::(&mut z[1..=n - zk_rows]); + ark_ff::fields::batch_inversion::(&mut z[1..n]); - for j in 0..n - zk_rows { - let x = z[j]; - z[j + 1] *= witness - .iter() - .zip(self.cs.shift.iter()) - .map(|(w, s)| w[j] + (self.cs.sid[j] * beta * s) + gamma) - .fold(x, |z, y| z * y); + //~ We randomize the evaluations at `n - zk_rows + 1` and `n - zk_rows + 2` order to add + //~ zero-knowledge to the protocol. + //~ + for j in 0..n - 1 { + if j != n - zk_rows && j != n - zk_rows + 1 { + let x = z[j]; + z[j + 1] *= witness + .iter() + .zip(self.cs.shift.iter()) + .map(|(w, s)| w[j] + (self.cs.sid[j] * beta * s) + gamma) + .fold(x, |z, y| z * y); + } else { + z[j + 1] = F::rand(rng); + } } //~ If computed correctly, we should have $z(g^{n-zk_rows}) = 1$. @@ -464,12 +496,6 @@ impl> ProverIndex { return Err(ProverError::Permutation("final value")); }; - //~ Finally, randomize the last `zk_rows-1` evaluations in order to add zero-knowledge to - //~ the protocol. - for i in n-zk_rows+1..n { - z[i] = F::rand(rng); - } - let res = Evaluations::>::from_vec_and_domain(z, self.cs.domain.d1).interpolate(); Ok(res) } diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 1529799ddd..a269af098c 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -314,19 +314,24 @@ where //~ 1. Derive $v$ from $v'$ using the endomorphism (TODO: specify). let v = v_chal.to_field(endo_r); + println!("v: {}", v); + //~ 1. Sample $u'$ with the Fr-Sponge. let u_chal = fr_sponge.challenge(); //~ 1. Derive $u$ from $u'$ using the endomorphism (TODO: specify). let u = u_chal.to_field(endo_r); + println!("u: {}", u); + //~ 1. Create a list of all polynomials that have an evaluation proof. let evals = self.evals.combine(&powers_of_eval_points_for_chunks); //~ 1. Compute the evaluation of $ft(\zeta)$. let ft_eval0 = { - let zkp = index.zkpm().evaluate(&zeta); + let permutation_vanishing_polynomial = + index.permutation_vanishing_polynomial_m().evaluate(&zeta); let zeta1m1 = zeta1 - G::ScalarField::one(); let mut alpha_powers = @@ -341,7 +346,10 @@ where .next() .expect("missing power of alpha for permutation"); - let init = (evals.w[PERMUTS - 1].zeta + gamma) * evals.z.zeta_omega * alpha0 * zkp; + let init = (evals.w[PERMUTS - 1].zeta + gamma) + * evals.z.zeta_omega + * alpha0 + * permutation_vanishing_polynomial; let mut ft_eval0 = evals .w .iter() @@ -359,7 +367,10 @@ where .iter() .zip(index.shift.iter()) .map(|(w, s)| gamma + (beta * zeta * s) + w.zeta) - .fold(alpha0 * zkp * evals.z.zeta, |x, y| x * y); + .fold( + alpha0 * permutation_vanishing_polynomial * evals.z.zeta, + |x, y| x * y, + ); let numerator = ((zeta1m1 * alpha1 * (zeta - index.w())) + (zeta1m1 * alpha2 * (zeta - G::ScalarField::one()))) @@ -647,7 +658,9 @@ where //~ in which case the evaluation should be used in place of the commitment. let f_comm = { // the permutation is written manually (not using the expr framework) - let zkp = verifier_index.zkpm().evaluate(&oracles.zeta); + let permutation_vanishing_polynomial = verifier_index + .permutation_vanishing_polynomial_m() + .evaluate(&oracles.zeta); let alphas = all_alphas.get_alphas(ArgumentType::Permutation, permutation::CONSTRAINTS); @@ -657,7 +670,7 @@ where oracles.beta, oracles.gamma, alphas, - zkp, + permutation_vanishing_polynomial, )]; // other gates are implemented using the expression framework diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 9672d9a4ba..c9c502a025 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -131,7 +131,7 @@ pub struct VerifierIndex { pub shift: [G::ScalarField; PERMUTS], /// zero-knowledge polynomial #[serde(skip)] - pub zkpm: OnceCell>, + pub permutation_vanishing_polynomial_m: OnceCell>, // TODO(mimoo): isn't this redundant with domain.d1.group_gen ? /// domain offset for zero-knowledge #[serde(skip)] @@ -287,9 +287,15 @@ impl ProverIndex { .map(|eval8| self.srs.commit_evaluations_non_hiding(domain, eval8)), shift: self.cs.shift, - zkpm: { + permutation_vanishing_polynomial_m: { let cell = OnceCell::new(); - cell.set(self.cs.precomputations().zkpm.clone()).unwrap(); + cell.set( + self.cs + .precomputations() + .permutation_vanishing_polynomial_m + .clone(), + ) + .unwrap(); cell }, w: { @@ -317,9 +323,9 @@ impl VerifierIndex { }) } - /// Gets zkpm from [`VerifierIndex`] lazily - pub fn zkpm(&self) -> &DensePolynomial { - self.zkpm + /// Gets permutation_vanishing_polynomial_m from [`VerifierIndex`] lazily + pub fn permutation_vanishing_polynomial_m(&self) -> &DensePolynomial { + self.permutation_vanishing_polynomial_m .get_or_init(|| vanishes_on_last_n_rows(self.domain, self.zk_rows)) } @@ -425,7 +431,7 @@ impl VerifierIndex { lookup_index, shift: _, - zkpm: _, + permutation_vanishing_polynomial_m: _, w: _, endo: _, From 9087c301a12402a3dd69acd8fb0e56a78954b294 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 10 Mar 2023 20:16:41 +0000 Subject: [PATCH 037/242] Use the correct number of zero-knowledge rows depending on chunk size --- kimchi/src/circuits/constraints.rs | 34 ++++++++++++++++++++++++++---- kimchi/src/error.rs | 5 +++++ kimchi/src/prover.rs | 8 +++++++ kimchi/src/prover_index.rs | 1 + kimchi/src/tests/chunked.rs | 2 +- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index c6f63719e6..979b48a7ca 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -193,6 +193,7 @@ pub struct Builder { runtime_tables: Option>>, precomputations: Option>>, disable_gates_checks: bool, + max_poly_size: Option, } /// Create selector polynomial for a circuit gate @@ -250,6 +251,7 @@ impl ConstraintSystem { runtime_tables: None, precomputations: None, disable_gates_checks: false, + max_poly_size: None, } } @@ -646,6 +648,11 @@ impl Builder { self } + pub fn max_poly_size(mut self, max_poly_size: Option) -> Self { + self.max_poly_size = max_poly_size; + self + } + /// Build the [ConstraintSystem] from a [Builder]. pub fn build(self) -> Result, SetupError> { let mut gates = self.gates; @@ -683,13 +690,32 @@ impl Builder { num_lookups }; - let zk_rows = 3; - //~ 2. Create a domain for the circuit. That is, //~ compute the smallest subgroup of the field that //~ has order greater or equal to `n + zk_rows` elements. - let domain_size_lower_bound = - std::cmp::max(gates.len(), num_lookups + 1) + zk_rows as usize; + let (zk_rows, domain_size_lower_bound) = { + let mut zk_rows = 3; + let get_domain_size_lower_bound = + |zk_rows: u64| std::cmp::max(gates.len(), num_lookups + 1) + zk_rows as usize; + let mut domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); + if let Some(max_poly_size) = self.max_poly_size { + // Iterate to find a fixed-point where zk_rows is sufficient for the number of + // chunks that we use, and also does not cause us to overflow the domain size. + // NB: We use iteration here rather than hard-coding an assumption about + // `compute_size_of_domain`s internals. In practice, this will never be executed + // more than once. + while { + let domain_size = D::::compute_size_of_domain(domain_size_lower_bound) + .ok_or(SetupError::DomainCreation( + "could not compute size of domain", + ))?; + zk_rows = ((16 * (domain_size / max_poly_size) + 4) / 7) as u64; + domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); + domain_size < domain_size_lower_bound + } {} + } + (zk_rows, domain_size_lower_bound) + }; let domain = EvaluationDomains::::create(domain_size_lower_bound)?; assert!(domain.d1.size > zk_rows); diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 017943f980..d979f1d321 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -10,6 +10,11 @@ pub enum ProverError { #[error("the circuit is too large")] NoRoomForZkInWitness, + #[error( + "there are not enough random rows to achieve zero-knowledge (expected: {0}, got: {1})" + )] + NotZeroKnowledge(usize, usize), + #[error("the witness columns are not all the same size")] WitnessCsInconsistent, diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index b58154e05e..d4e1465b01 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -186,6 +186,14 @@ where .checked_sub(length_witness) .ok_or(ProverError::NoRoomForZkInWitness)?; + let zero_knowledge_limit = (16 * num_chunks - 4) / 7 ; + if (index.cs.zk_rows as usize) < zero_knowledge_limit { + return Err(ProverError::NotZeroKnowledge( + zero_knowledge_limit, + index.cs.zk_rows as usize, + )); + } + if length_padding < index.cs.zk_rows as usize { return Err(ProverError::NoRoomForZkInWitness); } diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index c6b91b4886..1ba2c02d90 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -156,6 +156,7 @@ pub mod testing { .public(public) .prev_challenges(prev_challenges) .disable_gates_checks(disable_gates_checks) + .max_poly_size(override_srs_size) .build() .unwrap(); let srs_size = override_srs_size.unwrap_or_else(|| cs.domain.d1.size()); diff --git a/kimchi/src/tests/chunked.rs b/kimchi/src/tests/chunked.rs index 9db6998f40..7e00d715aa 100644 --- a/kimchi/src/tests/chunked.rs +++ b/kimchi/src/tests/chunked.rs @@ -22,7 +22,7 @@ fn test_generic_gate_with_srs_override( override_srs_size: Option, ) { let public = vec![Fp::from(1u8); 5]; - let circuit_size = (1 << circuit_size_log_2) - 5; + let circuit_size = (1 << circuit_size_log_2) - 15; let mut gates_row = iterate(0, |&i| i + 1); let mut gates = Vec::with_capacity(circuit_size); From 079b269406e6b6346758116feb4626e4611c64d2 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 10 Mar 2023 20:20:21 +0000 Subject: [PATCH 038/242] Zero out the sigmas in the zero-knowledge rows --- kimchi/src/circuits/constraints.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 979b48a7ca..812c17df58 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -374,6 +374,14 @@ impl ConstraintSystem { } } + // Zero out the sigmas in the zk rows, to ensure that the permutation aggregation is + // quasi-random for those rows. + for row in self.domain.d1.size() + 2 - (self.zk_rows as usize)..self.domain.d1.size() - 1 { + for sigma in sigmal1.iter_mut() { + sigma[row] = F::zero(); + } + } + let sigmal1: [_; PERMUTS] = { let [s0, s1, s2, s3, s4, s5, s6] = sigmal1; [ From 1602203394a38c83272130a4fd343e887f25bf5d Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 13 May 2023 00:20:57 +0100 Subject: [PATCH 039/242] Relax some equality checks for number of chunks --- kimchi/src/lagrange_basis_evaluations.rs | 2 +- kimchi/src/prover.rs | 6 +++++- kimchi/src/verifier.rs | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/kimchi/src/lagrange_basis_evaluations.rs b/kimchi/src/lagrange_basis_evaluations.rs index 08a94dd816..36c2e238e4 100644 --- a/kimchi/src/lagrange_basis_evaluations.rs +++ b/kimchi/src/lagrange_basis_evaluations.rs @@ -136,7 +136,7 @@ impl LagrangeBasisEvaluations { } pub fn new(max_poly_size: usize, domain: D, x: F) -> LagrangeBasisEvaluations { - if domain.size() == max_poly_size { + if domain.size() <= max_poly_size { Self::new_with_segment_size_1(domain, x) } else { Self::new_with_chunked_segments(max_poly_size, domain, x) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 712276a1fd..d44d136033 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -171,7 +171,11 @@ where let (_, endo_r) = G::endos(); - let num_chunks = d1_size / index.max_poly_size; + let num_chunks = if d1_size < index.max_poly_size { + 1 + } else { + d1_size / index.max_poly_size + }; // TODO: rng should be passed as arg let rng = &mut rand::rngs::OsRng; diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 4cf50d7b39..c8fb44d157 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -216,7 +216,7 @@ where let alpha = alpha_chal.to_field(endo_r); //~ 1. Enforce that the length of the $t$ commitment is of size 7. - if self.commitments.t_comm.unshifted.len() != chunk_size * 7 { + if self.commitments.t_comm.unshifted.len() <= chunk_size * 7 { return Err(VerifyError::IncorrectCommitmentLength( "t", chunk_size * 7, @@ -576,7 +576,14 @@ where } //~ 1. Check the length of evaluations inside the proof. - let chunk_size = verifier_index.domain.size() / verifier_index.max_poly_size; + let chunk_size = { + let d1_size = verifier_index.domain.size(); + if d1_size < verifier_index.max_poly_size { + 1 + } else { + d1_size / verifier_index.max_poly_size + } + }; check_proof_evals_len(proof, chunk_size)?; //~ 1. Commit to the negated public input polynomial. From e01e025214ef06081e005bc9ce7b9eaae78ada5e Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 13 May 2023 02:08:28 +0100 Subject: [PATCH 040/242] Fixup inverted inequality --- kimchi/src/verifier.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index c8fb44d157..ef13dbdb20 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -216,7 +216,7 @@ where let alpha = alpha_chal.to_field(endo_r); //~ 1. Enforce that the length of the $t$ commitment is of size 7. - if self.commitments.t_comm.unshifted.len() <= chunk_size * 7 { + if self.commitments.t_comm.unshifted.len() > chunk_size * 7 { return Err(VerifyError::IncorrectCommitmentLength( "t", chunk_size * 7, From 176cc72b79bf3a73eec2fe75492cc083a382e7a3 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 13 May 2023 03:20:24 +0100 Subject: [PATCH 041/242] Ensure that chunk size is always at least 1 --- kimchi/src/verifier.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index ef13dbdb20..39aa5db25b 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -120,7 +120,14 @@ where let n = index.domain.size; let (_, endo_r) = G::endos(); - let chunk_size = index.domain.size() / index.max_poly_size; + let chunk_size = { + let d1_size = index.domain.size(); + if d1_size < index.max_poly_size { + 1 + } else { + d1_size / index.max_poly_size + } + }; //~ 1. Setup the Fq-Sponge. let mut fq_sponge = EFqSponge::new(G::OtherCurve::sponge_params()); From 6e7f553eb7a2ffd1ad564640ed2ca77e5e748035 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 15 May 2023 18:41:07 +0100 Subject: [PATCH 042/242] Fixup grammar in comment --- book/src/specs/kimchi.md | 2 +- kimchi/src/circuits/polynomials/permutation.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 2461928bbf..3524cb95c9 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -310,7 +310,7 @@ z_2 = &\ (w_0(g^i) + \sigma_0 \cdot beta + \gamma) \cdot \\ \end{align} $$ -We randomize the evaluations at `n - zk_rows + 1` and `n - zk_rows + 2` order to add +We randomize the evaluations at `n - zk_rows + 1` and `n - zk_rows + 2` in order to add zero-knowledge to the protocol. If computed correctly, we should have $z(g^{n-zk_rows}) = 1$. diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 03d63b7da1..755f8ea7f2 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -474,7 +474,7 @@ impl> ProverIndex { ark_ff::fields::batch_inversion::(&mut z[1..n]); - //~ We randomize the evaluations at `n - zk_rows + 1` and `n - zk_rows + 2` order to add + //~ We randomize the evaluations at `n - zk_rows + 1` and `n - zk_rows + 2` in order to add //~ zero-knowledge to the protocol. //~ for j in 0..n - 1 { From abc78d6d3c3605de5ecc5090a60268941ed1abb6 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 15:51:26 +0100 Subject: [PATCH 043/242] Update inaccurate comment --- kimchi/src/lagrange_basis_evaluations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/lagrange_basis_evaluations.rs b/kimchi/src/lagrange_basis_evaluations.rs index 36c2e238e4..8f855f4dd9 100644 --- a/kimchi/src/lagrange_basis_evaluations.rs +++ b/kimchi/src/lagrange_basis_evaluations.rs @@ -113,7 +113,7 @@ impl LagrangeBasisEvaluations { } /// Compute all evaluations of the normalized lagrange basis polynomials of the - /// given domain at the given point. Runs in time O(domain size). + /// given domain at the given point. Runs in time O(n log(n)) for n = domain size. fn new_with_chunked_segments( max_poly_size: usize, domain: D, From 83d87440bf2745f46f7afe802f911a9318da5f15 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 15:55:18 +0100 Subject: [PATCH 044/242] Add comment cross-referencing the iFFT trick's source --- kimchi/src/lagrange_basis_evaluations.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kimchi/src/lagrange_basis_evaluations.rs b/kimchi/src/lagrange_basis_evaluations.rs index 8f855f4dd9..ee825a0ae1 100644 --- a/kimchi/src/lagrange_basis_evaluations.rs +++ b/kimchi/src/lagrange_basis_evaluations.rs @@ -129,6 +129,8 @@ impl LagrangeBasisEvaluations { chunked_evals[i * max_poly_size + j] = x_pow; x_pow *= x; } + // This uses the same trick as `poly_commitment::srs::SRS::add_lagrange_basis`, but + // applied to field elements instead of group elements. domain.ifft_in_place(&mut chunked_evals); evals.push(chunked_evals); } From 40b7edae5996fec75c30fa95b198f2997cfd1bc8 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 16:19:12 +0100 Subject: [PATCH 045/242] Revert to old OCaml format, with a separate public_input_evals --- kimchi/src/proof.rs | 43 ++++++++++++++++++++++++------------------- kimchi/src/prover.rs | 41 +++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 235072cc13..4a771de046 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -531,7 +531,6 @@ pub mod caml { #[allow(clippy::type_complexity)] #[derive(Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)] pub struct CamlProofEvaluations { - pub public: PointEvaluations>, pub w: ( PointEvaluations>, PointEvaluations>, @@ -585,7 +584,8 @@ pub mod caml { // ProofEvaluations> <-> CamlProofEvaluations // - impl From>>> for CamlProofEvaluations + impl From>>> + for (PointEvaluations>, CamlProofEvaluations) where F: Clone, CamlF: From, @@ -706,29 +706,34 @@ pub mod caml { .map(&|x| x.into_iter().map(Into::into).collect()), ); - Self { - public: pe.public.map(&|x| x.into_iter().map(Into::into).collect()), - w, - coefficients, - z: pe.z.map(&|x| x.into_iter().map(Into::into).collect()), - s, - generic_selector: pe - .generic_selector - .map(&|x| x.into_iter().map(Into::into).collect()), - poseidon_selector: pe - .poseidon_selector - .map(&|x| x.into_iter().map(Into::into).collect()), - lookup: pe.lookup.map(Into::into), - } + ( + pe.public.map(&|x| x.into_iter().map(Into::into).collect()), + CamlProofEvaluations { + w, + coefficients, + z: pe.z.map(&|x| x.into_iter().map(Into::into).collect()), + s, + generic_selector: pe + .generic_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + poseidon_selector: pe + .poseidon_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + lookup: pe.lookup.map(Into::into), + }, + ) } } - impl From> for ProofEvaluations>> + impl From<(PointEvaluations>, CamlProofEvaluations)> + for ProofEvaluations>> where F: Clone, F: From, { - fn from(cpe: CamlProofEvaluations) -> Self { + fn from( + (public, cpe): (PointEvaluations>, CamlProofEvaluations), + ) -> Self { let w = [ cpe.w.0.map(&|x| x.into_iter().map(Into::into).collect()), cpe.w.1.map(&|x| x.into_iter().map(Into::into).collect()), @@ -803,7 +808,7 @@ pub mod caml { ]; Self { - public: cpe.public.map(&|x| x.into_iter().map(Into::into).collect()), + public: public.map(&|x| x.into_iter().map(Into::into).collect()), w, coefficients, z: cpe.z.map(&|x| x.into_iter().map(Into::into).collect()), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index d44d136033..200242f39d 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1296,6 +1296,11 @@ pub mod caml { #[cfg(feature = "internal_tracing")] pub use internal_traces::caml::CamlTraces as CamlProverTraces; + pub struct CamlProofWithPublic { + pub public_evals: PointEvaluations>, + pub proof: CamlProverProof, + } + // // CamlProverProof // @@ -1493,37 +1498,49 @@ pub mod caml { } // - // ProverProof <-> CamlProverProof + // ProverProof <-> CamlProofWithPublic // - impl From<(ProverProof, Vec)> for CamlProverProof + impl From<(ProverProof, Vec)> + for CamlProofWithPublic where G: AffineCurve, CamlG: From, CamlF: From, { fn from(pp: (ProverProof, Vec)) -> Self { - Self { - commitments: pp.0.commitments.into(), - proof: pp.0.proof.into(), - evals: pp.0.evals.into(), - ft_eval1: pp.0.ft_eval1.into(), - public: pp.1.into_iter().map(Into::into).collect(), - prev_challenges: pp.0.prev_challenges.into_iter().map(Into::into).collect(), + let (public_evals, evals) = pp.0.evals.into(); + CamlProofWithPublic { + public_evals, + proof: CamlProverProof { + commitments: pp.0.commitments.into(), + proof: pp.0.proof.into(), + evals, + ft_eval1: pp.0.ft_eval1.into(), + public: pp.1.into_iter().map(Into::into).collect(), + prev_challenges: pp.0.prev_challenges.into_iter().map(Into::into).collect(), + }, } } } - impl From> for (ProverProof, Vec) + impl From> + for (ProverProof, Vec) where G: AffineCurve + From, G::ScalarField: From, { - fn from(caml_pp: CamlProverProof) -> (ProverProof, Vec) { + fn from( + caml_pp: CamlProofWithPublic, + ) -> (ProverProof, Vec) { + let CamlProofWithPublic { + public_evals, + proof: caml_pp, + } = caml_pp; let proof = ProverProof { commitments: caml_pp.commitments.into(), proof: caml_pp.proof.into(), - evals: caml_pp.evals.into(), + evals: (public_evals, caml_pp.evals).into(), ft_eval1: caml_pp.ft_eval1.into(), prev_challenges: caml_pp .prev_challenges From 7a9c7e01f24829d4b64a42c139b2f618c5dadc25 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 16:56:52 +0100 Subject: [PATCH 046/242] Use OCaml derivers of CamlProofWithPublic --- kimchi/src/prover.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 200242f39d..72f0536e1e 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1296,6 +1296,7 @@ pub mod caml { #[cfg(feature = "internal_tracing")] pub use internal_traces::caml::CamlTraces as CamlProverTraces; + #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)] pub struct CamlProofWithPublic { pub public_evals: PointEvaluations>, pub proof: CamlProverProof, From d6ac5a5575c7b2ad490a72222f5dec514b75fc43 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 18:36:47 +0100 Subject: [PATCH 047/242] Remove no-op code --- kimchi/src/oracles.rs | 3 +-- kimchi/src/verifier.rs | 14 +------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index 7d7c222547..23c3c39555 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -72,8 +72,7 @@ pub mod caml { let p_comm = PolyComm::::multi_scalar_mul(&lgr_comm_refs, &negated_public); - let oracles_result = - proof.oracles::(&index, &p_comm, public_input)?; + let oracles_result = proof.oracles::(&index, &p_comm)?; let (mut sponge, combined_inner_product, digest, oracles) = ( oracles_result.fq_sponge, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 39aa5db25b..e7ad46400a 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -110,7 +110,6 @@ where &self, index: &VerifierIndex, public_comm: &PolyComm, - public_input: &[G::ScalarField], ) -> Result> { //~ //~ #### Fiat-Shamir argument @@ -290,17 +289,6 @@ where let mut all_alphas = index.powers_of_alpha.clone(); all_alphas.instantiate(alpha); - // compute Lagrange base evaluation denominators - let w: Vec<_> = index.domain.elements().take(public_input.len()).collect(); - - let mut zeta_minus_x: Vec<_> = w.iter().map(|w| zeta - w).collect(); - - w.iter() - .take(public_input.len()) - .for_each(|w| zeta_minus_x.push(zetaw - w)); - - ark_ff::fields::batch_inversion::(&mut zeta_minus_x); - //~ 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. fr_sponge.absorb(&self.ft_eval1); @@ -633,7 +621,7 @@ where ft_eval0, combined_inner_product, .. - } = proof.oracles::(verifier_index, &public_comm, public_input)?; + } = proof.oracles::(verifier_index, &public_comm)?; //~ 1. Combine the chunked polynomials' evaluations //~ (TODO: most likely only the quotient polynomial is chunked) From 68809aaee11a114e484ca91abcfbeb53e6b2e697 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 19:02:38 +0100 Subject: [PATCH 048/242] Split oracles function in half --- kimchi/src/verifier.rs | 80 +++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index e7ad46400a..be893ebd2e 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -90,33 +90,35 @@ impl<'a, G: KimchiCurve> Context<'a, G> { } } +pub struct OraclesBeforeEvaluations { + fq_sponge: EFqSponge, + fq_sponge_digest: Fp, + endo_r: Fp, + alpha_chal: ScalarChallenge, + alpha: Fp, + beta: Fp, + gamma: Fp, + joint_combiner: Option<(ScalarChallenge, Fp)>, + zeta_chal: ScalarChallenge, + zeta: Fp, +} + impl ProverProof where G::BaseField: PrimeField, { - /// This function runs the random oracle argument - /// - /// # Errors - /// - /// Will give error if `commitment(s)` are invalid(missing or wrong length), or `proof` is verified as invalid. - /// - /// # Panics - /// - /// Will panic if `PolishToken` evaluation is invalid. - pub fn oracles< + pub fn oracles_before_evaluations< EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, >( &self, index: &VerifierIndex, public_comm: &PolyComm, - ) -> Result> { + ) -> Result> { //~ //~ #### Fiat-Shamir argument //~ //~ We run the following algorithm: //~ - let n = index.domain.size; let (_, endo_r) = G::endos(); let chunk_size = { @@ -238,9 +240,55 @@ where //~ 1. Derive $\zeta$ from $\zeta'$ using the endomorphism (TODO: specify). let zeta = zeta_chal.to_field(endo_r); + let digest = fq_sponge.clone().digest(); + + Ok(OraclesBeforeEvaluations { + fq_sponge, + fq_sponge_digest: digest, + endo_r: *endo_r, + alpha_chal, + alpha, + beta, + gamma, + joint_combiner, + zeta_chal, + zeta, + }) + } + + /// This function runs the random oracle argument + /// + /// # Errors + /// + /// Will give error if `commitment(s)` are invalid(missing or wrong length), or `proof` is verified as invalid. + /// + /// # Panics + /// + /// Will panic if `PolishToken` evaluation is invalid. + pub fn oracles< + EFqSponge: Clone + FqSponge, + EFrSponge: FrSponge, + >( + &self, + index: &VerifierIndex, + public_comm: &PolyComm, + ) -> Result> { + let OraclesBeforeEvaluations { + fq_sponge, + fq_sponge_digest: digest, + endo_r, + alpha_chal, + alpha, + beta, + gamma, + joint_combiner, + zeta_chal, + zeta, + } = self.oracles_before_evaluations::(index, public_comm)?; + + let n = index.domain.size; //~ 1. Setup the Fr-Sponge. - let digest = fq_sponge.clone().digest(); let mut fr_sponge = EFrSponge::new(G::sponge_params()); //~ 1. Squeeze the Fq-sponge and absorb the result with the Fr-Sponge. @@ -305,13 +353,13 @@ where let v_chal = fr_sponge.challenge(); //~ 1. Derive $v$ from $v'$ using the endomorphism (TODO: specify). - let v = v_chal.to_field(endo_r); + let v = v_chal.to_field(&endo_r); //~ 1. Sample $u'$ with the Fr-Sponge. let u_chal = fr_sponge.challenge(); //~ 1. Derive $u$ from $u'$ using the endomorphism (TODO: specify). - let u = u_chal.to_field(endo_r); + let u = u_chal.to_field(&endo_r); //~ 1. Create a list of all polynomials that have an evaluation proof. From e3b3ecebaf6768bbe8784e5c77c0c36535ed0b46 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 19:12:47 +0100 Subject: [PATCH 049/242] Reinstate code for generating the public input evals in a dedicated fn --- kimchi/src/verifier.rs | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index be893ebd2e..7c23369e05 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -256,6 +256,62 @@ where }) } + pub fn public_input_evals_unchunked( + &self, + index: &VerifierIndex, + oracles_before_evaluations: &OraclesBeforeEvaluations, + public_input: &[G::ScalarField], + ) -> PointEvaluations> { + let OraclesBeforeEvaluations { zeta, .. } = oracles_before_evaluations; + // compute Lagrange base evaluation denominators + let w: Vec<_> = index.domain.elements().take(public_input.len()).collect(); + + let mut zeta_minus_x: Vec<_> = w.iter().map(|w| *zeta - w).collect(); + + let n = index.domain.size; + let zeta1 = zeta.pow([n]); + let zetaw = *zeta * index.domain.group_gen; + + w.iter() + .take(public_input.len()) + .for_each(|w| zeta_minus_x.push(zetaw - w)); + + ark_ff::fields::batch_inversion::(&mut zeta_minus_x); + + // 1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. + // + // NOTE: this works only in the case when the poly segment size is not smaller than that of the domain. + if public_input.is_empty() { + PointEvaluations { + zeta: vec![G::ScalarField::zero()], + zeta_omega: vec![G::ScalarField::zero()], + } + } else { + PointEvaluations { + zeta: vec![ + (public_input + .iter() + .zip(zeta_minus_x.iter()) + .zip(index.domain.elements()) + .map(|((p, l), w)| -*l * p * w) + .fold(G::ScalarField::zero(), |x, y| x + y)) + * (zeta1 - G::ScalarField::one()) + * index.domain.size_inv, + ], + zeta_omega: vec![ + (public_input + .iter() + .zip(zeta_minus_x[public_input.len()..].iter()) + .zip(index.domain.elements()) + .map(|((p, l), w)| -*l * p * w) + .fold(G::ScalarField::zero(), |x, y| x + y)) + * index.domain.size_inv + * (zetaw.pow([n]) - G::ScalarField::one()), + ], + } + } + } + /// This function runs the random oracle argument /// /// # Errors From 16a5bcbe230be48055b9cb8bd9ce501cc0edafd0 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 19:21:12 +0100 Subject: [PATCH 050/242] Add oracles_with_unchunked_public_input helper --- kimchi/src/verifier.rs | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 7c23369e05..050cdd2003 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -321,13 +321,13 @@ where /// # Panics /// /// Will panic if `PolishToken` evaluation is invalid. - pub fn oracles< + pub fn oracles_finalize< EFqSponge: Clone + FqSponge, EFrSponge: FrSponge, >( &self, index: &VerifierIndex, - public_comm: &PolyComm, + oracles: OraclesBeforeEvaluations, ) -> Result> { let OraclesBeforeEvaluations { fq_sponge, @@ -340,7 +340,7 @@ where joint_combiner, zeta_chal, zeta, - } = self.oracles_before_evaluations::(index, public_comm)?; + } = oracles; let n = index.domain.size; @@ -572,6 +572,42 @@ where combined_inner_product, }) } + + pub fn oracles_with_unchunked_public_input< + EFqSponge: Clone + FqSponge, + EFrSponge: FrSponge, + >( + &mut self, + index: &VerifierIndex, + public_comm: &PolyComm, + public_input: &[G::ScalarField], + ) -> Result> { + let oracles = self.oracles_before_evaluations::(index, public_comm)?; + let public_input_evals = self.public_input_evals_unchunked(index, &oracles, public_input); + self.evals.public = public_input_evals; + self.oracles_finalize::(index, oracles) + } + + /// This function runs the random oracle argument + /// + /// # Errors + /// + /// Will give error if `commitment(s)` are invalid(missing or wrong length), or `proof` is verified as invalid. + /// + /// # Panics + /// + /// Will panic if `PolishToken` evaluation is invalid. + pub fn oracles< + EFqSponge: Clone + FqSponge, + EFrSponge: FrSponge, + >( + &self, + index: &VerifierIndex, + public_comm: &PolyComm, + ) -> Result> { + let oracles = self.oracles_before_evaluations::(index, public_comm)?; + self.oracles_finalize::(index, oracles) + } } /// Enforce the length of evaluations inside [`Proof`]. From 137079de2b615ee69a003a9ef5ed1f4ccbc70e4e Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 21:14:12 +0100 Subject: [PATCH 051/242] Re-add public_evals to OraclesResult --- kimchi/src/oracles.rs | 7 ++++++- kimchi/src/verifier.rs | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index 23c3c39555..9c692a12d9 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -20,6 +20,8 @@ where pub oracles: RandomOracles, /// the computed powers of alpha pub all_alphas: Alphas, + /// public polynomial evaluations + pub public_evals: [Vec; 2], /// zeta^n and (zeta * omega)^n pub powers_of_eval_points_for_chunks: PointEvaluations, /// recursion data @@ -48,6 +50,7 @@ pub mod caml { #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)] pub struct CamlOracles { pub o: CamlRandomOracles, + pub public_evals: (CamlF, CamlF), pub opening_prechallenges: Vec, pub digest_before_evaluations: CamlF, } @@ -74,9 +77,10 @@ pub mod caml { let oracles_result = proof.oracles::(&index, &p_comm)?; - let (mut sponge, combined_inner_product, digest, oracles) = ( + let (mut sponge, combined_inner_product, public_evals, digest, oracles) = ( oracles_result.fq_sponge, oracles_result.combined_inner_product, + oracles_result.public_evals, oracles_result.digest, oracles_result.oracles, ); @@ -92,6 +96,7 @@ pub mod caml { Ok(CamlOracles { o: oracles.into(), + public_evals: (public_evals[0][0].into(), public_evals[1][0].into()), opening_prechallenges, digest_before_evaluations: digest.into(), }) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 050cdd2003..c840fce614 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -393,6 +393,11 @@ where let mut all_alphas = index.powers_of_alpha.clone(); all_alphas.instantiate(alpha); + let public_evals = [ + self.evals.public.zeta.clone(), + self.evals.public.zeta_omega.clone(), + ]; + //~ 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. fr_sponge.absorb(&self.ft_eval1); @@ -565,6 +570,7 @@ where digest, oracles, all_alphas, + public_evals, powers_of_eval_points_for_chunks, polys, zeta1, From 9827fd106f9359b585d382b3088f0a90546589c7 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 21:20:06 +0100 Subject: [PATCH 052/242] Move public input absorption back out --- kimchi/src/plonk_sponge.rs | 4 ++-- kimchi/src/verifier.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index 255d98e8db..73f21342cf 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -60,7 +60,7 @@ impl FrSponge for DefaultFrSponge { self.last_squeezed = vec![]; let ProofEvaluations { - public, + public: _, // Must be absorbed first manually for now, to handle Mina annoyances w, z, s, @@ -70,7 +70,7 @@ impl FrSponge for DefaultFrSponge { poseidon_selector, } = e; - let mut points = vec![public, z, generic_selector, poseidon_selector]; + let mut points = vec![z, generic_selector, poseidon_selector]; w.iter().for_each(|w_i| points.push(w_i)); coefficients.iter().for_each(|c_i| points.push(c_i)); s.iter().for_each(|s_i| points.push(s_i)); diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index c840fce614..86e792bb35 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -408,6 +408,8 @@ where //~~ * poseidon selector //~~ * the 15 register/witness //~~ * 6 sigmas evaluations (the last one is not evaluated) + fr_sponge.absorb_multiple(&public_evals[0]); + fr_sponge.absorb_multiple(&public_evals[1]); fr_sponge.absorb_evaluations(&self.evals); //~ 1. Sample $v'$ with the Fr-Sponge. From a2fffd19d3543b62b618c24d111cad87b2171207 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 21:21:49 +0100 Subject: [PATCH 053/242] Use the public evals variable instead of the value from the proof --- kimchi/src/verifier.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 86e792bb35..3af9d8a89b 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -454,7 +454,7 @@ where .fold(init, |x, y| x * y); ft_eval0 -= DensePolynomial::eval_polynomial( - &self.evals.public.zeta, + &public_evals[0], powers_of_eval_points_for_chunks.zeta, ); @@ -502,13 +502,7 @@ where #[allow(clippy::type_complexity)] let mut es: Vec<(Vec>, Option)> = polys.iter().map(|(_, e)| (e.clone(), None)).collect(); - es.push(( - vec![ - self.evals.public.zeta.clone(), - self.evals.public.zeta_omega.clone(), - ], - None, - )); + es.push((public_evals.to_vec(), None)); es.push((vec![ft_eval0, ft_eval1], None)); for col in [ Column::Z, @@ -763,6 +757,7 @@ where fq_sponge, oracles, all_alphas, + public_evals, powers_of_eval_points_for_chunks, polys, zeta1: zeta_to_domain_size, @@ -864,10 +859,7 @@ where //~~ * public input commitment evaluations.push(Evaluation { commitment: public_comm, - evaluations: vec![ - proof.evals.public.zeta.clone(), - proof.evals.public.zeta_omega.clone(), - ], + evaluations: public_evals.to_vec(), degree_bound: None, }); From deffd1d4c6dd8b5300852820870b92c7cc4294c0 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 25 May 2023 22:39:35 +0100 Subject: [PATCH 054/242] Make the public input evaluation optional, reinstate old logic for false --- book/src/specs/kimchi.md | 5 +- kimchi/src/error.rs | 3 + kimchi/src/oracles.rs | 3 +- kimchi/src/proof.rs | 38 +++++-- kimchi/src/prover.rs | 8 +- kimchi/src/verifier.rs | 231 ++++++++++++--------------------------- 6 files changed, 110 insertions(+), 178 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index bb983c29e9..dfb8517eb1 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1955,7 +1955,7 @@ pub struct LookupEvaluations { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProofEvaluations { /// public input polynomials - pub public: Evals, + pub public: Option, /// witness polynomials pub w: [Evals; COLUMNS], /// permutation polynomial @@ -2240,6 +2240,9 @@ We run the following algorithm: 1. Squeeze the Fq-sponge and absorb the result with the Fr-Sponge. 1. Absorb the previous recursion challenges. 1. Compute evaluations for the previous recursion challenges. +1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. + + NOTE: this works only in the case when the poly segment size is not smaller than that of the domain. 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. 1. Absorb all the polynomial evaluations in $\zeta$ and $\zeta\omega$: * the public polynomial diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 2c787cc072..d8885670e2 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -73,6 +73,9 @@ pub enum VerifyError { #[error("the evaluation for {0:?} is missing")] MissingEvaluation(crate::circuits::expr::Column), + #[error("the evaluation for PublicInput is missing")] + MissingPublicInputEvaluation, + #[error("the commitment for {0:?} is missing")] MissingCommitment(crate::circuits::expr::Column), } diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index 9c692a12d9..b47c47287d 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -75,7 +75,8 @@ pub mod caml { let p_comm = PolyComm::::multi_scalar_mul(&lgr_comm_refs, &negated_public); - let oracles_result = proof.oracles::(&index, &p_comm)?; + let oracles_result = + proof.oracles::(&index, &p_comm, Some(public_input))?; let (mut sponge, combined_inner_product, public_evals, digest, oracles) = ( oracles_result.fq_sponge, diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 4a771de046..672bfe1106 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -62,7 +62,7 @@ pub struct LookupEvaluations { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProofEvaluations { /// public input polynomials - pub public: Evals, + pub public: Option, /// witness polynomials pub w: [Evals; COLUMNS], /// permutation polynomial @@ -210,7 +210,7 @@ impl ProofEvaluations { poseidon_selector, } = self; ProofEvaluations { - public: f(public), + public: public.map(f), w: w.map(f), z: f(z), s: s.map(f), @@ -233,7 +233,7 @@ impl ProofEvaluations { poseidon_selector, } = self; ProofEvaluations { - public: f(public), + public: public.as_ref().map(f), w: [ f(w0), f(w1), @@ -295,7 +295,13 @@ impl ProofEvaluations { ProofEvaluations { generic_selector: array::from_fn(|i| &evals[i].generic_selector), poseidon_selector: array::from_fn(|i| &evals[i].poseidon_selector), - public: array::from_fn(|i| &evals[i].public), + public: { + if evals.iter().all(|e| e.public.is_some()) { + Some(array::from_fn(|i| evals[i].public.as_ref().unwrap())) + } else { + None + } + }, z: array::from_fn(|i| &evals[i].z), w: array::from_fn(|j| array::from_fn(|i| &evals[i].w[j])), s: array::from_fn(|j| array::from_fn(|i| &evals[i].s[j])), @@ -380,7 +386,7 @@ impl ProofEvaluations> { zeta_omega: next, }; ProofEvaluations { - public: pt(F::zero(), F::zero()), + public: Some(pt(F::zero(), F::zero())), w: array::from_fn(|i| pt(curr[i], next[i])), z: pt(F::zero(), F::zero()), s: array::from_fn(|_| pt(F::zero(), F::zero())), @@ -585,7 +591,10 @@ pub mod caml { // impl From>>> - for (PointEvaluations>, CamlProofEvaluations) + for ( + Option>>, + CamlProofEvaluations, + ) where F: Clone, CamlF: From, @@ -707,7 +716,8 @@ pub mod caml { ); ( - pe.public.map(&|x| x.into_iter().map(Into::into).collect()), + pe.public + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), CamlProofEvaluations { w, coefficients, @@ -725,14 +735,20 @@ pub mod caml { } } - impl From<(PointEvaluations>, CamlProofEvaluations)> - for ProofEvaluations>> + impl + From<( + Option>>, + CamlProofEvaluations, + )> for ProofEvaluations>> where F: Clone, F: From, { fn from( - (public, cpe): (PointEvaluations>, CamlProofEvaluations), + (public, cpe): ( + Option>>, + CamlProofEvaluations, + ), ) -> Self { let w = [ cpe.w.0.map(&|x| x.into_iter().map(Into::into).collect()), @@ -808,7 +824,7 @@ pub mod caml { ]; Self { - public: public.map(&|x| x.into_iter().map(Into::into).collect()), + public: public.map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), w, coefficients, z: cpe.z.map(&|x| x.into_iter().map(Into::into).collect()), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 72f0536e1e..1b1db624dc 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -938,10 +938,10 @@ where let chunked_evals = ProofEvaluations::>> { public: { let chunked = public_poly.to_chunked_polynomial(num_chunks, index.max_poly_size); - PointEvaluations { + Some(PointEvaluations { zeta: chunked.evaluate_chunks(zeta), zeta_omega: chunked.evaluate_chunks(zeta_omega), - } + }) }, s: array::from_fn(|i| { chunked_evals_for_evaluations( @@ -1087,6 +1087,8 @@ where //~~ * poseidon selector //~~ * the 15 register/witness //~~ * 6 sigmas evaluations (the last one is not evaluated) + fr_sponge.absorb_multiple(&chunked_evals.public.as_ref().unwrap().zeta); + fr_sponge.absorb_multiple(&chunked_evals.public.as_ref().unwrap().zeta_omega); fr_sponge.absorb_evaluations(&chunked_evals); //~ 1. Sample $v'$ with the Fr-Sponge @@ -1298,7 +1300,7 @@ pub mod caml { #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)] pub struct CamlProofWithPublic { - pub public_evals: PointEvaluations>, + pub public_evals: Option>>, pub proof: CamlProverProof, } diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 3af9d8a89b..2aeccacead 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -90,35 +90,34 @@ impl<'a, G: KimchiCurve> Context<'a, G> { } } -pub struct OraclesBeforeEvaluations { - fq_sponge: EFqSponge, - fq_sponge_digest: Fp, - endo_r: Fp, - alpha_chal: ScalarChallenge, - alpha: Fp, - beta: Fp, - gamma: Fp, - joint_combiner: Option<(ScalarChallenge, Fp)>, - zeta_chal: ScalarChallenge, - zeta: Fp, -} - impl ProverProof where G::BaseField: PrimeField, { - pub fn oracles_before_evaluations< + /// This function runs the random oracle argument + /// + /// # Errors + /// + /// Will give error if `commitment(s)` are invalid(missing or wrong length), or `proof` is verified as invalid. + /// + /// # Panics + /// + /// Will panic if `PolishToken` evaluation is invalid. + pub fn oracles< EFqSponge: Clone + FqSponge, + EFrSponge: FrSponge, >( &self, index: &VerifierIndex, public_comm: &PolyComm, - ) -> Result> { + public_input: Option<&[G::ScalarField]>, + ) -> Result> { //~ //~ #### Fiat-Shamir argument //~ //~ We run the following algorithm: //~ + let n = index.domain.size; let (_, endo_r) = G::endos(); let chunk_size = { @@ -240,111 +239,9 @@ where //~ 1. Derive $\zeta$ from $\zeta'$ using the endomorphism (TODO: specify). let zeta = zeta_chal.to_field(endo_r); - let digest = fq_sponge.clone().digest(); - - Ok(OraclesBeforeEvaluations { - fq_sponge, - fq_sponge_digest: digest, - endo_r: *endo_r, - alpha_chal, - alpha, - beta, - gamma, - joint_combiner, - zeta_chal, - zeta, - }) - } - - pub fn public_input_evals_unchunked( - &self, - index: &VerifierIndex, - oracles_before_evaluations: &OraclesBeforeEvaluations, - public_input: &[G::ScalarField], - ) -> PointEvaluations> { - let OraclesBeforeEvaluations { zeta, .. } = oracles_before_evaluations; - // compute Lagrange base evaluation denominators - let w: Vec<_> = index.domain.elements().take(public_input.len()).collect(); - - let mut zeta_minus_x: Vec<_> = w.iter().map(|w| *zeta - w).collect(); - - let n = index.domain.size; - let zeta1 = zeta.pow([n]); - let zetaw = *zeta * index.domain.group_gen; - - w.iter() - .take(public_input.len()) - .for_each(|w| zeta_minus_x.push(zetaw - w)); - - ark_ff::fields::batch_inversion::(&mut zeta_minus_x); - - // 1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. - // - // NOTE: this works only in the case when the poly segment size is not smaller than that of the domain. - if public_input.is_empty() { - PointEvaluations { - zeta: vec![G::ScalarField::zero()], - zeta_omega: vec![G::ScalarField::zero()], - } - } else { - PointEvaluations { - zeta: vec![ - (public_input - .iter() - .zip(zeta_minus_x.iter()) - .zip(index.domain.elements()) - .map(|((p, l), w)| -*l * p * w) - .fold(G::ScalarField::zero(), |x, y| x + y)) - * (zeta1 - G::ScalarField::one()) - * index.domain.size_inv, - ], - zeta_omega: vec![ - (public_input - .iter() - .zip(zeta_minus_x[public_input.len()..].iter()) - .zip(index.domain.elements()) - .map(|((p, l), w)| -*l * p * w) - .fold(G::ScalarField::zero(), |x, y| x + y)) - * index.domain.size_inv - * (zetaw.pow([n]) - G::ScalarField::one()), - ], - } - } - } - - /// This function runs the random oracle argument - /// - /// # Errors - /// - /// Will give error if `commitment(s)` are invalid(missing or wrong length), or `proof` is verified as invalid. - /// - /// # Panics - /// - /// Will panic if `PolishToken` evaluation is invalid. - pub fn oracles_finalize< - EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, - >( - &self, - index: &VerifierIndex, - oracles: OraclesBeforeEvaluations, - ) -> Result> { - let OraclesBeforeEvaluations { - fq_sponge, - fq_sponge_digest: digest, - endo_r, - alpha_chal, - alpha, - beta, - gamma, - joint_combiner, - zeta_chal, - zeta, - } = oracles; - - let n = index.domain.size; //~ 1. Setup the Fr-Sponge. + let digest = fq_sponge.clone().digest(); let mut fr_sponge = EFrSponge::new(G::sponge_params()); //~ 1. Squeeze the Fq-sponge and absorb the result with the Fr-Sponge. @@ -393,10 +290,54 @@ where let mut all_alphas = index.powers_of_alpha.clone(); all_alphas.instantiate(alpha); - let public_evals = [ - self.evals.public.zeta.clone(), - self.evals.public.zeta_omega.clone(), - ]; + let public_evals = if let Some(public_evals) = &self.evals.public { + [public_evals.zeta.clone(), public_evals.zeta_omega.clone()] + } else if chunk_size > 1 { + return Err(VerifyError::MissingPublicInputEvaluation); + } else if let Some(public_input) = public_input { + // compute Lagrange base evaluation denominators + let w: Vec<_> = index.domain.elements().take(public_input.len()).collect(); + + let mut zeta_minus_x: Vec<_> = w.iter().map(|w| zeta - w).collect(); + + w.iter() + .take(public_input.len()) + .for_each(|w| zeta_minus_x.push(zetaw - w)); + + ark_ff::fields::batch_inversion::(&mut zeta_minus_x); + + //~ 1. Evaluate the negated public polynomial (if present) at $\zeta$ and $\zeta\omega$. + //~ + //~ NOTE: this works only in the case when the poly segment size is not smaller than that of the domain. + if public_input.is_empty() { + [vec![G::ScalarField::zero()], vec![G::ScalarField::zero()]] + } else { + [ + vec![ + (public_input + .iter() + .zip(zeta_minus_x.iter()) + .zip(index.domain.elements()) + .map(|((p, l), w)| -*l * p * w) + .fold(G::ScalarField::zero(), |x, y| x + y)) + * (zeta1 - G::ScalarField::one()) + * index.domain.size_inv, + ], + vec![ + (public_input + .iter() + .zip(zeta_minus_x[public_input.len()..].iter()) + .zip(index.domain.elements()) + .map(|((p, l), w)| -*l * p * w) + .fold(G::ScalarField::zero(), |x, y| x + y)) + * index.domain.size_inv + * (zetaw.pow([n]) - G::ScalarField::one()), + ], + ] + } + } else { + return Err(VerifyError::MissingPublicInputEvaluation); + }; //~ 1. Absorb the unique evaluation of ft: $ft(\zeta\omega)$. fr_sponge.absorb(&self.ft_eval1); @@ -416,13 +357,13 @@ where let v_chal = fr_sponge.challenge(); //~ 1. Derive $v$ from $v'$ using the endomorphism (TODO: specify). - let v = v_chal.to_field(&endo_r); + let v = v_chal.to_field(endo_r); //~ 1. Sample $u'$ with the Fr-Sponge. let u_chal = fr_sponge.challenge(); //~ 1. Derive $u$ from $u'$ using the endomorphism (TODO: specify). - let u = u_chal.to_field(&endo_r); + let u = u_chal.to_field(endo_r); //~ 1. Create a list of all polynomials that have an evaluation proof. @@ -574,42 +515,6 @@ where combined_inner_product, }) } - - pub fn oracles_with_unchunked_public_input< - EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, - >( - &mut self, - index: &VerifierIndex, - public_comm: &PolyComm, - public_input: &[G::ScalarField], - ) -> Result> { - let oracles = self.oracles_before_evaluations::(index, public_comm)?; - let public_input_evals = self.public_input_evals_unchunked(index, &oracles, public_input); - self.evals.public = public_input_evals; - self.oracles_finalize::(index, oracles) - } - - /// This function runs the random oracle argument - /// - /// # Errors - /// - /// Will give error if `commitment(s)` are invalid(missing or wrong length), or `proof` is verified as invalid. - /// - /// # Panics - /// - /// Will panic if `PolishToken` evaluation is invalid. - pub fn oracles< - EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, - >( - &self, - index: &VerifierIndex, - public_comm: &PolyComm, - ) -> Result> { - let oracles = self.oracles_before_evaluations::(index, public_comm)?; - self.oracles_finalize::(index, oracles) - } } /// Enforce the length of evaluations inside [`Proof`]. @@ -647,7 +552,9 @@ where } }; - check_eval_len(public, "public input")?; + if let Some(public) = public { + check_eval_len(public, "public input")?; + } for w_i in w { check_eval_len(w_i, "witness")?; @@ -764,7 +671,7 @@ where ft_eval0, combined_inner_product, .. - } = proof.oracles::(verifier_index, &public_comm)?; + } = proof.oracles::(verifier_index, &public_comm, Some(public_input))?; //~ 1. Combine the chunked polynomials' evaluations //~ (TODO: most likely only the quotient polynomial is chunked) From c9159031a7fb2c0179ac5a9fc4bda5094a655f8a Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 15:31:25 +0100 Subject: [PATCH 055/242] Use a named variable for a computation --- kimchi/src/circuits/lookup/constraints.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index ef11bc9588..75eca800f6 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -37,8 +37,9 @@ pub fn zk_patch( ) -> Evaluations> { let n = d.size(); let k = e.len(); - assert!(k <= n - zk_rows); - e.extend((0..((n - zk_rows) - k)).map(|_| F::zero())); + let last_non_zk_row = n - zk_rows; + assert!(k <= last_non_zk_row); + e.extend((0..(last_non_zk_row - k)).map(|_| F::zero())); e.extend((0..zk_rows).map(|_| F::rand(rng))); Evaluations::>::from_vec_and_domain(e, d) } From 2f675577538857fa150fab502101ba799bbc5638 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 15:32:41 +0100 Subject: [PATCH 056/242] Use a more direct range --- kimchi/src/circuits/lookup/constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index 75eca800f6..220149cd3b 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -39,7 +39,7 @@ pub fn zk_patch( let k = e.len(); let last_non_zk_row = n - zk_rows; assert!(k <= last_non_zk_row); - e.extend((0..(last_non_zk_row - k)).map(|_| F::zero())); + e.extend((k..last_non_zk_row).map(|_| F::zero())); e.extend((0..zk_rows).map(|_| F::rand(rng))); Evaluations::>::from_vec_and_domain(e, d) } From 46d9c822768206f306c3dc284e1c74ca504e94f7 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 15:37:11 +0100 Subject: [PATCH 057/242] Abstract out a constant --- kimchi/src/circuits/constraints.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 812c17df58..a7c84e2f69 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -703,8 +703,8 @@ impl Builder { //~ has order greater or equal to `n + zk_rows` elements. let (zk_rows, domain_size_lower_bound) = { let mut zk_rows = 3; - let get_domain_size_lower_bound = - |zk_rows: u64| std::cmp::max(gates.len(), num_lookups + 1) + zk_rows as usize; + let circuit_lower_bound = std::cmp::max(gates.len(), num_lookups + 1); + let get_domain_size_lower_bound = |zk_rows: u64| circuit_lower_bound + zk_rows as usize; let mut domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); if let Some(max_poly_size) = self.max_poly_size { // Iterate to find a fixed-point where zk_rows is sufficient for the number of From 988ec750f96e03c5729d2474f862cd16a42f2b66 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 15:37:43 +0100 Subject: [PATCH 058/242] Separate constant definitions from loop variables --- kimchi/src/circuits/constraints.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index a7c84e2f69..f28256224a 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -702,9 +702,10 @@ impl Builder { //~ compute the smallest subgroup of the field that //~ has order greater or equal to `n + zk_rows` elements. let (zk_rows, domain_size_lower_bound) = { - let mut zk_rows = 3; let circuit_lower_bound = std::cmp::max(gates.len(), num_lookups + 1); let get_domain_size_lower_bound = |zk_rows: u64| circuit_lower_bound + zk_rows as usize; + + let mut zk_rows = 3; let mut domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); if let Some(max_poly_size) = self.max_poly_size { // Iterate to find a fixed-point where zk_rows is sufficient for the number of From bfcb071d84474e8f7d913140c98659d3bc67f833 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 15:40:34 +0100 Subject: [PATCH 059/242] Update spec wording to be more concrete --- book/src/specs/kimchi.md | 2 +- kimchi/src/circuits/polynomials/permutation.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index a798eb340e..10f9876968 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -313,7 +313,7 @@ $$ We randomize the evaluations at `n - zk_rows + 1` and `n - zk_rows + 2` in order to add zero-knowledge to the protocol. -If computed correctly, we should have $z(g^{n-zk_rows}) = 1$. +For a valid witness, we then have have $z(g^{n-zk_rows}) = 1$. diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 755f8ea7f2..ce3664b75b 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -490,7 +490,7 @@ impl> ProverIndex { } } - //~ If computed correctly, we should have $z(g^{n-zk_rows}) = 1$. + //~ For a valid witness, we then have have $z(g^{n-zk_rows}) = 1$. //~ if z[n - zk_rows] != F::one() { return Err(ProverError::Permutation("final value")); From bc25094a8b9f1556eb2eaef617fb539eb7e6ba4d Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 15:43:43 +0100 Subject: [PATCH 060/242] Abstract domain size into a variable --- kimchi/src/circuits/constraints.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index f28256224a..fa93663c28 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -365,8 +365,9 @@ impl ConstraintSystem { // compute permutation polynomials let shifts = Shifts::new(&self.domain.d1); - let mut sigmal1: [Vec; PERMUTS] = - array::from_fn(|_| vec![F::zero(); self.domain.d1.size()]); + let n = self.domain.d1.size(); + + let mut sigmal1: [Vec; PERMUTS] = array::from_fn(|_| vec![F::zero(); n]); for (row, gate) in self.gates.iter().enumerate() { for (cell, sigma) in gate.wires.iter().zip(sigmal1.iter_mut()) { @@ -376,7 +377,7 @@ impl ConstraintSystem { // Zero out the sigmas in the zk rows, to ensure that the permutation aggregation is // quasi-random for those rows. - for row in self.domain.d1.size() + 2 - (self.zk_rows as usize)..self.domain.d1.size() - 1 { + for row in n + 2 - (self.zk_rows as usize)..n - 1 { for sigma in sigmal1.iter_mut() { sigma[row] = F::zero(); } From 2724c9e3f88644566d72a1e5083de0d1b347a8be Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 15:55:13 +0100 Subject: [PATCH 061/242] Separate out domain size computation --- kimchi/src/circuits/constraints.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index fa93663c28..54532d82f6 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -699,9 +699,6 @@ impl Builder { num_lookups }; - //~ 2. Create a domain for the circuit. That is, - //~ compute the smallest subgroup of the field that - //~ has order greater or equal to `n + zk_rows` elements. let (zk_rows, domain_size_lower_bound) = { let circuit_lower_bound = std::cmp::max(gates.len(), num_lookups + 1); let get_domain_size_lower_bound = |zk_rows: u64| circuit_lower_bound + zk_rows as usize; @@ -726,6 +723,10 @@ impl Builder { } (zk_rows, domain_size_lower_bound) }; + + //~ 2. Create a domain for the circuit. That is, + //~ compute the smallest subgroup of the field that + //~ has order greater or equal to `n + zk_rows` elements. let domain = EvaluationDomains::::create(domain_size_lower_bound)?; assert!(domain.d1.size > zk_rows); From 759b8fb1fa81893dfef3065ba4625db688e92a32 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 16:35:46 +0100 Subject: [PATCH 062/242] Add some documentation on how to derive the circuit size limit --- book/src/specs/kimchi.md | 21 +++++++++++++++++++++ kimchi/src/circuits/constraints.rs | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 10f9876968..6cdb37a0e2 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1600,6 +1600,27 @@ def sample(domain, i): The compilation steps to create the common index are as follow: 1. If the circuit is less than 2 gates, abort. +1. Compute the number of zero-knowledge rows (`zk_rows`) that will be required to + achieve zero-knowledge. The following constraints apply to `zk_rows`: + - The number of chunks `c` results in an evaluation at `zeta` and `zeta * omega` in + each column for `2*c` evaluations per column, so `zk_rows >= 2*c + 1`. + - The permutation argument interacts with the `c` chunks in parallel, so it is + possible to cross-correlate between them to compromise zero knowledge. We know + that there is some `c >= 1` such that `zk_rows = 2*c + k` from the above. Thus, + attempting to find the evaluation at a new point, we find that: + * the evaluation of every witness column in the permutation contains `k` unknowns; + * the evaluations of the permutation argument aggregation has `k-1` unknowns; + * the permutation argument applies on all but `zk_rows - 3` rows; + * and thus we form the equation `zk_rows - 3 < 7 * k + (k - 1)` to ensure that we + can construct fewer equations than we have unknowns. + + This simplifies to `k > (2 * c - 2) / 7`, giving `zk_rows > (16 * c - 2) / 7`. + We can derive `c` from the `max_poly_size` supported by the URS, and thus we find + `zk_rows` and `domain_size` satisfying the fixpoint + ``` + zk_rows = (16 * (domain_size / max_poly_size) + 5) / 7 + domain_size = circuit_size + zk_rows + ``` 2. Create a domain for the circuit. That is, compute the smallest subgroup of the field that has order greater or equal to `n + zk_rows` elements. diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 54532d82f6..24391359db 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -699,6 +699,27 @@ impl Builder { num_lookups }; + //~ 1. Compute the number of zero-knowledge rows (`zk_rows`) that will be required to + //~ achieve zero-knowledge. The following constraints apply to `zk_rows`: + //~ - The number of chunks `c` results in an evaluation at `zeta` and `zeta * omega` in + //~ each column for `2*c` evaluations per column, so `zk_rows >= 2*c + 1`. + //~ - The permutation argument interacts with the `c` chunks in parallel, so it is + //~ possible to cross-correlate between them to compromise zero knowledge. We know + //~ that there is some `c >= 1` such that `zk_rows = 2*c + k` from the above. Thus, + //~ attempting to find the evaluation at a new point, we find that: + //~ * the evaluation of every witness column in the permutation contains `k` unknowns; + //~ * the evaluations of the permutation argument aggregation has `k-1` unknowns; + //~ * the permutation argument applies on all but `zk_rows - 3` rows; + //~ * and thus we form the equation `zk_rows - 3 < 7 * k + (k - 1)` to ensure that we + //~ can construct fewer equations than we have unknowns. + //~ + //~ This simplifies to `k > (2 * c - 2) / 7`, giving `zk_rows > (16 * c - 2) / 7`. + //~ We can derive `c` from the `max_poly_size` supported by the URS, and thus we find + //~ `zk_rows` and `domain_size` satisfying the fixpoint + //~ ``` + //~ zk_rows = (16 * (domain_size / max_poly_size) + 5) / 7 + //~ domain_size = circuit_size + zk_rows + //~ ``` let (zk_rows, domain_size_lower_bound) = { let circuit_lower_bound = std::cmp::max(gates.len(), num_lookups + 1); let get_domain_size_lower_bound = |zk_rows: u64| circuit_lower_bound + zk_rows as usize; @@ -716,7 +737,7 @@ impl Builder { .ok_or(SetupError::DomainCreation( "could not compute size of domain", ))?; - zk_rows = ((16 * (domain_size / max_poly_size) + 4) / 7) as u64; + zk_rows = ((16 * (domain_size / max_poly_size) + 5) / 7) as u64; domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); domain_size < domain_size_lower_bound } {} From 80da6c22ed08d17af940fe814cedc6b8438a651f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 16:45:34 +0100 Subject: [PATCH 063/242] Remove debug prints --- kimchi/src/verifier.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index b1f01dbbe3..84a7199655 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -361,16 +361,12 @@ where //~ 1. Derive $v$ from $v'$ using the endomorphism (TODO: specify). let v = v_chal.to_field(endo_r); - println!("v: {}", v); - //~ 1. Sample $u'$ with the Fr-Sponge. let u_chal = fr_sponge.challenge(); //~ 1. Derive $u$ from $u'$ using the endomorphism (TODO: specify). let u = u_chal.to_field(endo_r); - println!("u: {}", u); - //~ 1. Create a list of all polynomials that have an evaluation proof. let evals = self.evals.combine(&powers_of_eval_points_for_chunks); From bad63360d5eedd31caa0d92c38010d746cdbf6bc Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 16:48:23 +0100 Subject: [PATCH 064/242] Fixup typo --- kimchi/src/prover.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index db6de79c43..36683ea33d 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -191,7 +191,7 @@ where .checked_sub(length_witness) .ok_or(ProverError::NoRoomForZkInWitness)?; - let zero_knowledge_limit = (16 * num_chunks - 4) / 7; + let zero_knowledge_limit = (16 * num_chunks - 2) / 7; if (index.cs.zk_rows as usize) < zero_knowledge_limit { return Err(ProverError::NotZeroKnowledge( zero_knowledge_limit, From bc7966fba736c1e925fc539a15019da416344a4f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 16:50:51 +0100 Subject: [PATCH 065/242] Fix the fussy spec builder.. --- book/src/specs/kimchi.md | 4 +++- kimchi/src/circuits/constraints.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 6cdb37a0e2..f3781470fc 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1617,10 +1617,12 @@ The compilation steps to create the common index are as follow: This simplifies to `k > (2 * c - 2) / 7`, giving `zk_rows > (16 * c - 2) / 7`. We can derive `c` from the `max_poly_size` supported by the URS, and thus we find `zk_rows` and `domain_size` satisfying the fixpoint - ``` + + ```text zk_rows = (16 * (domain_size / max_poly_size) + 5) / 7 domain_size = circuit_size + zk_rows ``` + 2. Create a domain for the circuit. That is, compute the smallest subgroup of the field that has order greater or equal to `n + zk_rows` elements. diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 24391359db..7d1812bb7c 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -716,10 +716,12 @@ impl Builder { //~ This simplifies to `k > (2 * c - 2) / 7`, giving `zk_rows > (16 * c - 2) / 7`. //~ We can derive `c` from the `max_poly_size` supported by the URS, and thus we find //~ `zk_rows` and `domain_size` satisfying the fixpoint - //~ ``` + //~ + //~ ```text //~ zk_rows = (16 * (domain_size / max_poly_size) + 5) / 7 //~ domain_size = circuit_size + zk_rows //~ ``` + //~ let (zk_rows, domain_size_lower_bound) = { let circuit_lower_bound = std::cmp::max(gates.len(), num_lookups + 1); let get_domain_size_lower_bound = |zk_rows: u64| circuit_lower_bound + zk_rows as usize; From 6123ca07c3596961df4a76b4c48b02d43074cda0 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 17:03:13 +0100 Subject: [PATCH 066/242] Formatting hell --- book/src/specs/kimchi.md | 8 ++++---- kimchi/src/circuits/constraints.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index f3781470fc..085819b217 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1602,9 +1602,9 @@ The compilation steps to create the common index are as follow: 1. If the circuit is less than 2 gates, abort. 1. Compute the number of zero-knowledge rows (`zk_rows`) that will be required to achieve zero-knowledge. The following constraints apply to `zk_rows`: - - The number of chunks `c` results in an evaluation at `zeta` and `zeta * omega` in + * The number of chunks `c` results in an evaluation at `zeta` and `zeta * omega` in each column for `2*c` evaluations per column, so `zk_rows >= 2*c + 1`. - - The permutation argument interacts with the `c` chunks in parallel, so it is + * The permutation argument interacts with the `c` chunks in parallel, so it is possible to cross-correlate between them to compromise zero knowledge. We know that there is some `c >= 1` such that `zk_rows = 2*c + k` from the above. Thus, attempting to find the evaluation at a new point, we find that: @@ -1623,10 +1623,10 @@ The compilation steps to create the common index are as follow: domain_size = circuit_size + zk_rows ``` -2. Create a domain for the circuit. That is, +1. Create a domain for the circuit. That is, compute the smallest subgroup of the field that has order greater or equal to `n + zk_rows` elements. -3. Pad the circuit: add zero gates to reach the domain size. +1. Pad the circuit: add zero gates to reach the domain size. 4. sample the `PERMUTS` shifts. diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 7d1812bb7c..14dd7229da 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -701,9 +701,9 @@ impl Builder { //~ 1. Compute the number of zero-knowledge rows (`zk_rows`) that will be required to //~ achieve zero-knowledge. The following constraints apply to `zk_rows`: - //~ - The number of chunks `c` results in an evaluation at `zeta` and `zeta * omega` in + //~ * The number of chunks `c` results in an evaluation at `zeta` and `zeta * omega` in //~ each column for `2*c` evaluations per column, so `zk_rows >= 2*c + 1`. - //~ - The permutation argument interacts with the `c` chunks in parallel, so it is + //~ * The permutation argument interacts with the `c` chunks in parallel, so it is //~ possible to cross-correlate between them to compromise zero knowledge. We know //~ that there is some `c >= 1` such that `zk_rows = 2*c + k` from the above. Thus, //~ attempting to find the evaluation at a new point, we find that: @@ -747,14 +747,14 @@ impl Builder { (zk_rows, domain_size_lower_bound) }; - //~ 2. Create a domain for the circuit. That is, + //~ 1. Create a domain for the circuit. That is, //~ compute the smallest subgroup of the field that //~ has order greater or equal to `n + zk_rows` elements. let domain = EvaluationDomains::::create(domain_size_lower_bound)?; assert!(domain.d1.size > zk_rows); - //~ 3. Pad the circuit: add zero gates to reach the domain size. + //~ 1. Pad the circuit: add zero gates to reach the domain size. let d1_size = domain.d1.size(); let mut padding = (gates.len()..d1_size) .map(|i| { From 752c854f5cf319836190ea979cecaa3ab2e760b9 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 17:07:53 +0100 Subject: [PATCH 067/242] Why did we automate the complaining, but not the fixing :| --- book/src/specs/kimchi.md | 2 +- kimchi/src/circuits/constraints.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 085819b217..108e404f51 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1627,7 +1627,7 @@ The compilation steps to create the common index are as follow: compute the smallest subgroup of the field that has order greater or equal to `n + zk_rows` elements. 1. Pad the circuit: add zero gates to reach the domain size. -4. sample the `PERMUTS` shifts. +1. sample the `PERMUTS` shifts. ### Lookup Index diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 14dd7229da..dd141f7860 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -788,7 +788,7 @@ impl Builder { } } - //~ 4. sample the `PERMUTS` shifts. + //~ 1. sample the `PERMUTS` shifts. let shifts = Shifts::new(&domain.d1); // From 7762c8785bcdd78ca2e3f0e464d78ef90c80c607 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 17:10:35 +0100 Subject: [PATCH 068/242] Use PERMUTS instead of a literal 7 --- kimchi/src/circuits/constraints.rs | 2 +- kimchi/src/prover.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index dd141f7860..9cb999e5ba 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -739,7 +739,7 @@ impl Builder { .ok_or(SetupError::DomainCreation( "could not compute size of domain", ))?; - zk_rows = ((16 * (domain_size / max_poly_size) + 5) / 7) as u64; + zk_rows = ((16 * (domain_size / max_poly_size) + 5) / PERMUTS) as u64; domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); domain_size < domain_size_lower_bound } {} diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 36683ea33d..3e6603f85a 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -191,7 +191,7 @@ where .checked_sub(length_witness) .ok_or(ProverError::NoRoomForZkInWitness)?; - let zero_knowledge_limit = (16 * num_chunks - 2) / 7; + let zero_knowledge_limit = (16 * num_chunks - 2) / PERMUTS; if (index.cs.zk_rows as usize) < zero_knowledge_limit { return Err(ProverError::NotZeroKnowledge( zero_knowledge_limit, From a62896b22fc223556b7227bb1c8876c62afdd583 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 17:16:35 +0100 Subject: [PATCH 069/242] Remove magic constants from zk_rows computation --- kimchi/src/circuits/constraints.rs | 3 ++- kimchi/src/prover.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 9cb999e5ba..a3f4306f7b 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -739,7 +739,8 @@ impl Builder { .ok_or(SetupError::DomainCreation( "could not compute size of domain", ))?; - zk_rows = ((16 * (domain_size / max_poly_size) + 5) / PERMUTS) as u64; + let num_chunks = domain_size / max_poly_size; + zk_rows = ((2 * (PERMUTS + 1) * num_chunks - 2) / PERMUTS + 1) as u64; domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); domain_size < domain_size_lower_bound } {} diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 3e6603f85a..2f5b9fae1e 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -191,7 +191,7 @@ where .checked_sub(length_witness) .ok_or(ProverError::NoRoomForZkInWitness)?; - let zero_knowledge_limit = (16 * num_chunks - 2) / PERMUTS; + let zero_knowledge_limit = (2 * (PERMUTS + 1) * num_chunks - 2) / PERMUTS; if (index.cs.zk_rows as usize) < zero_knowledge_limit { return Err(ProverError::NotZeroKnowledge( zero_knowledge_limit, From d21637712662adc0127d8e1c33db8d9ab2dece35 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 26 May 2023 17:24:13 +0100 Subject: [PATCH 070/242] Use a helper for the zk_rows_strict_lower_bound --- kimchi/src/circuits/constraints.rs | 6 +++++- kimchi/src/prover.rs | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index a3f4306f7b..c4474af777 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -604,6 +604,10 @@ impl ConstraintSystem { } } +pub fn zk_rows_strict_lower_bound(num_chunks: usize) -> usize { + (2 * (PERMUTS + 1) * num_chunks - 2) / PERMUTS +} + impl Builder { /// Set up the number of public inputs. /// If not invoked, it equals `0` by default. @@ -740,7 +744,7 @@ impl Builder { "could not compute size of domain", ))?; let num_chunks = domain_size / max_poly_size; - zk_rows = ((2 * (PERMUTS + 1) * num_chunks - 2) / PERMUTS + 1) as u64; + zk_rows = (zk_rows_strict_lower_bound(num_chunks) + 1) as u64; domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); domain_size < domain_size_lower_bound } {} diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 2f5b9fae1e..42787f9991 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -3,6 +3,7 @@ use crate::{ circuits::{ argument::{Argument, ArgumentType}, + constraints::zk_rows_strict_lower_bound, expr::{self, l0_1, Constants, Environment, LookupEnvironment}, gate::GateType, lookup::{self, runtime_tables::RuntimeTable, tables::combine_table_entry}, @@ -191,7 +192,7 @@ where .checked_sub(length_witness) .ok_or(ProverError::NoRoomForZkInWitness)?; - let zero_knowledge_limit = (2 * (PERMUTS + 1) * num_chunks - 2) / PERMUTS; + let zero_knowledge_limit = zk_rows_strict_lower_bound(num_chunks); if (index.cs.zk_rows as usize) < zero_knowledge_limit { return Err(ProverError::NotZeroKnowledge( zero_knowledge_limit, From 1990bf54855c860fff2703a4387ca27b9768b6f1 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 1 Jun 2023 16:39:42 +0100 Subject: [PATCH 071/242] Capture zk_rows as a variable in the expression framework --- kimchi/src/circuits/expr.rs | 86 +++++++++++++++++++---- kimchi/src/circuits/lookup/constraints.rs | 18 +++-- kimchi/src/linearization.rs | 10 ++- kimchi/src/prover.rs | 1 - kimchi/src/prover_index.rs | 2 +- 5 files changed, 92 insertions(+), 25 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index b62371ebde..92a78ef9a5 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -459,6 +459,12 @@ impl FeatureFlag { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct RowOffset { + pub zk_rows: bool, + pub offset: i32, +} + /// An multi-variate polynomial over the base ring `C` with /// variables /// @@ -479,7 +485,7 @@ pub enum Expr { VanishesOnZeroKnowledgeAndPreviousRows, /// UnnormalizedLagrangeBasis(i) is /// (x^n - 1) / (x - omega^i) - UnnormalizedLagrangeBasis(i32), + UnnormalizedLagrangeBasis(RowOffset), Pow(Box>, u64), Cache(CacheId, Box>), /// If the feature flag is enabled, return the first expression; otherwise, return the second. @@ -649,7 +655,7 @@ pub enum PolishToken { Mul, Sub, VanishesOnZeroKnowledgeAndPreviousRows, - UnnormalizedLagrangeBasis(i32), + UnnormalizedLagrangeBasis(RowOffset), Store, Load(usize), /// Skip the given number of tokens if the feature is enabled. @@ -725,7 +731,12 @@ impl PolishToken { stack.push(eval_vanishes_on_last_n_rows(d, c.zk_rows + 1, pt)) } UnnormalizedLagrangeBasis(i) => { - stack.push(unnormalized_lagrange_basis(&d, *i, &pt)) + let offset = if i.zk_rows { + -(c.zk_rows as i32) + i.offset + } else { + i.offset + }; + stack.push(unnormalized_lagrange_basis(&d, offset, &pt)) } Literal(x) => stack.push(*x), Dup => stack.push(stack[stack.len() - 1]), @@ -1548,7 +1559,14 @@ impl Expr> { VanishesOnZeroKnowledgeAndPreviousRows => { Ok(eval_vanishes_on_last_n_rows(d, c.zk_rows + 1, pt)) } - UnnormalizedLagrangeBasis(i) => Ok(unnormalized_lagrange_basis(&d, *i, &pt)), + UnnormalizedLagrangeBasis(i) => { + let offset = if i.zk_rows { + -(c.zk_rows as i32) + i.offset + } else { + i.offset + }; + Ok(unnormalized_lagrange_basis(&d, offset, &pt)) + } Cell(v) => v.evaluate(evals), Cache(_, e) => e.evaluate_(d, pt, evals, c), IfFeature(feature, e1, e2) => { @@ -1610,7 +1628,14 @@ impl Expr { VanishesOnZeroKnowledgeAndPreviousRows => { Ok(eval_vanishes_on_last_n_rows(d, zk_rows + 1, pt)) } - UnnormalizedLagrangeBasis(i) => Ok(unnormalized_lagrange_basis(&d, *i, &pt)), + UnnormalizedLagrangeBasis(i) => { + let offset = if i.zk_rows { + -(zk_rows as i32) + i.offset + } else { + i.offset + }; + Ok(unnormalized_lagrange_basis(&d, offset, &pt)) + } Cell(v) => v.evaluate(evals), Cache(_, e) => e.evaluate(d, pt, zk_rows, evals), IfFeature(feature, e1, e2) => { @@ -1748,10 +1773,17 @@ impl Expr { evals: env.vanishes_on_zero_knowledge_and_previous_rows, }, Expr::Constant(x) => EvalResult::Constant(*x), - Expr::UnnormalizedLagrangeBasis(i) => EvalResult::Evals { - domain: d, - evals: unnormalized_lagrange_evals(env.l0_1, *i, d, env), - }, + Expr::UnnormalizedLagrangeBasis(i) => { + let offset = if i.zk_rows { + -(env.constants.zk_rows as i32) + i.offset + } else { + i.offset + }; + EvalResult::Evals { + domain: d, + evals: unnormalized_lagrange_evals(env.l0_1, offset, d, env), + } + } Expr::Cell(Variable { col, row }) => { let evals: &'a Evaluations> = { match env.get_column(col) { @@ -2442,7 +2474,9 @@ where Double(x) => format!("double({})", x.ocaml(cache)), Constant(x) => x.ocaml(), Cell(v) => format!("cell({})", v.ocaml()), - UnnormalizedLagrangeBasis(i) => format!("unnormalized_lagrange_basis({})", *i), + UnnormalizedLagrangeBasis(i) => { + format!("unnormalized_lagrange_basis({}, {})", i.zk_rows, i.offset) + } VanishesOnZeroKnowledgeAndPreviousRows => { "vanishes_on_zero_knowledge_and_previous_rows".to_string() } @@ -2493,7 +2527,18 @@ where Double(x) => format!("2 ({})", x.latex(cache)), Constant(x) => x.latex(), Cell(v) => v.latex(), - UnnormalizedLagrangeBasis(i) => format!("unnormalized\\_lagrange\\_basis({})", *i), + UnnormalizedLagrangeBasis(RowOffset { + zk_rows: true, + offset: i, + }) => { + format!("unnormalized\\_lagrange\\_basis(zk\\_rows + {})", *i) + } + UnnormalizedLagrangeBasis(RowOffset { + zk_rows: false, + offset: i, + }) => { + format!("unnormalized\\_lagrange\\_basis({})", *i) + } VanishesOnZeroKnowledgeAndPreviousRows => { "vanishes\\_on\\_zero\\_knowledge\\_and\\_previous\\_row".to_string() } @@ -2518,7 +2563,24 @@ where Double(x) => format!("double({})", x.text(cache)), Constant(x) => x.text(), Cell(v) => v.text(), - UnnormalizedLagrangeBasis(i) => format!("unnormalized_lagrange_basis({})", *i), + UnnormalizedLagrangeBasis(RowOffset { + zk_rows: true, + offset: i, + }) => { + if *i > 0 { + format!("unnormalized_lagrange_basis(zk_rows + {})", *i) + } else if *i == 0 { + format!("unnormalized_lagrange_basis(zk_rows)") + } else { + format!("unnormalized_lagrange_basis(zk_rows - {})", (-*i)) + } + } + UnnormalizedLagrangeBasis(RowOffset { + zk_rows: false, + offset: i, + }) => { + format!("unnormalized_lagrange_basis({})", *i) + } VanishesOnZeroKnowledgeAndPreviousRows => { "vanishes_on_zero_knowledge_and_previous_rows".to_string() } diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index 220149cd3b..9a5fc37eae 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -1,6 +1,6 @@ use crate::{ circuits::{ - expr::{prologue::*, Column, ConstantExpr}, + expr::{prologue::*, Column, ConstantExpr, RowOffset}, gate::{CircuitGate, CurrOrNext}, lookup::lookups::{ JointLookup, JointLookupSpec, JointLookupValue, LocalPosition, LookupInfo, @@ -371,7 +371,6 @@ impl LookupConfiguration { pub fn constraints( configuration: &LookupConfiguration, generate_feature_flags: bool, - zk_rows: usize, ) -> Vec> { // Something important to keep in mind is that the last 2 rows of // all columns will have random values in them to maintain zero-knowledge. @@ -601,14 +600,20 @@ pub fn constraints( let aggreg_equation = E::cell(Column::LookupAggreg, Next) * denominator - E::cell(Column::LookupAggreg, Curr) * numerator; - let final_lookup_row: i32 = -(zk_rows as i32) - 1; + let final_lookup_row = RowOffset { + zk_rows: true, + offset: -1, + }; let mut res = vec![ // the accumulator except for the last zk_rows+1 rows // (contains the zk-rows and the last value of the accumulator) E::VanishesOnZeroKnowledgeAndPreviousRows * aggreg_equation, // the initial value of the accumulator - E::UnnormalizedLagrangeBasis(0) * (E::cell(Column::LookupAggreg, Curr) - E::one()), + E::UnnormalizedLagrangeBasis(RowOffset { + zk_rows: false, + offset: 0, + }) * (E::cell(Column::LookupAggreg, Curr) - E::one()), // Check that the final value of the accumulator is 1 E::UnnormalizedLagrangeBasis(final_lookup_row) * (E::cell(Column::LookupAggreg, Curr) - E::one()), @@ -622,7 +627,10 @@ pub fn constraints( final_lookup_row } else { // Check compatibility of the first elements - 0 + RowOffset { + zk_rows: false, + offset: 0, + } }; let mut expr = E::UnnormalizedLagrangeBasis(first_or_last) * (column(Column::LookupSorted(i)) - column(Column::LookupSorted(i + 1))); diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 3bfcb3081a..b71bfbb64f 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -38,7 +38,6 @@ use ark_ff::{FftField, PrimeField, SquareRootField, Zero}; pub fn constraints_expr( feature_flags: Option<&FeatureFlags>, generic: bool, - zk_rows: usize, ) -> (Expr>, Alphas) { // register powers of alpha so that we don't reuse them across mutually inclusive constraints let mut powers_of_alpha = Alphas::::default(); @@ -167,7 +166,7 @@ pub fn constraints_expr( let lookup_configuration = LookupConfiguration::new(LookupInfo::create(feature_flags.lookup_features)); let constraints = - lookup::constraints::constraints(&lookup_configuration, false, zk_rows); + lookup::constraints::constraints(&lookup_configuration, false); // note: the number of constraints depends on the lookup configuration, // specifically the presence of runtime tables. @@ -193,7 +192,7 @@ pub fn constraints_expr( joint_lookup_used: true, }; let lookup_configuration = LookupConfiguration::new(LookupInfo::create(all_features)); - let constraints = lookup::constraints::constraints(&lookup_configuration, true, zk_rows); + let constraints = lookup::constraints::constraints(&lookup_configuration, true); // note: the number of constraints depends on the lookup configuration, // specifically the presence of runtime tables. @@ -224,7 +223,7 @@ pub fn constraints_expr( // flags. if cfg!(feature = "check_feature_flags") { if let Some(feature_flags) = feature_flags { - let (feature_flagged_expr, _) = constraints_expr(None, generic, zk_rows); + let (feature_flagged_expr, _) = constraints_expr(None, generic); let feature_flagged_expr = feature_flagged_expr.apply_feature_flags(feature_flags); assert_eq!(expr, feature_flagged_expr); } @@ -321,11 +320,10 @@ pub fn linearization_columns( pub fn expr_linearization( feature_flags: Option<&FeatureFlags>, generic: bool, - zk_rows: usize, ) -> (Linearization>>, Alphas) { let evaluated_cols = linearization_columns::(feature_flags); - let (expr, powers_of_alpha) = constraints_expr(feature_flags, generic, zk_rows); + let (expr, powers_of_alpha) = constraints_expr(feature_flags, generic); let linearization = expr .linearize(evaluated_cols) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 42787f9991..b5ec8af5cc 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -806,7 +806,6 @@ where let constraints = lookup::constraints::constraints( &lcs.configuration, false, - index.cs.zk_rows as usize, ); let constraints_len = u32::try_from(constraints.len()) .expect("not expecting a large amount of constraints"); diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index f7e8b5ac6c..7183b1ecc6 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -66,7 +66,7 @@ impl ProverIndex { // pre-compute the linearization let (linearization, powers_of_alpha) = - expr_linearization(Some(&cs.feature_flags), true, cs.zk_rows as usize); + expr_linearization(Some(&cs.feature_flags), true); let evaluated_column_coefficients = cs.evaluated_column_coefficients(); From a85f2cd470ef4655e36acfab2d85ac80088e023b Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 6 Jun 2023 15:29:47 +0100 Subject: [PATCH 072/242] cargo fmt --- kimchi/src/linearization.rs | 3 +-- kimchi/src/prover.rs | 5 +---- kimchi/src/prover_index.rs | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index b71bfbb64f..ec42689059 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -165,8 +165,7 @@ pub fn constraints_expr( if feature_flags.lookup_features.patterns != LookupPatterns::default() { let lookup_configuration = LookupConfiguration::new(LookupInfo::create(feature_flags.lookup_features)); - let constraints = - lookup::constraints::constraints(&lookup_configuration, false); + let constraints = lookup::constraints::constraints(&lookup_configuration, false); // note: the number of constraints depends on the lookup configuration, // specifically the presence of runtime tables. diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index b5ec8af5cc..3978afb376 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -803,10 +803,7 @@ where // lookup { if let Some(lcs) = index.cs.lookup_constraint_system.as_ref() { - let constraints = lookup::constraints::constraints( - &lcs.configuration, - false, - ); + let constraints = lookup::constraints::constraints(&lcs.configuration, false); let constraints_len = u32::try_from(constraints.len()) .expect("not expecting a large amount of constraints"); let lookup_alphas = diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 7183b1ecc6..faa4c8cc3b 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -65,8 +65,7 @@ impl ProverIndex { cs.endo = endo_q; // pre-compute the linearization - let (linearization, powers_of_alpha) = - expr_linearization(Some(&cs.feature_flags), true); + let (linearization, powers_of_alpha) = expr_linearization(Some(&cs.feature_flags), true); let evaluated_column_coefficients = cs.evaluated_column_coefficients(); From b1628308445c74a87d628234b3a4fa4042c126b6 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 24 Jun 2023 17:31:51 +0100 Subject: [PATCH 073/242] Factor out combine_polys --- poly-commitment/src/evaluation_proof.rs | 184 ++++++++++++------------ 1 file changed, 95 insertions(+), 89 deletions(-) diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 7c030787cc..1f170856be 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -71,6 +71,100 @@ impl<'a, F: Field> ScaledChunkedPolynomial { } } +/// Combine the polynomials using `polyscale`, creating a single unified polynomial to open. +pub fn combine_polys>( + plnms: &[( + DensePolynomialOrEvaluations, + Option, + PolyComm, + )], // vector of polynomial with optional degree bound and commitment randomness + polyscale: G::ScalarField, // scaling factor for polynoms + srs_length: usize, +) -> (DensePolynomial, G::ScalarField) { + let mut plnm = ScaledChunkedPolynomial::::default(); + let mut plnm_evals_part = { + // For now just check that all the evaluation polynomials are the same degree so that we + // can do just a single FFT. + // Furthermore we check they have size less than the SRS size so we don't have to do chunking. + // If/when we change this, we can add more complicated code to handle different degrees. + let degree = plnms + .iter() + .fold(None, |acc, (p, _, _)| match p { + DensePolynomialOrEvaluations::DensePolynomial(_) => acc, + DensePolynomialOrEvaluations::Evaluations(_, d) => { + if let Some(n) = acc { + assert_eq!(n, d.size()); + } + Some(d.size()) + } + }) + .unwrap_or(0); + vec![G::ScalarField::zero(); degree] + }; + // let mut plnm_chunks: Vec<(G::ScalarField, OptShiftedPolynomial<_>)> = vec![]; + + let mut omega = G::ScalarField::zero(); + let mut scale = G::ScalarField::one(); + + // iterating over polynomials in the batch + for (p_i, degree_bound, omegas) in plnms { + match p_i { + DensePolynomialOrEvaluations::Evaluations(evals_i, sub_domain) => { + let stride = evals_i.evals.len() / sub_domain.size(); + let evals = &evals_i.evals; + plnm_evals_part + .par_iter_mut() + .enumerate() + .for_each(|(i, x)| { + *x += scale * evals[i * stride]; + }); + assert_eq!(omegas.unshifted.len(), 1); + omega += &(omegas.unshifted[0] * scale); + scale *= &polyscale; + } + + DensePolynomialOrEvaluations::DensePolynomial(p_i) => { + let mut offset = 0; + // iterating over chunks of the polynomial + if let Some(m) = degree_bound { + assert!(p_i.coeffs.len() <= m + 1); + } else { + assert!(omegas.shifted.is_none()); + } + for j in 0..omegas.unshifted.len() { + let segment = + &p_i.coeffs[offset..std::cmp::min(offset + srs_length, p_i.coeffs.len())]; + // always mixing in the unshifted segments + plnm.add_unshifted(scale, segment); + + omega += &(omegas.unshifted[j] * scale); + scale *= &polyscale; + offset += srs_length; + if let Some(m) = degree_bound { + if offset >= *m { + if offset > *m { + // mixing in the shifted segment since degree is bounded + plnm.add_shifted(scale, srs_length - m % srs_length, segment); + } + omega += &(omegas.shifted.unwrap() * scale); + scale *= &polyscale; + } + } + } + } + } + } + + let mut plnm = plnm.to_dense_polynomial(); + if !plnm_evals_part.is_empty() { + let n = plnm_evals_part.len(); + plnm += + &Evaluations::from_vec_and_domain(plnm_evals_part, D::new(n).unwrap()).interpolate(); + } + + (plnm, omega) +} + impl SRS { /// This function opens polynomial commitments in batch /// plnms: batch of polynomials to open commitments for with, optionally, max degrees @@ -112,95 +206,7 @@ impl SRS { let mut g = self.g.clone(); g.extend(vec![G::zero(); padding]); - let (p, blinding_factor) = { - let mut plnm = ScaledChunkedPolynomial::::default(); - let mut plnm_evals_part = { - // For now just check that all the evaluation polynomials are the same degree so that we - // can do just a single FFT. - // Furthermore we check they have size less than the SRS size so we don't have to do chunking. - // If/when we change this, we can add more complicated code to handle different degrees. - let degree = plnms - .iter() - .fold(None, |acc, (p, _, _)| match p { - DensePolynomialOrEvaluations::DensePolynomial(_) => acc, - DensePolynomialOrEvaluations::Evaluations(_, d) => { - if let Some(n) = acc { - assert_eq!(n, d.size()); - } - Some(d.size()) - } - }) - .unwrap_or(0); - assert!(degree <= padded_length); - vec![G::ScalarField::zero(); degree] - }; - // let mut plnm_chunks: Vec<(G::ScalarField, OptShiftedPolynomial<_>)> = vec![]; - - let mut omega = G::ScalarField::zero(); - let mut scale = G::ScalarField::one(); - - // iterating over polynomials in the batch - for (p_i, degree_bound, omegas) in plnms { - match p_i { - DensePolynomialOrEvaluations::Evaluations(evals_i, sub_domain) => { - let stride = evals_i.evals.len() / sub_domain.size(); - let evals = &evals_i.evals; - plnm_evals_part - .par_iter_mut() - .enumerate() - .for_each(|(i, x)| { - *x += scale * evals[i * stride]; - }); - assert_eq!(omegas.unshifted.len(), 1); - omega += &(omegas.unshifted[0] * scale); - scale *= &polyscale; - } - - DensePolynomialOrEvaluations::DensePolynomial(p_i) => { - let mut offset = 0; - // iterating over chunks of the polynomial - if let Some(m) = degree_bound { - assert!(p_i.coeffs.len() <= m + 1); - } else { - assert!(omegas.shifted.is_none()); - } - for j in 0..omegas.unshifted.len() { - let segment = &p_i.coeffs - [offset..std::cmp::min(offset + self.g.len(), p_i.coeffs.len())]; - // always mixing in the unshifted segments - plnm.add_unshifted(scale, segment); - - omega += &(omegas.unshifted[j] * scale); - scale *= &polyscale; - offset += self.g.len(); - if let Some(m) = degree_bound { - if offset >= *m { - if offset > *m { - // mixing in the shifted segment since degree is bounded - plnm.add_shifted( - scale, - self.g.len() - m % self.g.len(), - segment, - ); - } - omega += &(omegas.shifted.unwrap() * scale); - scale *= &polyscale; - } - } - } - } - } - } - - let mut plnm = plnm.to_dense_polynomial(); - if !plnm_evals_part.is_empty() { - let n = plnm_evals_part.len(); - plnm += &Evaluations::from_vec_and_domain(plnm_evals_part, D::new(n).unwrap()) - .interpolate(); - } - - (plnm, omega) - }; + let (p, blinding_factor) = combine_polys::(plnms, polyscale, self.g.len()); let rounds = math::ceil_log2(self.g.len()); From 76b2dcd8205ad5c7eeca614d58f50ea0709c64fc Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 24 Jun 2023 19:23:32 +0100 Subject: [PATCH 074/242] Factor out combine_commitments --- poly-commitment/src/commitment.rs | 78 ++++++++++++++++++------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 001e4b021e..b992716ee8 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -518,6 +518,45 @@ where pub combined_inner_product: G::ScalarField, } +pub fn combine_commitments( + evaluations: &Vec>, + scalars: &mut Vec, + points: &mut Vec, + polyscale: G::ScalarField, + rand_base: G::ScalarField, +) { + let mut xi_i = G::ScalarField::one(); + + for Evaluation { + commitment, + degree_bound, + .. + } in evaluations + .iter() + .filter(|x| !x.commitment.unshifted.is_empty()) + { + // iterating over the polynomial segments + for comm_ch in &commitment.unshifted { + scalars.push(rand_base * xi_i); + points.push(*comm_ch); + + xi_i *= polyscale; + } + + if let Some(_m) = degree_bound { + if let Some(comm_ch) = commitment.shifted { + if !comm_ch.is_zero() { + // polyscale^i sum_j evalscale^j elm_j^{N - m} f(elm_j) + scalars.push(rand_base * xi_i); + points.push(comm_ch); + + xi_i *= polyscale; + } + } + } + } +} + impl SRS { /// Commits a polynomial, potentially splitting the result in multiple commitments. pub fn commit( @@ -798,38 +837,13 @@ impl SRS { // sum_j evalscale^j (sum_i polyscale^i f_i) (elm_j) // == sum_j sum_i evalscale^j polyscale^i f_i(elm_j) // == sum_i polyscale^i sum_j evalscale^j f_i(elm_j) - { - let mut xi_i = G::ScalarField::one(); - - for Evaluation { - commitment, - degree_bound, - .. - } in evaluations - .iter() - .filter(|x| !x.commitment.unshifted.is_empty()) - { - // iterating over the polynomial segments - for comm_ch in &commitment.unshifted { - scalars.push(rand_base_i_c_i * xi_i); - points.push(*comm_ch); - - xi_i *= *polyscale; - } - - if let Some(_m) = degree_bound { - if let Some(comm_ch) = commitment.shifted { - if !comm_ch.is_zero() { - // polyscale^i sum_j evalscale^j elm_j^{N - m} f(elm_j) - scalars.push(rand_base_i_c_i * xi_i); - points.push(comm_ch); - - xi_i *= *polyscale; - } - } - } - } - }; + combine_commitments( + evaluations, + &mut scalars, + &mut points, + *polyscale, + rand_base_i_c_i, + ); scalars.push(rand_base_i_c_i * *combined_inner_product); points.push(u); From 67992cd8473a1725721cc9ba0dd88c67c132389d Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 24 Jun 2023 20:35:13 +0100 Subject: [PATCH 075/242] Extract part of CommitmentCurve trait into EndoCurve --- kimchi/src/curve.rs | 7 +++++-- poly-commitment/src/commitment.rs | 15 +++++++++++---- poly-commitment/src/evaluation_proof.rs | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/kimchi/src/curve.rs b/kimchi/src/curve.rs index 981cc0b5f4..58926d48a1 100644 --- a/kimchi/src/curve.rs +++ b/kimchi/src/curve.rs @@ -8,10 +8,13 @@ use mina_curves::pasta::curves::{ }; use mina_poseidon::poseidon::ArithmeticSpongeParams; use once_cell::sync::Lazy; -use poly_commitment::{commitment::CommitmentCurve, srs::endos}; +use poly_commitment::{ + commitment::{CommitmentCurve, EndoCurve}, + srs::endos, +}; /// Represents additional information that a curve needs in order to be used with Kimchi -pub trait KimchiCurve: CommitmentCurve { +pub trait KimchiCurve: CommitmentCurve + EndoCurve { /// A human readable name. const NAME: &'static str; diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index b992716ee8..a8ac78ab7b 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -357,7 +357,12 @@ pub trait CommitmentCurve: AffineCurve { fn to_coordinates(&self) -> Option<(Self::BaseField, Self::BaseField)>; fn of_coordinates(x: Self::BaseField, y: Self::BaseField) -> Self; +} +/// A trait extending CommitmentCurve for endomorphisms. +/// Unfortunately, we can't specify that `AffineCurve`, +/// so usage of this traits must manually bind `G::BaseField: PrimeField`. +pub trait EndoCurve: CommitmentCurve { /// Combine where x1 = one fn combine_one(g1: &[Self], g2: &[Self], x2: Self::ScalarField) -> Vec { crate::combine::window_combine(g1, g2, Self::ScalarField::one(), x2) @@ -384,10 +389,7 @@ pub trait CommitmentCurve: AffineCurve { } } -impl CommitmentCurve for SWJAffine

-where - P::BaseField: PrimeField, -{ +impl CommitmentCurve for SWJAffine

{ type Params = P; type Map = BWParameters

; @@ -402,7 +404,12 @@ where fn of_coordinates(x: P::BaseField, y: P::BaseField) -> SWJAffine

{ SWJAffine::

::new(x, y, false) } +} +impl EndoCurve for SWJAffine

+where + P::BaseField: PrimeField, +{ fn combine_one(g1: &[Self], g2: &[Self], x2: Self::ScalarField) -> Vec { crate::combine::affine_window_combine_one(g1, g2, x2) } diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 1f170856be..348022606c 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -195,6 +195,7 @@ impl SRS { EFqSponge: Clone + FqSponge, RNG: RngCore + CryptoRng, G::BaseField: PrimeField, + G: EndoCurve, { let (endo_q, endo_r) = endos::(); From f166ee1fd53c76fe6db53274a503c573e4d67d2c Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 24 Jun 2023 20:54:47 +0100 Subject: [PATCH 076/242] Generalize point_of_random_bytes --- poly-commitment/src/srs.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/poly-commitment/src/srs.rs b/poly-commitment/src/srs.rs index f4ae235871..08a7bbcdec 100644 --- a/poly-commitment/src/srs.rs +++ b/poly-commitment/src/srs.rs @@ -3,7 +3,7 @@ use crate::commitment::CommitmentCurve; use crate::PolyComm; use ark_ec::{AffineCurve, ProjectiveCurve}; -use ark_ff::{BigInteger, PrimeField, Zero}; +use ark_ff::{BigInteger, Field, One, PrimeField, Zero}; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as D}; use blake2::{Blake2b512, Digest}; use groupmap::GroupMap; @@ -59,19 +59,30 @@ where fn point_of_random_bytes(map: &G::Map, random_bytes: &[u8]) -> G where - G::BaseField: PrimeField, + G::BaseField: Field, { // packing in bit-representation const N: usize = 31; - let mut bits = [false; 8 * N]; - for i in 0..N { - for j in 0..8 { - bits[8 * i + j] = (random_bytes[i] >> j) & 1 == 1; + let extension_degree = G::BaseField::extension_degree() as usize; + + let mut base_fields = Vec::with_capacity(N * extension_degree); + + for base_count in 0..extension_degree { + let mut bits = [false; 8 * N]; + let offset = base_count * N; + for i in 0..N { + for j in 0..8 { + bits[8 * i + j] = (random_bytes[offset + i] >> j) & 1 == 1; + } } - } - let n = ::BigInt::from_bits_be(&bits); - let t = G::BaseField::from_repr(n).expect("packing code has a bug"); + let n = + <::BasePrimeField as PrimeField>::BigInt::from_bits_be(&bits); + let t = <::BasePrimeField as PrimeField>::from_repr(n) + .expect("packing code has a bug"); + base_fields.push(t) + } + let t = G::BaseField::from_base_prime_field_elems(&base_fields).unwrap(); let (x, y) = map.to_group(t); G::of_coordinates(x, y) } From f13266ddb56e2b95fbb33fbdcb508b71b7069ac8 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 24 Jun 2023 20:56:15 +0100 Subject: [PATCH 077/242] Generalize SRS --- poly-commitment/src/srs.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/poly-commitment/src/srs.rs b/poly-commitment/src/srs.rs index 08a7bbcdec..a4114debdf 100644 --- a/poly-commitment/src/srs.rs +++ b/poly-commitment/src/srs.rs @@ -5,6 +5,7 @@ use crate::PolyComm; use ark_ec::{AffineCurve, ProjectiveCurve}; use ark_ff::{BigInteger, Field, One, PrimeField, Zero}; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as D}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use blake2::{Blake2b512, Digest}; use groupmap::GroupMap; use serde::{Deserialize, Serialize}; @@ -15,7 +16,8 @@ use std::collections::HashMap; #[serde_as] #[derive(Debug, Clone, Default, Serialize, Deserialize, Eq)] -pub struct SRS { +#[serde(bound = "G: CanonicalDeserialize + CanonicalSerialize")] +pub struct SRS { /// The vector of group elements for committing to polynomials in coefficient form #[serde_as(as = "Vec")] pub g: Vec, @@ -31,7 +33,7 @@ pub struct SRS { impl PartialEq for SRS where - G: CommitmentCurve, + G: PartialEq, { fn eq(&self, other: &Self) -> bool { self.g == other.g && self.h == other.h @@ -88,8 +90,6 @@ where } impl SRS -where - G::BaseField: PrimeField, { pub fn max_degree(&self) -> usize { self.g.len() @@ -229,7 +229,12 @@ where .collect(); self.lagrange_bases.insert(n, chunked_commitments); } +} +impl SRS +where + G::BaseField: PrimeField, +{ /// This function creates SRS instance for circuits with number of rows up to `depth`. pub fn create(depth: usize) -> Self { let m = G::Map::setup(); From 4403f2f0570f31a16fcbb90eea3aa13eafd327c4 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 01:00:28 +0100 Subject: [PATCH 078/242] Make KimchiCurve more generalized --- kimchi/src/curve.rs | 95 +++++++++++++++++++++++++++------- kimchi/src/prover.rs | 2 +- kimchi/src/prover_index.rs | 3 +- kimchi/src/snarky/constants.rs | 8 +-- kimchi/src/verifier.rs | 2 +- kimchi/src/verifier_index.rs | 2 +- 6 files changed, 83 insertions(+), 29 deletions(-) diff --git a/kimchi/src/curve.rs b/kimchi/src/curve.rs index 58926d48a1..1b476f61d1 100644 --- a/kimchi/src/curve.rs +++ b/kimchi/src/curve.rs @@ -1,7 +1,7 @@ //! This module contains a useful trait for recursion: [KimchiCurve], //! which defines how a pair of curves interact. -use ark_ec::{short_weierstrass_jacobian::GroupAffine, ModelParameters}; +use ark_ec::{short_weierstrass_jacobian::GroupAffine, AffineCurve, ModelParameters}; use mina_curves::pasta::curves::{ pallas::{LegacyPallasParameters, PallasParameters}, vesta::{LegacyVestaParameters, VestaParameters}, @@ -18,30 +18,35 @@ pub trait KimchiCurve: CommitmentCurve + EndoCurve { /// A human readable name. const NAME: &'static str; - /// The other curve that forms the cycle used for recursion. - type OtherCurve: KimchiCurve< - ScalarField = Self::BaseField, - BaseField = Self::ScalarField, - OtherCurve = Self, - >; - /// Provides the sponge params to be used with this curve. - /// If the params for the base field are needed, they can be obtained from [`KimchiCurve::OtherCurve`]. fn sponge_params() -> &'static ArithmeticSpongeParams; - /// Provides the coefficients for the curve endomorphism called (q,r) in some places. + /// Provides the sponge params to be used with the other curve. + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams; + + /// Provides the coefficients for the curve endomorphism, called (q,r) in some places. fn endos() -> &'static (Self::BaseField, Self::ScalarField); + + /// Provides the coefficient for the curve endomorphism over the other field, called q in some + /// places. + fn other_curve_endo() -> &'static Self::ScalarField; + + /// Accessor for the other curve's prime subgroup generator, as coordinates + // TODO: This leaked from snarky.rs. Stop the bleed. + fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField); } impl KimchiCurve for GroupAffine { const NAME: &'static str = "vesta"; - type OtherCurve = GroupAffine; - fn sponge_params() -> &'static ArithmeticSpongeParams { mina_poseidon::pasta::fp_kimchi::static_params() } + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams { + mina_poseidon::pasta::fq_kimchi::static_params() + } + fn endos() -> &'static (Self::BaseField, Self::ScalarField) { static VESTA_ENDOS: Lazy<( ::BaseField, @@ -49,17 +54,31 @@ impl KimchiCurve for GroupAffine { )> = Lazy::new(endos::>); &VESTA_ENDOS } + + fn other_curve_endo() -> &'static Self::ScalarField { + static PALLAS_ENDOS: Lazy<::BaseField> = + Lazy::new(|| endos::>().0); + &PALLAS_ENDOS + } + + fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { + GroupAffine::::prime_subgroup_generator() + .to_coordinates() + .unwrap() + } } impl KimchiCurve for GroupAffine { const NAME: &'static str = "pallas"; - type OtherCurve = GroupAffine; - fn sponge_params() -> &'static ArithmeticSpongeParams { mina_poseidon::pasta::fq_kimchi::static_params() } + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams { + mina_poseidon::pasta::fp_kimchi::static_params() + } + fn endos() -> &'static (Self::BaseField, Self::ScalarField) { static PALLAS_ENDOS: Lazy<( ::BaseField, @@ -67,6 +86,18 @@ impl KimchiCurve for GroupAffine { )> = Lazy::new(endos::>); &PALLAS_ENDOS } + + fn other_curve_endo() -> &'static Self::ScalarField { + static VESTA_ENDOS: Lazy<::BaseField> = + Lazy::new(|| endos::>().0); + &VESTA_ENDOS + } + + fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { + GroupAffine::::prime_subgroup_generator() + .to_coordinates() + .unwrap() + } } // @@ -76,27 +107,55 @@ impl KimchiCurve for GroupAffine { impl KimchiCurve for GroupAffine { const NAME: &'static str = "legacy_vesta"; - type OtherCurve = GroupAffine; - fn sponge_params() -> &'static ArithmeticSpongeParams { mina_poseidon::pasta::fp_legacy::static_params() } + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams { + mina_poseidon::pasta::fq_legacy::static_params() + } + fn endos() -> &'static (Self::BaseField, Self::ScalarField) { GroupAffine::::endos() } + + fn other_curve_endo() -> &'static Self::ScalarField { + static PALLAS_ENDOS: Lazy<::BaseField> = + Lazy::new(|| endos::>().0); + &PALLAS_ENDOS + } + + fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { + GroupAffine::::prime_subgroup_generator() + .to_coordinates() + .unwrap() + } } impl KimchiCurve for GroupAffine { const NAME: &'static str = "legacy_pallas"; - type OtherCurve = GroupAffine; - fn sponge_params() -> &'static ArithmeticSpongeParams { mina_poseidon::pasta::fq_legacy::static_params() } + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams { + mina_poseidon::pasta::fp_legacy::static_params() + } + fn endos() -> &'static (Self::BaseField, Self::ScalarField) { GroupAffine::::endos() } + + fn other_curve_endo() -> &'static Self::ScalarField { + static VESTA_ENDOS: Lazy<::BaseField> = + Lazy::new(|| endos::>().0); + &VESTA_ENDOS + } + + fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { + GroupAffine::::prime_subgroup_generator() + .to_coordinates() + .unwrap() + } } diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 9f6f8f701e..725d145333 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -215,7 +215,7 @@ where //~ 1. Setup the Fq-Sponge. internal_tracing::checkpoint!(internal_traces; set_up_fq_sponge); - let mut fq_sponge = EFqSponge::new(G::OtherCurve::sponge_params()); + let mut fq_sponge = EFqSponge::new(G::other_curve_sponge_params()); //~ 1. Absorb the digest of the VerifierIndex. let verifier_index_digest = index.verifier_index_digest::(); diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 8140703408..baf56ef9d3 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -141,7 +141,6 @@ pub mod testing { precomputed_srs, }; use ark_ff::{PrimeField, SquareRootField}; - use poly_commitment::srs::endos; /// Create new index for lookups. /// @@ -181,7 +180,7 @@ pub mod testing { srs.add_lagrange_basis(cs.domain.d1); let srs = Arc::new(srs); - let (endo_q, _endo_r) = endos::(); + let &endo_q = G::other_curve_endo(); ProverIndex::::create(cs, endo_q, srs) } diff --git a/kimchi/src/snarky/constants.rs b/kimchi/src/snarky/constants.rs index bf11fce2a8..2324d4ff87 100644 --- a/kimchi/src/snarky/constants.rs +++ b/kimchi/src/snarky/constants.rs @@ -1,9 +1,7 @@ //! Constants used for poseidon. -use ark_ec::AffineCurve; use ark_ff::Field; use mina_poseidon::poseidon::ArithmeticSpongeParams; -use poly_commitment::commitment::CommitmentCurve; use crate::curve::KimchiCurve; @@ -20,10 +18,8 @@ where { pub fn new>() -> Self { let poseidon = Curve::sponge_params().clone(); - let (endo_q, _endo_r) = Curve::OtherCurve::endos(); - let base = Curve::OtherCurve::prime_subgroup_generator() - .to_coordinates() - .unwrap(); + let endo_q = Curve::other_curve_endo(); + let base = Curve::other_curve_prime_subgroup_generator(); Self { poseidon, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index c2796fccca..3abff377ae 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -120,7 +120,7 @@ where let (_, endo_r) = G::endos(); //~ 1. Setup the Fq-Sponge. - let mut fq_sponge = EFqSponge::new(G::OtherCurve::sponge_params()); + let mut fq_sponge = EFqSponge::new(G::other_curve_sponge_params()); //~ 1. Absorb the digest of the VerifierIndex. let verifier_index_digest = index.digest::(); diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 1163885f0d..6a6b01ea64 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -389,7 +389,7 @@ impl VerifierIndex { pub fn digest>( &self, ) -> G::BaseField { - let mut fq_sponge = EFqSponge::new(G::OtherCurve::sponge_params()); + let mut fq_sponge = EFqSponge::new(G::other_curve_sponge_params()); // We fully expand this to make the compiler check that we aren't missing any commitments let VerifierIndex { domain: _, From cbb2c60d8069c8802d6e2419010e938f6ab54c55 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 01:05:29 +0100 Subject: [PATCH 079/242] Deduplicate --- kimchi/src/curve.rs | 54 +++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/kimchi/src/curve.rs b/kimchi/src/curve.rs index 1b476f61d1..71f489b5bd 100644 --- a/kimchi/src/curve.rs +++ b/kimchi/src/curve.rs @@ -36,6 +36,28 @@ pub trait KimchiCurve: CommitmentCurve + EndoCurve { fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField); } +fn vesta_endos() -> &'static ( + ::BaseField, + ::ScalarField, +) { + static VESTA_ENDOS: Lazy<( + ::BaseField, + ::ScalarField, + )> = Lazy::new(endos::>); + &VESTA_ENDOS +} + +fn pallas_endos() -> &'static ( + ::BaseField, + ::ScalarField, +) { + static PALLAS_ENDOS: Lazy<( + ::BaseField, + ::ScalarField, + )> = Lazy::new(endos::>); + &PALLAS_ENDOS +} + impl KimchiCurve for GroupAffine { const NAME: &'static str = "vesta"; @@ -48,17 +70,11 @@ impl KimchiCurve for GroupAffine { } fn endos() -> &'static (Self::BaseField, Self::ScalarField) { - static VESTA_ENDOS: Lazy<( - ::BaseField, - ::ScalarField, - )> = Lazy::new(endos::>); - &VESTA_ENDOS + vesta_endos() } fn other_curve_endo() -> &'static Self::ScalarField { - static PALLAS_ENDOS: Lazy<::BaseField> = - Lazy::new(|| endos::>().0); - &PALLAS_ENDOS + &pallas_endos().0 } fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { @@ -80,17 +96,11 @@ impl KimchiCurve for GroupAffine { } fn endos() -> &'static (Self::BaseField, Self::ScalarField) { - static PALLAS_ENDOS: Lazy<( - ::BaseField, - ::ScalarField, - )> = Lazy::new(endos::>); - &PALLAS_ENDOS + pallas_endos() } fn other_curve_endo() -> &'static Self::ScalarField { - static VESTA_ENDOS: Lazy<::BaseField> = - Lazy::new(|| endos::>().0); - &VESTA_ENDOS + &vesta_endos().0 } fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { @@ -116,13 +126,11 @@ impl KimchiCurve for GroupAffine { } fn endos() -> &'static (Self::BaseField, Self::ScalarField) { - GroupAffine::::endos() + vesta_endos() } fn other_curve_endo() -> &'static Self::ScalarField { - static PALLAS_ENDOS: Lazy<::BaseField> = - Lazy::new(|| endos::>().0); - &PALLAS_ENDOS + &pallas_endos().0 } fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { @@ -144,13 +152,11 @@ impl KimchiCurve for GroupAffine { } fn endos() -> &'static (Self::BaseField, Self::ScalarField) { - GroupAffine::::endos() + pallas_endos() } fn other_curve_endo() -> &'static Self::ScalarField { - static VESTA_ENDOS: Lazy<::BaseField> = - Lazy::new(|| endos::>().0); - &VESTA_ENDOS + &vesta_endos().0 } fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { From 9bf70038c42a939d084c3a24282e34c91e591c98 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 01:27:47 +0100 Subject: [PATCH 080/242] Add an OpenProof trait --- poly-commitment/src/evaluation_proof.rs | 35 +++++++++++++++++++++++++ poly-commitment/src/lib.rs | 35 +++++++++++++++++++++++++ poly-commitment/src/srs.rs | 3 +-- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 348022606c..bac1eba0ef 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -371,6 +371,41 @@ pub struct OpeningProof { pub sg: G, } +impl< + BaseField: PrimeField, + G: AffineCurve + CommitmentCurve + EndoCurve, + > crate::OpenProof for OpeningProof +{ + type G = G; + type SRS = SRS; + + fn open::ScalarField>>( + srs: &Self::SRS, + group_map: &::Map, + plnms: &[( + DensePolynomialOrEvaluations<::ScalarField, D>, + Option, + PolyComm<::ScalarField>, + )], // vector of polynomial with optional degree bound and commitment randomness + elm: &[::ScalarField], // vector of evaluation points + polyscale: ::ScalarField, // scaling factor for polynoms + evalscale: ::ScalarField, // scaling factor for evaluation point powers + sponge: EFqSponge, // sponge + rng: &mut RNG, + ) -> Self + where + EFqSponge: Clone + + FqSponge< + ::BaseField, + Self::G, + ::ScalarField, + >, + RNG: RngCore + CryptoRng, + { + srs.open(group_map, plnms, elm, polyscale, evalscale, sponge, rng) + } +} + pub struct Challenges { pub chal: Vec, pub chal_inv: Vec, diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 3b6cd8b3e6..09ba3e4bcf 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -9,3 +9,38 @@ pub mod srs; mod tests; pub use commitment::PolyComm; + +use crate::commitment::CommitmentCurve; +use crate::evaluation_proof::DensePolynomialOrEvaluations; +use ark_ec::AffineCurve; +use ark_poly::EvaluationDomain; +use mina_poseidon::FqSponge; +use rand_core::{CryptoRng, RngCore}; + +pub trait OpenProof { + type G: CommitmentCurve; + type SRS; + + fn open::ScalarField>>( + srs: &Self::SRS, + group_map: &::Map, + plnms: &[( + DensePolynomialOrEvaluations<::ScalarField, D>, + Option, + PolyComm<::ScalarField>, + )], // vector of polynomial with optional degree bound and commitment randomness + elm: &[::ScalarField], // vector of evaluation points + polyscale: ::ScalarField, // scaling factor for polynoms + evalscale: ::ScalarField, // scaling factor for evaluation point powers + sponge: EFqSponge, // sponge + rng: &mut RNG, + ) -> Self + where + EFqSponge: Clone + + FqSponge< + ::BaseField, + Self::G, + ::ScalarField, + >, + RNG: RngCore + CryptoRng; +} diff --git a/poly-commitment/src/srs.rs b/poly-commitment/src/srs.rs index a4114debdf..356e9dc9fe 100644 --- a/poly-commitment/src/srs.rs +++ b/poly-commitment/src/srs.rs @@ -89,8 +89,7 @@ where G::of_coordinates(x, y) } -impl SRS -{ +impl SRS { pub fn max_degree(&self) -> usize { self.g.len() } From 97881ac1a8b997d49453f9878e5851dc2121792a Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 01:45:26 +0100 Subject: [PATCH 081/242] Abstract ProverProof over OpeningProof --- book/src/specs/kimchi.md | 8 ++++++-- kimchi/src/bench.rs | 6 +++--- kimchi/src/oracles.rs | 4 ++-- kimchi/src/proof.rs | 13 +++++++------ kimchi/src/prover.rs | 21 ++++++++++++++------- kimchi/src/tests/serde.rs | 5 +++-- kimchi/src/verifier.rs | 23 +++++++++++++---------- 7 files changed, 48 insertions(+), 32 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 1852146616..aeb09bd189 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2003,12 +2003,16 @@ pub struct ProverCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverProof { +pub struct ProverProof { /// All the polynomial commitments required in the proof pub commitments: ProverCommitments, /// batched commitment opening proof - pub proof: OpeningProof, + #[serde(bound( + serialize = "OpeningProof: Serialize", + deserialize = "OpeningProof: Deserialize<'de>" + ))] + pub proof: OpeningProof, /// Two evaluations over a number of committed polynomials pub evals: ProofEvaluations>>, diff --git a/kimchi/src/bench.rs b/kimchi/src/bench.rs index 1af338d9ed..6fa40b77b2 100644 --- a/kimchi/src/bench.rs +++ b/kimchi/src/bench.rs @@ -7,7 +7,7 @@ use mina_poseidon::{ sponge::{DefaultFqSponge, DefaultFrSponge}, }; use o1_utils::math; -use poly_commitment::commitment::CommitmentCurve; +use poly_commitment::{commitment::CommitmentCurve, evaluation_proof::OpeningProof}; use crate::{ circuits::{ @@ -77,7 +77,7 @@ impl BenchmarkCtx { } /// Produces a proof - pub fn create_proof(&self) -> (ProverProof, Vec) { + pub fn create_proof(&self) -> (ProverProof>, Vec) { // create witness let witness: [Vec; COLUMNS] = array::from_fn(|_| vec![1u32.into(); self.num_gates]); @@ -96,7 +96,7 @@ impl BenchmarkCtx { ) } - pub fn batch_verification(&self, batch: &[(ProverProof, Vec)]) { + pub fn batch_verification(&self, batch: &[(ProverProof>, Vec)]) { // verify the proof let batch: Vec<_> = batch .iter() diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index aaa91e186d..5f95d63b17 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -38,7 +38,7 @@ where #[cfg(feature = "ocaml_types")] pub mod caml { use ark_ff::PrimeField; - use poly_commitment::commitment::shift_scalar; + use poly_commitment::{commitment::shift_scalar, evaluation_proof::OpeningProof}; use crate::{ circuits::scalars::caml::CamlRandomOracles, curve::KimchiCurve, error::VerifyError, @@ -58,7 +58,7 @@ pub mod caml { pub fn create_caml_oracles( lgr_comm: Vec>, index: VerifierIndex, - proof: ProverProof, + proof: ProverProof>, public_input: &[G::ScalarField], ) -> Result, VerifyError> where diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index d335a5bfed..c534808f33 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -9,10 +9,7 @@ use ark_ec::AffineCurve; use ark_ff::{FftField, One, Zero}; use ark_poly::univariate::DensePolynomial; use o1_utils::ExtendedDensePolynomial; -use poly_commitment::{ - commitment::{b_poly, b_poly_coefficients, PolyComm}, - evaluation_proof::OpeningProof, -}; +use poly_commitment::commitment::{b_poly, b_poly_coefficients, PolyComm}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use std::array; @@ -110,12 +107,16 @@ pub struct ProverCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverProof { +pub struct ProverProof { /// All the polynomial commitments required in the proof pub commitments: ProverCommitments, /// batched commitment opening proof - pub proof: OpeningProof, + #[serde(bound( + serialize = "OpeningProof: Serialize", + deserialize = "OpeningProof: Deserialize<'de>" + ))] + pub proof: OpeningProof, /// Two evaluations over a number of committed polynomials pub evals: ProofEvaluations>>, diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 725d145333..08ce22193a 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -45,7 +45,7 @@ use poly_commitment::{ commitment::{ absorb_commitment, b_poly_coefficients, BlindedCommitment, CommitmentCurve, PolyComm, }, - evaluation_proof::DensePolynomialOrEvaluations, + evaluation_proof::{DensePolynomialOrEvaluations, OpeningProof}, }; use rayon::prelude::*; use std::array; @@ -114,7 +114,7 @@ where runtime_second_col_d8: Option>>, } -impl ProverProof +impl ProverProof> where G::BaseField: PrimeField, { @@ -1294,7 +1294,10 @@ pub mod caml { use super::*; use crate::proof::caml::{CamlProofEvaluations, CamlRecursionChallenge}; use ark_ec::AffineCurve; - use poly_commitment::commitment::caml::{CamlOpeningProof, CamlPolyComm}; + use poly_commitment::{ + commitment::caml::{CamlOpeningProof, CamlPolyComm}, + evaluation_proof::OpeningProof, + }; #[cfg(feature = "internal_tracing")] pub use internal_traces::caml::CamlTraces as CamlProverTraces; @@ -1499,13 +1502,14 @@ pub mod caml { // ProverProof <-> CamlProverProof // - impl From<(ProverProof, Vec)> for CamlProverProof + impl From<(ProverProof>, Vec)> + for CamlProverProof where G: AffineCurve, CamlG: From, CamlF: From, { - fn from(pp: (ProverProof, Vec)) -> Self { + fn from(pp: (ProverProof>, Vec)) -> Self { Self { commitments: pp.0.commitments.into(), proof: pp.0.proof.into(), @@ -1517,12 +1521,15 @@ pub mod caml { } } - impl From> for (ProverProof, Vec) + impl From> + for (ProverProof>, Vec) where G: AffineCurve + From, G::ScalarField: From, { - fn from(caml_pp: CamlProverProof) -> (ProverProof, Vec) { + fn from( + caml_pp: CamlProverProof, + ) -> (ProverProof>, Vec) { let proof = ProverProof { commitments: caml_pp.commitments.into(), proof: caml_pp.proof.into(), diff --git a/kimchi/src/tests/serde.rs b/kimchi/src/tests/serde.rs index 4de9369100..cce58e8055 100644 --- a/kimchi/src/tests/serde.rs +++ b/kimchi/src/tests/serde.rs @@ -17,7 +17,7 @@ use mina_poseidon::{ constants::PlonkSpongeConstantsKimchi, sponge::{DefaultFqSponge, DefaultFrSponge}, }; -use poly_commitment::{commitment::CommitmentCurve, srs::SRS}; +use poly_commitment::{commitment::CommitmentCurve, evaluation_proof::OpeningProof, srs::SRS}; use std::array; use std::time::Instant; @@ -41,7 +41,8 @@ mod tests { println!("proof size: {} bytes", ser_pf.len()); // deserialize the proof - let de_pf: ProverProof = rmp_serde::from_slice(&ser_pf).unwrap(); + let de_pf: ProverProof> = + rmp_serde::from_slice(&ser_pf).unwrap(); // verify the deserialized proof (must accept the proof) ctx.batch_verification(&vec![(de_pf, public_input)]); diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 3abff377ae..e5dc591857 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -24,26 +24,29 @@ use ark_ec::AffineCurve; use ark_ff::{Field, One, PrimeField, Zero}; use ark_poly::{EvaluationDomain, Polynomial}; use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; -use poly_commitment::commitment::{ - absorb_commitment, combined_inner_product, BatchEvaluationProof, Evaluation, PolyComm, +use poly_commitment::{ + commitment::{ + absorb_commitment, combined_inner_product, BatchEvaluationProof, Evaluation, PolyComm, + }, + evaluation_proof::OpeningProof, }; use rand::thread_rng; /// The result of a proof verification. pub type Result = std::result::Result; -pub struct Context<'a, G: KimchiCurve> { +pub struct Context<'a, G: KimchiCurve, OpeningProof> { /// The [VerifierIndex] associated to the proof pub verifier_index: &'a VerifierIndex, /// The proof to verify - pub proof: &'a ProverProof, + pub proof: &'a ProverProof, /// The public input used in the creation of the proof pub public_input: &'a [G::ScalarField], } -impl<'a, G: KimchiCurve> Context<'a, G> { +impl<'a, G: KimchiCurve, OpeningProof> Context<'a, G, OpeningProof> { pub fn get_column(&self, col: Column) -> Option<&'a PolyComm> { use Column::*; match col { @@ -89,7 +92,7 @@ impl<'a, G: KimchiCurve> Context<'a, G> { } } -impl ProverProof +impl ProverProof> where G::BaseField: PrimeField, { @@ -499,7 +502,7 @@ where /// Enforce the length of evaluations inside [`Proof`]. /// Atm, the length of evaluations(both `zeta` and `zeta_omega`) SHOULD be 1. /// The length value is prone to future change. -fn check_proof_evals_len(proof: &ProverProof) -> Result<()> +fn check_proof_evals_len(proof: &ProverProof) -> Result<()> where G: KimchiCurve, G::BaseField: PrimeField, @@ -556,7 +559,7 @@ where fn to_batch<'a, G, EFqSponge, EFrSponge>( verifier_index: &VerifierIndex, - proof: &'a ProverProof, + proof: &'a ProverProof>, public_input: &'a [::ScalarField], ) -> Result> where @@ -861,7 +864,7 @@ where pub fn verify( group_map: &G::Map, verifier_index: &VerifierIndex, - proof: &ProverProof, + proof: &ProverProof>, public_input: &[G::ScalarField], ) -> Result<()> where @@ -887,7 +890,7 @@ where /// Will give error if `srs` of `proof` is invalid or `verify` process fails. pub fn batch_verify( group_map: &G::Map, - proofs: &[Context], + proofs: &[Context>], ) -> Result<()> where G: KimchiCurve, From c0fad3079b7de19584a089940efb6a3e952db840 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 01:50:15 +0100 Subject: [PATCH 082/242] Abstract ProverProof::create_recursive over OpenProof --- kimchi/src/prover.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 08ce22193a..2ca1e01734 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -45,7 +45,9 @@ use poly_commitment::{ commitment::{ absorb_commitment, b_poly_coefficients, BlindedCommitment, CommitmentCurve, PolyComm, }, - evaluation_proof::{DensePolynomialOrEvaluations, OpeningProof}, + evaluation_proof::DensePolynomialOrEvaluations, + srs::SRS, + OpenProof, }; use rayon::prelude::*; use std::array; @@ -114,7 +116,7 @@ where runtime_second_col_d8: Option>>, } -impl ProverProof> +impl>> ProverProof where G::BaseField: PrimeField, { @@ -1231,7 +1233,8 @@ where //~ 1. Create an aggregated evaluation proof for all of these polynomials at $\zeta$ and $\zeta\omega$ using $u$ and $v$. internal_tracing::checkpoint!(internal_traces; create_aggregated_evaluation_proof); - let proof = index.srs.open( + let proof = OpenProof::open( + &*index.srs, group_map, &polynomials, &[zeta, zeta_omega], From 3e863d55abbb976bc581e331c63ec4f071368ba1 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 03:06:38 +0100 Subject: [PATCH 083/242] Add a trait for SRS, use it to generalize most OpeningProofs --- book/src/specs/kimchi.md | 12 ++- kimchi/src/bench.rs | 4 +- kimchi/src/circuits/constraints.rs | 10 +- kimchi/src/circuits/expr.rs | 7 +- kimchi/src/circuits/gate.rs | 5 +- kimchi/src/circuits/polynomials/generic.rs | 5 +- .../src/circuits/polynomials/permutation.rs | 9 +- kimchi/src/oracles.rs | 2 +- kimchi/src/prover.rs | 19 ++-- kimchi/src/prover_index.rs | 35 ++++--- kimchi/src/tests/foreign_field_add.rs | 16 +++- kimchi/src/tests/framework.rs | 17 ++-- kimchi/src/tests/not.rs | 3 +- kimchi/src/tests/range_check.rs | 8 +- kimchi/src/tests/recursion.rs | 2 +- kimchi/src/tests/rot.rs | 7 +- kimchi/src/tests/serde.rs | 2 +- kimchi/src/tests/xor.rs | 7 +- kimchi/src/verifier.rs | 13 +-- kimchi/src/verifier_index.rs | 49 +++++----- poly-commitment/Cargo.toml | 1 + poly-commitment/src/commitment.rs | 60 ++++++++++-- poly-commitment/src/evaluation_proof.rs | 27 +++--- poly-commitment/src/lib.rs | 92 +++++++++++++++---- poly-commitment/src/srs.rs | 28 ++++++ poly-commitment/src/tests/batch_15_wires.rs | 1 + poly-commitment/src/tests/commitment.rs | 1 + tools/kimchi-visu/src/lib.rs | 9 +- 28 files changed, 319 insertions(+), 132 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index aeb09bd189..491e5a93cb 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1681,7 +1681,7 @@ Both the prover and the verifier index, besides the common parts described above These pre-computations are optimizations, in the context of normal proofs, but they are necessary for recursion. ```rs -pub struct ProverIndex { +pub struct ProverIndex> { /// constraints system polynomials #[serde(bound = "ConstraintSystem: Serialize + DeserializeOwned")] pub cs: ConstraintSystem, @@ -1696,7 +1696,8 @@ pub struct ProverIndex { /// polynomial commitment keys #[serde(skip)] - pub srs: Arc>, + #[serde(bound(deserialize = "OpeningProof::SRS: Default"))] + pub srs: Arc, /// maximal size of polynomial section pub max_poly_size: usize, @@ -1706,7 +1707,7 @@ pub struct ProverIndex { /// The verifier index corresponding to this prover index #[serde(skip)] - pub verifier_index: Option>, + pub verifier_index: Option>, /// The verifier index digest corresponding to this prover index #[serde_as(as = "Option")] @@ -1744,7 +1745,7 @@ pub struct LookupVerifierIndex { #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VerifierIndex { +pub struct VerifierIndex> { /// evaluation domain #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub domain: D, @@ -1752,7 +1753,8 @@ pub struct VerifierIndex { pub max_poly_size: usize, /// polynomial commitment keys #[serde(skip)] - pub srs: OnceCell>>, + #[serde(bound(deserialize = "OpeningProof::SRS: Default"))] + pub srs: Arc, /// number of public inputs pub public: usize, /// number of previous evaluation challenges, for recursive proving diff --git a/kimchi/src/bench.rs b/kimchi/src/bench.rs index 6fa40b77b2..e6284331b7 100644 --- a/kimchi/src/bench.rs +++ b/kimchi/src/bench.rs @@ -28,8 +28,8 @@ type ScalarSponge = DefaultFrSponge; pub struct BenchmarkCtx { num_gates: usize, group_map: BWParameters, - index: ProverIndex, - verifier_index: VerifierIndex, + index: ProverIndex>, + verifier_index: VerifierIndex>, } impl BenchmarkCtx { diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 238e725bc1..133e8c8caf 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -21,6 +21,7 @@ use ark_poly::{ }; use o1_utils::ExtendedEvaluations; use once_cell::sync::OnceCell; +use poly_commitment::OpenProof; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_with::serde_as; use std::array; @@ -263,7 +264,12 @@ impl ConstraintSystem { } } -impl> ProverIndex { +impl< + F: PrimeField + SquareRootField, + G: KimchiCurve, + OpeningProof: OpenProof, + > ProverIndex +{ /// This function verifies the consistency of the wire /// assignments (witness) against the constraints /// witness: wire assignment witness @@ -307,7 +313,7 @@ impl> ProverInd } // check the gate's satisfiability - gate.verify::(row, &witness, self, public) + gate.verify(row, &witness, self, public) .map_err(|err| GateError::Custom { row, err })?; } diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 9f084f6903..3aa337b707 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -2832,7 +2832,10 @@ pub mod test { }; use ark_ff::UniformRand; use mina_curves::pasta::{Fp, Pallas, Vesta}; - use poly_commitment::srs::{endos, SRS}; + use poly_commitment::{ + evaluation_proof::OpeningProof, + srs::{endos, SRS}, + }; use rand::{prelude::StdRng, SeedableRng}; use std::array; use std::sync::Arc; @@ -2882,7 +2885,7 @@ pub mod test { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::::create(constraint_system, endo_q, srs) + ProverIndex::>::create(constraint_system, endo_q, srs) }; let witness_cols: [_; COLUMNS] = array::from_fn(|_| DensePolynomial::zero()); diff --git a/kimchi/src/circuits/gate.rs b/kimchi/src/circuits/gate.rs index 58a8309407..a1c0449393 100644 --- a/kimchi/src/circuits/gate.rs +++ b/kimchi/src/circuits/gate.rs @@ -16,6 +16,7 @@ use crate::{ use ark_ff::{bytes::ToBytes, PrimeField, SquareRootField}; use num_traits::cast::ToPrimitive; use o1_utils::hasher::CryptoDigest; +use poly_commitment::OpenProof; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use std::io::{Result as IoResult, Write}; @@ -193,11 +194,11 @@ impl CircuitGate { /// # Errors /// /// Will give error if verify process returns error. - pub fn verify>( + pub fn verify, OpeningProof: OpenProof>( &self, row: usize, witness: &[Vec; COLUMNS], - index: &ProverIndex, + index: &ProverIndex, public: &[F], ) -> Result<(), String> { use GateType::*; diff --git a/kimchi/src/circuits/polynomials/generic.rs b/kimchi/src/circuits/polynomials/generic.rs index e535db8dab..a04b01e1f7 100644 --- a/kimchi/src/circuits/polynomials/generic.rs +++ b/kimchi/src/circuits/polynomials/generic.rs @@ -43,6 +43,7 @@ use crate::circuits::{ use crate::{curve::KimchiCurve, prover_index::ProverIndex}; use ark_ff::{FftField, PrimeField, Zero}; use ark_poly::univariate::DensePolynomial; +use poly_commitment::OpenProof; use std::array; use std::marker::PhantomData; @@ -278,7 +279,9 @@ pub mod testing { } } - impl> ProverIndex { + impl, OpeningProof: OpenProof> + ProverIndex + { /// Function to verify the generic polynomials with a witness. pub fn verify_generic( &self, diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 8ca2057b3d..5f826721c8 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -57,6 +57,7 @@ use ark_poly::{ use ark_poly::{Polynomial, UVPolynomial}; use blake2::{Blake2b512, Digest}; use o1_utils::{ExtendedDensePolynomial, ExtendedEvaluations}; +use poly_commitment::OpenProof; use rand::{CryptoRng, RngCore}; use rayon::prelude::*; use std::array; @@ -191,7 +192,9 @@ where } } -impl> ProverIndex { +impl, OpeningProof: OpenProof> + ProverIndex +{ /// permutation quotient poly contribution computation /// /// # Errors @@ -390,7 +393,9 @@ impl ConstraintSystem { } } -impl> ProverIndex { +impl, OpeningProof: OpenProof> + ProverIndex +{ /// permutation aggregation polynomial computation /// /// # Errors diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index 5f95d63b17..fd02398f7b 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -57,7 +57,7 @@ pub mod caml { pub fn create_caml_oracles( lgr_comm: Vec>, - index: VerifierIndex, + index: VerifierIndex>, proof: ProverProof>, public_input: &[G::ScalarField], ) -> Result, VerifyError> diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 2ca1e01734..d01df7c187 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -31,6 +31,7 @@ use crate::{ ProverCommitments, ProverProof, RecursionChallenge, }, prover_index::ProverIndex, + verifier_index::VerifierIndex, }; use ark_ec::ProjectiveCurve; use ark_ff::{FftField, Field, One, PrimeField, UniformRand, Zero}; @@ -47,7 +48,7 @@ use poly_commitment::{ }, evaluation_proof::DensePolynomialOrEvaluations, srs::SRS, - OpenProof, + OpenProof, SRS as _, }; use rayon::prelude::*; use std::array; @@ -116,7 +117,7 @@ where runtime_second_col_d8: Option>>, } -impl>> ProverProof +impl>> ProverProof where G::BaseField: PrimeField, { @@ -132,8 +133,11 @@ where groupmap: &G::Map, witness: [Vec; COLUMNS], runtime_tables: &[RuntimeTable], - index: &ProverIndex, - ) -> Result { + index: &ProverIndex, + ) -> Result + where + VerifierIndex: Clone, + { Self::create_recursive::( groupmap, witness, @@ -160,10 +164,13 @@ where group_map: &G::Map, mut witness: [Vec; COLUMNS], runtime_tables: &[RuntimeTable], - index: &ProverIndex, + index: &ProverIndex, prev_challenges: Vec>, blinders: Option<[Option>; COLUMNS]>, - ) -> Result { + ) -> Result + where + VerifierIndex: Clone, + { internal_tracing::checkpoint!(internal_traces; create_recursive); // make sure that the SRS is not smaller than the domain size diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index baf56ef9d3..469000e8ed 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -10,9 +10,10 @@ use crate::{ linearization::expr_linearization, verifier_index::VerifierIndex, }; +use ark_ff::PrimeField; use ark_poly::EvaluationDomain; use mina_poseidon::FqSponge; -use poly_commitment::srs::SRS; +use poly_commitment::{evaluation_proof::OpeningProof, srs::SRS, OpenProof, SRS as _}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_with::serde_as; use std::sync::Arc; @@ -21,7 +22,7 @@ use std::sync::Arc; #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] //~spec:startcode -pub struct ProverIndex { +pub struct ProverIndex> { /// constraints system polynomials #[serde(bound = "ConstraintSystem: Serialize + DeserializeOwned")] pub cs: ConstraintSystem, @@ -36,7 +37,8 @@ pub struct ProverIndex { /// polynomial commitment keys #[serde(skip)] - pub srs: Arc>, + #[serde(bound(deserialize = "OpeningProof::SRS: Default"))] + pub srs: Arc, /// maximal size of polynomial section pub max_poly_size: usize, @@ -46,7 +48,7 @@ pub struct ProverIndex { /// The verifier index corresponding to this prover index #[serde(skip)] - pub verifier_index: Option>, + pub verifier_index: Option>, /// The verifier index digest corresponding to this prover index #[serde_as(as = "Option")] @@ -54,7 +56,10 @@ pub struct ProverIndex { } //~spec:endcode -impl ProverIndex { +impl> ProverIndex +where + G::BaseField: PrimeField, +{ /// this function compiles the index from constraints /// /// # Panics @@ -63,9 +68,9 @@ impl ProverIndex { pub fn create( mut cs: ConstraintSystem, endo_q: G::ScalarField, - srs: Arc>, + srs: Arc, ) -> Self { - let max_poly_size = srs.g.len(); + let max_poly_size = srs.max_poly_size(); if cs.public > 0 { assert!( max_poly_size >= cs.domain.d1.size(), @@ -99,7 +104,10 @@ impl ProverIndex { EFqSponge: Clone + FqSponge, >( &mut self, - ) -> G::BaseField { + ) -> G::BaseField + where + VerifierIndex: Clone, + { if let Some(verifier_index_digest) = self.verifier_index_digest { return verifier_index_digest; } @@ -116,7 +124,10 @@ impl ProverIndex { /// Retrieve or compute the digest for the corresponding verifier index. pub fn verifier_index_digest>( &self, - ) -> G::BaseField { + ) -> G::BaseField + where + VerifierIndex: Clone, + { if let Some(verifier_index_digest) = self.verifier_index_digest { return verifier_index_digest; } @@ -154,7 +165,7 @@ pub mod testing { lookup_tables: Vec>, runtime_tables: Option>>, disable_gates_checks: bool, - ) -> ProverIndex + ) -> ProverIndex> where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, @@ -181,13 +192,13 @@ pub mod testing { let srs = Arc::new(srs); let &endo_q = G::other_curve_endo(); - ProverIndex::::create(cs, endo_q, srs) + ProverIndex::create(cs, endo_q, srs) } pub fn new_index_for_test( gates: Vec>, public: usize, - ) -> ProverIndex + ) -> ProverIndex> where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, diff --git a/kimchi/src/tests/foreign_field_add.rs b/kimchi/src/tests/foreign_field_add.rs index 6589097a2d..9f3b9cde10 100644 --- a/kimchi/src/tests/foreign_field_add.rs +++ b/kimchi/src/tests/foreign_field_add.rs @@ -31,7 +31,10 @@ use o1_utils::{ foreign_field::{BigUintForeignFieldHelpers, ForeignElement, HI, LO, MI, TWO_TO_LIMB}, FieldHelpers, Two, }; -use poly_commitment::srs::{endos, SRS}; +use poly_commitment::{ + evaluation_proof::OpeningProof, + srs::{endos, SRS}, +}; use rand::{rngs::StdRng, Rng, SeedableRng}; use std::array; use std::sync::Arc; @@ -321,7 +324,7 @@ fn create_test_constraint_system_ffadd( opcodes: &[FFOps], foreign_field_modulus: BigUint, full: bool, -) -> ProverIndex { +) -> ProverIndex> { let (_next_row, gates) = if full { full_circuit(opcodes, &foreign_field_modulus) } else { @@ -334,7 +337,7 @@ fn create_test_constraint_system_ffadd( let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) } // helper to reduce lines of code in repetitive test structure @@ -343,7 +346,10 @@ fn test_ffadd( inputs: Vec, opcodes: &[FFOps], full: bool, -) -> ([Vec; COLUMNS], ProverIndex) { +) -> ( + [Vec; COLUMNS], + ProverIndex>, +) { let index = create_test_constraint_system_ffadd(opcodes, foreign_field_modulus.clone(), full); let witness = if full { @@ -1514,7 +1520,7 @@ fn test_ffadd_finalization() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; for row in 0..witness[0].len() { diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index f637ddc8d3..be1bf03609 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -20,13 +20,16 @@ use ark_ff::PrimeField; use groupmap::GroupMap; use mina_poseidon::sponge::FqSponge; use num_bigint::BigUint; -use poly_commitment::commitment::CommitmentCurve; +use poly_commitment::{commitment::CommitmentCurve, evaluation_proof::OpeningProof}; use std::{fmt::Write, mem, time::Instant}; // aliases #[derive(Default, Clone)] -pub(crate) struct TestFramework { +pub(crate) struct TestFramework +where + G::BaseField: PrimeField, +{ gates: Option>>, witness: Option<[Vec; COLUMNS]>, public_inputs: Vec, @@ -37,12 +40,14 @@ pub(crate) struct TestFramework { num_prev_challenges: usize, disable_gates_checks: bool, - prover_index: Option>, - verifier_index: Option>, + prover_index: Option>>, + verifier_index: Option>>, } #[derive(Clone)] -pub(crate) struct TestRunner(TestFramework); +pub(crate) struct TestRunner(TestFramework) +where + G::BaseField: PrimeField; impl TestFramework where @@ -148,7 +153,7 @@ where self } - pub(crate) fn prover_index(&self) -> &ProverIndex { + pub(crate) fn prover_index(&self) -> &ProverIndex> { self.0.prover_index.as_ref().unwrap() } diff --git a/kimchi/src/tests/not.rs b/kimchi/src/tests/not.rs index 92e3d15918..d1342c72bb 100644 --- a/kimchi/src/tests/not.rs +++ b/kimchi/src/tests/not.rs @@ -25,6 +25,7 @@ use mina_poseidon::{ }; use num_bigint::BigUint; use o1_utils::{BigUintHelpers, BitwiseOps, FieldHelpers, RandomField}; +use poly_commitment::evaluation_proof::OpeningProof; use rand::{rngs::StdRng, SeedableRng}; type PallasField = ::BaseField; @@ -415,7 +416,7 @@ fn test_bad_not_gnrc() { let index = new_index_for_test_with_lookups(cs.gates, 1, 0, vec![xor::lookup_table()], None, false); assert_eq!( - index.cs.gates[1].verify::(1, &witness, &index, &[]), + index.cs.gates[1].verify::>(1, &witness, &index, &[]), Err(("generic: incorrect gate").to_string()) ); } diff --git a/kimchi/src/tests/range_check.rs b/kimchi/src/tests/range_check.rs index c9188de577..685697c129 100644 --- a/kimchi/src/tests/range_check.rs +++ b/kimchi/src/tests/range_check.rs @@ -38,6 +38,7 @@ use mina_poseidon::{ }; use poly_commitment::{ commitment::CommitmentCurve, + evaluation_proof::OpeningProof, srs::{endos, SRS}, }; @@ -53,7 +54,10 @@ const RNG_SEED: [u8; 32] = [ 0, 33, 210, 215, 172, 130, 24, 164, 12, ]; -fn create_test_prover_index(public_size: usize, compact: bool) -> ProverIndex { +fn create_test_prover_index( + public_size: usize, + compact: bool, +) -> ProverIndex> { let (_next_row, gates) = if compact { CircuitGate::::create_compact_multi_range_check(0) } else { @@ -1091,7 +1095,7 @@ fn verify_64_bit_range_check() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; // Witness layout (positive test case) diff --git a/kimchi/src/tests/recursion.rs b/kimchi/src/tests/recursion.rs index 7936bb738e..07f6df1b43 100644 --- a/kimchi/src/tests/recursion.rs +++ b/kimchi/src/tests/recursion.rs @@ -11,7 +11,7 @@ use mina_poseidon::{ sponge::{DefaultFqSponge, DefaultFrSponge}, }; use o1_utils::math; -use poly_commitment::commitment::b_poly_coefficients; +use poly_commitment::{commitment::b_poly_coefficients, SRS as _}; use rand::prelude::*; use std::array; diff --git a/kimchi/src/tests/rot.rs b/kimchi/src/tests/rot.rs index 3ba4dfdd66..9ed16d5b4b 100644 --- a/kimchi/src/tests/rot.rs +++ b/kimchi/src/tests/rot.rs @@ -26,7 +26,10 @@ use mina_poseidon::{ FqSponge, }; use o1_utils::Two; -use poly_commitment::srs::{endos, SRS}; +use poly_commitment::{ + evaluation_proof::OpeningProof, + srs::{endos, SRS}, +}; use rand::{rngs::StdRng, Rng, SeedableRng}; type PallasField = ::BaseField; @@ -338,7 +341,7 @@ fn test_rot_finalization() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; for row in 0..witness[0].len() { diff --git a/kimchi/src/tests/serde.rs b/kimchi/src/tests/serde.rs index cce58e8055..4ce97b2f8a 100644 --- a/kimchi/src/tests/serde.rs +++ b/kimchi/src/tests/serde.rs @@ -73,7 +73,7 @@ mod tests { .unwrap(); // deserialize the verifier index - let mut verifier_index_deserialize: VerifierIndex> = + let mut verifier_index_deserialize: VerifierIndex, _> = serde_json::from_str(&verifier_index_serialize).unwrap(); // add srs with lagrange bases diff --git a/kimchi/src/tests/xor.rs b/kimchi/src/tests/xor.rs index a28be35091..6841f154b0 100644 --- a/kimchi/src/tests/xor.rs +++ b/kimchi/src/tests/xor.rs @@ -26,7 +26,10 @@ use mina_poseidon::{ }; use num_bigint::BigUint; use o1_utils::{BigUintHelpers, BitwiseOps, FieldHelpers, RandomField}; -use poly_commitment::srs::{endos, SRS}; +use poly_commitment::{ + evaluation_proof::OpeningProof, + srs::{endos, SRS}, +}; use rand::{rngs::StdRng, SeedableRng}; use super::framework::TestFramework; @@ -415,7 +418,7 @@ fn test_xor_finalization() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; for row in 0..witness[0].len() { diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index e5dc591857..1f56fa6f1f 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -29,15 +29,16 @@ use poly_commitment::{ absorb_commitment, combined_inner_product, BatchEvaluationProof, Evaluation, PolyComm, }, evaluation_proof::OpeningProof, + OpenProof, SRS as _, }; use rand::thread_rng; /// The result of a proof verification. pub type Result = std::result::Result; -pub struct Context<'a, G: KimchiCurve, OpeningProof> { +pub struct Context<'a, G: KimchiCurve, OpeningProof: OpenProof> { /// The [VerifierIndex] associated to the proof - pub verifier_index: &'a VerifierIndex, + pub verifier_index: &'a VerifierIndex, /// The proof to verify pub proof: &'a ProverProof, @@ -46,7 +47,7 @@ pub struct Context<'a, G: KimchiCurve, OpeningProof> { pub public_input: &'a [G::ScalarField], } -impl<'a, G: KimchiCurve, OpeningProof> Context<'a, G, OpeningProof> { +impl<'a, G: KimchiCurve, OpeningProof: OpenProof> Context<'a, G, OpeningProof> { pub fn get_column(&self, col: Column) -> Option<&'a PolyComm> { use Column::*; match col { @@ -110,7 +111,7 @@ where EFrSponge: FrSponge, >( &self, - index: &VerifierIndex, + index: &VerifierIndex>, public_comm: &PolyComm, public_input: &[G::ScalarField], ) -> Result> { @@ -558,7 +559,7 @@ where } fn to_batch<'a, G, EFqSponge, EFrSponge>( - verifier_index: &VerifierIndex, + verifier_index: &VerifierIndex>, proof: &'a ProverProof>, public_input: &'a [::ScalarField], ) -> Result> @@ -863,7 +864,7 @@ where /// Will give error if `proof(s)` are not verified as valid. pub fn verify( group_map: &G::Map, - verifier_index: &VerifierIndex, + verifier_index: &VerifierIndex>, proof: &ProverProof>, public_input: &[G::ScalarField], ) -> Result<()> diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 6a6b01ea64..066fcdf448 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -10,7 +10,6 @@ use crate::{ wires::{COLUMNS, PERMUTS}, }, curve::KimchiCurve, - error::VerifierIndexError, prover_index::ProverIndex, }; use ark_ff::{One, PrimeField}; @@ -19,7 +18,7 @@ use mina_poseidon::FqSponge; use once_cell::sync::OnceCell; use poly_commitment::{ commitment::{CommitmentCurve, PolyComm}, - srs::SRS, + OpenProof, SRS as _, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_with::serde_as; @@ -56,7 +55,7 @@ pub struct LookupVerifierIndex { #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VerifierIndex { +pub struct VerifierIndex> { /// evaluation domain #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub domain: D, @@ -64,7 +63,8 @@ pub struct VerifierIndex { pub max_poly_size: usize, /// polynomial commitment keys #[serde(skip)] - pub srs: OnceCell>>, + #[serde(bound(deserialize = "OpeningProof::SRS: Default"))] + pub srs: Arc, /// number of public inputs pub public: usize, /// number of previous evaluation challenges, for recursive proving @@ -149,13 +149,19 @@ pub struct VerifierIndex { } //~spec:endcode -impl ProverIndex { +impl> ProverIndex +where + G::BaseField: PrimeField, +{ /// Produces the [`VerifierIndex`] from the prover's [`ProverIndex`]. /// /// # Panics /// /// Will panic if `srs` cannot be in `cell`. - pub fn verifier_index(&self) -> VerifierIndex { + pub fn verifier_index(&self) -> VerifierIndex + where + VerifierIndex: Clone, + { if let Some(verifier_index) = &self.verifier_index { return verifier_index.clone(); } @@ -203,11 +209,7 @@ impl ProverIndex { powers_of_alpha: self.powers_of_alpha.clone(), public: self.cs.public, prev_challenges: self.cs.prev_challenges, - srs: { - let cell = OnceCell::new(); - cell.set(Arc::clone(&self.srs)).unwrap(); - cell - }, + srs: Arc::clone(&self.srs), sigma_comm: array::from_fn(|i| { self.srs.commit_evaluations_non_hiding( @@ -301,17 +303,13 @@ impl ProverIndex { } } -impl VerifierIndex { +impl> VerifierIndex { /// Gets srs from [`VerifierIndex`] lazily - pub fn srs(&self) -> &Arc> + pub fn srs(&self) -> &Arc where G::BaseField: PrimeField, { - self.srs.get_or_init(|| { - let mut srs = SRS::::create(self.max_poly_size); - srs.add_lagrange_basis(self.domain); - Arc::new(srs) - }) + &self.srs } /// Gets zkpm from [`VerifierIndex`] lazily @@ -330,12 +328,15 @@ impl VerifierIndex { /// /// Will give error if it fails to deserialize from file or unable to set `srs` in `verifier_index`. pub fn from_file( - srs: Option>>, + srs: Arc, path: &Path, offset: Option, // TODO: we shouldn't have to pass these endo: G::ScalarField, - ) -> Result { + ) -> Result + where + OpeningProof::SRS: Default, + { // open file let file = File::open(path).map_err(|e| e.to_string())?; @@ -350,13 +351,7 @@ impl VerifierIndex { .map_err(|e| e.to_string())?; // fill in the rest - if let Some(srs) = srs { - verifier_index - .srs - .set(srs) - .map_err(|_| VerifierIndexError::SRSHasBeenSet.to_string())?; - }; - + verifier_index.srs = srs; verifier_index.endo = endo; Ok(verifier_index) diff --git a/poly-commitment/Cargo.toml b/poly-commitment/Cargo.toml index a90301cb5d..02e879d71d 100644 --- a/poly-commitment/Cargo.toml +++ b/poly-commitment/Cargo.toml @@ -14,6 +14,7 @@ ark-ff = { version = "0.3.0", features = [ "parallel", "asm" ] } ark-ec = { version = "0.3.0", features = [ "parallel" ] } ark-poly = { version = "0.3.0", features = [ "parallel" ] } ark-serialize = "0.3.0" +ark-bn254 = { version = "0.3.0" } blake2 = "0.10.0" itertools = "0.10.3" diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index a8ac78ab7b..91d32bd7a9 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -7,6 +7,7 @@ //! 3. Verify batch of batched opening proofs use crate::srs::endos; +use crate::SRS as SRSTrait; use crate::{error::CommitmentError, srs::SRS}; use ark_ec::{ models::short_weierstrass_jacobian::GroupAffine as SWJAffine, msm::VariableBaseMSM, @@ -564,9 +565,52 @@ pub fn combine_commitments( } } -impl SRS { +pub fn combine_evaluations( + evaluations: &Vec>, + polyscale: G::ScalarField, +) -> Vec { + let mut xi_i = G::ScalarField::one(); + let mut acc = { + let num_evals = if evaluations.len() > 0 { + evaluations[0].evaluations.len() + } else { + 0 + }; + vec![G::ScalarField::zero(); num_evals] + }; + + for Evaluation { + evaluations, + degree_bound, + .. + } in evaluations + .iter() + .filter(|x| !x.commitment.unshifted.is_empty()) + { + // iterating over the polynomial segments + for j in 0..evaluations[0].len() { + for i in 0..evaluations.len() { + acc[i] += evaluations[i][j] * xi_i; + } + xi_i *= polyscale; + } + + if let Some(_m) = degree_bound { + todo!("Misaligned chunked commitments are not supported") + } + } + + acc +} + +impl SRSTrait for SRS { + /// The maximum polynomial degree that can be committed to + fn max_poly_size(&self) -> usize { + self.g.len() + } + /// Commits a polynomial, potentially splitting the result in multiple commitments. - pub fn commit( + fn commit( &self, plnm: &DensePolynomial, max: Option, @@ -576,7 +620,7 @@ impl SRS { } /// Turns a non-hiding polynomial commitment into a hidding polynomial commitment. Transforms each given `` into `( + wH, w)` with a random `w` per commitment. - pub fn mask( + fn mask( &self, comm: PolyComm, rng: &mut (impl RngCore + CryptoRng), @@ -586,7 +630,7 @@ impl SRS { } /// Same as [SRS::mask] except that you can pass the blinders manually. - pub fn mask_custom( + fn mask_custom( &self, com: PolyComm, blinders: &PolyComm, @@ -611,7 +655,7 @@ impl SRS { /// The function returns an unbounded commitment vector (which splits the commitment into several commitments of size at most `n`), /// as well as an optional bounded commitment (if `max` is set). /// Note that a maximum degree cannot (and doesn't need to) be enforced via a shift if `max` is a multiple of `n`. - pub fn commit_non_hiding( + fn commit_non_hiding( &self, plnm: &DensePolynomial, max: Option, @@ -659,7 +703,7 @@ impl SRS { PolyComm:: { unshifted, shifted } } - pub fn commit_evaluations_non_hiding( + fn commit_evaluations_non_hiding( &self, domain: D, plnm: &Evaluations>, @@ -684,7 +728,7 @@ impl SRS { } } - pub fn commit_evaluations( + fn commit_evaluations( &self, domain: D, plnm: &Evaluations>, @@ -692,7 +736,9 @@ impl SRS { ) -> BlindedCommitment { self.mask(self.commit_evaluations_non_hiding(domain, plnm), rng) } +} +impl SRS { /// This function verifies batch of batched polynomial commitment opening proofs /// batch: batch of batched polynomial commitment opening proofs /// vector of evaluation points diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index bac1eba0ef..d1e3e5e7fc 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -374,32 +374,27 @@ pub struct OpeningProof { impl< BaseField: PrimeField, G: AffineCurve + CommitmentCurve + EndoCurve, - > crate::OpenProof for OpeningProof + > crate::OpenProof for OpeningProof { - type G = G; type SRS = SRS; - fn open::ScalarField>>( + fn open::ScalarField>>( srs: &Self::SRS, - group_map: &::Map, + group_map: &::Map, plnms: &[( - DensePolynomialOrEvaluations<::ScalarField, D>, + DensePolynomialOrEvaluations<::ScalarField, D>, Option, - PolyComm<::ScalarField>, + PolyComm<::ScalarField>, )], // vector of polynomial with optional degree bound and commitment randomness - elm: &[::ScalarField], // vector of evaluation points - polyscale: ::ScalarField, // scaling factor for polynoms - evalscale: ::ScalarField, // scaling factor for evaluation point powers - sponge: EFqSponge, // sponge + elm: &[::ScalarField], // vector of evaluation points + polyscale: ::ScalarField, // scaling factor for polynoms + evalscale: ::ScalarField, // scaling factor for evaluation point powers + sponge: EFqSponge, // sponge rng: &mut RNG, ) -> Self where - EFqSponge: Clone - + FqSponge< - ::BaseField, - Self::G, - ::ScalarField, - >, + EFqSponge: + Clone + FqSponge<::BaseField, G, ::ScalarField>, RNG: RngCore + CryptoRng, { srs.open(group_map, plnms, elm, polyscale, evalscale, sponge, rng) diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 09ba3e4bcf..739ae72bcf 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -10,37 +10,91 @@ mod tests; pub use commitment::PolyComm; -use crate::commitment::CommitmentCurve; +use crate::commitment::{BlindedCommitment, CommitmentCurve}; +use crate::error::CommitmentError; use crate::evaluation_proof::DensePolynomialOrEvaluations; use ark_ec::AffineCurve; -use ark_poly::EvaluationDomain; +use ark_ff::UniformRand; +use ark_poly::{ + univariate::DensePolynomial, EvaluationDomain, Evaluations, Radix2EvaluationDomain as D, +}; use mina_poseidon::FqSponge; use rand_core::{CryptoRng, RngCore}; -pub trait OpenProof { - type G: CommitmentCurve; - type SRS; +pub trait SRS { + /// The maximum polynomial degree that can be committed to + fn max_poly_size(&self) -> usize; - fn open::ScalarField>>( + /// Commits a polynomial, potentially splitting the result in multiple commitments. + fn commit( + &self, + plnm: &DensePolynomial, + max: Option, + rng: &mut (impl RngCore + CryptoRng), + ) -> BlindedCommitment; + + /// Turns a non-hiding polynomial commitment into a hidding polynomial commitment. Transforms each given `` into `( + wH, w)` with a random `w` per commitment. + fn mask_custom( + &self, + com: PolyComm, + blinders: &PolyComm, + ) -> Result, CommitmentError>; + + /// Same as [SRS::mask] except that you can pass the blinders manually. + fn mask( + &self, + comm: PolyComm, + rng: &mut (impl RngCore + CryptoRng), + ) -> BlindedCommitment { + let blinders = comm.map(|_| G::ScalarField::rand(rng)); + self.mask_custom(comm, &blinders).unwrap() + } + + /// This function commits a polynomial using the SRS' basis of size `n`. + /// - `plnm`: polynomial to commit to with max size of sections + /// - `max`: maximal degree of the polynomial (not inclusive), if none, no degree bound + /// The function returns an unbounded commitment vector (which splits the commitment into several commitments of size at most `n`), + /// as well as an optional bounded commitment (if `max` is set). + /// Note that a maximum degree cannot (and doesn't need to) be enforced via a shift if `max` is a multiple of `n`. + fn commit_non_hiding( + &self, + plnm: &DensePolynomial, + max: Option, + ) -> PolyComm; + + fn commit_evaluations_non_hiding( + &self, + domain: D, + plnm: &Evaluations>, + ) -> PolyComm; + + fn commit_evaluations( + &self, + domain: D, + plnm: &Evaluations>, + rng: &mut (impl RngCore + CryptoRng), + ) -> BlindedCommitment; +} + +pub trait OpenProof { + type SRS: SRS; + + fn open::ScalarField>>( srs: &Self::SRS, - group_map: &::Map, + group_map: &::Map, plnms: &[( - DensePolynomialOrEvaluations<::ScalarField, D>, + DensePolynomialOrEvaluations<::ScalarField, D>, Option, - PolyComm<::ScalarField>, + PolyComm<::ScalarField>, )], // vector of polynomial with optional degree bound and commitment randomness - elm: &[::ScalarField], // vector of evaluation points - polyscale: ::ScalarField, // scaling factor for polynoms - evalscale: ::ScalarField, // scaling factor for evaluation point powers - sponge: EFqSponge, // sponge + elm: &[::ScalarField], // vector of evaluation points + polyscale: ::ScalarField, // scaling factor for polynoms + evalscale: ::ScalarField, // scaling factor for evaluation point powers + sponge: EFqSponge, // sponge rng: &mut RNG, ) -> Self where - EFqSponge: Clone - + FqSponge< - ::BaseField, - Self::G, - ::ScalarField, - >, + EFqSponge: + Clone + FqSponge<::BaseField, G, ::ScalarField>, RNG: RngCore + CryptoRng; } diff --git a/poly-commitment/src/srs.rs b/poly-commitment/src/srs.rs index 356e9dc9fe..c4cd29251b 100644 --- a/poly-commitment/src/srs.rs +++ b/poly-commitment/src/srs.rs @@ -228,6 +228,34 @@ impl SRS { .collect(); self.lagrange_bases.insert(n, chunked_commitments); } + + /// This function creates a trusted-setup SRS instance for circuits with number of rows up to `depth`. + pub fn create_trusted_setup(x: G::ScalarField, depth: usize) -> Self { + let m = G::Map::setup(); + + let mut x_pow = G::ScalarField::one(); + let g: Vec<_> = (0..depth) + .map(|_| { + let res = G::prime_subgroup_generator().mul(x_pow); + x_pow *= x; + res.into_affine() + }) + .collect(); + + const MISC: usize = 1; + let [h]: [G; MISC] = array::from_fn(|i| { + let mut h = Blake2b512::new(); + h.update("srs_misc".as_bytes()); + h.update((i as u32).to_be_bytes()); + point_of_random_bytes(&m, &h.finalize()) + }); + + SRS { + g, + h, + lagrange_bases: HashMap::new(), + } + } } impl SRS diff --git a/poly-commitment/src/tests/batch_15_wires.rs b/poly-commitment/src/tests/batch_15_wires.rs index 5d35aed6b3..516c892ee0 100644 --- a/poly-commitment/src/tests/batch_15_wires.rs +++ b/poly-commitment/src/tests/batch_15_wires.rs @@ -5,6 +5,7 @@ use crate::{ commitment::{combined_inner_product, BatchEvaluationProof, CommitmentCurve, Evaluation}, evaluation_proof::DensePolynomialOrEvaluations, srs::SRS, + SRS as _, }; use ark_ff::{UniformRand, Zero}; use ark_poly::{univariate::DensePolynomial, Radix2EvaluationDomain, UVPolynomial}; diff --git a/poly-commitment/src/tests/commitment.rs b/poly-commitment/src/tests/commitment.rs index b32101daf2..c3b2acc15a 100644 --- a/poly-commitment/src/tests/commitment.rs +++ b/poly-commitment/src/tests/commitment.rs @@ -5,6 +5,7 @@ use crate::{ }, evaluation_proof::{DensePolynomialOrEvaluations, OpeningProof}, srs::SRS, + SRS as _, }; use ark_ff::{UniformRand, Zero}; use ark_poly::{univariate::DensePolynomial, Radix2EvaluationDomain, UVPolynomial}; diff --git a/tools/kimchi-visu/src/lib.rs b/tools/kimchi-visu/src/lib.rs index dd917dea43..390a6924b5 100644 --- a/tools/kimchi-visu/src/lib.rs +++ b/tools/kimchi-visu/src/lib.rs @@ -13,7 +13,7 @@ use kimchi::{ curve::KimchiCurve, prover_index::ProverIndex, }; -use poly_commitment::commitment::CommitmentCurve; +use poly_commitment::{commitment::CommitmentCurve, evaluation_proof::OpeningProof}; use serde::Serialize; use std::{ collections::HashMap, @@ -75,7 +75,12 @@ where /// # Panics /// /// Will panic if `TinyTemplate::render()` returns `Error` or `std::fs::File::create()` returns `Error`. -pub fn visu(index: &ProverIndex, witness: Option>) { +pub fn visu( + index: &ProverIndex>, + witness: Option>, +) where + G::BaseField: PrimeField, +{ // serialize index let index = serde_json::to_string(index).expect("couldn't serialize index"); let mut data = format!("const index = {index};"); From 049a5c9cae61ff2aab3970e5ff05566e21a95434 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 03:13:20 +0100 Subject: [PATCH 084/242] Shift some uses of OpeningProof into the test module --- kimchi/src/prover_index.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 469000e8ed..00e3c5a71f 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -13,7 +13,7 @@ use crate::{ use ark_ff::PrimeField; use ark_poly::EvaluationDomain; use mina_poseidon::FqSponge; -use poly_commitment::{evaluation_proof::OpeningProof, srs::SRS, OpenProof, SRS as _}; +use poly_commitment::{OpenProof, SRS as _}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_with::serde_as; use std::sync::Arc; @@ -152,6 +152,7 @@ pub mod testing { precomputed_srs, }; use ark_ff::{PrimeField, SquareRootField}; + use poly_commitment::{evaluation_proof::OpeningProof, srs::SRS}; /// Create new index for lookups. /// From c9695d14912103b9df134de6423bf660d0a6d070 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 03:19:33 +0100 Subject: [PATCH 085/242] Generalize BatchEvaluationProof over OpeningProof --- kimchi/src/verifier.rs | 2 +- poly-commitment/src/commitment.rs | 6 +++--- poly-commitment/src/tests/commitment.rs | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 1f56fa6f1f..cc72115e9e 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -562,7 +562,7 @@ fn to_batch<'a, G, EFqSponge, EFrSponge>( verifier_index: &VerifierIndex>, proof: &'a ProverProof>, public_input: &'a [::ScalarField], -) -> Result> +) -> Result>> where G: KimchiCurve, G::BaseField: PrimeField, diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 91d32bd7a9..890bbf09e4 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -508,7 +508,7 @@ where /// Contains the batch evaluation // TODO: I think we should really change this name to something more correct -pub struct BatchEvaluationProof<'a, G, EFqSponge> +pub struct BatchEvaluationProof<'a, G, EFqSponge, OpeningProof> where G: AffineCurve, EFqSponge: FqSponge, @@ -522,7 +522,7 @@ where /// scaling factor for polynomials pub evalscale: G::ScalarField, /// batched opening proof - pub opening: &'a OpeningProof, + pub opening: &'a OpeningProof, pub combined_inner_product: G::ScalarField, } @@ -752,7 +752,7 @@ impl SRS { pub fn verify( &self, group_map: &G::Map, - batch: &mut [BatchEvaluationProof], + batch: &mut [BatchEvaluationProof>], rng: &mut RNG, ) -> bool where diff --git a/poly-commitment/src/tests/commitment.rs b/poly-commitment/src/tests/commitment.rs index c3b2acc15a..b393fab2cd 100644 --- a/poly-commitment/src/tests/commitment.rs +++ b/poly-commitment/src/tests/commitment.rs @@ -77,7 +77,8 @@ impl AggregatedEvaluationProof { pub fn verify_type( &self, srs: &SRS, - ) -> BatchEvaluationProof> { + ) -> BatchEvaluationProof, OpeningProof> + { let mut coms = vec![]; for eval_com in &self.eval_commitments { assert_eq!(self.eval_points.len(), eval_com.chunked_evals.len()); From 72c7ed7683949209a51ffb162173f854024cea30 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 03:51:22 +0100 Subject: [PATCH 086/242] Add verify to OpenProof trait --- poly-commitment/src/evaluation_proof.rs | 13 +++++++++++++ poly-commitment/src/lib.rs | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index d1e3e5e7fc..93f8b3e6f4 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -399,6 +399,19 @@ impl< { srs.open(group_map, plnms, elm, polyscale, evalscale, sponge, rng) } + + fn verify( + srs: &Self::SRS, + group_map: &G::Map, + batch: &mut [BatchEvaluationProof], + rng: &mut RNG, + ) -> bool + where + EFqSponge: FqSponge, + RNG: RngCore + CryptoRng, + { + srs.verify(group_map, batch, rng) + } } pub struct Challenges { diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 739ae72bcf..97c2b01c9b 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -10,7 +10,7 @@ mod tests; pub use commitment::PolyComm; -use crate::commitment::{BlindedCommitment, CommitmentCurve}; +use crate::commitment::{BatchEvaluationProof, BlindedCommitment, CommitmentCurve}; use crate::error::CommitmentError; use crate::evaluation_proof::DensePolynomialOrEvaluations; use ark_ec::AffineCurve; @@ -76,7 +76,7 @@ pub trait SRS { ) -> BlindedCommitment; } -pub trait OpenProof { +pub trait OpenProof: Sized { type SRS: SRS; fn open::ScalarField>>( @@ -97,4 +97,14 @@ pub trait OpenProof { EFqSponge: Clone + FqSponge<::BaseField, G, ::ScalarField>, RNG: RngCore + CryptoRng; + + fn verify( + srs: &Self::SRS, + group_map: &G::Map, + batch: &mut [BatchEvaluationProof], + rng: &mut RNG, + ) -> bool + where + EFqSponge: FqSponge, + RNG: RngCore + CryptoRng; } From 35573de000744d2cc88d0d8b8249f0c27d0e32a7 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 04:04:02 +0100 Subject: [PATCH 087/242] Generalize verifier over OpenProof --- kimchi/src/bench.rs | 6 ++++- kimchi/src/tests/framework.rs | 2 +- kimchi/src/tests/range_check.rs | 2 +- kimchi/src/tests/serde.rs | 2 +- kimchi/src/verifier.rs | 38 +++++++++++++++---------------- poly-commitment/src/commitment.rs | 4 ++++ poly-commitment/src/lib.rs | 3 +++ 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/kimchi/src/bench.rs b/kimchi/src/bench.rs index e6284331b7..a77d9d34cf 100644 --- a/kimchi/src/bench.rs +++ b/kimchi/src/bench.rs @@ -106,7 +106,11 @@ impl BenchmarkCtx { public_input: public, }) .collect(); - batch_verify::(&self.group_map, &batch).unwrap(); + batch_verify::>( + &self.group_map, + &batch, + ) + .unwrap(); } } diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index be1bf03609..f76df45b81 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -192,7 +192,7 @@ where // verify the proof (propagate any errors) let start = Instant::now(); - verify::( + verify::>( &group_map, &self.0.verifier_index.unwrap(), &proof, diff --git a/kimchi/src/tests/range_check.rs b/kimchi/src/tests/range_check.rs index 685697c129..d32c4b00a5 100644 --- a/kimchi/src/tests/range_check.rs +++ b/kimchi/src/tests/range_check.rs @@ -1221,7 +1221,7 @@ fn verify_range_check_valid_proof1() { let verifier_index = prover_index.verifier_index(); // Verify proof - let res = verify::( + let res = verify::>( &group_map, &verifier_index, &proof, diff --git a/kimchi/src/tests/serde.rs b/kimchi/src/tests/serde.rs index 4ce97b2f8a..4af830a041 100644 --- a/kimchi/src/tests/serde.rs +++ b/kimchi/src/tests/serde.rs @@ -84,7 +84,7 @@ mod tests { // verify the proof let start = Instant::now(); - verify::( + verify::>( &group_map, &verifier_index_deserialize, &proof, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index cc72115e9e..0412fc4c94 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -28,7 +28,6 @@ use poly_commitment::{ commitment::{ absorb_commitment, combined_inner_product, BatchEvaluationProof, Evaluation, PolyComm, }, - evaluation_proof::OpeningProof, OpenProof, SRS as _, }; use rand::thread_rng; @@ -93,7 +92,7 @@ impl<'a, G: KimchiCurve, OpeningProof: OpenProof> Context<'a, G, OpeningProof } } -impl ProverProof> +impl> ProverProof where G::BaseField: PrimeField, { @@ -111,7 +110,7 @@ where EFrSponge: FrSponge, >( &self, - index: &VerifierIndex>, + index: &VerifierIndex, public_comm: &PolyComm, public_input: &[G::ScalarField], ) -> Result> { @@ -468,7 +467,7 @@ where )) } - combined_inner_product(&evaluation_points, &v, &u, &es, index.srs().g.len()) + combined_inner_product(&evaluation_points, &v, &u, &es, index.srs().max_poly_size()) }; let oracles = RandomOracles { @@ -558,11 +557,11 @@ where Ok(()) } -fn to_batch<'a, G, EFqSponge, EFrSponge>( - verifier_index: &VerifierIndex>, - proof: &'a ProverProof>, +fn to_batch<'a, G, EFqSponge, EFrSponge, OpeningProof: OpenProof>( + verifier_index: &VerifierIndex, + proof: &'a ProverProof, public_input: &'a [::ScalarField], -) -> Result>> +) -> Result> where G: KimchiCurve, G::BaseField: PrimeField, @@ -601,8 +600,7 @@ where } let lgr_comm = verifier_index .srs() - .lagrange_bases - .get(&verifier_index.domain.size()) + .get_lagrange_basis(verifier_index.domain.size()) .expect("pre-computed committed lagrange bases not found"); let com: Vec<_> = lgr_comm.iter().take(verifier_index.public).collect(); let elm: Vec<_> = public_input.iter().map(|s| -*s).collect(); @@ -862,10 +860,10 @@ where /// # Errors /// /// Will give error if `proof(s)` are not verified as valid. -pub fn verify( +pub fn verify>( group_map: &G::Map, - verifier_index: &VerifierIndex>, - proof: &ProverProof>, + verifier_index: &VerifierIndex, + proof: &ProverProof, public_input: &[G::ScalarField], ) -> Result<()> where @@ -879,7 +877,7 @@ where proof, public_input, }]; - batch_verify::(group_map, &proofs) + batch_verify::(group_map, &proofs) } /// This function verifies the batch of zk-proofs @@ -889,9 +887,9 @@ where /// # Errors /// /// Will give error if `srs` of `proof` is invalid or `verify` process fails. -pub fn batch_verify( +pub fn batch_verify>( group_map: &G::Map, - proofs: &[Context>], + proofs: &[Context], ) -> Result<()> where G: KimchiCurve, @@ -915,12 +913,12 @@ where // TODO: Account for the different SRS lengths let srs = proofs[0].verifier_index.srs(); for &Context { verifier_index, .. } in proofs { - if verifier_index.srs().g.len() != srs.g.len() { + if verifier_index.srs().max_poly_size() != srs.max_poly_size() { return Err(VerifyError::DifferentSRS); } // also make sure that the SRS is not smaller than the domain size - if verifier_index.srs().max_degree() < verifier_index.domain.size() { + if verifier_index.srs().max_poly_size() < verifier_index.domain.size() { return Err(VerifyError::SRSTooSmall); } } @@ -933,7 +931,7 @@ where public_input, } in proofs { - batch.push(to_batch::( + batch.push(to_batch::( verifier_index, proof, public_input, @@ -941,7 +939,7 @@ where } //~ 1. Use the [`PolyCom.verify`](#polynomial-commitments) to verify the partially evaluated proofs. - if srs.verify::(group_map, &mut batch, &mut thread_rng()) { + if OpeningProof::verify(srs, group_map, &mut batch, &mut thread_rng()) { Ok(()) } else { Err(VerifyError::OpenProof) diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 890bbf09e4..0eb5a40be0 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -609,6 +609,10 @@ impl SRSTrait for SRS { self.g.len() } + fn get_lagrange_basis(&self, domain_size: usize) -> Option<&Vec>> { + self.lagrange_bases.get(&domain_size) + } + /// Commits a polynomial, potentially splitting the result in multiple commitments. fn commit( &self, diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 97c2b01c9b..b8bfb91dfc 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -25,6 +25,9 @@ pub trait SRS { /// The maximum polynomial degree that can be committed to fn max_poly_size(&self) -> usize; + /// Retrieve the precomputed Lagrange basis for the given domain size + fn get_lagrange_basis(&self, domain_size: usize) -> Option<&Vec>>; + /// Commits a polynomial, potentially splitting the result in multiple commitments. fn commit( &self, From 79f9a3942a83ab2c22dbedee3f0617028234a3ff Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 04:24:07 +0100 Subject: [PATCH 088/242] Generalize prover, test framework over OpenProof --- kimchi/src/prover.rs | 7 +++-- kimchi/src/tests/framework.rs | 34 +++++++++++++++++-------- poly-commitment/src/commitment.rs | 2 ++ poly-commitment/src/evaluation_proof.rs | 2 +- poly-commitment/src/lib.rs | 3 +++ 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index d01df7c187..bfc72f14a4 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -47,7 +47,6 @@ use poly_commitment::{ absorb_commitment, b_poly_coefficients, BlindedCommitment, CommitmentCurve, PolyComm, }, evaluation_proof::DensePolynomialOrEvaluations, - srs::SRS, OpenProof, SRS as _, }; use rayon::prelude::*; @@ -117,7 +116,7 @@ where runtime_second_col_d8: Option>>, } -impl>> ProverProof +impl> ProverProof where G::BaseField: PrimeField, { @@ -175,7 +174,7 @@ where // make sure that the SRS is not smaller than the domain size let d1_size = index.cs.domain.d1.size(); - if index.srs.max_degree() < d1_size { + if index.srs.max_poly_size() < d1_size { return Err(ProverError::SRSTooSmall); } @@ -850,7 +849,7 @@ where t_comm .commitment .unshifted - .push(index.srs.h.mul(w).into_affine()); + .push(index.srs.blinding_commitment().mul(w).into_affine()); t_comm.blinders.unshifted.push(w); } t_comm diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index f76df45b81..86d341dde8 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -20,15 +20,17 @@ use ark_ff::PrimeField; use groupmap::GroupMap; use mina_poseidon::sponge::FqSponge; use num_bigint::BigUint; -use poly_commitment::{commitment::CommitmentCurve, evaluation_proof::OpeningProof}; +use poly_commitment::{commitment::CommitmentCurve, evaluation_proof::OpeningProof as DlogOpeningProof, OpenProof}; use std::{fmt::Write, mem, time::Instant}; // aliases #[derive(Default, Clone)] -pub(crate) struct TestFramework +pub(crate) struct TestFramework = DlogOpeningProof> where G::BaseField: PrimeField, + OpeningProof::SRS: Clone, + VerifierIndex: Clone, { gates: Option>>, witness: Option<[Vec; COLUMNS]>, @@ -40,19 +42,22 @@ where num_prev_challenges: usize, disable_gates_checks: bool, - prover_index: Option>>, - verifier_index: Option>>, + prover_index: Option>, + verifier_index: Option>, } #[derive(Clone)] -pub(crate) struct TestRunner(TestFramework) +pub(crate) struct TestRunner = DlogOpeningProof>(TestFramework) where - G::BaseField: PrimeField; + G::BaseField: PrimeField, + OpeningProof::SRS: Clone, + VerifierIndex: Clone; -impl TestFramework +impl> TestFramework where G::BaseField: PrimeField, - G::ScalarField: PrimeField, + OpeningProof::SRS: Clone, + VerifierIndex: Clone, { #[must_use] pub(crate) fn gates(mut self, gates: Vec>) -> Self { @@ -98,7 +103,12 @@ where self.disable_gates_checks = disable_gates_checks; self } +} +impl TestFramework +where + G::BaseField: PrimeField, +{ /// creates the indexes #[must_use] pub(crate) fn setup(mut self) -> TestRunner { @@ -127,10 +137,12 @@ where } } -impl TestRunner +impl> TestRunner where G::ScalarField: PrimeField + Clone, G::BaseField: PrimeField + Clone, + OpeningProof::SRS: Clone, + VerifierIndex: Clone, { #[must_use] pub(crate) fn runtime_tables( @@ -153,7 +165,7 @@ where self } - pub(crate) fn prover_index(&self) -> &ProverIndex> { + pub(crate) fn prover_index(&self) -> &ProverIndex { self.0.prover_index.as_ref().unwrap() } @@ -192,7 +204,7 @@ where // verify the proof (propagate any errors) let start = Instant::now(); - verify::>( + verify::( &group_map, &self.0.verifier_index.unwrap(), &proof, diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 0eb5a40be0..78fda46bdd 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -613,6 +613,8 @@ impl SRSTrait for SRS { self.lagrange_bases.get(&domain_size) } + fn blinding_commitment(&self) -> G { self.h } + /// Commits a polynomial, potentially splitting the result in multiple commitments. fn commit( &self, diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 93f8b3e6f4..29c0bae888 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -355,7 +355,7 @@ impl SRS { } #[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] pub struct OpeningProof { /// vector of rounds of L & R commitments diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index b8bfb91dfc..4b8bc1bed8 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -28,6 +28,9 @@ pub trait SRS { /// Retrieve the precomputed Lagrange basis for the given domain size fn get_lagrange_basis(&self, domain_size: usize) -> Option<&Vec>>; + /// Get the group element used for blinding commitments + fn blinding_commitment(&self) -> G; + /// Commits a polynomial, potentially splitting the result in multiple commitments. fn commit( &self, From 98ff21fbe961f12c2527bf72c3861efabcf0be2c Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 04:48:34 +0100 Subject: [PATCH 089/242] Update test framework to allow for use with KZG commitments --- kimchi/src/prover_index.rs | 66 +++++++++++++++++++++++-------- kimchi/src/tests/framework.rs | 47 ++++++++++++++++++++-- poly-commitment/src/commitment.rs | 4 +- 3 files changed, 96 insertions(+), 21 deletions(-) diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 00e3c5a71f..a4292f583c 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -152,21 +152,22 @@ pub mod testing { precomputed_srs, }; use ark_ff::{PrimeField, SquareRootField}; - use poly_commitment::{evaluation_proof::OpeningProof, srs::SRS}; + use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as D}; + use poly_commitment::{evaluation_proof::OpeningProof, srs::SRS, OpenProof}; - /// Create new index for lookups. - /// - /// # Panics - /// - /// Will panic if `constraint system` is not built with `gates` input. - pub fn new_index_for_test_with_lookups( + pub fn new_index_for_test_with_lookups_and_custom_srs< + G: KimchiCurve, + OpeningProof: OpenProof, + F: FnMut(D) -> OpeningProof::SRS, + >( gates: Vec>, public: usize, prev_challenges: usize, lookup_tables: Vec>, runtime_tables: Option>>, disable_gates_checks: bool, - ) -> ProverIndex> + mut get_srs: F, + ) -> ProverIndex where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, @@ -181,21 +182,52 @@ pub mod testing { .build() .unwrap(); - let mut srs = if cs.domain.d1.log_size_of_group <= precomputed_srs::SERIALIZED_SRS_SIZE { - // TODO: we should trim it if it's smaller - precomputed_srs::get_srs() - } else { - // TODO: we should resume the SRS generation starting from the serialized one - SRS::::create(cs.domain.d1.size()) - }; - - srs.add_lagrange_basis(cs.domain.d1); + let srs = get_srs(cs.domain.d1); let srs = Arc::new(srs); let &endo_q = G::other_curve_endo(); ProverIndex::create(cs, endo_q, srs) } + /// Create new index for lookups. + /// + /// # Panics + /// + /// Will panic if `constraint system` is not built with `gates` input. + pub fn new_index_for_test_with_lookups( + gates: Vec>, + public: usize, + prev_challenges: usize, + lookup_tables: Vec>, + runtime_tables: Option>>, + disable_gates_checks: bool, + ) -> ProverIndex> + where + G::BaseField: PrimeField, + G::ScalarField: PrimeField + SquareRootField, + { + new_index_for_test_with_lookups_and_custom_srs( + gates, + public, + prev_challenges, + lookup_tables, + runtime_tables, + disable_gates_checks, + |d1: D| { + let mut srs = if d1.log_size_of_group <= precomputed_srs::SERIALIZED_SRS_SIZE { + // TODO: we should trim it if it's smaller + precomputed_srs::get_srs() + } else { + // TODO: we should resume the SRS generation starting from the serialized one + SRS::::create(d1.size()) + }; + + srs.add_lagrange_basis(d1); + srs + }, + ) + } + pub fn new_index_for_test( gates: Vec>, public: usize, diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index 86d341dde8..18d8a8553d 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -12,15 +12,23 @@ use crate::{ curve::KimchiCurve, plonk_sponge::FrSponge, proof::{ProverProof, RecursionChallenge}, - prover_index::{testing::new_index_for_test_with_lookups, ProverIndex}, + prover_index::{ + testing::{ + new_index_for_test_with_lookups, new_index_for_test_with_lookups_and_custom_srs, + }, + ProverIndex, + }, verifier::verify, verifier_index::VerifierIndex, }; use ark_ff::PrimeField; +use ark_poly::Radix2EvaluationDomain as D; use groupmap::GroupMap; use mina_poseidon::sponge::FqSponge; use num_bigint::BigUint; -use poly_commitment::{commitment::CommitmentCurve, evaluation_proof::OpeningProof as DlogOpeningProof, OpenProof}; +use poly_commitment::{ + commitment::CommitmentCurve, evaluation_proof::OpeningProof as DlogOpeningProof, OpenProof, +}; use std::{fmt::Write, mem, time::Instant}; // aliases @@ -47,7 +55,9 @@ where } #[derive(Clone)] -pub(crate) struct TestRunner = DlogOpeningProof>(TestFramework) +pub(crate) struct TestRunner = DlogOpeningProof>( + TestFramework, +) where G::BaseField: PrimeField, OpeningProof::SRS: Clone, @@ -103,6 +113,37 @@ where self.disable_gates_checks = disable_gates_checks; self } + + /// creates the indexes + #[must_use] + pub(crate) fn setup_with_custom_srs) -> OpeningProof::SRS>( + mut self, + get_srs: F, + ) -> TestRunner { + let start = Instant::now(); + + let lookup_tables = std::mem::take(&mut self.lookup_tables); + let runtime_tables_setup = mem::replace(&mut self.runtime_tables_setup, None); + + let index = new_index_for_test_with_lookups_and_custom_srs( + self.gates.take().unwrap(), + self.public_inputs.len(), + self.num_prev_challenges, + lookup_tables, + runtime_tables_setup, + self.disable_gates_checks, + get_srs, + ); + println!( + "- time to create prover index: {:?}s", + start.elapsed().as_secs() + ); + + self.verifier_index = Some(index.verifier_index()); + self.prover_index = Some(index); + + TestRunner(self) + } } impl TestFramework diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 78fda46bdd..716c9fd3dc 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -613,7 +613,9 @@ impl SRSTrait for SRS { self.lagrange_bases.get(&domain_size) } - fn blinding_commitment(&self) -> G { self.h } + fn blinding_commitment(&self) -> G { + self.h + } /// Commits a polynomial, potentially splitting the result in multiple commitments. fn commit( From 3d5aab7f5679c0d564b4f6af6e9ddb90551c6547 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 06:17:14 +0100 Subject: [PATCH 090/242] Add implementation for pairings, tests --- Cargo.lock | 13 + kimchi/Cargo.toml | 2 + kimchi/src/curve.rs | 37 ++ kimchi/src/tests/generic.rs | 38 ++ poly-commitment/Cargo.toml | 2 +- poly-commitment/src/lib.rs | 1 + poly-commitment/src/pairing_proof.rs | 432 ++++++++++++++ poseidon/src/dummy_values.rs | 831 +++++++++++++++++++++++++++ poseidon/src/lib.rs | 1 + 9 files changed, 1356 insertions(+), 1 deletion(-) create mode 100644 poly-commitment/src/pairing_proof.rs create mode 100644 poseidon/src/dummy_values.rs diff --git a/Cargo.lock b/Cargo.lock index ad9920e2d1..b26d8e1c04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,17 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bn254" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea691771ebbb28aea556c044e2e5c5227398d840cee0c34d4d20fa8eb2689e8c" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-ec" version = "0.3.0" @@ -1054,6 +1065,7 @@ dependencies = [ name = "kimchi" version = "0.1.0" dependencies = [ + "ark-bn254", "ark-ec", "ark-ff", "ark-poly", @@ -1724,6 +1736,7 @@ dependencies = [ name = "poly-commitment" version = "0.1.0" dependencies = [ + "ark-bn254", "ark-ec", "ark-ff", "ark-poly", diff --git a/kimchi/Cargo.toml b/kimchi/Cargo.toml index e5b7cae40d..a2dedda78a 100644 --- a/kimchi/Cargo.toml +++ b/kimchi/Cargo.toml @@ -18,6 +18,7 @@ ark-ff = { version = "0.3.0", features = [ "parallel", "asm" ] } ark-ec = { version = "0.3.0", features = [ "parallel" ] } ark-poly = { version = "0.3.0", features = [ "parallel" ] } ark-serialize = "0.3.0" +ark-bn254 = { version = "0.3.0", optional = true } blake2 = "0.10.0" num-bigint = { version = "0.4.3", features = ["rand", "serde"]} num-derive = "0.3" @@ -81,5 +82,6 @@ harness = false default = [] internal_tracing = [ "internal-tracing/enabled" ] ocaml_types = [ "ocaml", "ocaml-gen", "poly-commitment/ocaml_types", "mina-poseidon/ocaml_types", "internal-tracing/ocaml_types" ] +bn254 = [ "ark-bn254" ] wasm_types = [ "wasm-bindgen" ] check_feature_flags = [] diff --git a/kimchi/src/curve.rs b/kimchi/src/curve.rs index 71f489b5bd..57790b10f7 100644 --- a/kimchi/src/curve.rs +++ b/kimchi/src/curve.rs @@ -165,3 +165,40 @@ impl KimchiCurve for GroupAffine { .unwrap() } } + +#[cfg(feature = "bn254")] +use mina_poseidon::dummy_values::kimchi_dummy; + +#[cfg(feature = "bn254")] +impl KimchiCurve for GroupAffine { + const NAME: &'static str = "bn254"; + + fn sponge_params() -> &'static ArithmeticSpongeParams { + // TODO: Generate some params + static PARAMS: Lazy> = Lazy::new(kimchi_dummy); + &PARAMS + } + + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams { + // TODO: Generate some params + static PARAMS: Lazy> = Lazy::new(kimchi_dummy); + &PARAMS + } + + fn endos() -> &'static (Self::BaseField, Self::ScalarField) { + static ENDOS: Lazy<(ark_bn254::Fq, ark_bn254::Fr)> = + Lazy::new(endos::); + &ENDOS + } + + fn other_curve_endo() -> &'static Self::ScalarField { + // TODO: Dummy value, this is definitely not right + static ENDO: Lazy = Lazy::new(|| 13u64.into()); + &ENDO + } + + fn other_curve_prime_subgroup_generator() -> (Self::ScalarField, Self::ScalarField) { + // TODO: Dummy value, this is definitely not right + (44u64.into(), 88u64.into()) + } +} diff --git a/kimchi/src/tests/generic.rs b/kimchi/src/tests/generic.rs index 3f8cbc98b6..b3d923e67b 100644 --- a/kimchi/src/tests/generic.rs +++ b/kimchi/src/tests/generic.rs @@ -86,3 +86,41 @@ fn test_generic_gate_pub_empty() { .prove_and_verify::() .unwrap(); } + +#[cfg(feature = "bn254")] +#[test] +fn test_generic_gate_pairing() { + type Fp = ark_bn254::Fr; + type SpongeParams = PlonkSpongeConstantsKimchi; + type BaseSponge = DefaultFqSponge; + type ScalarSponge = DefaultFrSponge; + + use ark_ff::UniformRand; + use ark_poly::EvaluationDomain; + + let public = vec![Fp::from(3u8); 5]; + let gates = create_circuit(0, public.len()); + + let rng = &mut rand::rngs::OsRng; + let x = Fp::rand(rng); + + // create witness + let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + fill_in_witness(0, &mut witness, &public); + + // create and verify proof based on the witness + >, + > as Default>::default() + .gates(gates) + .witness(witness) + .public_inputs(public) + .setup_with_custom_srs(|d1| { + let mut srs = poly_commitment::pairing_proof::PairingSRS::create(x, d1.size()); + srs.full_srs.add_lagrange_basis(d1); + srs + }) + .prove_and_verify::() + .unwrap(); +} diff --git a/poly-commitment/Cargo.toml b/poly-commitment/Cargo.toml index 02e879d71d..576791e0b4 100644 --- a/poly-commitment/Cargo.toml +++ b/poly-commitment/Cargo.toml @@ -14,7 +14,6 @@ ark-ff = { version = "0.3.0", features = [ "parallel", "asm" ] } ark-ec = { version = "0.3.0", features = [ "parallel" ] } ark-poly = { version = "0.3.0", features = [ "parallel" ] } ark-serialize = "0.3.0" -ark-bn254 = { version = "0.3.0" } blake2 = "0.10.0" itertools = "0.10.3" @@ -38,6 +37,7 @@ ocaml-gen = { version = "0.1.0", optional = true } [dev-dependencies] colored = "2.0.0" rand_chacha = { version = "0.3.0" } +ark-bn254 = { version = "0.3.0" } [features] ocaml_types = [ "ocaml", "ocaml-gen" ] diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 4b8bc1bed8..dd2ce64240 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -3,6 +3,7 @@ mod combine; pub mod commitment; pub mod error; pub mod evaluation_proof; +pub mod pairing_proof; pub mod srs; #[cfg(test)] diff --git a/poly-commitment/src/pairing_proof.rs b/poly-commitment/src/pairing_proof.rs new file mode 100644 index 0000000000..68d9534e50 --- /dev/null +++ b/poly-commitment/src/pairing_proof.rs @@ -0,0 +1,432 @@ +use crate::commitment::*; +use crate::evaluation_proof::{combine_polys, DensePolynomialOrEvaluations}; +use crate::srs::SRS; +use crate::{CommitmentError, SRS as SRSTrait}; +use ark_ec::{msm::VariableBaseMSM, AffineCurve, PairingEngine}; +use ark_ff::{PrimeField, Zero}; +use ark_poly::{ + univariate::{DenseOrSparsePolynomial, DensePolynomial}, + EvaluationDomain, Evaluations, Polynomial, Radix2EvaluationDomain as D, UVPolynomial, +}; +use mina_poseidon::FqSponge; +use rand_core::{CryptoRng, RngCore}; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +#[serde_as] +#[derive(Debug, Serialize, Deserialize)] +#[serde( + bound = "Pair::G1Affine: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize" +)] +pub struct PairingProof { + #[serde_as(as = "o1_utils::serialization::SerdeAs")] + pub quotient: Pair::G1Affine, + #[serde_as(as = "o1_utils::serialization::SerdeAs")] + pub blinding: ::ScalarField, +} + +impl Default for PairingProof { + fn default() -> Self { + Self { + quotient: Pair::G1Affine::prime_subgroup_generator(), + blinding: ::ScalarField::zero(), + } + } +} + +impl Clone for PairingProof { + fn clone(&self) -> Self { + Self { + quotient: self.quotient.clone(), + blinding: self.blinding.clone(), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct PairingSRS { + pub full_srs: SRS, + pub verifier_srs: SRS, +} + +impl Default for PairingSRS { + fn default() -> Self { + Self { + full_srs: SRS::default(), + verifier_srs: SRS::default(), + } + } +} + +impl Clone for PairingSRS { + fn clone(&self) -> Self { + Self { + full_srs: self.full_srs.clone(), + verifier_srs: self.verifier_srs.clone(), + } + } +} + +impl< + F: PrimeField, + G: CommitmentCurve, + G2: CommitmentCurve, + Pair: PairingEngine, + > PairingSRS +{ + pub fn create(x: F, n: usize) -> Self { + PairingSRS { + full_srs: SRS::create_trusted_setup(x, n), + verifier_srs: SRS::create_trusted_setup(x, 3), + } + } +} + +impl< + F: PrimeField, + G: CommitmentCurve, + G2: CommitmentCurve, + Pair: PairingEngine, + > crate::OpenProof for PairingProof +{ + type SRS = PairingSRS; + + fn open::ScalarField>>( + srs: &Self::SRS, + _group_map: &::Map, + plnms: &[( + DensePolynomialOrEvaluations<::ScalarField, D>, + Option, + PolyComm<::ScalarField>, + )], // vector of polynomial with optional degree bound and commitment randomness + elm: &[::ScalarField], // vector of evaluation points + polyscale: ::ScalarField, // scaling factor for polynoms + _evalscale: ::ScalarField, // scaling factor for evaluation point powers + _sponge: EFqSponge, // sponge + _rng: &mut RNG, + ) -> Self + where + EFqSponge: + Clone + FqSponge<::BaseField, G, ::ScalarField>, + RNG: RngCore + CryptoRng, + { + PairingProof::create(srs, plnms, elm, polyscale).unwrap() + } + + fn verify( + srs: &Self::SRS, + _group_map: &G::Map, + batch: &mut [BatchEvaluationProof], + _rng: &mut RNG, + ) -> bool + where + EFqSponge: FqSponge, + RNG: RngCore + CryptoRng, + { + for BatchEvaluationProof { + sponge: _, + evaluations, + evaluation_points, + polyscale, + evalscale: _, + opening, + combined_inner_product: _, + } in batch.iter() + { + if !opening.verify(srs, evaluations, *polyscale, evaluation_points) { + return false; + } + } + true + } +} + +impl< + F: PrimeField, + G: CommitmentCurve, + G2: CommitmentCurve, + Pair: PairingEngine, + > SRSTrait for PairingSRS +{ + fn max_poly_size(&self) -> usize { + self.full_srs.max_poly_size() + } + + fn get_lagrange_basis(&self, domain_size: usize) -> Option<&Vec>> { + self.full_srs.get_lagrange_basis(domain_size) + } + + fn blinding_commitment(&self) -> G { + self.full_srs.blinding_commitment() + } + + fn commit( + &self, + plnm: &DensePolynomial, + max: Option, + rng: &mut (impl RngCore + CryptoRng), + ) -> BlindedCommitment { + self.full_srs.commit(plnm, max, rng) + } + + fn mask_custom( + &self, + com: PolyComm, + blinders: &PolyComm, + ) -> Result, CommitmentError> { + self.full_srs.mask_custom(com, blinders) + } + + fn mask( + &self, + comm: PolyComm, + rng: &mut (impl RngCore + CryptoRng), + ) -> BlindedCommitment { + self.full_srs.mask(comm, rng) + } + + fn commit_non_hiding( + &self, + plnm: &DensePolynomial, + max: Option, + ) -> PolyComm { + self.full_srs.commit_non_hiding(plnm, max) + } + + fn commit_evaluations_non_hiding( + &self, + domain: D, + plnm: &Evaluations>, + ) -> PolyComm { + self.full_srs.commit_evaluations_non_hiding(domain, plnm) + } + + fn commit_evaluations( + &self, + domain: D, + plnm: &Evaluations>, + rng: &mut (impl RngCore + CryptoRng), + ) -> BlindedCommitment { + self.full_srs.commit_evaluations(domain, plnm, rng) + } +} + +/// The polynomial that evaluates to each of `evals` for the respective `elm`s. +fn eval_polynomial(elm: &[F], evals: &[F]) -> DensePolynomial { + assert_eq!(elm.len(), evals.len()); + let (zeta, zeta_omega) = if elm.len() == 2 { + (elm[0], elm[1]) + } else { + todo!() + }; + let (eval_zeta, eval_zeta_omega) = if evals.len() == 2 { + (evals[0], evals[1]) + } else { + todo!() + }; + + // The polynomial that evaluates to `p(zeta)` at `zeta` and `p(zeta_omega)` at + // `zeta_omega`. + // We write `p(x) = a + bx`, which gives + // ```text + // p(zeta) = a + b * zeta + // p(zeta_omega) = a + b * zeta_omega + // ``` + // and so + // ```text + // b = (p(zeta_omega) - p(zeta)) / (zeta_omega - zeta) + // a = p(zeta) - b * zeta + // ``` + let b = (eval_zeta_omega - eval_zeta) / (zeta_omega - zeta); + let a = eval_zeta - b * zeta; + DensePolynomial::from_coefficients_slice(&[a, b]) +} + +/// The polynomial that evaluates to `0` at the evaluation points. +fn divisor_polynomial(elm: &[F]) -> DensePolynomial { + elm.iter() + .map(|value| DensePolynomial::from_coefficients_slice(&[-(*value), F::one()])) + .reduce(|poly1, poly2| &poly1 * &poly2) + .unwrap() +} + +impl< + F: PrimeField, + G: CommitmentCurve, + G2: CommitmentCurve, + Pair: PairingEngine, + > PairingProof +{ + pub fn create>( + srs: &PairingSRS, + plnms: &[( + DensePolynomialOrEvaluations, + Option, + PolyComm, + )], // vector of polynomial with optional degree bound and commitment randomness + elm: &[G::ScalarField], // vector of evaluation points + polyscale: G::ScalarField, // scaling factor for polynoms + ) -> Option { + let (p, blinding_factor) = combine_polys::(plnms, polyscale, srs.full_srs.g.len()); + let evals: Vec<_> = elm.iter().map(|pt| p.evaluate(pt)).collect(); + + let quotient_poly = { + let eval_polynomial = eval_polynomial(elm, &evals); + let divisor_polynomial = divisor_polynomial(elm); + let numerator_polynomial = &p - &eval_polynomial; + let (quotient, remainder) = DenseOrSparsePolynomial::divide_with_q_and_r( + &numerator_polynomial.clone().into(), + &divisor_polynomial.into(), + )?; + if !remainder.is_zero() { + return None; + } + quotient + }; + + let quotient = srs + .full_srs + .commit_non_hiding("ient_poly, None) + .unshifted[0]; + + Some(PairingProof { + quotient, + blinding: blinding_factor, + }) + } + pub fn verify( + &self, + srs: &PairingSRS, // SRS + evaluations: &Vec>, // commitments to the polynomials + polyscale: G::ScalarField, // scaling factor for polynoms + elm: &[G::ScalarField], // vector of evaluation points + ) -> bool { + let poly_commitment = { + let mut scalars: Vec = Vec::new(); + let mut points = Vec::new(); + combine_commitments( + evaluations, + &mut scalars, + &mut points, + polyscale, + F::one(), /* TODO: This is inefficient */ + ); + let scalars: Vec<_> = scalars.iter().map(|x| x.into_repr()).collect(); + + VariableBaseMSM::multi_scalar_mul(&points, &scalars) + }; + let evals = combine_evaluations(evaluations, polyscale); + let blinding_commitment = srs.full_srs.h.mul(self.blinding); + let divisor_commitment = srs + .verifier_srs + .commit_non_hiding(&divisor_polynomial(elm), None) + .unshifted[0]; + let eval_commitment = srs + .full_srs + .commit_non_hiding(&eval_polynomial(elm, &evals), None) + .unshifted[0] + .into_projective(); + let numerator_commitment = { poly_commitment - eval_commitment - blinding_commitment }; + + let numerator = Pair::pairing( + numerator_commitment, + Pair::G2Affine::prime_subgroup_generator(), + ); + let scaled_quotient = Pair::pairing(self.quotient, divisor_commitment); + numerator == scaled_quotient + } +} + +#[cfg(test)] +mod tests { + use super::{PairingProof, PairingSRS}; + use crate::commitment::Evaluation; + use crate::evaluation_proof::DensePolynomialOrEvaluations; + use crate::srs::SRS; + use crate::SRS as _; + use ark_bn254::Fr as ScalarField; + use ark_bn254::{G1Affine as G1, G2Affine as G2, Parameters}; + use ark_ec::bn::Bn; + use ark_ff::UniformRand; + use ark_poly::{ + univariate::DensePolynomial, EvaluationDomain, Polynomial, Radix2EvaluationDomain as D, + UVPolynomial, + }; + + use rand::{rngs::StdRng, SeedableRng}; + + #[test] + fn test_pairing_proof() { + let n = 64; + let domain = D::::new(n).unwrap(); + + let rng = &mut StdRng::from_seed([0u8; 32]); + + let x = ScalarField::rand(rng); + + let mut srs = SRS::::create_trusted_setup(x, n); + let verifier_srs = SRS::::create_trusted_setup(x, 3); + srs.add_lagrange_basis(domain); + + let srs = PairingSRS { + full_srs: srs, + verifier_srs, + }; + + let polynomials: Vec<_> = (0..4) + .map(|_| { + let coeffs = (0..63).map(|_| ScalarField::rand(rng)).collect(); + DensePolynomial::from_coefficients_vec(coeffs) + }) + .collect(); + + let comms: Vec<_> = polynomials + .iter() + .map(|p| srs.full_srs.commit(p, None, rng)) + .collect(); + + let polynomials_and_blinders: Vec<(DensePolynomialOrEvaluations<_, D<_>>, _, _)> = + polynomials + .iter() + .zip(comms.iter()) + .map(|(p, comm)| { + let p = DensePolynomialOrEvaluations::DensePolynomial(p); + (p, None, comm.blinders.clone()) + }) + .collect(); + + let evaluation_points = vec![ScalarField::rand(rng), ScalarField::rand(rng)]; + + let evaluations: Vec<_> = polynomials + .iter() + .zip(comms.into_iter()) + .map(|(p, commitment)| { + let evaluations = evaluation_points + .iter() + .map(|x| { + // Inputs are chosen to use only 1 chunk + vec![p.evaluate(x)] + }) + .collect(); + Evaluation { + commitment: commitment.commitment, + evaluations, + degree_bound: None, + } + }) + .collect(); + + let polyscale = ScalarField::rand(rng); + + let pairing_proof = PairingProof::>::create( + &srs, + polynomials_and_blinders.as_slice(), + &evaluation_points, + polyscale, + ) + .unwrap(); + + let res = pairing_proof.verify(&srs, &evaluations, polyscale, &evaluation_points); + assert!(res); + } +} diff --git a/poseidon/src/dummy_values.rs b/poseidon/src/dummy_values.rs new file mode 100644 index 0000000000..9bfbc82335 --- /dev/null +++ b/poseidon/src/dummy_values.rs @@ -0,0 +1,831 @@ +use crate::poseidon::ArithmeticSpongeParams; +use ark_ff::Field; +use std::{fmt::Debug, str::FromStr}; + +/// Placeholder dummy value for the kimchi configuration, suitable for fields of bitlength 254 and +/// above. +/// These parameters are duplicated from the Vesta parameters, generated with +/// ```text +/// ./pasta/params.sage --rounds 55 rust 3 kimchi +/// ``` +pub fn kimchi_dummy>() -> ArithmeticSpongeParams { + ArithmeticSpongeParams { + mds: vec![ + vec![ + Fp::from_str( + "12035446894107573964500871153637039653510326950134440362813193268448863222019", + ) + .unwrap(), + Fp::from_str( + "25461374787957152039031444204194007219326765802730624564074257060397341542093", + ) + .unwrap(), + Fp::from_str( + "27667907157110496066452777015908813333407980290333709698851344970789663080149", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "4491931056866994439025447213644536587424785196363427220456343191847333476930", + ) + .unwrap(), + Fp::from_str( + "14743631939509747387607291926699970421064627808101543132147270746750887019919", + ) + .unwrap(), + Fp::from_str( + "9448400033389617131295304336481030167723486090288313334230651810071857784477", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "10525578725509990281643336361904863911009900817790387635342941550657754064843", + ) + .unwrap(), + Fp::from_str( + "27437632000253211280915908546961303399777448677029255413769125486614773776695", + ) + .unwrap(), + Fp::from_str( + "27566319851776897085443681456689352477426926500749993803132851225169606086988", + ) + .unwrap(), + ], + ], + + round_constants: vec![ + vec![ + Fp::from_str( + "21155079691556475130150866428468322463125560312786319980770950159250751855431", + ) + .unwrap(), + Fp::from_str( + "16883442198399350202652499677723930673110172289234921799701652810789093522349", + ) + .unwrap(), + Fp::from_str( + "17030687036425314703519085065002231920937594822150793091243263847382891822670", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "25216718237129482752721276445368692059997901880654047883630276346421457427360", + ) + .unwrap(), + Fp::from_str( + "9054264347380455706540423067244764093107767235485930776517975315876127782582", + ) + .unwrap(), + Fp::from_str( + "26439087121446593160953570192891907825526260324480347638727375735543609856888", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "15251000790817261169639394496851831733819930596125214313084182526610855787494", + ) + .unwrap(), + Fp::from_str( + "10861916012597714684433535077722887124099023163589869801449218212493070551767", + ) + .unwrap(), + Fp::from_str( + "18597653523270601187312528478986388028263730767495975370566527202946430104139", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "15831416454198644276563319006805490049460322229057756462580029181847589006611", + ) + .unwrap(), + Fp::from_str( + "15171856919255965617705854914448645702014039524159471542852132430360867202292", + ) + .unwrap(), + Fp::from_str( + "15488495958879593647482715143904752785889816789652405888927117106448507625751", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "19039802679983063488134304670998725949842655199289961967801223969839823940152", + ) + .unwrap(), + Fp::from_str( + "4720101937153217036737330058775388037616286510783561045464678919473230044408", + ) + .unwrap(), + Fp::from_str( + "10226318327254973427513859412126640040910264416718766418164893837597674300190", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "20878756131129218406920515859235137275859844638301967889441262030146031838819", + ) + .unwrap(), + Fp::from_str( + "7178475685651744631172532830973371642652029385893667810726019303466125436953", + ) + .unwrap(), + Fp::from_str( + "1996970955918516145107673266490486752153434673064635795711751450164177339618", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "15205545916434157464929420145756897321482314798910153575340430817222504672630", + ) + .unwrap(), + Fp::from_str( + "25660296961552699573824264215804279051322332899472350724416657386062327210698", + ) + .unwrap(), + Fp::from_str( + "13842611741937412200312851417353455040950878279339067816479233688850376089318", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "1383799642177300432144836486981606294838630135265094078921115713566691160459", + ) + .unwrap(), + Fp::from_str( + "1135532281155277588005319334542025976079676424839948500020664227027300010929", + ) + .unwrap(), + Fp::from_str( + "4384117336930380014868572224801371377488688194169758696438185377724744869360", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "21725577575710270071808882335900370909424604447083353471892004026180492193649", + ) + .unwrap(), + Fp::from_str( + "676128913284806802699862508051022306366147359505124346651466289788974059668", + ) + .unwrap(), + Fp::from_str( + "25186611339598418732666781049829183886812651492845008333418424746493100589207", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "10402240124664763733060094237696964473609580414190944671778761753887884341073", + ) + .unwrap(), + Fp::from_str( + "11918307118590866200687906627767559273324023585642003803337447146531313172441", + ) + .unwrap(), + Fp::from_str( + "16895677254395661024186292503536662354181715337630376909778003268311296637301", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "23818602699032741669874498456696325705498383130221297580399035778119213224810", + ) + .unwrap(), + Fp::from_str( + "4285193711150023248690088154344086684336247475445482883105661485741762600154", + ) + .unwrap(), + Fp::from_str( + "19133204443389422404056150665863951250222934590192266371578950735825153238612", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "5515589673266504033533906836494002702866463791762187140099560583198974233395", + ) + .unwrap(), + Fp::from_str( + "11830435563729472715615302060564876527985621376031612798386367965451821182352", + ) + .unwrap(), + Fp::from_str( + "7510711479224915247011074129666445216001563200717943545636462819681638560128", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "24694843201907722940091503626731830056550128225297370217610328578733387733444", + ) + .unwrap(), + Fp::from_str( + "27361655066973784653563425664091383058914302579694897188019422193564924110528", + ) + .unwrap(), + Fp::from_str( + "21606788186194534241166833954371013788633495786419718955480491478044413102713", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "19934060063390905409309407607814787335159021816537006003398035237707924006757", + ) + .unwrap(), + Fp::from_str( + "8495813630060004961768092461554180468161254914257386012937942498774724649553", + ) + .unwrap(), + Fp::from_str( + "27524960680529762202005330464726908693944660961000958842417927307941561848461", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "15178481650950399259757805400615635703086255035073919114667254549690862896985", + ) + .unwrap(), + Fp::from_str( + "16164780354695672259791105197274509251141405713012804937107314962551600380870", + ) + .unwrap(), + Fp::from_str( + "10529167793600778056702353412758954281652843049850979705476598375597148191979", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "721141070179074082553302896292167103755384741083338957818644728290501449040", + ) + .unwrap(), + Fp::from_str( + "22044408985956234023934090378372374883099115753118261312473550998188148912041", + ) + .unwrap(), + Fp::from_str( + "27068254103241989852888872162525066148367014691482601147536314217249046186315", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "3880429241956357176819112098792744584376727450211873998699580893624868748961", + ) + .unwrap(), + Fp::from_str( + "17387097125522937623262508065966749501583017524609697127088211568136333655623", + ) + .unwrap(), + Fp::from_str( + "6256814421247770895467770393029354017922744712896100913895513234184920631289", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "2942627347777337187690939671601251987500285937340386328746818861972711408579", + ) + .unwrap(), + Fp::from_str( + "24031654937764287280548628128490074801809101323243546313826173430897408945397", + ) + .unwrap(), + Fp::from_str( + "14401457902976567713827506689641442844921449636054278900045849050301331732143", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "20170632877385406450742199836933900257692624353889848352407590794211839130727", + ) + .unwrap(), + Fp::from_str( + "24056496193857444725324410428861722338174099794084586764867109123681727290181", + ) + .unwrap(), + Fp::from_str( + "11257913009612703357266904349759250619633397075667824800196659858304604714965", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "22228158921984425749199071461510152694025757871561406897041788037116931009246", + ) + .unwrap(), + Fp::from_str( + "9152163378317846541430311327336774331416267016980485920222768197583559318682", + ) + .unwrap(), + Fp::from_str( + "13906695403538884432896105059360907560653506400343268230130536740148070289175", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "7220714562509721437034241786731185291972496952091254931195414855962344025067", + ) + .unwrap(), + Fp::from_str( + "27608867305903811397208862801981345878179337369367554478205559689592889691927", + ) + .unwrap(), + Fp::from_str( + "13288465747219756218882697408422850918209170830515545272152965967042670763153", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "8251343892709140154567051772980662609566359215743613773155065627504813327653", + ) + .unwrap(), + Fp::from_str( + "22035238365102171608166944627493632660244312563934708756134297161332908879090", + ) + .unwrap(), + Fp::from_str( + "13560937766273321037807329177749403409731524715067067740487246745322577571823", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "21652518608959234550262559135285358020552897349934571164032339186996805408040", + ) + .unwrap(), + Fp::from_str( + "22479086963324173427634460342145551255011746993910136574926173581069603086891", + ) + .unwrap(), + Fp::from_str( + "13676501958531751140966255121288182631772843001727158043704693838707387130095", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "5680310394102577950568930199056707827608275306479994663197187031893244826674", + ) + .unwrap(), + Fp::from_str( + "25125360450906166639190392763071557410047335755341060350879819485506243289998", + ) + .unwrap(), + Fp::from_str( + "22659254028501616785029594492374243581602744364859762239504348429834224676676", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "23101411405087512171421838856759448177512679869882987631073569441496722536782", + ) + .unwrap(), + Fp::from_str( + "24149774013240355952057123660656464942409328637280437515964899830988178868108", + ) + .unwrap(), + Fp::from_str( + "5782097512368226173095183217893826020351125522160843964147125728530147423065", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "13540762114500083869920564649399977644344247485313990448129838910231204868111", + ) + .unwrap(), + Fp::from_str( + "20421637734328811337527547703833013277831804985438407401987624070721139913982", + ) + .unwrap(), + Fp::from_str( + "7742664118615900772129122541139124149525273579639574972380600206383923500701", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "1109643801053963021778418773196543643970146666329661268825691230294798976318", + ) + .unwrap(), + Fp::from_str( + "16580663920817053843121063692728699890952505074386761779275436996241901223840", + ) + .unwrap(), + Fp::from_str( + "14638514680222429058240285918830106208025229459346033470787111294847121792366", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "17080385857812672649489217965285727739557573467014392822992021264701563205891", + ) + .unwrap(), + Fp::from_str( + "26176268111736737558502775993925696791974738793095023824029827577569530708665", + ) + .unwrap(), + Fp::from_str( + "4382756253392449071896813428140986330161215829425086284611219278674857536001", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "13934033814940585315406666445960471293638427404971553891617533231178815348902", + ) + .unwrap(), + Fp::from_str( + "27054912732979753314774418228399230433963143177662848084045249524271046173121", + ) + .unwrap(), + Fp::from_str( + "28916070403698593376490976676534962592542013020010643734621202484860041243391", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "24820015636966360150164458094894587765384135259446295278101998130934963922381", + ) + .unwrap(), + Fp::from_str( + "7969535238488580655870884015145760954416088335296905520306227531221721881868", + ) + .unwrap(), + Fp::from_str( + "7690547696740080985104189563436871930607055124031711216224219523236060212249", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "9712576468091272384496248353414290908377825697488757134833205246106605867289", + ) + .unwrap(), + Fp::from_str( + "12148698031438398980683630141370402088785182722473169207262735228500190477924", + ) + .unwrap(), + Fp::from_str( + "14359657643133476969781351728574842164124292705609900285041476162075031948227", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "23563839965372067275137992801035780013422228997724286060975035719045352435470", + ) + .unwrap(), + Fp::from_str( + "4184634822776323233231956802962638484057536837393405750680645555481330909086", + ) + .unwrap(), + Fp::from_str( + "16249511905185772125762038789038193114431085603985079639889795722501216492487", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "11001863048692031559800673473526311616702863826063550559568315794438941516621", + ) + .unwrap(), + Fp::from_str( + "4702354107983530219070178410740869035350641284373933887080161024348425080464", + ) + .unwrap(), + Fp::from_str( + "23751680507533064238793742311430343910720206725883441625894258483004979501613", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "28670526516158451470169873496541739545860177757793329093045522432279094518766", + ) + .unwrap(), + Fp::from_str( + "3568312993091537758218792253361873752799472566055209125947589819564395417072", + ) + .unwrap(), + Fp::from_str( + "1819755756343439646550062754332039103654718693246396323207323333948654200950", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "5372129954699791301953948907349887257752247843844511069896766784624930478273", + ) + .unwrap(), + Fp::from_str( + "17512156688034945920605615850550150476471921176481039715733979181538491476080", + ) + .unwrap(), + Fp::from_str( + "25777105342317622165159064911913148785971147228777677435200128966844208883059", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "25350392006158741749134238306326265756085455157012701586003300872637887157982", + ) + .unwrap(), + Fp::from_str( + "20096724945283767296886159120145376967480397366990493578897615204296873954844", + ) + .unwrap(), + Fp::from_str( + "8063283381910110762785892100479219642751540456251198202214433355775540036851", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "4393613870462297385565277757207010824900723217720226130342463666351557475823", + ) + .unwrap(), + Fp::from_str( + "9874972555132910032057499689351411450892722671352476280351715757363137891038", + ) + .unwrap(), + Fp::from_str( + "23590926474329902351439438151596866311245682682435235170001347511997242904868", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "17723373371137275859467518615551278584842947963894791032296774955869958211070", + ) + .unwrap(), + Fp::from_str( + "2350345015303336966039836492267992193191479606566494799781846958620636621159", + ) + .unwrap(), + Fp::from_str( + "27755207882790211140683010581856487965587066971982625511152297537534623405016", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "6584607987789185408123601849106260907671314994378225066806060862710814193906", + ) + .unwrap(), + Fp::from_str( + "609759108847171587253578490536519506369136135254150754300671591987320319770", + ) + .unwrap(), + Fp::from_str( + "28435187585965602110074342250910608316032945187476441868666714022529803033083", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "16016664911651770663938916450245705908287192964254704641717751103464322455303", + ) + .unwrap(), + Fp::from_str( + "17551273293154696089066968171579395800922204266630874071186322718903959339163", + ) + .unwrap(), + Fp::from_str( + "20414195497994754529479032467015716938594722029047207834858832838081413050198", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "19773307918850685463180290966774465805537520595602496529624568184993487593855", + ) + .unwrap(), + Fp::from_str( + "24598603838812162820757838364185126333280131847747737533989799467867231166980", + ) + .unwrap(), + Fp::from_str( + "11040972566103463398651864390163813377135738019556270484707889323659789290225", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "5189242080957784038860188184443287562488963023922086723850863987437818393811", + ) + .unwrap(), + Fp::from_str( + "1435203288979376557721239239445613396009633263160237764653161500252258220144", + ) + .unwrap(), + Fp::from_str( + "13066591163578079667911016543985168493088721636164837520689376346534152547210", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "17345901407013599418148210465150865782628422047458024807490502489711252831342", + ) + .unwrap(), + Fp::from_str( + "22139633362249671900128029132387275539363684188353969065288495002671733200348", + ) + .unwrap(), + Fp::from_str( + "1061056418502836172283188490483332922126033656372467737207927075184389487061", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "10241738906190857416046229928455551829189196941239601756375665129874835232299", + ) + .unwrap(), + Fp::from_str( + "27808033332417845112292408673209999320983657696373938259351951416571545364415", + ) + .unwrap(), + Fp::from_str( + "18820154989873674261497645724903918046694142479240549687085662625471577737140", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "7983688435214640842673294735439196010654951226956101271763849527529940619307", + ) + .unwrap(), + Fp::from_str( + "17067928657801807648925755556866676899145460770352731818062909643149568271566", + ) + .unwrap(), + Fp::from_str( + "24472070825156236829515738091791182856425635433388202153358580534810244942762", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "25752201169361795911258625731016717414310986450004737514595241038036936283227", + ) + .unwrap(), + Fp::from_str( + "26041505376284666160132119888949817249574689146924196064963008712979256107535", + ) + .unwrap(), + Fp::from_str( + "23977050489096115210391718599021827780049209314283111721864956071820102846008", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "26678257097278788410676026718736087312816016749016738933942134600725962413805", + ) + .unwrap(), + Fp::from_str( + "10480026985951498884090911619636977502506079971893083605102044931823547311729", + ) + .unwrap(), + Fp::from_str( + "21126631300593007055117122830961273871167754554670317425822083333557535463396", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "1564862894215434177641156287699106659379648851457681469848362532131406827573", + ) + .unwrap(), + Fp::from_str( + "13247162472821152334486419054854847522301612781818744556576865965657773174584", + ) + .unwrap(), + Fp::from_str( + "8673615954922496961704442777870253767001276027366984739283715623634850885984", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "2794525076937490807476666942602262298677291735723129868457629508555429470085", + ) + .unwrap(), + Fp::from_str( + "4656175953888995612264371467596648522808911819700660048695373348629527757049", + ) + .unwrap(), + Fp::from_str( + "23221574237857660318443567292601561932489621919104226163978909845174616477329", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "1878392460078272317716114458784636517603142716091316893054365153068227117145", + ) + .unwrap(), + Fp::from_str( + "2370412714505757731457251173604396662292063533194555369091306667486647634097", + ) + .unwrap(), + Fp::from_str( + "17409784861870189930766639925394191888667317762328427589153989811980152373276", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "25869136641898166514111941708608048269584233242773814014385564101168774293194", + ) + .unwrap(), + Fp::from_str( + "11361209360311194794795494027949518465383235799633128250259863567683341091323", + ) + .unwrap(), + Fp::from_str( + "14913258820718821235077379851098720071902170702113538811112331615559409988569", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "12957012022018304419868287033513141736995211906682903915897515954290678373899", + ) + .unwrap(), + Fp::from_str( + "17128889547450684566010972445328859295804027707361763477802050112063630550300", + ) + .unwrap(), + Fp::from_str( + "23329219085372232771288306767242735245018143857623151155581182779769305489903", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "1607741027962933685476527275858938699728586794398382348454736018784568853937", + ) + .unwrap(), + Fp::from_str( + "2611953825405141009309433982109911976923326848135736099261873796908057448476", + ) + .unwrap(), + Fp::from_str( + "7372230383134982628913227482618052530364724821976589156840317933676130378411", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "20203606758501212620842735123770014952499754751430660463060696990317556818571", + ) + .unwrap(), + Fp::from_str( + "4678361398979174017885631008335559529633853759463947250620930343087749944307", + ) + .unwrap(), + Fp::from_str( + "27176462634198471376002287271754121925750749676999036165457559387195124025594", + ) + .unwrap(), + ], + vec![ + Fp::from_str( + "6361981813552614697928697527332318530502852015189048838072565811230204474643", + ) + .unwrap(), + Fp::from_str( + "13815234633287489023151647353581705241145927054858922281829444557905946323248", + ) + .unwrap(), + Fp::from_str( + "10888828634279127981352133512429657747610298502219125571406085952954136470354", + ) + .unwrap(), + ], + ], + } +} diff --git a/poseidon/src/lib.rs b/poseidon/src/lib.rs index 20d7ca4df8..943d54cb87 100644 --- a/poseidon/src/lib.rs +++ b/poseidon/src/lib.rs @@ -1,4 +1,5 @@ pub mod constants; +pub mod dummy_values; pub mod pasta; pub mod permutation; pub mod poseidon; From d86a6c05d47171a0797296dd948e6cd080023561 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 25 Jun 2023 18:08:37 +0100 Subject: [PATCH 091/242] Fixup failing test --- kimchi/src/tests/serde.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/kimchi/src/tests/serde.rs b/kimchi/src/tests/serde.rs index 4af830a041..43883066d9 100644 --- a/kimchi/src/tests/serde.rs +++ b/kimchi/src/tests/serde.rs @@ -81,6 +81,7 @@ mod tests { srs.add_lagrange_basis(verifier_index.domain); verifier_index_deserialize.powers_of_alpha = index.powers_of_alpha; verifier_index_deserialize.linearization = index.linearization; + verifier_index_deserialize.srs = std::sync::Arc::new(srs); // verify the proof let start = Instant::now(); From 6ee80e866b8e7a215979749b4d394a980e19ee2f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sun, 19 Feb 2023 00:24:39 +0000 Subject: [PATCH 092/242] Use the same cache for all constraints, to avoid accidental aliasing --- kimchi/src/circuits/argument.rs | 24 ++++++------ kimchi/src/circuits/gate.rs | 38 +++++++++++-------- .../src/circuits/polynomials/complete_add.rs | 4 +- .../circuits/polynomials/endomul_scalar.rs | 4 +- kimchi/src/circuits/polynomials/endosclmul.rs | 6 +-- .../foreign_field_add/circuitgates.rs | 7 +++- .../foreign_field_mul/circuitgates.rs | 4 +- .../polynomials/foreign_field_mul/gadget.rs | 14 ++++--- kimchi/src/circuits/polynomials/generic.rs | 4 +- kimchi/src/circuits/polynomials/poseidon.rs | 3 +- .../polynomials/range_check/circuitgates.rs | 9 +++-- .../polynomials/range_check/gadget.rs | 17 ++++++--- kimchi/src/circuits/polynomials/rot.rs | 7 +++- kimchi/src/circuits/polynomials/turshi.rs | 26 +++++++------ kimchi/src/circuits/polynomials/varbasemul.rs | 6 +-- kimchi/src/circuits/polynomials/xor.rs | 4 +- kimchi/src/linearization.rs | 31 +++++++++------ kimchi/src/prover.rs | 9 +++-- tools/kimchi-visu/src/lib.rs | 6 ++- 19 files changed, 129 insertions(+), 94 deletions(-) diff --git a/kimchi/src/circuits/argument.rs b/kimchi/src/circuits/argument.rs index de39c99916..22fd183081 100644 --- a/kimchi/src/circuits/argument.rs +++ b/kimchi/src/circuits/argument.rs @@ -11,7 +11,7 @@ use ark_ff::{Field, PrimeField}; use serde::{Deserialize, Serialize}; use super::{ - expr::{constraints::ExprOps, ConstantExpr, Constants}, + expr::{constraints::ExprOps, Cache, ConstantExpr, Constants}, gate::{CurrOrNext, GateType}, polynomial::COLUMNS, }; @@ -142,17 +142,17 @@ pub trait Argument { const CONSTRAINTS: u32; /// Constraints for this argument - fn constraint_checks>(env: &ArgumentEnv) -> Vec; + fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec; /// Returns the set of constraints required to prove this argument. - fn constraints() -> Vec> { + fn constraints(cache: &mut Cache) -> Vec> { // Generate constraints - Self::constraint_checks(&ArgumentEnv::default()) + Self::constraint_checks(&ArgumentEnv::default(), cache) } /// Returns constraints safely combined via the passed combinator. - fn combined_constraints(alphas: &Alphas) -> E { - let constraints = Self::constraints(); + fn combined_constraints(alphas: &Alphas, cache: &mut Cache) -> E { + let constraints = Self::constraints(cache); assert_eq!(constraints.len(), Self::CONSTRAINTS as usize); let alphas = alphas.get_exponents(Self::ARGUMENT_TYPE, Self::CONSTRAINTS); let combined_constraints = E::combine_constraints(alphas, constraints); @@ -168,17 +168,17 @@ pub trait Argument { } pub trait DynArgument { - fn constraints(&self) -> Vec>; - fn combined_constraints(&self, alphas: &Alphas) -> E; + fn constraints(&self, cache: &mut Cache) -> Vec>; + fn combined_constraints(&self, alphas: &Alphas, cache: &mut Cache) -> E; fn argument_type(&self) -> ArgumentType; } impl> DynArgument for T { - fn constraints(&self) -> Vec> { - >::constraints() + fn constraints(&self, cache: &mut Cache) -> Vec> { + >::constraints(cache) } - fn combined_constraints(&self, alphas: &Alphas) -> E { - >::combined_constraints(alphas) + fn combined_constraints(&self, alphas: &Alphas, cache: &mut Cache) -> E { + >::combined_constraints(alphas, cache) } fn argument_type(&self) -> ArgumentType { >::ARGUMENT_TYPE diff --git a/kimchi/src/circuits/gate.rs b/kimchi/src/circuits/gate.rs index f2a247851f..58a8309407 100644 --- a/kimchi/src/circuits/gate.rs +++ b/kimchi/src/circuits/gate.rs @@ -277,6 +277,8 @@ impl CircuitGate { } } + let mut cache = expr::Cache::default(); + // Perform witness verification on each constraint for this gate let results = match self.typ { GateType::Zero => { @@ -286,33 +288,39 @@ impl CircuitGate { // TODO: implement the verification for the generic gate vec![] } - GateType::Poseidon => poseidon::Poseidon::constraint_checks(&env), - GateType::CompleteAdd => complete_add::CompleteAdd::constraint_checks(&env), - GateType::VarBaseMul => varbasemul::VarbaseMul::constraint_checks(&env), - GateType::EndoMul => endosclmul::EndosclMul::constraint_checks(&env), - GateType::EndoMulScalar => endomul_scalar::EndomulScalar::constraint_checks(&env), + GateType::Poseidon => poseidon::Poseidon::constraint_checks(&env, &mut cache), + GateType::CompleteAdd => complete_add::CompleteAdd::constraint_checks(&env, &mut cache), + GateType::VarBaseMul => varbasemul::VarbaseMul::constraint_checks(&env, &mut cache), + GateType::EndoMul => endosclmul::EndosclMul::constraint_checks(&env, &mut cache), + GateType::EndoMulScalar => { + endomul_scalar::EndomulScalar::constraint_checks(&env, &mut cache) + } GateType::Lookup => { // TODO: implement the verification for the lookup gate vec![] } - GateType::CairoClaim => turshi::Claim::constraint_checks(&env), - GateType::CairoInstruction => turshi::Instruction::constraint_checks(&env), - GateType::CairoFlags => turshi::Flags::constraint_checks(&env), - GateType::CairoTransition => turshi::Transition::constraint_checks(&env), + GateType::CairoClaim => turshi::Claim::constraint_checks(&env, &mut cache), + GateType::CairoInstruction => turshi::Instruction::constraint_checks(&env, &mut cache), + GateType::CairoFlags => turshi::Flags::constraint_checks(&env, &mut cache), + GateType::CairoTransition => turshi::Transition::constraint_checks(&env, &mut cache), GateType::RangeCheck0 => { - range_check::circuitgates::RangeCheck0::constraint_checks(&env) + range_check::circuitgates::RangeCheck0::constraint_checks(&env, &mut cache) } GateType::RangeCheck1 => { - range_check::circuitgates::RangeCheck1::constraint_checks(&env) + range_check::circuitgates::RangeCheck1::constraint_checks(&env, &mut cache) } GateType::ForeignFieldAdd => { - foreign_field_add::circuitgates::ForeignFieldAdd::constraint_checks(&env) + foreign_field_add::circuitgates::ForeignFieldAdd::constraint_checks( + &env, &mut cache, + ) } GateType::ForeignFieldMul => { - foreign_field_mul::circuitgates::ForeignFieldMul::constraint_checks(&env) + foreign_field_mul::circuitgates::ForeignFieldMul::constraint_checks( + &env, &mut cache, + ) } - GateType::Xor16 => xor::Xor16::constraint_checks(&env), - GateType::Rot64 => rot::Rot64::constraint_checks(&env), + GateType::Xor16 => xor::Xor16::constraint_checks(&env, &mut cache), + GateType::Rot64 => rot::Rot64::constraint_checks(&env, &mut cache), }; // Check for failed constraints diff --git a/kimchi/src/circuits/polynomials/complete_add.rs b/kimchi/src/circuits/polynomials/complete_add.rs index c745498b30..015bbe2b22 100644 --- a/kimchi/src/circuits/polynomials/complete_add.rs +++ b/kimchi/src/circuits/polynomials/complete_add.rs @@ -98,7 +98,7 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::CompleteAdd); const CONSTRAINTS: u32 = 7; - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { // This function makes 2 + 1 + 1 + 1 + 2 = 7 constraints let x1 = env.witness_curr(0); let y1 = env.witness_curr(1); @@ -119,8 +119,6 @@ where // This variable is used to constrain same_x let x21_inv = env.witness_curr(10); - let mut cache = Cache::default(); - let x21 = cache.cache(x2.clone() - x1.clone()); let y21 = cache.cache(y2 - y1.clone()); diff --git a/kimchi/src/circuits/polynomials/endomul_scalar.rs b/kimchi/src/circuits/polynomials/endomul_scalar.rs index 18475278d7..701ce892bf 100644 --- a/kimchi/src/circuits/polynomials/endomul_scalar.rs +++ b/kimchi/src/circuits/polynomials/endomul_scalar.rs @@ -167,7 +167,7 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::EndoMulScalar); const CONSTRAINTS: u32 = 11; - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { let n0 = env.witness_curr(0); let n8 = env.witness_curr(1); let a0 = env.witness_curr(2); @@ -178,8 +178,6 @@ where // x0..x7 let xs: [_; 8] = array::from_fn(|i| env.witness_curr(6 + i)); - let mut cache = Cache::default(); - let c_coeffs = [ F::zero(), F::from(11u64) / F::from(6u64), diff --git a/kimchi/src/circuits/polynomials/endosclmul.rs b/kimchi/src/circuits/polynomials/endosclmul.rs index 8ddf04b95f..6dc41ba185 100644 --- a/kimchi/src/circuits/polynomials/endosclmul.rs +++ b/kimchi/src/circuits/polynomials/endosclmul.rs @@ -150,7 +150,7 @@ impl CircuitGate { let evals: ProofEvaluations> = ProofEvaluations::dummy_with_witness_evaluations(this, next); - let constraints = EndosclMul::constraints(); + let constraints = EndosclMul::constraints(&mut Cache::default()); for (i, c) in constraints.iter().enumerate() { match c.evaluate_(cs.domain.d1, pt, &evals, &constants) { Ok(x) => { @@ -185,7 +185,7 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::EndoMul); const CONSTRAINTS: u32 = 11; - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { let b1 = env.witness_curr(11); let b2 = env.witness_curr(12); let b3 = env.witness_curr(13); @@ -203,8 +203,6 @@ where let xr = env.witness_curr(7); let yr = env.witness_curr(8); - let mut cache = Cache::default(); - let s1 = env.witness_curr(9); let s3 = env.witness_curr(10); diff --git a/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs b/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs index 464ec849e9..cc25e60565 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs @@ -2,7 +2,10 @@ use crate::circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::constraints::{compact_limb, ExprOps}, + expr::{ + constraints::{compact_limb, ExprOps}, + Cache, + }, gate::GateType, }; use ark_ff::PrimeField; @@ -139,7 +142,7 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::ForeignFieldAdd); const CONSTRAINTS: u32 = 4; - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { let foreign_modulus: [T; LIMB_COUNT] = array::from_fn(|i| env.coeff(i)); // stored as coefficient for better correspondance with the relation being proved diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs index d2720f9ce6..a739857816 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs @@ -94,7 +94,7 @@ use crate::{ auto_clone_array, circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::constraints::ExprOps, + expr::{constraints::ExprOps, Cache}, gate::GateType, }, }; @@ -206,7 +206,7 @@ where const CONSTRAINTS: u32 = 9; // DEGREE is 4 - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { let mut constraints = vec![]; // diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs index c8d291e2fe..f5f4508dab 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs @@ -8,7 +8,7 @@ use crate::{ alphas::Alphas, circuits::{ argument::Argument, - expr::E, + expr::{Cache, E}, gate::{CircuitGate, GateType}, lookup::{ self, @@ -80,9 +80,13 @@ pub fn circuit_gates() -> [GateType; GATE_COUNT] { } /// Get combined constraints for a given foreign field multiplication circuit gate -pub fn circuit_gate_constraints(typ: GateType, alphas: &Alphas) -> E { +pub fn circuit_gate_constraints( + typ: GateType, + alphas: &Alphas, + cache: &mut Cache, +) -> E { match typ { - GateType::ForeignFieldMul => ForeignFieldMul::combined_constraints(alphas), + GateType::ForeignFieldMul => ForeignFieldMul::combined_constraints(alphas, cache), _ => panic!("invalid gate type"), } } @@ -96,8 +100,8 @@ pub fn circuit_gate_constraint_count(typ: GateType) -> u32 { } /// Get the combined constraints for all foreign field multiplication circuit gates -pub fn combined_constraints(alphas: &Alphas) -> E { - ForeignFieldMul::combined_constraints(alphas) +pub fn combined_constraints(alphas: &Alphas, cache: &mut Cache) -> E { + ForeignFieldMul::combined_constraints(alphas, cache) } /// Get the foreign field multiplication lookup table diff --git a/kimchi/src/circuits/polynomials/generic.rs b/kimchi/src/circuits/polynomials/generic.rs index 4ac0e32dd8..e535db8dab 100644 --- a/kimchi/src/circuits/polynomials/generic.rs +++ b/kimchi/src/circuits/polynomials/generic.rs @@ -35,7 +35,7 @@ use crate::circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::constraints::ExprOps, + expr::{constraints::ExprOps, Cache}, gate::{CircuitGate, GateType}, polynomial::COLUMNS, wires::GateWires, @@ -74,7 +74,7 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::Generic); const CONSTRAINTS: u32 = 2; - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { // First generic gate let left_coeff1 = env.coeff(0); let right_coeff1 = env.coeff(1); diff --git a/kimchi/src/circuits/polynomials/poseidon.rs b/kimchi/src/circuits/polynomials/poseidon.rs index b620583435..c587c506e8 100644 --- a/kimchi/src/circuits/polynomials/poseidon.rs +++ b/kimchi/src/circuits/polynomials/poseidon.rs @@ -339,9 +339,8 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::Poseidon); const CONSTRAINTS: u32 = 15; - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { let mut res = vec![]; - let mut cache = Cache::default(); let mut idx = 0; diff --git a/kimchi/src/circuits/polynomials/range_check/circuitgates.rs b/kimchi/src/circuits/polynomials/range_check/circuitgates.rs index 4575cd0ab4..fd56e6514f 100644 --- a/kimchi/src/circuits/polynomials/range_check/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/range_check/circuitgates.rs @@ -118,7 +118,10 @@ use std::marker::PhantomData; use crate::circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::constraints::{crumb, ExprOps}, + expr::{ + constraints::{crumb, ExprOps}, + Cache, + }, gate::GateType, polynomial::COLUMNS, }; @@ -175,7 +178,7 @@ where // * Operates on Curr row // * Range constrain all limbs except vp0 and vp1 (barring plookup constraints, which are done elsewhere) // * Constrain that combining all limbs equals the limb stored in column 0 - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { // 1) Apply range constraints on the limbs // * Columns 1-2 are 12-bit copy constraints // * They are copied 3 rows ahead (to the final row) and are constrained by lookups @@ -276,7 +279,7 @@ where // * Operates on Curr and Next row // * Range constrain all limbs (barring plookup constraints, which are done elsewhere) // * Constrain that combining all limbs equals the value v2 stored in row Curr, column 0 - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { // 1) Apply range constraints on limbs for Curr row // * Column 2 is a 2-bit crumb let mut constraints = vec![crumb(&env.witness_curr(2))]; diff --git a/kimchi/src/circuits/polynomials/range_check/gadget.rs b/kimchi/src/circuits/polynomials/range_check/gadget.rs index ab91133e42..f8d3d6e696 100644 --- a/kimchi/src/circuits/polynomials/range_check/gadget.rs +++ b/kimchi/src/circuits/polynomials/range_check/gadget.rs @@ -6,7 +6,7 @@ use crate::{ alphas::Alphas, circuits::{ argument::Argument, - expr::E, + expr::{Cache, E}, gate::{CircuitGate, Connect, GateType}, lookup::{ self, @@ -136,17 +136,22 @@ pub fn circuit_gate_constraint_count(typ: GateType) -> u32 { /// # Panics /// /// Will panic if `typ` is not `RangeCheck`-related gate type. -pub fn circuit_gate_constraints(typ: GateType, alphas: &Alphas) -> E { +pub fn circuit_gate_constraints( + typ: GateType, + alphas: &Alphas, + cache: &mut Cache, +) -> E { match typ { - GateType::RangeCheck0 => RangeCheck0::combined_constraints(alphas), - GateType::RangeCheck1 => RangeCheck1::combined_constraints(alphas), + GateType::RangeCheck0 => RangeCheck0::combined_constraints(alphas, cache), + GateType::RangeCheck1 => RangeCheck1::combined_constraints(alphas, cache), _ => panic!("invalid gate type"), } } /// Get the combined constraints for all range check circuit gate types -pub fn combined_constraints(alphas: &Alphas) -> E { - RangeCheck0::combined_constraints(alphas) + RangeCheck1::combined_constraints(alphas) +pub fn combined_constraints(alphas: &Alphas, cache: &mut Cache) -> E { + RangeCheck0::combined_constraints(alphas, cache) + + RangeCheck1::combined_constraints(alphas, cache) } /// Get the range check lookup table diff --git a/kimchi/src/circuits/polynomials/rot.rs b/kimchi/src/circuits/polynomials/rot.rs index d42f60a6d3..80c4022d41 100644 --- a/kimchi/src/circuits/polynomials/rot.rs +++ b/kimchi/src/circuits/polynomials/rot.rs @@ -4,7 +4,10 @@ use super::range_check::witness::range_check_0_row; use crate::{ circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::constraints::{crumb, ExprOps}, + expr::{ + constraints::{crumb, ExprOps}, + Cache, + }, gate::{CircuitGate, Connect, GateType}, lookup::{ self, @@ -198,7 +201,7 @@ where // (stored in coefficient as a power-of-two form) // * Operates on Curr row // * Shifts the words by `rot` bits and then adds the excess to obtain the rotated word. - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { // Check that the last 8 columns are 2-bit crumbs // C1..C8: x * (x - 1) * (x - 2) * (x - 3) = 0 let mut constraints = (7..COLUMNS) diff --git a/kimchi/src/circuits/polynomials/turshi.rs b/kimchi/src/circuits/polynomials/turshi.rs index 41a5e6de85..f038b24aa0 100644 --- a/kimchi/src/circuits/polynomials/turshi.rs +++ b/kimchi/src/circuits/polynomials/turshi.rs @@ -208,7 +208,8 @@ impl CircuitGate { alphas.register(ArgumentType::Gate(self.typ), Instruction::::CONSTRAINTS); // Get constraints for this circuit gate - let constraints = circuit_gate_combined_constraints(self.typ, &alphas); + let constraints = + circuit_gate_combined_constraints(self.typ, &alphas, &mut Cache::default()); // Linearize let linearized = constraints.linearize(polys).unwrap(); @@ -737,12 +738,16 @@ fn two>() -> T { /// # Panics /// /// Will panic if the `typ` is not `Cairo`-related gate type or `zero` gate type. -pub fn circuit_gate_combined_constraints(typ: GateType, alphas: &Alphas) -> E { +pub fn circuit_gate_combined_constraints( + typ: GateType, + alphas: &Alphas, + cache: &mut Cache, +) -> E { match typ { - GateType::CairoClaim => Claim::combined_constraints(alphas), - GateType::CairoInstruction => Instruction::combined_constraints(alphas), - GateType::CairoFlags => Flags::combined_constraints(alphas), - GateType::CairoTransition => Transition::combined_constraints(alphas), + GateType::CairoClaim => Claim::combined_constraints(alphas, cache), + GateType::CairoInstruction => Instruction::combined_constraints(alphas, cache), + GateType::CairoFlags => Flags::combined_constraints(alphas, cache), + GateType::CairoTransition => Transition::combined_constraints(alphas, cache), GateType::Zero => E::literal(F::zero()), _ => panic!("invalid gate type"), } @@ -759,7 +764,7 @@ where /// Generates the constraints for the Cairo initial claim and first memory checks /// Accesses Curr and Next rows - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { let pc_ini = env.witness_curr(0); // copy from public input let ap_ini = env.witness_curr(1); // copy from public input let pc_fin = env.witness_curr(2); // copy from public input @@ -796,7 +801,7 @@ where /// Generates the constraints for the Cairo instruction /// Accesses Curr and Next rows - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { // load all variables of the witness corresponding to Cairoinstruction gates let pc = env.witness_curr(0); let ap = env.witness_curr(1); @@ -836,7 +841,6 @@ where // LIST OF CONSTRAINTS // ------------------- let mut constraints: Vec = vec![]; - let mut cache = Cache::default(); // INSTRUCTIONS RELATED @@ -943,7 +947,7 @@ where /// Generates the constraints for the Cairo flags /// Accesses Curr and Next rows - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { // Load current row let f_pc_abs = env.witness_curr(7); let f_pc_rel = env.witness_curr(8); @@ -1010,7 +1014,7 @@ where /// Generates the constraints for the Cairo transition /// Accesses Curr and Next rows (Next only first 3 entries) - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { // load computed updated registers let pcup = env.witness_curr(7); let apup = env.witness_curr(8); diff --git a/kimchi/src/circuits/polynomials/varbasemul.rs b/kimchi/src/circuits/polynomials/varbasemul.rs index 9e71332a26..22b9522195 100644 --- a/kimchi/src/circuits/polynomials/varbasemul.rs +++ b/kimchi/src/circuits/polynomials/varbasemul.rs @@ -407,7 +407,7 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::VarBaseMul); const CONSTRAINTS: u32 = 21; - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { let Layout { base, accs, @@ -417,8 +417,6 @@ where n_next, } = Layout::create().new_from_env::(env); - let mut c = Cache::default(); - // n' // = 2^5 * n + 2^4 b0 + 2^3 b1 + 2^2 b2 + 2^1 b3 + b4 // = b4 + 2 (b3 + 2 (b2 + 2 (b1 + 2(b0 + 2 n)))) @@ -427,7 +425,7 @@ where for i in 0..5 { res.append(&mut single_bit( - &mut c, + cache, &bits[i], base.clone(), &ss[i], diff --git a/kimchi/src/circuits/polynomials/xor.rs b/kimchi/src/circuits/polynomials/xor.rs index 110f6bd5af..ea5fbc2cbd 100644 --- a/kimchi/src/circuits/polynomials/xor.rs +++ b/kimchi/src/circuits/polynomials/xor.rs @@ -4,7 +4,7 @@ use crate::{ circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::constraints::ExprOps, + expr::{constraints::ExprOps, Cache}, gate::{CircuitGate, Connect, GateType}, lookup::{ self, @@ -150,7 +150,7 @@ where // * Operates on Curr and Next rows // * Constrain the decomposition of `in1`, `in2` and `out` of multiples of 16 bits // * The actual XOR is performed thanks to the plookups of 4-bit XORs. - fn constraint_checks>(env: &ArgumentEnv) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { let two = T::from(2u64); // in1 = in1_0 + in1_1 * 2^4 + in1_2 * 2^8 + in1_3 * 2^12 + next_in1 * 2^16 // in2 = in2_0 + in2_1 * 2^4 + in2_2 * 2^8 + in2_3 * 2^12 + next_in2 * 2^16 diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 76e33efa96..ec42689059 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -2,6 +2,7 @@ use crate::alphas::Alphas; use crate::circuits::argument::{Argument, ArgumentType}; +use crate::circuits::expr; use crate::circuits::lookup; use crate::circuits::lookup::{ constraints::LookupConfiguration, @@ -48,14 +49,17 @@ pub fn constraints_expr( VarbaseMul::::CONSTRAINTS, ); - let mut expr = Poseidon::combined_constraints(&powers_of_alpha); - expr += VarbaseMul::combined_constraints(&powers_of_alpha); - expr += CompleteAdd::combined_constraints(&powers_of_alpha); - expr += EndosclMul::combined_constraints(&powers_of_alpha); - expr += EndomulScalar::combined_constraints(&powers_of_alpha); + let mut cache = expr::Cache::default(); + + let mut expr = Poseidon::combined_constraints(&powers_of_alpha, &mut cache); + expr += VarbaseMul::combined_constraints(&powers_of_alpha, &mut cache); + expr += CompleteAdd::combined_constraints(&powers_of_alpha, &mut cache); + expr += EndosclMul::combined_constraints(&powers_of_alpha, &mut cache); + expr += EndomulScalar::combined_constraints(&powers_of_alpha, &mut cache); { - let range_check0_expr = || RangeCheck0::combined_constraints(&powers_of_alpha); + let mut range_check0_expr = + || RangeCheck0::combined_constraints(&powers_of_alpha, &mut cache); if let Some(feature_flags) = feature_flags { if feature_flags.range_check0 { @@ -71,7 +75,8 @@ pub fn constraints_expr( } { - let range_check1_expr = || RangeCheck1::combined_constraints(&powers_of_alpha); + let mut range_check1_expr = + || RangeCheck1::combined_constraints(&powers_of_alpha, &mut cache); if let Some(feature_flags) = feature_flags { if feature_flags.range_check1 { @@ -87,7 +92,8 @@ pub fn constraints_expr( } { - let foreign_field_add_expr = || ForeignFieldAdd::combined_constraints(&powers_of_alpha); + let mut foreign_field_add_expr = + || ForeignFieldAdd::combined_constraints(&powers_of_alpha, &mut cache); if let Some(feature_flags) = feature_flags { if feature_flags.foreign_field_add { expr += foreign_field_add_expr(); @@ -102,7 +108,8 @@ pub fn constraints_expr( } { - let foreign_field_mul_expr = || ForeignFieldMul::combined_constraints(&powers_of_alpha); + let mut foreign_field_mul_expr = + || ForeignFieldMul::combined_constraints(&powers_of_alpha, &mut cache); if let Some(feature_flags) = feature_flags { if feature_flags.foreign_field_mul { expr += foreign_field_mul_expr(); @@ -117,7 +124,7 @@ pub fn constraints_expr( } { - let xor_expr = || xor::Xor16::combined_constraints(&powers_of_alpha); + let mut xor_expr = || xor::Xor16::combined_constraints(&powers_of_alpha, &mut cache); if let Some(feature_flags) = feature_flags { if feature_flags.xor { expr += xor_expr(); @@ -132,7 +139,7 @@ pub fn constraints_expr( } { - let rot_expr = || rot::Rot64::combined_constraints(&powers_of_alpha); + let mut rot_expr = || rot::Rot64::combined_constraints(&powers_of_alpha, &mut cache); if let Some(feature_flags) = feature_flags { if feature_flags.rot { expr += rot_expr(); @@ -147,7 +154,7 @@ pub fn constraints_expr( } if generic { - expr += generic::Generic::combined_constraints(&powers_of_alpha); + expr += generic::Generic::combined_constraints(&powers_of_alpha, &mut cache); } // permutation diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 9ff74d8f20..c450c50f9d 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -3,7 +3,7 @@ use crate::{ circuits::{ argument::{Argument, ArgumentType}, - expr::{l0_1, Constants, Environment, LookupEnvironment}, + expr::{self, l0_1, Constants, Environment, LookupEnvironment}, gate::GateType, lookup::{self, runtime_tables::RuntimeTable, tables::combine_table_entry}, polynomials::{ @@ -675,10 +675,13 @@ where } }; + let mut cache = expr::Cache::default(); + let quotient_poly = { // generic let mut t4 = { - let generic_constraint = generic::Generic::combined_constraints(&all_alphas); + let generic_constraint = + generic::Generic::combined_constraints(&all_alphas, &mut cache); let generic4 = generic_constraint.evaluations(&env); if cfg!(debug_assertions) { @@ -746,7 +749,7 @@ where .into_iter() .filter_map(|(gate, is_enabled)| if is_enabled { Some(gate) } else { None }) { - let constraint = gate.combined_constraints(&all_alphas); + let constraint = gate.combined_constraints(&all_alphas, &mut cache); let eval = constraint.evaluations(&env); if eval.domain().size == t4.domain().size { t4 += &eval; diff --git a/tools/kimchi-visu/src/lib.rs b/tools/kimchi-visu/src/lib.rs index 4fea2ffcae..dd917dea43 100644 --- a/tools/kimchi-visu/src/lib.rs +++ b/tools/kimchi-visu/src/lib.rs @@ -4,6 +4,7 @@ use ark_ff::PrimeField; use kimchi::{ circuits::{ argument::Argument, + expr, polynomials::{ complete_add::CompleteAdd, endomul_scalar::EndomulScalar, endosclmul::EndosclMul, poseidon::Poseidon, varbasemul::VarbaseMul, @@ -40,7 +41,10 @@ where F: PrimeField, { fn latex() -> Vec> { - Self::constraints().iter().map(|c| c.latex_str()).collect() + Self::constraints(&mut expr::Cache::default()) + .iter() + .map(|c| c.latex_str()) + .collect() } } From 545292cd7ab3ee7fb52686c9f2818d8f7050f0ba Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 26 Jun 2023 00:58:52 +0100 Subject: [PATCH 093/242] Evaluate selectors for non-optional gates --- book/src/specs/kimchi.md | 8 +++++ kimchi/src/plonk_sponge.rs | 14 ++++++++- kimchi/src/proof.rs | 64 ++++++++++++++++++++++++++++++++++++++ kimchi/src/prover.rs | 28 +++++++++++++++++ kimchi/src/verifier.rs | 16 ++++++++++ 5 files changed, 129 insertions(+), 1 deletion(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 1852146616..74371190c8 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1969,6 +1969,14 @@ pub struct ProofEvaluations { pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial pub poseidon_selector: Evals, + /// evaluation of the EC addition selector polynomial + pub complete_add_selector: Evals, + /// evaluation of the EC variable base scalar multiplication selector polynomial + pub mul_selector: Evals, + /// evaluation of the endoscalar multiplication selector polynomial + pub emul_selector: Evals, + /// evaluation of the endoscalar multiplication scalar computation selector polynomial + pub endomul_scalar_selector: Evals, } /// Commitments linked to the lookup feature diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index da54379f4d..b8c6fbcd77 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -67,9 +67,21 @@ impl FrSponge for DefaultFrSponge { lookup, generic_selector, poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, } = e; - let mut points = vec![z, generic_selector, poseidon_selector]; + let mut points = vec![ + z, + generic_selector, + poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, + ]; w.iter().for_each(|w_i| points.push(w_i)); coefficients.iter().for_each(|c_i| points.push(c_i)); s.iter().for_each(|s_i| points.push(s_i)); diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index d335a5bfed..2979043924 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -76,6 +76,14 @@ pub struct ProofEvaluations { pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial pub poseidon_selector: Evals, + /// evaluation of the EC addition selector polynomial + pub complete_add_selector: Evals, + /// evaluation of the EC variable base scalar multiplication selector polynomial + pub mul_selector: Evals, + /// evaluation of the endoscalar multiplication selector polynomial + pub emul_selector: Evals, + /// evaluation of the endoscalar multiplication scalar computation selector polynomial + pub endomul_scalar_selector: Evals, } /// Commitments linked to the lookup feature @@ -205,6 +213,10 @@ impl ProofEvaluations { lookup, generic_selector, poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, } = self; ProofEvaluations { w: w.map(f), @@ -214,6 +226,10 @@ impl ProofEvaluations { lookup: lookup.map(|x| LookupEvaluations::map(x, f)), generic_selector: f(generic_selector), poseidon_selector: f(poseidon_selector), + complete_add_selector: f(complete_add_selector), + mul_selector: f(mul_selector), + emul_selector: f(emul_selector), + endomul_scalar_selector: f(endomul_scalar_selector), } } @@ -226,6 +242,10 @@ impl ProofEvaluations { lookup, generic_selector, poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, } = self; ProofEvaluations { w: [ @@ -267,6 +287,10 @@ impl ProofEvaluations { lookup: lookup.as_ref().map(|l| l.map_ref(f)), generic_selector: f(generic_selector), poseidon_selector: f(poseidon_selector), + complete_add_selector: f(complete_add_selector), + mul_selector: f(mul_selector), + emul_selector: f(emul_selector), + endomul_scalar_selector: f(endomul_scalar_selector), } } } @@ -289,6 +313,10 @@ impl ProofEvaluations { ProofEvaluations { generic_selector: array::from_fn(|i| &evals[i].generic_selector), poseidon_selector: array::from_fn(|i| &evals[i].poseidon_selector), + complete_add_selector: array::from_fn(|i| &evals[i].complete_add_selector), + mul_selector: array::from_fn(|i| &evals[i].mul_selector), + emul_selector: array::from_fn(|i| &evals[i].emul_selector), + endomul_scalar_selector: array::from_fn(|i| &evals[i].endomul_scalar_selector), z: array::from_fn(|i| &evals[i].z), w: array::from_fn(|j| array::from_fn(|i| &evals[i].w[j])), s: array::from_fn(|j| array::from_fn(|i| &evals[i].s[j])), @@ -380,6 +408,10 @@ impl ProofEvaluations> { lookup: None, generic_selector: pt(F::zero(), F::zero()), poseidon_selector: pt(F::zero(), F::zero()), + complete_add_selector: pt(F::zero(), F::zero()), + mul_selector: pt(F::zero(), F::zero()), + emul_selector: pt(F::zero(), F::zero()), + endomul_scalar_selector: pt(F::zero(), F::zero()), } } } @@ -406,6 +438,10 @@ impl ProofEvaluations { Column::LookupRuntimeTable => Some(self.lookup.as_ref()?.runtime.as_ref()?), Column::Index(GateType::Generic) => Some(&self.generic_selector), Column::Index(GateType::Poseidon) => Some(&self.poseidon_selector), + Column::Index(GateType::CompleteAdd) => Some(&self.complete_add_selector), + Column::Index(GateType::VarBaseMul) => Some(&self.mul_selector), + Column::Index(GateType::EndoMul) => Some(&self.emul_selector), + Column::Index(GateType::EndoMulScalar) => Some(&self.endomul_scalar_selector), Column::Index(_) => None, Column::Coefficient(i) => Some(&self.coefficients[i]), Column::Permutation(i) => Some(&self.s[i]), @@ -570,6 +606,10 @@ pub mod caml { pub generic_selector: PointEvaluations>, pub poseidon_selector: PointEvaluations>, + pub complete_add_selector: PointEvaluations>, + pub mul_selector: PointEvaluations>, + pub emul_selector: PointEvaluations>, + pub endomul_scalar_selector: PointEvaluations>, } // @@ -708,6 +748,18 @@ pub mod caml { poseidon_selector: pe .poseidon_selector .map(&|x| x.into_iter().map(Into::into).collect()), + complete_add_selector: pe + .complete_add_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + mul_selector: pe + .mul_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + emul_selector: pe + .emul_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + endomul_scalar_selector: pe + .endomul_scalar_selector + .map(&|x| x.into_iter().map(Into::into).collect()), lookup: pe.lookup.map(Into::into), } } @@ -803,6 +855,18 @@ pub mod caml { poseidon_selector: cpe .poseidon_selector .map(&|x| x.into_iter().map(Into::into).collect()), + complete_add_selector: cpe + .complete_add_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + mul_selector: cpe + .mul_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + emul_selector: cpe + .emul_selector + .map(&|x| x.into_iter().map(Into::into).collect()), + endomul_scalar_selector: cpe + .endomul_scalar_selector + .map(&|x| x.into_iter().map(Into::into).collect()), lookup: cpe.lookup.map(Into::into), } } diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index c450c50f9d..8645c7e187 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -957,6 +957,14 @@ where poseidon_selector: chunked_evals_for_selector( &index.column_evaluations.poseidon_selector8, ), + complete_add_selector: chunked_evals_for_selector( + &index.column_evaluations.complete_add_selector4, + ), + mul_selector: chunked_evals_for_selector(&index.column_evaluations.mul_selector8), + emul_selector: chunked_evals_for_selector(&index.column_evaluations.emul_selector8), + endomul_scalar_selector: chunked_evals_for_selector( + &index.column_evaluations.endomul_scalar_selector8, + ), }; let zeta_to_srs_len = zeta.pow([index.max_poly_size as u64]); @@ -1135,6 +1143,26 @@ where None, fixed_hiding(1), )); + polynomials.push(( + evaluations_form(&index.column_evaluations.complete_add_selector4), + None, + non_hiding(1), + )); + polynomials.push(( + evaluations_form(&index.column_evaluations.mul_selector8), + None, + non_hiding(1), + )); + polynomials.push(( + evaluations_form(&index.column_evaluations.emul_selector8), + None, + non_hiding(1), + )); + polynomials.push(( + evaluations_form(&index.column_evaluations.endomul_scalar_selector8), + None, + non_hiding(1), + )); polynomials.extend( witness_poly .iter() diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index c2796fccca..7dc2b714f8 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -428,6 +428,10 @@ where Column::Z, Column::Index(GateType::Generic), Column::Index(GateType::Poseidon), + Column::Index(GateType::CompleteAdd), + Column::Index(GateType::VarBaseMul), + Column::Index(GateType::EndoMul), + Column::Index(GateType::EndoMulScalar), ] .into_iter() .chain((0..COLUMNS).map(Column::Witness)) @@ -512,6 +516,10 @@ where lookup, generic_selector, poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, } = &proof.evals; let check_eval_len = |eval: &PointEvaluations>| -> Result<()> { @@ -550,6 +558,10 @@ where } check_eval_len(generic_selector)?; check_eval_len(poseidon_selector)?; + check_eval_len(complete_add_selector)?; + check_eval_len(mul_selector)?; + check_eval_len(emul_selector)?; + check_eval_len(endomul_scalar_selector)?; Ok(()) } @@ -740,6 +752,10 @@ where //~~ * index commitments that use the coefficients Column::Index(GateType::Generic), Column::Index(GateType::Poseidon), + Column::Index(GateType::CompleteAdd), + Column::Index(GateType::VarBaseMul), + Column::Index(GateType::EndoMul), + Column::Index(GateType::EndoMulScalar), ] .into_iter() //~~ * witness commitments From 499c7f39934510ec2daa7ce1e7290b3ae3b3f9b9 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 26 Jun 2023 02:02:50 +0100 Subject: [PATCH 094/242] Remove evaluated columns from linearization --- kimchi/src/circuits/expr.rs | 4 ++++ kimchi/src/linearization.rs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 9f084f6903..c83749e507 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -675,6 +675,10 @@ impl Variable { LookupRuntimeTable => l.and_then(|l| l.runtime.ok_or(ExprError::MissingRuntime)), Index(GateType::Poseidon) => Ok(evals.poseidon_selector), Index(GateType::Generic) => Ok(evals.generic_selector), + Index(GateType::CompleteAdd) => Ok(evals.complete_add_selector), + Index(GateType::VarBaseMul) => Ok(evals.mul_selector), + Index(GateType::EndoMul) => Ok(evals.emul_selector), + Index(GateType::EndoMulScalar) => Ok(evals.endomul_scalar_selector), Permutation(i) => Ok(evals.s[i]), Coefficient(i) => Ok(evals.coefficients[i]), LookupKindIndex(_) | LookupRuntimeSelector | Index(_) => { diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index ec42689059..472b878a1b 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -305,6 +305,11 @@ pub fn linearization_columns( // the generic selector polynomial h.insert(Index(GateType::Generic)); + h.insert(Index(GateType::CompleteAdd)); + h.insert(Index(GateType::VarBaseMul)); + h.insert(Index(GateType::EndoMul)); + h.insert(Index(GateType::EndoMulScalar)); + h } From e6219d2b56181acaa58d221c38c9d95588c30ee6 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 26 Jun 2023 02:53:22 +0100 Subject: [PATCH 095/242] Fixed hiding for selectors --- kimchi/src/prover.rs | 8 ++++---- kimchi/src/verifier_index.rs | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 8645c7e187..986b23e7ff 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1146,22 +1146,22 @@ where polynomials.push(( evaluations_form(&index.column_evaluations.complete_add_selector4), None, - non_hiding(1), + fixed_hiding(1), )); polynomials.push(( evaluations_form(&index.column_evaluations.mul_selector8), None, - non_hiding(1), + fixed_hiding(1), )); polynomials.push(( evaluations_form(&index.column_evaluations.emul_selector8), None, - non_hiding(1), + fixed_hiding(1), )); polynomials.push(( evaluations_form(&index.column_evaluations.endomul_scalar_selector8), None, - non_hiding(1), + fixed_hiding(1), )); polynomials.extend( witness_poly diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 1163885f0d..9e3651ed4b 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -233,21 +233,23 @@ impl ProverIndex { &self.column_evaluations.poseidon_selector8, )), - complete_add_comm: self.srs.commit_evaluations_non_hiding( + complete_add_comm: mask_fixed(self.srs.commit_evaluations_non_hiding( domain, &self.column_evaluations.complete_add_selector4, + )), + mul_comm: mask_fixed( + self.srs + .commit_evaluations_non_hiding(domain, &self.column_evaluations.mul_selector8), + ), + emul_comm: mask_fixed( + self.srs + .commit_evaluations_non_hiding(domain, &self.column_evaluations.emul_selector8), ), - mul_comm: self - .srs - .commit_evaluations_non_hiding(domain, &self.column_evaluations.mul_selector8), - emul_comm: self - .srs - .commit_evaluations_non_hiding(domain, &self.column_evaluations.emul_selector8), - endomul_scalar_comm: self.srs.commit_evaluations_non_hiding( + endomul_scalar_comm: mask_fixed(self.srs.commit_evaluations_non_hiding( domain, &self.column_evaluations.endomul_scalar_selector8, - ), + )), range_check0_comm: self .column_evaluations From f896881679f0dee46c7b1d4bf50a4dfbf3559eea Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 26 Jun 2023 03:13:03 +0100 Subject: [PATCH 096/242] Delete unused transpose function --- kimchi/src/proof.rs | 49 --------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 2979043924..44e7c898c8 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -295,55 +295,6 @@ impl ProofEvaluations { } } -impl ProofEvaluations { - /// Transpose the `ProofEvaluations`. - /// - /// # Panics - /// - /// Will panic if `ProofEvaluation` is None. - pub fn transpose( - evals: [&ProofEvaluations; N], - ) -> ProofEvaluations<[&F; N]> { - let has_lookup = evals.iter().all(|e| e.lookup.is_some()); - let has_runtime = has_lookup - && evals - .iter() - .all(|e| e.lookup.as_ref().unwrap().runtime.is_some()); - - ProofEvaluations { - generic_selector: array::from_fn(|i| &evals[i].generic_selector), - poseidon_selector: array::from_fn(|i| &evals[i].poseidon_selector), - complete_add_selector: array::from_fn(|i| &evals[i].complete_add_selector), - mul_selector: array::from_fn(|i| &evals[i].mul_selector), - emul_selector: array::from_fn(|i| &evals[i].emul_selector), - endomul_scalar_selector: array::from_fn(|i| &evals[i].endomul_scalar_selector), - z: array::from_fn(|i| &evals[i].z), - w: array::from_fn(|j| array::from_fn(|i| &evals[i].w[j])), - s: array::from_fn(|j| array::from_fn(|i| &evals[i].s[j])), - coefficients: array::from_fn(|j| array::from_fn(|i| &evals[i].coefficients[j])), - lookup: if has_lookup { - let sorted_length = evals[0].lookup.as_ref().unwrap().sorted.len(); - Some(LookupEvaluations { - aggreg: array::from_fn(|i| &evals[i].lookup.as_ref().unwrap().aggreg), - table: array::from_fn(|i| &evals[i].lookup.as_ref().unwrap().table), - sorted: (0..sorted_length) - .map(|j| array::from_fn(|i| &evals[i].lookup.as_ref().unwrap().sorted[j])) - .collect(), - runtime: if has_runtime { - Some(array::from_fn(|i| { - evals[i].lookup.as_ref().unwrap().runtime.as_ref().unwrap() - })) - } else { - None - }, - }) - } else { - None - }, - } - } -} - impl RecursionChallenge { pub fn new(chals: Vec, comm: PolyComm) -> RecursionChallenge { RecursionChallenge { chals, comm } From 6f26d039086d83459e462f58727695d3a9eb2523 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 26 Jun 2023 03:13:51 +0100 Subject: [PATCH 097/242] Add evaluation for optional gate selectors --- book/src/specs/kimchi.md | 14 ++++++ kimchi/src/plonk_sponge.rs | 27 ++++++++++++ kimchi/src/proof.rs | 87 ++++++++++++++++++++++++++++++++++++++ kimchi/src/prover.rs | 31 ++++++++++++++ kimchi/src/verifier.rs | 27 ++++++++++++ 5 files changed, 186 insertions(+) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 74371190c8..d7d3b6dee5 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1977,6 +1977,20 @@ pub struct ProofEvaluations { pub emul_selector: Evals, /// evaluation of the endoscalar multiplication scalar computation selector polynomial pub endomul_scalar_selector: Evals, + + // Optional gates + /// evaluation of the RangeCheck0 selector polynomial + pub range_check0_selector: Option, + /// evaluation of the RangeCheck1 selector polynomial + pub range_check1_selector: Option, + /// evaluation of the ForeignFieldAdd selector polynomial + pub foreign_field_add_selector: Option, + /// evaluation of the ForeignFieldMul selector polynomial + pub foreign_field_mul_selector: Option, + /// evaluation of the Xor selector polynomial + pub xor_selector: Option, + /// evaluation of the Rot selector polynomial + pub rot_selector: Option, } /// Commitments linked to the lookup feature diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index b8c6fbcd77..a5a9e4ac23 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -71,6 +71,12 @@ impl FrSponge for DefaultFrSponge { mul_selector, emul_selector, endomul_scalar_selector, + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, } = e; let mut points = vec![ @@ -86,6 +92,27 @@ impl FrSponge for DefaultFrSponge { coefficients.iter().for_each(|c_i| points.push(c_i)); s.iter().for_each(|s_i| points.push(s_i)); + // Optional gates + + if let Some(range_check0_selector) = range_check0_selector.as_ref() { + points.push(range_check0_selector) + } + if let Some(range_check1_selector) = range_check1_selector.as_ref() { + points.push(range_check1_selector) + } + if let Some(foreign_field_add_selector) = foreign_field_add_selector.as_ref() { + points.push(foreign_field_add_selector) + } + if let Some(foreign_field_mul_selector) = foreign_field_mul_selector.as_ref() { + points.push(foreign_field_mul_selector) + } + if let Some(xor_selector) = xor_selector.as_ref() { + points.push(xor_selector) + } + if let Some(rot_selector) = rot_selector.as_ref() { + points.push(rot_selector) + } + if let Some(l) = lookup.as_ref() { let LookupEvaluations { sorted, diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 44e7c898c8..680289c30d 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -84,6 +84,20 @@ pub struct ProofEvaluations { pub emul_selector: Evals, /// evaluation of the endoscalar multiplication scalar computation selector polynomial pub endomul_scalar_selector: Evals, + + // Optional gates + /// evaluation of the RangeCheck0 selector polynomial + pub range_check0_selector: Option, + /// evaluation of the RangeCheck1 selector polynomial + pub range_check1_selector: Option, + /// evaluation of the ForeignFieldAdd selector polynomial + pub foreign_field_add_selector: Option, + /// evaluation of the ForeignFieldMul selector polynomial + pub foreign_field_mul_selector: Option, + /// evaluation of the Xor selector polynomial + pub xor_selector: Option, + /// evaluation of the Rot selector polynomial + pub rot_selector: Option, } /// Commitments linked to the lookup feature @@ -217,6 +231,12 @@ impl ProofEvaluations { mul_selector, emul_selector, endomul_scalar_selector, + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, } = self; ProofEvaluations { w: w.map(f), @@ -230,6 +250,12 @@ impl ProofEvaluations { mul_selector: f(mul_selector), emul_selector: f(emul_selector), endomul_scalar_selector: f(endomul_scalar_selector), + range_check0_selector: range_check0_selector.map(f), + range_check1_selector: range_check1_selector.map(f), + foreign_field_add_selector: foreign_field_add_selector.map(f), + foreign_field_mul_selector: foreign_field_mul_selector.map(f), + xor_selector: xor_selector.map(f), + rot_selector: rot_selector.map(f), } } @@ -246,6 +272,12 @@ impl ProofEvaluations { mul_selector, emul_selector, endomul_scalar_selector, + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, } = self; ProofEvaluations { w: [ @@ -291,6 +323,12 @@ impl ProofEvaluations { mul_selector: f(mul_selector), emul_selector: f(emul_selector), endomul_scalar_selector: f(endomul_scalar_selector), + range_check0_selector: range_check0_selector.as_ref().map(f), + range_check1_selector: range_check1_selector.as_ref().map(f), + foreign_field_add_selector: foreign_field_add_selector.as_ref().map(f), + foreign_field_mul_selector: foreign_field_mul_selector.as_ref().map(f), + xor_selector: xor_selector.as_ref().map(f), + rot_selector: rot_selector.as_ref().map(f), } } } @@ -363,6 +401,12 @@ impl ProofEvaluations> { mul_selector: pt(F::zero(), F::zero()), emul_selector: pt(F::zero(), F::zero()), endomul_scalar_selector: pt(F::zero(), F::zero()), + range_check0_selector: None, + range_check1_selector: None, + foreign_field_add_selector: None, + foreign_field_mul_selector: None, + xor_selector: None, + rot_selector: None, } } } @@ -561,6 +605,13 @@ pub mod caml { pub mul_selector: PointEvaluations>, pub emul_selector: PointEvaluations>, pub endomul_scalar_selector: PointEvaluations>, + + pub range_check0_selector: Option>>, + pub range_check1_selector: Option>>, + pub foreign_field_add_selector: Option>>, + pub foreign_field_mul_selector: Option>>, + pub xor_selector: Option>>, + pub rot_selector: Option>>, } // @@ -711,6 +762,24 @@ pub mod caml { endomul_scalar_selector: pe .endomul_scalar_selector .map(&|x| x.into_iter().map(Into::into).collect()), + range_check0_selector: pe + .range_check0_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + range_check1_selector: pe + .range_check1_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + foreign_field_add_selector: pe + .foreign_field_add_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + foreign_field_mul_selector: pe + .foreign_field_mul_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + xor_selector: pe + .xor_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + rot_selector: pe + .rot_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), lookup: pe.lookup.map(Into::into), } } @@ -818,6 +887,24 @@ pub mod caml { endomul_scalar_selector: cpe .endomul_scalar_selector .map(&|x| x.into_iter().map(Into::into).collect()), + range_check0_selector: cpe + .range_check0_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + range_check1_selector: cpe + .range_check1_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + foreign_field_add_selector: cpe + .foreign_field_add_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + foreign_field_mul_selector: cpe + .foreign_field_mul_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + xor_selector: cpe + .xor_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + rot_selector: cpe + .rot_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), lookup: cpe.lookup.map(Into::into), } } diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 986b23e7ff..c78fefb90c 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -965,6 +965,37 @@ where endomul_scalar_selector: chunked_evals_for_selector( &index.column_evaluations.endomul_scalar_selector8, ), + + range_check0_selector: index + .column_evaluations + .range_check0_selector8 + .as_ref() + .map(chunked_evals_for_selector), + range_check1_selector: index + .column_evaluations + .range_check1_selector8 + .as_ref() + .map(chunked_evals_for_selector), + foreign_field_add_selector: index + .column_evaluations + .foreign_field_add_selector8 + .as_ref() + .map(chunked_evals_for_selector), + foreign_field_mul_selector: index + .column_evaluations + .foreign_field_mul_selector8 + .as_ref() + .map(chunked_evals_for_selector), + xor_selector: index + .column_evaluations + .xor_selector8 + .as_ref() + .map(chunked_evals_for_selector), + rot_selector: index + .column_evaluations + .rot_selector8 + .as_ref() + .map(chunked_evals_for_selector), }; let zeta_to_srs_len = zeta.pow([index.max_poly_size as u64]); diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 7dc2b714f8..7674869a78 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -520,6 +520,12 @@ where mul_selector, emul_selector, endomul_scalar_selector, + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, } = &proof.evals; let check_eval_len = |eval: &PointEvaluations>| -> Result<()> { @@ -563,6 +569,27 @@ where check_eval_len(emul_selector)?; check_eval_len(endomul_scalar_selector)?; + // Optional gates + + if let Some(range_check0_selector) = range_check0_selector { + check_eval_len(range_check0_selector)? + } + if let Some(range_check1_selector) = range_check1_selector { + check_eval_len(range_check1_selector)? + } + if let Some(foreign_field_add_selector) = foreign_field_add_selector { + check_eval_len(foreign_field_add_selector)? + } + if let Some(foreign_field_mul_selector) = foreign_field_mul_selector { + check_eval_len(foreign_field_mul_selector)? + } + if let Some(xor_selector) = xor_selector { + check_eval_len(xor_selector)? + } + if let Some(rot_selector) = rot_selector { + check_eval_len(rot_selector)? + } + Ok(()) } From b94cd5f3fe38c69399579ba84657301a89a8cf89 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 27 Jun 2023 18:15:23 +0100 Subject: [PATCH 098/242] Evaluate optional gate selectors --- book/src/specs/kimchi.md | 2 ++ kimchi/src/circuits/expr.rs | 18 +++++++++++ kimchi/src/proof.rs | 6 ++++ kimchi/src/prover.rs | 50 +++++++++++++++++++++++++++++- kimchi/src/verifier.rs | 61 +++++++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 1 deletion(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index d7d3b6dee5..f199726a48 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2216,6 +2216,7 @@ The prover then follows the following steps to create the proof: * the poseidon selector * the 15 registers/witness columns * the 6 sigmas + * the optional gates * optionally, the runtime table 1. if using lookup: * add the lookup sorted polynomials @@ -2312,6 +2313,7 @@ Essentially, this steps verifies that $f(\zeta) = t(\zeta) * Z_H(\zeta)$. * witness commitments * coefficient commitments * sigma commitments + * optional gate commitments * lookup commitments #### Batch verification of proofs diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index c83749e507..91a6b236fc 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -679,6 +679,24 @@ impl Variable { Index(GateType::VarBaseMul) => Ok(evals.mul_selector), Index(GateType::EndoMul) => Ok(evals.emul_selector), Index(GateType::EndoMulScalar) => Ok(evals.endomul_scalar_selector), + Index(GateType::RangeCheck0) => evals + .range_check0_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Index(GateType::RangeCheck1) => evals + .range_check1_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Index(GateType::ForeignFieldAdd) => evals + .foreign_field_add_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Index(GateType::ForeignFieldMul) => evals + .foreign_field_mul_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Index(GateType::Xor16) => evals + .xor_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Index(GateType::Rot64) => evals + .rot_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), Permutation(i) => Ok(evals.s[i]), Coefficient(i) => Ok(evals.coefficients[i]), LookupKindIndex(_) | LookupRuntimeSelector | Index(_) => { diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 680289c30d..df10883c66 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -437,6 +437,12 @@ impl ProofEvaluations { Column::Index(GateType::VarBaseMul) => Some(&self.mul_selector), Column::Index(GateType::EndoMul) => Some(&self.emul_selector), Column::Index(GateType::EndoMulScalar) => Some(&self.endomul_scalar_selector), + Column::Index(GateType::RangeCheck0) => self.range_check0_selector.as_ref(), + Column::Index(GateType::RangeCheck1) => self.range_check1_selector.as_ref(), + Column::Index(GateType::ForeignFieldAdd) => self.foreign_field_add_selector.as_ref(), + Column::Index(GateType::ForeignFieldMul) => self.foreign_field_mul_selector.as_ref(), + Column::Index(GateType::Xor16) => self.xor_selector.as_ref(), + Column::Index(GateType::Rot64) => self.rot_selector.as_ref(), Column::Index(_) => None, Column::Coefficient(i) => Some(&self.coefficients[i]), Column::Permutation(i) => Some(&self.s[i]), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index c78fefb90c..9cd59cf88c 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1160,7 +1160,6 @@ where //~~ * the poseidon selector //~~ * the 15 registers/witness columns //~~ * the 6 sigmas - //~~ * optionally, the runtime table polynomials.push((coefficients_form(&public_poly), None, fixed_hiding(1))); polynomials.push((coefficients_form(&ft), None, blinding_ft)); polynomials.push((coefficients_form(&z_poly), None, z_comm.blinders)); @@ -1216,6 +1215,55 @@ where .collect::>(), ); + //~~ * the optional gates + if let Some(range_check0_selector8) = + index.column_evaluations.range_check0_selector8.as_ref() + { + polynomials.push(( + evaluations_form(range_check0_selector8), + None, + non_hiding(1), + )); + } + if let Some(range_check1_selector8) = + index.column_evaluations.range_check1_selector8.as_ref() + { + polynomials.push(( + evaluations_form(range_check1_selector8), + None, + non_hiding(1), + )); + } + if let Some(foreign_field_add_selector8) = index + .column_evaluations + .foreign_field_add_selector8 + .as_ref() + { + polynomials.push(( + evaluations_form(foreign_field_add_selector8), + None, + non_hiding(1), + )); + } + if let Some(foreign_field_mul_selector8) = index + .column_evaluations + .foreign_field_mul_selector8 + .as_ref() + { + polynomials.push(( + evaluations_form(foreign_field_mul_selector8), + None, + non_hiding(1), + )); + } + if let Some(xor_selector8) = index.column_evaluations.xor_selector8.as_ref() { + polynomials.push((evaluations_form(xor_selector8), None, non_hiding(1))); + } + if let Some(rot_selector8) = index.column_evaluations.rot_selector8.as_ref() { + polynomials.push((evaluations_form(rot_selector8), None, non_hiding(1))); + } + + //~~ * optionally, the runtime table //~ 1. if using lookup: if let Some(lcs) = &index.cs.lookup_constraint_system { //~~ * add the lookup sorted polynomials diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 7674869a78..e47fb0d426 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -437,6 +437,36 @@ where .chain((0..COLUMNS).map(Column::Witness)) .chain((0..COLUMNS).map(Column::Coefficient)) .chain((0..PERMUTS - 1).map(Column::Permutation)) + .chain(if index.range_check0_comm.is_some() { + Some(Column::Index(GateType::RangeCheck0)) + } else { + None + }) + .chain(if index.range_check1_comm.is_some() { + Some(Column::Index(GateType::RangeCheck1)) + } else { + None + }) + .chain(if index.foreign_field_add_comm.is_some() { + Some(Column::Index(GateType::ForeignFieldAdd)) + } else { + None + }) + .chain(if index.foreign_field_mul_comm.is_some() { + Some(Column::Index(GateType::ForeignFieldMul)) + } else { + None + }) + .chain(if index.xor_comm.is_some() { + Some(Column::Index(GateType::Xor16)) + } else { + None + }) + .chain(if index.rot_comm.is_some() { + Some(Column::Index(GateType::Rot64)) + } else { + None + }) .chain( index .lookup_index @@ -791,6 +821,37 @@ where .chain((0..COLUMNS).map(Column::Coefficient)) //~~ * sigma commitments .chain((0..PERMUTS - 1).map(Column::Permutation)) + //~~ * optional gate commitments + .chain(if verifier_index.range_check0_comm.is_some() { + Some(Column::Index(GateType::RangeCheck0)) + } else { + None + }) + .chain(if verifier_index.range_check1_comm.is_some() { + Some(Column::Index(GateType::RangeCheck1)) + } else { + None + }) + .chain(if verifier_index.foreign_field_add_comm.is_some() { + Some(Column::Index(GateType::ForeignFieldAdd)) + } else { + None + }) + .chain(if verifier_index.foreign_field_mul_comm.is_some() { + Some(Column::Index(GateType::ForeignFieldMul)) + } else { + None + }) + .chain(if verifier_index.xor_comm.is_some() { + Some(Column::Index(GateType::Xor16)) + } else { + None + }) + .chain(if verifier_index.rot_comm.is_some() { + Some(Column::Index(GateType::Rot64)) + } else { + None + }) //~~ * lookup commitments //~ .chain( From 080bf6e6389821521dbc785e01d25c62cd2ed174 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 27 Jun 2023 19:57:05 +0100 Subject: [PATCH 099/242] Stop linearizing optional gate selectors --- kimchi/src/linearization.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 472b878a1b..cda83d8b54 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -310,6 +310,14 @@ pub fn linearization_columns( h.insert(Index(GateType::EndoMul)); h.insert(Index(GateType::EndoMulScalar)); + // optional columns + h.insert(Index(GateType::RangeCheck0)); + h.insert(Index(GateType::RangeCheck1)); + h.insert(Index(GateType::ForeignFieldAdd)); + h.insert(Index(GateType::ForeignFieldMul)); + h.insert(Index(GateType::Xor16)); + h.insert(Index(GateType::Rot64)); + h } From 58dfcb7e3df9677c0ba27cb975f339c502487eba Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 29 Jun 2023 19:28:27 +0100 Subject: [PATCH 100/242] Use evals to gate oracle selection --- kimchi/src/verifier.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index e47fb0d426..78ccd78b79 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -437,32 +437,32 @@ where .chain((0..COLUMNS).map(Column::Witness)) .chain((0..COLUMNS).map(Column::Coefficient)) .chain((0..PERMUTS - 1).map(Column::Permutation)) - .chain(if index.range_check0_comm.is_some() { + .chain(if self.evals.range_check0_selector.is_some() { Some(Column::Index(GateType::RangeCheck0)) } else { None }) - .chain(if index.range_check1_comm.is_some() { + .chain(if self.evals.range_check1_selector.is_some() { Some(Column::Index(GateType::RangeCheck1)) } else { None }) - .chain(if index.foreign_field_add_comm.is_some() { + .chain(if self.evals.foreign_field_add_selector.is_some() { Some(Column::Index(GateType::ForeignFieldAdd)) } else { None }) - .chain(if index.foreign_field_mul_comm.is_some() { + .chain(if self.evals.foreign_field_mul_selector.is_some() { Some(Column::Index(GateType::ForeignFieldMul)) } else { None }) - .chain(if index.xor_comm.is_some() { + .chain(if self.evals.xor_selector.is_some() { Some(Column::Index(GateType::Xor16)) } else { None }) - .chain(if index.rot_comm.is_some() { + .chain(if self.evals.rot_selector.is_some() { Some(Column::Index(GateType::Rot64)) } else { None From d9bedacd485f5920ec546060ea0cdcfb73c44730 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 30 Jun 2023 20:18:07 +0100 Subject: [PATCH 101/242] Stop giving lookup evaluations special treatment --- book/src/specs/kimchi.md | 28 ++---- kimchi/src/circuits/expr.rs | 20 ++-- kimchi/src/plonk_sponge.rs | 32 +++--- kimchi/src/proof.rs | 189 ++++++++++++++---------------------- kimchi/src/prover.rs | 58 +++++++---- kimchi/src/verifier.rs | 52 +++++----- 6 files changed, 177 insertions(+), 202 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index f199726a48..8f4184be38 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1931,22 +1931,6 @@ pub struct PointEvaluations { pub zeta_omega: Evals, } -/// Evaluations of lookup polynomials -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LookupEvaluations { - /// sorted lookup table polynomial - pub sorted: Vec, - /// lookup aggregation polynomial - pub aggreg: Evals, - // TODO: May be possible to optimize this away? - /// lookup table polynomial - pub table: Evals, - - /// Optionally, a runtime table polynomial. - pub runtime: Option, -} - // TODO: this should really be vectors here, perhaps create another type for chunked evaluations? /// Polynomial evaluations contained in a `ProverProof`. /// - **Chunked evaluations** `Field` is instantiated with vectors with a length that equals the length of the chunk @@ -1963,8 +1947,6 @@ pub struct ProofEvaluations { pub s: [Evals; PERMUTS - 1], /// coefficient polynomials pub coefficients: [Evals; COLUMNS], - /// lookup-related evaluations - pub lookup: Option>, /// evaluation of the generic selector polynomial pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial @@ -1991,6 +1973,16 @@ pub struct ProofEvaluations { pub xor_selector: Option, /// evaluation of the Rot selector polynomial pub rot_selector: Option, + + // lookup-related evaluations + /// evaluation of lookup aggregation polynomial + pub lookup_aggregation: Option, + /// evaluation of lookup table polynomial + pub lookup_table: Option, + /// evaluation of lookup sorted polynomials + pub lookup_sorted: [Option; 5], + /// evaluation of runtime lookup table polynomial + pub runtime_lookup_table: Option, } /// Commitments linked to the lookup feature diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 91a6b236fc..9bdd751481 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -662,17 +662,21 @@ impl Variable { ) -> Result { let point_evaluations = { use Column::*; - let l = evals - .lookup - .as_ref() - .ok_or(ExprError::LookupShouldNotBeUsed); match self.col { Witness(i) => Ok(evals.w[i]), Z => Ok(evals.z), - LookupSorted(i) => l.map(|l| l.sorted[i]), - LookupAggreg => l.map(|l| l.aggreg), - LookupTable => l.map(|l| l.table), - LookupRuntimeTable => l.and_then(|l| l.runtime.ok_or(ExprError::MissingRuntime)), + LookupSorted(i) => { + evals.lookup_sorted[i].ok_or(ExprError::MissingIndexEvaluation(self.col)) + } + LookupAggreg => evals + .lookup_aggregation + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + LookupTable => evals + .lookup_table + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + LookupRuntimeTable => evals + .runtime_lookup_table + .ok_or(ExprError::MissingIndexEvaluation(self.col)), Index(GateType::Poseidon) => Ok(evals.poseidon_selector), Index(GateType::Generic) => Ok(evals.generic_selector), Index(GateType::CompleteAdd) => Ok(evals.complete_add_selector), diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index a5a9e4ac23..9430fb21bf 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -5,7 +5,7 @@ use mina_poseidon::{ poseidon::{ArithmeticSponge, ArithmeticSpongeParams, Sponge}, }; -use crate::proof::{LookupEvaluations, PointEvaluations, ProofEvaluations}; +use crate::proof::{PointEvaluations, ProofEvaluations}; pub trait FrSponge { /// Creates a new Fr-Sponge. @@ -64,7 +64,6 @@ impl FrSponge for DefaultFrSponge { z, s, coefficients, - lookup, generic_selector, poseidon_selector, complete_add_selector, @@ -77,6 +76,10 @@ impl FrSponge for DefaultFrSponge { foreign_field_mul_selector, xor_selector, rot_selector, + lookup_aggregation, + lookup_table, + lookup_sorted, + runtime_lookup_table, } = e; let mut points = vec![ @@ -112,18 +115,19 @@ impl FrSponge for DefaultFrSponge { if let Some(rot_selector) = rot_selector.as_ref() { points.push(rot_selector) } - - if let Some(l) = lookup.as_ref() { - let LookupEvaluations { - sorted, - aggreg, - table, - runtime, - } = l; - points.push(aggreg); - points.push(table); - sorted.iter().for_each(|s| points.push(s)); - runtime.iter().for_each(|x| points.push(x)); + if let Some(lookup_aggregation) = lookup_aggregation.as_ref() { + points.push(lookup_aggregation) + } + if let Some(lookup_table) = lookup_table.as_ref() { + points.push(lookup_table) + } + for lookup_sorted in lookup_sorted { + if let Some(lookup_sorted) = lookup_sorted.as_ref() { + points.push(lookup_sorted) + } + } + if let Some(runtime_lookup_table) = runtime_lookup_table.as_ref() { + points.push(runtime_lookup_table) } points.into_iter().for_each(|p| { diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index df10883c66..79c586eecf 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -38,22 +38,6 @@ pub struct PointEvaluations { pub zeta_omega: Evals, } -/// Evaluations of lookup polynomials -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LookupEvaluations { - /// sorted lookup table polynomial - pub sorted: Vec, - /// lookup aggregation polynomial - pub aggreg: Evals, - // TODO: May be possible to optimize this away? - /// lookup table polynomial - pub table: Evals, - - /// Optionally, a runtime table polynomial. - pub runtime: Option, -} - // TODO: this should really be vectors here, perhaps create another type for chunked evaluations? /// Polynomial evaluations contained in a `ProverProof`. /// - **Chunked evaluations** `Field` is instantiated with vectors with a length that equals the length of the chunk @@ -70,8 +54,6 @@ pub struct ProofEvaluations { pub s: [Evals; PERMUTS - 1], /// coefficient polynomials pub coefficients: [Evals; COLUMNS], - /// lookup-related evaluations - pub lookup: Option>, /// evaluation of the generic selector polynomial pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial @@ -98,6 +80,16 @@ pub struct ProofEvaluations { pub xor_selector: Option, /// evaluation of the Rot selector polynomial pub rot_selector: Option, + + // lookup-related evaluations + /// evaluation of lookup aggregation polynomial + pub lookup_aggregation: Option, + /// evaluation of lookup table polynomial + pub lookup_table: Option, + /// evaluation of lookup sorted polynomials + pub lookup_sorted: [Option; 5], + /// evaluation of runtime lookup table polynomial + pub runtime_lookup_table: Option, } /// Commitments linked to the lookup feature @@ -185,38 +177,6 @@ impl PointEvaluations { } } -impl LookupEvaluations { - pub fn map Eval2>(self, f: &FN) -> LookupEvaluations { - let LookupEvaluations { - sorted, - aggreg, - table, - runtime, - } = self; - LookupEvaluations { - sorted: sorted.into_iter().map(f).collect(), - aggreg: f(aggreg), - table: f(table), - runtime: runtime.map(f), - } - } - - pub fn map_ref Eval2>(&self, f: &FN) -> LookupEvaluations { - let LookupEvaluations { - sorted, - aggreg, - table, - runtime, - } = self; - LookupEvaluations { - sorted: sorted.iter().map(f).collect(), - aggreg: f(aggreg), - table: f(table), - runtime: runtime.as_ref().map(f), - } - } -} - impl ProofEvaluations { pub fn map Eval2>(self, f: &FN) -> ProofEvaluations { let ProofEvaluations { @@ -224,7 +184,6 @@ impl ProofEvaluations { z, s, coefficients, - lookup, generic_selector, poseidon_selector, complete_add_selector, @@ -237,13 +196,16 @@ impl ProofEvaluations { foreign_field_mul_selector, xor_selector, rot_selector, + lookup_aggregation, + lookup_table, + lookup_sorted, + runtime_lookup_table, } = self; ProofEvaluations { w: w.map(f), z: f(z), s: s.map(f), coefficients: coefficients.map(f), - lookup: lookup.map(|x| LookupEvaluations::map(x, f)), generic_selector: f(generic_selector), poseidon_selector: f(poseidon_selector), complete_add_selector: f(complete_add_selector), @@ -256,6 +218,10 @@ impl ProofEvaluations { foreign_field_mul_selector: foreign_field_mul_selector.map(f), xor_selector: xor_selector.map(f), rot_selector: rot_selector.map(f), + lookup_aggregation: lookup_aggregation.map(f), + lookup_table: lookup_table.map(f), + lookup_sorted: lookup_sorted.map(|x| x.map(f)), + runtime_lookup_table: runtime_lookup_table.map(f), } } @@ -265,7 +231,6 @@ impl ProofEvaluations { z, s: [s0, s1, s2, s3, s4, s5], coefficients: [c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14], - lookup, generic_selector, poseidon_selector, complete_add_selector, @@ -278,6 +243,10 @@ impl ProofEvaluations { foreign_field_mul_selector, xor_selector, rot_selector, + lookup_aggregation, + lookup_table, + lookup_sorted, + runtime_lookup_table, } = self; ProofEvaluations { w: [ @@ -316,7 +285,6 @@ impl ProofEvaluations { f(c13), f(c14), ], - lookup: lookup.as_ref().map(|l| l.map_ref(f)), generic_selector: f(generic_selector), poseidon_selector: f(poseidon_selector), complete_add_selector: f(complete_add_selector), @@ -329,6 +297,10 @@ impl ProofEvaluations { foreign_field_mul_selector: foreign_field_mul_selector.as_ref().map(f), xor_selector: xor_selector.as_ref().map(f), rot_selector: rot_selector.as_ref().map(f), + lookup_aggregation: lookup_aggregation.as_ref().map(f), + lookup_table: lookup_table.as_ref().map(f), + lookup_sorted: array::from_fn(|i| lookup_sorted[i].as_ref().map(f)), + runtime_lookup_table: runtime_lookup_table.as_ref().map(f), } } } @@ -394,7 +366,6 @@ impl ProofEvaluations> { z: pt(F::zero(), F::zero()), s: array::from_fn(|_| pt(F::zero(), F::zero())), coefficients: array::from_fn(|_| pt(F::zero(), F::zero())), - lookup: None, generic_selector: pt(F::zero(), F::zero()), poseidon_selector: pt(F::zero(), F::zero()), complete_add_selector: pt(F::zero(), F::zero()), @@ -407,6 +378,10 @@ impl ProofEvaluations> { foreign_field_mul_selector: None, xor_selector: None, rot_selector: None, + lookup_aggregation: None, + lookup_table: None, + lookup_sorted: array::from_fn(|_| None), + runtime_lookup_table: None, } } } @@ -425,12 +400,12 @@ impl ProofEvaluations { match col { Column::Witness(i) => Some(&self.w[i]), Column::Z => Some(&self.z), - Column::LookupSorted(i) => Some(&self.lookup.as_ref()?.sorted[i]), - Column::LookupAggreg => Some(&self.lookup.as_ref()?.aggreg), - Column::LookupTable => Some(&self.lookup.as_ref()?.table), + Column::LookupSorted(i) => self.lookup_sorted[i].as_ref(), + Column::LookupAggreg => self.lookup_aggregation.as_ref(), + Column::LookupTable => self.lookup_table.as_ref(), Column::LookupKindIndex(_) => None, Column::LookupRuntimeSelector => None, - Column::LookupRuntimeTable => Some(self.lookup.as_ref()?.runtime.as_ref()?), + Column::LookupRuntimeTable => self.runtime_lookup_table.as_ref(), Column::Index(GateType::Generic) => Some(&self.generic_selector), Column::Index(GateType::Poseidon) => Some(&self.poseidon_selector), Column::Index(GateType::CompleteAdd) => Some(&self.complete_add_selector), @@ -500,59 +475,6 @@ pub mod caml { } } - // - // CamlLookupEvaluations - // - - #[derive(Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)] - pub struct CamlLookupEvaluations { - pub sorted: Vec>>, - pub aggreg: PointEvaluations>, - pub table: PointEvaluations>, - pub runtime: Option>>, - } - - impl From>>> for CamlLookupEvaluations - where - F: Clone, - CamlF: From, - { - fn from(le: LookupEvaluations>>) -> Self { - Self { - sorted: le - .sorted - .into_iter() - .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())) - .collect(), - aggreg: le.aggreg.map(&|x| x.into_iter().map(Into::into).collect()), - table: le.table.map(&|x| x.into_iter().map(Into::into).collect()), - runtime: le - .runtime - .map(|r| r.map(&|r| r.into_iter().map(Into::into).collect())), - } - } - } - - impl From> for LookupEvaluations>> - where - F: From + Clone, - { - fn from(pe: CamlLookupEvaluations) -> Self { - Self { - sorted: pe - .sorted - .into_iter() - .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())) - .collect(), - aggreg: pe.aggreg.map(&|x| x.into_iter().map(Into::into).collect()), - table: pe.table.map(&|x| x.into_iter().map(Into::into).collect()), - runtime: pe - .runtime - .map(|r| r.map(&|r| r.into_iter().map(Into::into).collect())), - } - } - } - // // CamlProofEvaluations // @@ -603,7 +525,6 @@ pub mod caml { PointEvaluations>, PointEvaluations>, ), - pub lookup: Option>, pub generic_selector: PointEvaluations>, pub poseidon_selector: PointEvaluations>, @@ -618,6 +539,10 @@ pub mod caml { pub foreign_field_mul_selector: Option>>, pub xor_selector: Option>>, pub rot_selector: Option>>, + pub lookup_aggregation: Option>>, + pub lookup_table: Option>>, + pub lookup_sorted: Vec>>>, + pub runtime_lookup_table: Option>>, } // @@ -786,7 +711,24 @@ pub mod caml { rot_selector: pe .rot_selector .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), - lookup: pe.lookup.map(Into::into), + lookup_aggregation: pe + .lookup_aggregation + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + lookup_table: pe + .lookup_table + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + lookup_sorted: pe + .lookup_sorted + .iter() + .map(|x| { + x.as_ref().map(|x| { + x.map_ref(&|x| x.clone().into_iter().map(Into::into).collect()) + }) + }) + .collect::>(), + runtime_lookup_table: pe + .runtime_lookup_table + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), } } } @@ -794,6 +736,7 @@ pub mod caml { impl From> for ProofEvaluations>> where F: Clone, + CamlF: Clone, F: From, { fn from(cpe: CamlProofEvaluations) -> Self { @@ -911,7 +854,23 @@ pub mod caml { rot_selector: cpe .rot_selector .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), - lookup: cpe.lookup.map(Into::into), + lookup_aggregation: cpe + .lookup_aggregation + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + lookup_table: cpe + .lookup_table + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + lookup_sorted: { + assert_eq!(cpe.lookup_sorted.len(), 5); // Invalid proof + array::from_fn(|i| { + cpe.lookup_sorted[i] + .as_ref() + .map(|x| x.clone().map(&|x| x.into_iter().map(Into::into).collect())) + }) + }, + runtime_lookup_table: cpe + .runtime_lookup_table + .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), } } } diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 9cd59cf88c..6f9f89e95c 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -27,8 +27,8 @@ use crate::{ lagrange_basis_evaluations::LagrangeBasisEvaluations, plonk_sponge::FrSponge, proof::{ - LookupCommitments, LookupEvaluations, PointEvaluations, ProofEvaluations, - ProverCommitments, ProverProof, RecursionChallenge, + LookupCommitments, PointEvaluations, ProofEvaluations, ProverCommitments, ProverProof, + RecursionChallenge, }, prover_index::ProverIndex, }; @@ -104,8 +104,15 @@ where aggreg_comm: Option>, aggreg8: Option>>, - /// The evaluations of the aggregation polynomial for the proof - eval: Option>>>, + // lookup-related evaluations + /// evaluation of lookup aggregation polynomial + pub lookup_aggregation_eval: Option>>, + /// evaluation of lookup table polynomial + pub lookup_table_eval: Option>>, + /// evaluation of lookup sorted polynomials + pub lookup_sorted_eval: [Option>>; 5], + /// evaluation of runtime lookup table polynomial + pub runtime_lookup_table_eval: Option>>, /// Runtime table runtime_table: Option>, @@ -860,35 +867,40 @@ where .as_ref() .unwrap() .iter() - .map(|c| c.to_chunked_polynomial(index.max_poly_size)); + .map(|c| c.to_chunked_polynomial(index.max_poly_size)) + .collect::>(); //~~ * the table polynonial let joint_table = lookup_context.joint_lookup_table.as_ref().unwrap(); let joint_table = joint_table.to_chunked_polynomial(index.max_poly_size); - lookup_context.eval = Some(LookupEvaluations { - aggreg: PointEvaluations { - zeta: aggreg.evaluate_chunks(zeta), - zeta_omega: aggreg.evaluate_chunks(zeta_omega), - }, - sorted: sorted - .map(|sorted| PointEvaluations { + lookup_context.lookup_aggregation_eval = Some(PointEvaluations { + zeta: aggreg.evaluate_chunks(zeta), + zeta_omega: aggreg.evaluate_chunks(zeta_omega), + }); + lookup_context.lookup_table_eval = Some(PointEvaluations { + zeta: joint_table.evaluate_chunks(zeta), + zeta_omega: joint_table.evaluate_chunks(zeta_omega), + }); + lookup_context.lookup_sorted_eval = array::from_fn(|i| { + if i < sorted.len() { + let sorted = &sorted[i]; + Some(PointEvaluations { zeta: sorted.evaluate_chunks(zeta), zeta_omega: sorted.evaluate_chunks(zeta_omega), }) - .collect(), - table: PointEvaluations { - zeta: joint_table.evaluate_chunks(zeta), - zeta_omega: joint_table.evaluate_chunks(zeta_omega), - }, - runtime: lookup_context.runtime_table.as_ref().map(|runtime_table| { + } else { + None + } + }); + lookup_context.runtime_lookup_table_eval = + lookup_context.runtime_table.as_ref().map(|runtime_table| { let runtime_table = runtime_table.to_chunked_polynomial(index.max_poly_size); PointEvaluations { zeta: runtime_table.evaluate_chunks(zeta), zeta_omega: runtime_table.evaluate_chunks(zeta_omega), } - }), - }) + }); } //~ 1. Chunk evaluate the following polynomials at both $\zeta$ and $\zeta \omega$: @@ -950,7 +962,10 @@ where } }, - lookup: lookup_context.eval.take(), + lookup_aggregation: lookup_context.lookup_aggregation_eval.take(), + lookup_table: lookup_context.lookup_table_eval.take(), + lookup_sorted: array::from_fn(|i| lookup_context.lookup_sorted_eval[i].take()), + runtime_lookup_table: lookup_context.runtime_lookup_table_eval.take(), generic_selector: chunked_evals_for_selector( &index.column_evaluations.generic_selector4, ), @@ -1577,6 +1592,7 @@ pub mod caml { impl From> for (ProverProof, Vec) where + CamlF: Clone, G: AffineCurve + From, G::ScalarField: From, { diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 78ccd78b79..403c1d74e1 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -15,9 +15,7 @@ use crate::{ error::VerifyError, oracles::OraclesResult, plonk_sponge::FrSponge, - proof::{ - LookupEvaluations, PointEvaluations, ProofEvaluations, ProverProof, RecursionChallenge, - }, + proof::{PointEvaluations, ProofEvaluations, ProverProof, RecursionChallenge}, verifier_index::VerifierIndex, }; use ark_ec::AffineCurve; @@ -543,7 +541,6 @@ where z, s, coefficients, - lookup, generic_selector, poseidon_selector, complete_add_selector, @@ -556,6 +553,10 @@ where foreign_field_mul_selector, xor_selector, rot_selector, + lookup_aggregation, + lookup_table, + lookup_sorted, + runtime_lookup_table, } = &proof.evals; let check_eval_len = |eval: &PointEvaluations>| -> Result<()> { @@ -576,22 +577,23 @@ where for coeff in coefficients { check_eval_len(coeff)?; } - if let Some(LookupEvaluations { - sorted, - aggreg, - table, - runtime, - }) = lookup - { - for sorted_i in sorted { - check_eval_len(sorted_i)?; - } - check_eval_len(aggreg)?; - check_eval_len(table)?; - if let Some(runtime) = &runtime { - check_eval_len(runtime)?; + + // Lookup evaluations + for sorted in lookup_sorted { + if let Some(sorted) = sorted { + check_eval_len(sorted)?; } } + if let Some(lookup_aggregation) = lookup_aggregation { + check_eval_len(lookup_aggregation)?; + } + if let Some(lookup_table) = lookup_table { + check_eval_len(lookup_table)?; + } + if let Some(runtime_lookup_table) = runtime_lookup_table { + check_eval_len(runtime_lookup_table)?; + } + check_eval_len(generic_selector)?; check_eval_len(poseidon_selector)?; check_eval_len(complete_add_selector)?; @@ -888,11 +890,13 @@ where .lookup .as_ref() .ok_or(VerifyError::LookupCommitmentMissing)?; - let lookup_eval = proof + + let lookup_table = proof .evals - .lookup + .lookup_table .as_ref() .ok_or(VerifyError::LookupEvalsMissing)?; + let runtime_lookup_table = proof.evals.runtime_lookup_table.as_ref(); // compute table commitment let table_comm = { @@ -917,10 +921,7 @@ where // add evaluation of the table polynomial evaluations.push(Evaluation { commitment: table_comm, - evaluations: vec![ - lookup_eval.table.zeta.clone(), - lookup_eval.table.zeta_omega.clone(), - ], + evaluations: vec![lookup_table.zeta.clone(), lookup_table.zeta_omega.clone()], degree_bound: None, }); @@ -930,8 +931,7 @@ where .runtime .as_ref() .ok_or(VerifyError::IncorrectRuntimeProof)?; - let runtime_eval = lookup_eval - .runtime + let runtime_eval = runtime_lookup_table .as_ref() .map(|x| x.map_ref(&|x| x.clone())) .ok_or(VerifyError::IncorrectRuntimeProof)?; From 9514e781670d4f3eeed257ae968f41aa6d6f9bbf Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 10 Jul 2023 15:11:11 +0100 Subject: [PATCH 102/242] Evaluate lookup selectors --- book/src/specs/kimchi.md | 12 ++++++ kimchi/src/plonk_sponge.rs | 21 +++++++++ kimchi/src/proof.rs | 87 +++++++++++++++++++++++++++++++++++++- kimchi/src/prover.rs | 38 +++++++++++++++++ kimchi/src/verifier.rs | 23 ++++++++++ 5 files changed, 179 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 8f4184be38..69184a2841 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1983,6 +1983,18 @@ pub struct ProofEvaluations { pub lookup_sorted: [Option; 5], /// evaluation of runtime lookup table polynomial pub runtime_lookup_table: Option, + + // lookup selectors + /// evaluation of the runtime lookup table selector polynomial + pub runtime_lookup_table_selector: Option, + /// evaluation of the Xor range check pattern selector polynomial + pub xor_lookup_selector: Option, + /// evaluation of the Lookup range check pattern selector polynomial + pub lookup_gate_lookup_selector: Option, + /// evaluation of the RangeCheck range check pattern selector polynomial + pub range_check_lookup_selector: Option, + /// evaluation of the ForeignFieldMul range check pattern selector polynomial + pub foreign_field_mul_lookup_selector: Option, } /// Commitments linked to the lookup feature diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index 9430fb21bf..5bfa9627d1 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -80,6 +80,11 @@ impl FrSponge for DefaultFrSponge { lookup_table, lookup_sorted, runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, } = e; let mut points = vec![ @@ -129,6 +134,22 @@ impl FrSponge for DefaultFrSponge { if let Some(runtime_lookup_table) = runtime_lookup_table.as_ref() { points.push(runtime_lookup_table) } + if let Some(runtime_lookup_table_selector) = runtime_lookup_table_selector.as_ref() { + points.push(runtime_lookup_table_selector) + } + if let Some(xor_lookup_selector) = xor_lookup_selector.as_ref() { + points.push(xor_lookup_selector) + } + if let Some(lookup_gate_lookup_selector) = lookup_gate_lookup_selector.as_ref() { + points.push(lookup_gate_lookup_selector) + } + if let Some(range_check_lookup_selector) = range_check_lookup_selector.as_ref() { + points.push(range_check_lookup_selector) + } + if let Some(foreign_field_mul_lookup_selector) = foreign_field_mul_lookup_selector.as_ref() + { + points.push(foreign_field_mul_lookup_selector) + } points.into_iter().for_each(|p| { self.sponge.absorb(&p.zeta); diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 79c586eecf..a7a0749151 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -3,6 +3,7 @@ use crate::circuits::{ expr::Column, gate::GateType, + lookup::lookups::LookupPattern, wires::{COLUMNS, PERMUTS}, }; use ark_ec::AffineCurve; @@ -90,6 +91,18 @@ pub struct ProofEvaluations { pub lookup_sorted: [Option; 5], /// evaluation of runtime lookup table polynomial pub runtime_lookup_table: Option, + + // lookup selectors + /// evaluation of the runtime lookup table selector polynomial + pub runtime_lookup_table_selector: Option, + /// evaluation of the Xor range check pattern selector polynomial + pub xor_lookup_selector: Option, + /// evaluation of the Lookup range check pattern selector polynomial + pub lookup_gate_lookup_selector: Option, + /// evaluation of the RangeCheck range check pattern selector polynomial + pub range_check_lookup_selector: Option, + /// evaluation of the ForeignFieldMul range check pattern selector polynomial + pub foreign_field_mul_lookup_selector: Option, } /// Commitments linked to the lookup feature @@ -200,6 +213,11 @@ impl ProofEvaluations { lookup_table, lookup_sorted, runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, } = self; ProofEvaluations { w: w.map(f), @@ -222,6 +240,11 @@ impl ProofEvaluations { lookup_table: lookup_table.map(f), lookup_sorted: lookup_sorted.map(|x| x.map(f)), runtime_lookup_table: runtime_lookup_table.map(f), + runtime_lookup_table_selector: runtime_lookup_table_selector.map(f), + xor_lookup_selector: xor_lookup_selector.map(f), + lookup_gate_lookup_selector: lookup_gate_lookup_selector.map(f), + range_check_lookup_selector: range_check_lookup_selector.map(f), + foreign_field_mul_lookup_selector: foreign_field_mul_lookup_selector.map(f), } } @@ -247,6 +270,11 @@ impl ProofEvaluations { lookup_table, lookup_sorted, runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, } = self; ProofEvaluations { w: [ @@ -301,6 +329,11 @@ impl ProofEvaluations { lookup_table: lookup_table.as_ref().map(f), lookup_sorted: array::from_fn(|i| lookup_sorted[i].as_ref().map(f)), runtime_lookup_table: runtime_lookup_table.as_ref().map(f), + runtime_lookup_table_selector: runtime_lookup_table_selector.as_ref().map(f), + xor_lookup_selector: xor_lookup_selector.as_ref().map(f), + lookup_gate_lookup_selector: lookup_gate_lookup_selector.as_ref().map(f), + range_check_lookup_selector: range_check_lookup_selector.as_ref().map(f), + foreign_field_mul_lookup_selector: foreign_field_mul_lookup_selector.as_ref().map(f), } } } @@ -382,6 +415,11 @@ impl ProofEvaluations> { lookup_table: None, lookup_sorted: array::from_fn(|_| None), runtime_lookup_table: None, + runtime_lookup_table_selector: None, + xor_lookup_selector: None, + lookup_gate_lookup_selector: None, + range_check_lookup_selector: None, + foreign_field_mul_lookup_selector: None, } } } @@ -403,8 +441,17 @@ impl ProofEvaluations { Column::LookupSorted(i) => self.lookup_sorted[i].as_ref(), Column::LookupAggreg => self.lookup_aggregation.as_ref(), Column::LookupTable => self.lookup_table.as_ref(), - Column::LookupKindIndex(_) => None, - Column::LookupRuntimeSelector => None, + Column::LookupKindIndex(LookupPattern::Xor) => self.xor_lookup_selector.as_ref(), + Column::LookupKindIndex(LookupPattern::Lookup) => { + self.lookup_gate_lookup_selector.as_ref() + } + Column::LookupKindIndex(LookupPattern::RangeCheck) => { + self.range_check_lookup_selector.as_ref() + } + Column::LookupKindIndex(LookupPattern::ForeignFieldMul) => { + self.foreign_field_mul_lookup_selector.as_ref() + } + Column::LookupRuntimeSelector => self.runtime_lookup_table_selector.as_ref(), Column::LookupRuntimeTable => self.runtime_lookup_table.as_ref(), Column::Index(GateType::Generic) => Some(&self.generic_selector), Column::Index(GateType::Poseidon) => Some(&self.poseidon_selector), @@ -543,6 +590,12 @@ pub mod caml { pub lookup_table: Option>>, pub lookup_sorted: Vec>>>, pub runtime_lookup_table: Option>>, + + pub runtime_lookup_table_selector: Option>>, + pub xor_lookup_selector: Option>>, + pub lookup_gate_lookup_selector: Option>>, + pub range_check_lookup_selector: Option>>, + pub foreign_field_mul_lookup_selector: Option>>, } // @@ -729,6 +782,21 @@ pub mod caml { runtime_lookup_table: pe .runtime_lookup_table .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + runtime_lookup_table_selector: pe + .runtime_lookup_table_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + xor_lookup_selector: pe + .xor_lookup_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + lookup_gate_lookup_selector: pe + .lookup_gate_lookup_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + range_check_lookup_selector: pe + .range_check_lookup_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + foreign_field_mul_lookup_selector: pe + .foreign_field_mul_lookup_selector + .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), } } } @@ -871,6 +939,21 @@ pub mod caml { runtime_lookup_table: cpe .runtime_lookup_table .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), + runtime_lookup_table_selector: cpe + .runtime_lookup_table_selector + .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), + xor_lookup_selector: cpe + .xor_lookup_selector + .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), + lookup_gate_lookup_selector: cpe + .lookup_gate_lookup_selector + .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), + range_check_lookup_selector: cpe + .range_check_lookup_selector + .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), + foreign_field_mul_lookup_selector: cpe + .foreign_field_mul_lookup_selector + .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), } } } diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 6f9f89e95c..6a167a8b43 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1011,6 +1011,44 @@ where .rot_selector8 .as_ref() .map(chunked_evals_for_selector), + + runtime_lookup_table_selector: index.cs.lookup_constraint_system.as_ref().and_then( + |lcs| { + lcs.runtime_selector + .as_ref() + .map(chunked_evals_for_selector) + }, + ), + xor_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then(|lcs| { + lcs.lookup_selectors + .xor + .as_ref() + .map(chunked_evals_for_selector) + }), + lookup_gate_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then( + |lcs| { + lcs.lookup_selectors + .lookup + .as_ref() + .map(chunked_evals_for_selector) + }, + ), + range_check_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then( + |lcs| { + lcs.lookup_selectors + .range_check + .as_ref() + .map(chunked_evals_for_selector) + }, + ), + foreign_field_mul_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then( + |lcs| { + lcs.lookup_selectors + .ffmul + .as_ref() + .map(chunked_evals_for_selector) + }, + ), }; let zeta_to_srs_len = zeta.pow([index.max_poly_size as u64]); diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 403c1d74e1..7b40ddebeb 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -557,6 +557,11 @@ where lookup_table, lookup_sorted, runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, } = &proof.evals; let check_eval_len = |eval: &PointEvaluations>| -> Result<()> { @@ -622,6 +627,24 @@ where check_eval_len(rot_selector)? } + // Lookup selectors + + if let Some(runtime_lookup_table_selector) = runtime_lookup_table_selector { + check_eval_len(runtime_lookup_table_selector)? + } + if let Some(xor_lookup_selector) = xor_lookup_selector { + check_eval_len(xor_lookup_selector)? + } + if let Some(lookup_gate_lookup_selector) = lookup_gate_lookup_selector { + check_eval_len(lookup_gate_lookup_selector)? + } + if let Some(range_check_lookup_selector) = range_check_lookup_selector { + check_eval_len(range_check_lookup_selector)? + } + if let Some(foreign_field_mul_lookup_selector) = foreign_field_mul_lookup_selector { + check_eval_len(foreign_field_mul_lookup_selector)? + } + Ok(()) } From 268fabe149fa135d5b06e7a5337e84c304625962 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 10 Jul 2023 17:56:16 +0100 Subject: [PATCH 103/242] Evaluate all lookup selectors --- book/src/specs/kimchi.md | 1 + kimchi/src/prover.rs | 31 ++++++++++++++++ kimchi/src/verifier.rs | 79 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 69184a2841..5e0ed21e6c 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2227,6 +2227,7 @@ The prover then follows the following steps to create the proof: * add the lookup aggreg polynomial * add the combined table polynomial * if present, add the runtime table polynomial + * the lookup selectors 1. Create an aggregated evaluation proof for all of these polynomials at $\zeta$ and $\zeta\omega$ using $u$ and $v$. diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 6a167a8b43..1a6460b03d 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1366,6 +1366,37 @@ where runtime_table_comm.blinders.clone(), )); } + + //~~ * the lookup selectors + + if let Some(runtime_lookup_table_selector) = lcs.runtime_selector.as_ref() { + println!("selector prover"); + polynomials.push(( + evaluations_form(runtime_lookup_table_selector), + None, + non_hiding(1), + )) + } + if let Some(xor_lookup_selector) = lcs.lookup_selectors.xor.as_ref() { + polynomials.push((evaluations_form(xor_lookup_selector), None, non_hiding(1))) + } + if let Some(lookup_gate_selector) = lcs.lookup_selectors.lookup.as_ref() { + polynomials.push((evaluations_form(lookup_gate_selector), None, non_hiding(1))) + } + if let Some(range_check_lookup_selector) = lcs.lookup_selectors.range_check.as_ref() { + polynomials.push(( + evaluations_form(range_check_lookup_selector), + None, + non_hiding(1), + )) + } + if let Some(foreign_field_mul_lookup_selector) = lcs.lookup_selectors.ffmul.as_ref() { + polynomials.push(( + evaluations_form(foreign_field_mul_lookup_selector), + None, + non_hiding(1), + )) + } } //~ 1. Create an aggregated evaluation proof for all of these polynomials at $\zeta$ and $\zeta\omega$ using $u$ and $v$. diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 7b40ddebeb..8ba760eb88 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -6,7 +6,7 @@ use crate::{ constraints::ConstraintSystem, expr::{Column, Constants, PolishToken}, gate::GateType, - lookup::tables::combine_table, + lookup::{lookups::LookupPattern, tables::combine_table}, polynomials::permutation, scalars::RandomOracles, wires::{COLUMNS, PERMUTS}, @@ -62,7 +62,7 @@ impl<'a, G: KimchiCurve> Context<'a, G> { .runtime_tables_selector .as_ref()?, ), - LookupRuntimeTable => None, + LookupRuntimeTable => self.proof.commitments.lookup.as_ref()?.runtime.as_ref(), Index(t) => { use GateType::*; match t { @@ -480,6 +480,32 @@ where .into_iter() .flatten(), ) + .chain(if self.evals.runtime_lookup_table_selector.is_some() { + println!("verifier commitments"); + Some(Column::LookupRuntimeSelector) + } else { + None + }) + .chain(if self.evals.xor_lookup_selector.is_some() { + Some(Column::LookupKindIndex(LookupPattern::Xor)) + } else { + None + }) + .chain(if self.evals.lookup_gate_lookup_selector.is_some() { + Some(Column::LookupKindIndex(LookupPattern::Lookup)) + } else { + None + }) + .chain(if self.evals.range_check_lookup_selector.is_some() { + Some(Column::LookupKindIndex(LookupPattern::RangeCheck)) + } else { + None + }) + .chain(if self.evals.foreign_field_mul_lookup_selector.is_some() { + Some(Column::LookupKindIndex(LookupPattern::ForeignFieldMul)) + } else { + None + }) }) .into_iter() .flatten(), @@ -967,6 +993,55 @@ where } } + for col in verifier_index + .lookup_index + .as_ref() + .map(|li| { + (if li.runtime_tables_selector.is_some() { + println!("verifier cip"); + Some(Column::LookupRuntimeSelector) + } else { + None + }) + .into_iter() + .chain(if li.lookup_selectors.xor.is_some() { + Some(Column::LookupKindIndex(LookupPattern::Xor)) + } else { + None + }) + .chain(if li.lookup_selectors.lookup.is_some() { + Some(Column::LookupKindIndex(LookupPattern::Lookup)) + } else { + None + }) + .chain(if li.lookup_selectors.range_check.is_some() { + Some(Column::LookupKindIndex(LookupPattern::RangeCheck)) + } else { + None + }) + .chain(if li.lookup_selectors.ffmul.is_some() { + Some(Column::LookupKindIndex(LookupPattern::ForeignFieldMul)) + } else { + None + }) + }) + .into_iter() + .flatten() + { + let evals = proof + .evals + .get_column(col) + .ok_or(VerifyError::MissingEvaluation(col))?; + evaluations.push(Evaluation { + commitment: context + .get_column(col) + .ok_or(VerifyError::MissingCommitment(col))? + .clone(), + evaluations: vec![evals.zeta.clone(), evals.zeta_omega.clone()], + degree_bound: None, + }); + } + // prepare for the opening proof verification let evaluation_points = vec![oracles.zeta, oracles.zeta * verifier_index.domain.group_gen]; Ok(BatchEvaluationProof { From 7deec015ac500c05103b2d4ae1bfcec6d774ae75 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 10 Jul 2023 18:31:22 +0100 Subject: [PATCH 104/242] Stop println --- kimchi/src/prover.rs | 1 - kimchi/src/verifier.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 1a6460b03d..83c427aacf 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1370,7 +1370,6 @@ where //~~ * the lookup selectors if let Some(runtime_lookup_table_selector) = lcs.runtime_selector.as_ref() { - println!("selector prover"); polynomials.push(( evaluations_form(runtime_lookup_table_selector), None, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 8ba760eb88..43f8b911c3 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -481,7 +481,6 @@ where .flatten(), ) .chain(if self.evals.runtime_lookup_table_selector.is_some() { - println!("verifier commitments"); Some(Column::LookupRuntimeSelector) } else { None @@ -998,7 +997,6 @@ where .as_ref() .map(|li| { (if li.runtime_tables_selector.is_some() { - println!("verifier cip"); Some(Column::LookupRuntimeSelector) } else { None From e0b04cb235ea23e23f120b4b823ed51f521ca516 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 10 Jul 2023 19:00:51 +0100 Subject: [PATCH 105/242] Evaluate all lookup selectors --- kimchi/src/circuits/expr.rs | 19 ++++++++++++++++--- kimchi/src/linearization.rs | 9 ++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 9bdd751481..a5d81fbfea 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -703,9 +703,22 @@ impl Variable { .ok_or(ExprError::MissingIndexEvaluation(self.col)), Permutation(i) => Ok(evals.s[i]), Coefficient(i) => Ok(evals.coefficients[i]), - LookupKindIndex(_) | LookupRuntimeSelector | Index(_) => { - Err(ExprError::MissingIndexEvaluation(self.col)) - } + Column::LookupKindIndex(LookupPattern::Xor) => evals + .xor_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Column::LookupKindIndex(LookupPattern::Lookup) => evals + .lookup_gate_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Column::LookupKindIndex(LookupPattern::RangeCheck) => evals + .range_check_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Column::LookupKindIndex(LookupPattern::ForeignFieldMul) => evals + .foreign_field_mul_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Column::LookupRuntimeSelector => evals + .runtime_lookup_table_selector + .ok_or(ExprError::MissingIndexEvaluation(self.col)), + Index(_) => Err(ExprError::MissingIndexEvaluation(self.col)), } }?; match self.row { diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index cda83d8b54..707856839e 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -6,7 +6,7 @@ use crate::circuits::expr; use crate::circuits::lookup; use crate::circuits::lookup::{ constraints::LookupConfiguration, - lookups::{LookupFeatures, LookupInfo, LookupPatterns}, + lookups::{LookupFeatures, LookupInfo, LookupPattern, LookupPatterns}, }; use crate::circuits::polynomials::{ complete_add::CompleteAdd, @@ -318,6 +318,13 @@ pub fn linearization_columns( h.insert(Index(GateType::Xor16)); h.insert(Index(GateType::Rot64)); + // lookup selectors + h.insert(LookupRuntimeSelector); + h.insert(LookupKindIndex(LookupPattern::Xor)); + h.insert(LookupKindIndex(LookupPattern::Lookup)); + h.insert(LookupKindIndex(LookupPattern::RangeCheck)); + h.insert(LookupKindIndex(LookupPattern::ForeignFieldMul)); + h } From f6ecc27044f49789cda4656723af56b0c9f8e61a Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 10 Jul 2023 22:35:34 +0100 Subject: [PATCH 106/242] Assert that we aren't linearizing --- kimchi/src/linearization.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 707856839e..566ef58216 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -349,5 +349,7 @@ pub fn expr_linearization( .unwrap() .map(|e| e.to_polish()); + assert_eq!(linearization.index_terms.len(), 0); + (linearization, powers_of_alpha) } From 5702626e316fe48537d0f3c8cad4a07eda86ef1f Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Tue, 18 Jul 2023 16:04:05 +0200 Subject: [PATCH 107/242] Update book/src/specs/kimchi.md --- book/src/specs/kimchi.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 74371190c8..a59b3dcc53 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1969,9 +1969,9 @@ pub struct ProofEvaluations { pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial pub poseidon_selector: Evals, - /// evaluation of the EC addition selector polynomial + /// evaluation of the elliptic curve addition selector polynomial pub complete_add_selector: Evals, - /// evaluation of the EC variable base scalar multiplication selector polynomial + /// evaluation of the elliptic curve variable base scalar multiplication selector polynomial pub mul_selector: Evals, /// evaluation of the endoscalar multiplication selector polynomial pub emul_selector: Evals, From ca64a50bbd25f550a3674b4b18a125fc86860438 Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Tue, 18 Jul 2023 16:04:13 +0200 Subject: [PATCH 108/242] Update kimchi/src/proof.rs --- kimchi/src/proof.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 2979043924..4331eadedb 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -76,9 +76,9 @@ pub struct ProofEvaluations { pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial pub poseidon_selector: Evals, - /// evaluation of the EC addition selector polynomial + /// evaluation of the elliptic curve addition selector polynomial pub complete_add_selector: Evals, - /// evaluation of the EC variable base scalar multiplication selector polynomial + /// evaluation of the elliptic curve variable base scalar multiplication selector polynomial pub mul_selector: Evals, /// evaluation of the endoscalar multiplication selector polynomial pub emul_selector: Evals, From d504c2dbfb0e6a13a184637d8a50d4ccd2b055d2 Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Tue, 18 Jul 2023 16:57:37 +0200 Subject: [PATCH 109/242] fixup! Evaluate optional gate selectors --- kimchi/src/verifier.rs | 132 ++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 60 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index e47fb0d426..162dc1d92d 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -437,36 +437,42 @@ where .chain((0..COLUMNS).map(Column::Witness)) .chain((0..COLUMNS).map(Column::Coefficient)) .chain((0..PERMUTS - 1).map(Column::Permutation)) - .chain(if index.range_check0_comm.is_some() { - Some(Column::Index(GateType::RangeCheck0)) - } else { - None - }) - .chain(if index.range_check1_comm.is_some() { - Some(Column::Index(GateType::RangeCheck1)) - } else { - None - }) - .chain(if index.foreign_field_add_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldAdd)) - } else { - None - }) - .chain(if index.foreign_field_mul_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldMul)) - } else { - None - }) - .chain(if index.xor_comm.is_some() { - Some(Column::Index(GateType::Xor16)) - } else { - None - }) - .chain(if index.rot_comm.is_some() { - Some(Column::Index(GateType::Rot64)) - } else { - None - }) + .chain( + index + .range_check0_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck0)), + ) + .chain( + index + .range_check1_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck1)), + ) + .chain( + index + .foreign_field_add_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldAdd)), + ) + .chain( + index + .foreign_field_mul_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldMul)), + ) + .chain( + index + .xor_comm + .as_ref() + .map(|_| Column::Index(GateType::Xor16)), + ) + .chain( + index + .rot_comm + .as_ref() + .map(|_| Column::Index(GateType::Rot64)), + ) .chain( index .lookup_index @@ -822,36 +828,42 @@ where //~~ * sigma commitments .chain((0..PERMUTS - 1).map(Column::Permutation)) //~~ * optional gate commitments - .chain(if verifier_index.range_check0_comm.is_some() { - Some(Column::Index(GateType::RangeCheck0)) - } else { - None - }) - .chain(if verifier_index.range_check1_comm.is_some() { - Some(Column::Index(GateType::RangeCheck1)) - } else { - None - }) - .chain(if verifier_index.foreign_field_add_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldAdd)) - } else { - None - }) - .chain(if verifier_index.foreign_field_mul_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldMul)) - } else { - None - }) - .chain(if verifier_index.xor_comm.is_some() { - Some(Column::Index(GateType::Xor16)) - } else { - None - }) - .chain(if verifier_index.rot_comm.is_some() { - Some(Column::Index(GateType::Rot64)) - } else { - None - }) + .chain( + verifier_index + .range_check0_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck0)), + ) + .chain( + verifier_index + .range_check1_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck1)), + ) + .chain( + verifier_index + .foreign_field_add_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldAdd)), + ) + .chain( + verifier_index + .foreign_field_mul_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldMul)), + ) + .chain( + verifier_index + .xor_comm + .as_ref() + .map(|_| Column::Index(GateType::Xor16)), + ) + .chain( + verifier_index + .rot_comm + .as_ref() + .map(|_| Column::Index(GateType::Rot64)), + ) //~~ * lookup commitments //~ .chain( From a3b0873346ee06f25124750aa60f44a7a0e04159 Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Wed, 19 Jul 2023 16:19:10 +0200 Subject: [PATCH 110/242] Verifier: use Option.map instad of if is_some() pattern --- kimchi/src/verifier.rs | 272 +++++++++++++++++++++-------------------- 1 file changed, 138 insertions(+), 134 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 43f8b911c3..e8e9e886f5 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -413,116 +413,118 @@ where ft_eval0 }; - let combined_inner_product = { - let ft_eval0 = vec![ft_eval0]; - let ft_eval1 = vec![self.ft_eval1]; - - #[allow(clippy::type_complexity)] - let mut es: Vec<(Vec>, Option)> = - polys.iter().map(|(_, e)| (e.clone(), None)).collect(); - es.push((public_evals.to_vec(), None)); - es.push((vec![ft_eval0, ft_eval1], None)); - for col in [ - Column::Z, - Column::Index(GateType::Generic), - Column::Index(GateType::Poseidon), - Column::Index(GateType::CompleteAdd), - Column::Index(GateType::VarBaseMul), - Column::Index(GateType::EndoMul), - Column::Index(GateType::EndoMulScalar), - ] - .into_iter() - .chain((0..COLUMNS).map(Column::Witness)) - .chain((0..COLUMNS).map(Column::Coefficient)) - .chain((0..PERMUTS - 1).map(Column::Permutation)) - .chain(if self.evals.range_check0_selector.is_some() { - Some(Column::Index(GateType::RangeCheck0)) - } else { - None - }) - .chain(if self.evals.range_check1_selector.is_some() { - Some(Column::Index(GateType::RangeCheck1)) - } else { - None - }) - .chain(if self.evals.foreign_field_add_selector.is_some() { - Some(Column::Index(GateType::ForeignFieldAdd)) - } else { - None - }) - .chain(if self.evals.foreign_field_mul_selector.is_some() { - Some(Column::Index(GateType::ForeignFieldMul)) - } else { - None - }) - .chain(if self.evals.xor_selector.is_some() { - Some(Column::Index(GateType::Xor16)) - } else { - None - }) - .chain(if self.evals.rot_selector.is_some() { - Some(Column::Index(GateType::Rot64)) - } else { - None - }) - .chain( - index - .lookup_index - .as_ref() - .map(|li| { - (0..li.lookup_info.max_per_row + 1) - .map(Column::LookupSorted) - .chain([Column::LookupAggreg, Column::LookupTable].into_iter()) - .chain( - li.runtime_tables_selector - .as_ref() - .map(|_| [Column::LookupRuntimeTable].into_iter()) - .into_iter() - .flatten(), - ) - .chain(if self.evals.runtime_lookup_table_selector.is_some() { - Some(Column::LookupRuntimeSelector) - } else { - None - }) - .chain(if self.evals.xor_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Xor)) - } else { - None - }) - .chain(if self.evals.lookup_gate_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Lookup)) - } else { - None - }) - .chain(if self.evals.range_check_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::RangeCheck)) - } else { - None - }) - .chain(if self.evals.foreign_field_mul_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::ForeignFieldMul)) - } else { - None - }) - }) - .into_iter() - .flatten(), - ) { - es.push(( - { - let evals = self - .evals - .get_column(col) - .ok_or(VerifyError::MissingEvaluation(col))?; - vec![evals.zeta.clone(), evals.zeta_omega.clone()] - }, - None, - )) - } + let combined_inner_product = + { + let ft_eval0 = vec![ft_eval0]; + let ft_eval1 = vec![self.ft_eval1]; + + #[allow(clippy::type_complexity)] + let mut es: Vec<(Vec>, Option)> = + polys.iter().map(|(_, e)| (e.clone(), None)).collect(); + es.push((public_evals.to_vec(), None)); + es.push((vec![ft_eval0, ft_eval1], None)); + for col in [ + Column::Z, + Column::Index(GateType::Generic), + Column::Index(GateType::Poseidon), + Column::Index(GateType::CompleteAdd), + Column::Index(GateType::VarBaseMul), + Column::Index(GateType::EndoMul), + Column::Index(GateType::EndoMulScalar), + ] + .into_iter() + .chain((0..COLUMNS).map(Column::Witness)) + .chain((0..COLUMNS).map(Column::Coefficient)) + .chain((0..PERMUTS - 1).map(Column::Permutation)) + .chain(if self.evals.range_check0_selector.is_some() { + Some(Column::Index(GateType::RangeCheck0)) + } else { + None + }) + .chain(if self.evals.range_check1_selector.is_some() { + Some(Column::Index(GateType::RangeCheck1)) + } else { + None + }) + .chain(if self.evals.foreign_field_add_selector.is_some() { + Some(Column::Index(GateType::ForeignFieldAdd)) + } else { + None + }) + .chain(if self.evals.foreign_field_mul_selector.is_some() { + Some(Column::Index(GateType::ForeignFieldMul)) + } else { + None + }) + .chain(if self.evals.xor_selector.is_some() { + Some(Column::Index(GateType::Xor16)) + } else { + None + }) + .chain(if self.evals.rot_selector.is_some() { + Some(Column::Index(GateType::Rot64)) + } else { + None + }) + .chain( + index + .lookup_index + .as_ref() + .map(|li| { + (0..li.lookup_info.max_per_row + 1) + .map(Column::LookupSorted) + .chain([Column::LookupAggreg, Column::LookupTable].into_iter()) + .chain( + li.runtime_tables_selector + .as_ref() + .map(|_| [Column::LookupRuntimeTable].into_iter()) + .into_iter() + .flatten(), + ) + .chain( + self.evals + .runtime_lookup_table_selector + .as_ref() + .map(|_| Column::LookupRuntimeSelector), + ) + .chain( + self.evals + .xor_lookup_selector + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Xor)), + ) + .chain( + self.evals + .lookup_gate_lookup_selector + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Lookup)), + ) + .chain( + self.evals.range_check_lookup_selector.as_ref().map(|_| { + Column::LookupKindIndex(LookupPattern::RangeCheck) + }), + ) + .chain(self.evals.foreign_field_mul_lookup_selector.as_ref().map( + |_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul), + )) + }) + .into_iter() + .flatten(), + ) { + es.push(( + { + let evals = self + .evals + .get_column(col) + .ok_or(VerifyError::MissingEvaluation(col))?; + vec![evals.zeta.clone(), evals.zeta_omega.clone()] + }, + None, + )) + } - combined_inner_product(&evaluation_points, &v, &u, &es, index.srs().g.len()) - }; + combined_inner_product(&evaluation_points, &v, &u, &es, index.srs().g.len()) + }; let oracles = RandomOracles { joint_combiner, @@ -996,32 +998,34 @@ where .lookup_index .as_ref() .map(|li| { - (if li.runtime_tables_selector.is_some() { - Some(Column::LookupRuntimeSelector) - } else { - None - }) + (li.runtime_tables_selector + .as_ref() + .map(|_| Column::LookupRuntimeSelector)) .into_iter() - .chain(if li.lookup_selectors.xor.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Xor)) - } else { - None - }) - .chain(if li.lookup_selectors.lookup.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Lookup)) - } else { - None - }) - .chain(if li.lookup_selectors.range_check.is_some() { - Some(Column::LookupKindIndex(LookupPattern::RangeCheck)) - } else { - None - }) - .chain(if li.lookup_selectors.ffmul.is_some() { - Some(Column::LookupKindIndex(LookupPattern::ForeignFieldMul)) - } else { - None - }) + .chain( + li.lookup_selectors + .xor + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Xor)), + ) + .chain( + li.lookup_selectors + .lookup + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Lookup)), + ) + .chain( + li.lookup_selectors + .range_check + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::RangeCheck)), + ) + .chain( + li.lookup_selectors + .ffmul + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul)), + ) }) .into_iter() .flatten() From 439d223ff2251901fb359a4a96d3eb024ae4958c Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 20 Jul 2023 17:37:07 +0200 Subject: [PATCH 111/242] Remove sourcegraph from CI in berkeley --- .github/workflows/sourcegraph.yml | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 .github/workflows/sourcegraph.yml diff --git a/.github/workflows/sourcegraph.yml b/.github/workflows/sourcegraph.yml deleted file mode 100644 index 315f213d55..0000000000 --- a/.github/workflows/sourcegraph.yml +++ /dev/null @@ -1,19 +0,0 @@ -# This Github action allows us to obtain better browsable code -# on https://sourcegraph.com/github.com/o1-labs/proof-systems - -name: Sourcegraph (LSIF) - -on: - - push - -jobs: - index: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Generate LSIF data - uses: sourcegraph/lsif-rust-action@main - - name: Upload LSIF data - uses: sourcegraph/lsif-upload-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} From 03c12bba2a05f87f5466b42b2c73ec293f5a5bfc Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 20 Jul 2023 21:38:26 +0200 Subject: [PATCH 112/242] Bump up actions/checkout to v3 Addressing https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/ --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9d130c8810..d99986aa59 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -28,7 +28,7 @@ jobs: name: Run some basic checks and tests steps: - name: Checkout PR - uses: actions/checkout@v2 + uses: actions/checkout@v3 # as action-rs does not seem to be maintained anymore, building from # scratch the environment using rustup From aa5abdc24f629a36c3e349125424bd57c8131cd3 Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Fri, 21 Jul 2023 10:35:12 +0200 Subject: [PATCH 113/242] Kimchi: apply clippy suggestions to use flatten() --- kimchi/src/verifier.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 403c1d74e1..71104c0848 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -579,11 +579,10 @@ where } // Lookup evaluations - for sorted in lookup_sorted { - if let Some(sorted) = sorted { - check_eval_len(sorted)?; - } + for sorted in lookup_sorted.iter().flatten() { + check_eval_len(sorted)? } + if let Some(lookup_aggregation) = lookup_aggregation { check_eval_len(lookup_aggregation)?; } From fe3985259e53f7fcd5f16a8a0c76255423818221 Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Tue, 18 Jul 2023 16:57:37 +0200 Subject: [PATCH 114/242] fixup! Evaluate optional gate selectors --- kimchi/src/verifier.rs | 132 ++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 60 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index e47fb0d426..162dc1d92d 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -437,36 +437,42 @@ where .chain((0..COLUMNS).map(Column::Witness)) .chain((0..COLUMNS).map(Column::Coefficient)) .chain((0..PERMUTS - 1).map(Column::Permutation)) - .chain(if index.range_check0_comm.is_some() { - Some(Column::Index(GateType::RangeCheck0)) - } else { - None - }) - .chain(if index.range_check1_comm.is_some() { - Some(Column::Index(GateType::RangeCheck1)) - } else { - None - }) - .chain(if index.foreign_field_add_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldAdd)) - } else { - None - }) - .chain(if index.foreign_field_mul_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldMul)) - } else { - None - }) - .chain(if index.xor_comm.is_some() { - Some(Column::Index(GateType::Xor16)) - } else { - None - }) - .chain(if index.rot_comm.is_some() { - Some(Column::Index(GateType::Rot64)) - } else { - None - }) + .chain( + index + .range_check0_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck0)), + ) + .chain( + index + .range_check1_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck1)), + ) + .chain( + index + .foreign_field_add_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldAdd)), + ) + .chain( + index + .foreign_field_mul_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldMul)), + ) + .chain( + index + .xor_comm + .as_ref() + .map(|_| Column::Index(GateType::Xor16)), + ) + .chain( + index + .rot_comm + .as_ref() + .map(|_| Column::Index(GateType::Rot64)), + ) .chain( index .lookup_index @@ -822,36 +828,42 @@ where //~~ * sigma commitments .chain((0..PERMUTS - 1).map(Column::Permutation)) //~~ * optional gate commitments - .chain(if verifier_index.range_check0_comm.is_some() { - Some(Column::Index(GateType::RangeCheck0)) - } else { - None - }) - .chain(if verifier_index.range_check1_comm.is_some() { - Some(Column::Index(GateType::RangeCheck1)) - } else { - None - }) - .chain(if verifier_index.foreign_field_add_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldAdd)) - } else { - None - }) - .chain(if verifier_index.foreign_field_mul_comm.is_some() { - Some(Column::Index(GateType::ForeignFieldMul)) - } else { - None - }) - .chain(if verifier_index.xor_comm.is_some() { - Some(Column::Index(GateType::Xor16)) - } else { - None - }) - .chain(if verifier_index.rot_comm.is_some() { - Some(Column::Index(GateType::Rot64)) - } else { - None - }) + .chain( + verifier_index + .range_check0_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck0)), + ) + .chain( + verifier_index + .range_check1_comm + .as_ref() + .map(|_| Column::Index(GateType::RangeCheck1)), + ) + .chain( + verifier_index + .foreign_field_add_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldAdd)), + ) + .chain( + verifier_index + .foreign_field_mul_comm + .as_ref() + .map(|_| Column::Index(GateType::ForeignFieldMul)), + ) + .chain( + verifier_index + .xor_comm + .as_ref() + .map(|_| Column::Index(GateType::Xor16)), + ) + .chain( + verifier_index + .rot_comm + .as_ref() + .map(|_| Column::Index(GateType::Rot64)), + ) //~~ * lookup commitments //~ .chain( From e82459eeddc5d61fa9a9a46c785500a89b51bc63 Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Fri, 21 Jul 2023 10:35:12 +0200 Subject: [PATCH 115/242] Kimchi: apply clippy suggestions to use flatten() --- kimchi/src/verifier.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 403c1d74e1..71104c0848 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -579,11 +579,10 @@ where } // Lookup evaluations - for sorted in lookup_sorted { - if let Some(sorted) = sorted { - check_eval_len(sorted)?; - } + for sorted in lookup_sorted.iter().flatten() { + check_eval_len(sorted)? } + if let Some(lookup_aggregation) = lookup_aggregation { check_eval_len(lookup_aggregation)?; } From 0e8f1b23ce182eace825aa5bae1682910f732765 Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Wed, 19 Jul 2023 16:19:10 +0200 Subject: [PATCH 116/242] Verifier: use Option.map instad of if is_some() pattern --- kimchi/src/verifier.rs | 272 +++++++++++++++++++++-------------------- 1 file changed, 138 insertions(+), 134 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 43f8b911c3..e8e9e886f5 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -413,116 +413,118 @@ where ft_eval0 }; - let combined_inner_product = { - let ft_eval0 = vec![ft_eval0]; - let ft_eval1 = vec![self.ft_eval1]; - - #[allow(clippy::type_complexity)] - let mut es: Vec<(Vec>, Option)> = - polys.iter().map(|(_, e)| (e.clone(), None)).collect(); - es.push((public_evals.to_vec(), None)); - es.push((vec![ft_eval0, ft_eval1], None)); - for col in [ - Column::Z, - Column::Index(GateType::Generic), - Column::Index(GateType::Poseidon), - Column::Index(GateType::CompleteAdd), - Column::Index(GateType::VarBaseMul), - Column::Index(GateType::EndoMul), - Column::Index(GateType::EndoMulScalar), - ] - .into_iter() - .chain((0..COLUMNS).map(Column::Witness)) - .chain((0..COLUMNS).map(Column::Coefficient)) - .chain((0..PERMUTS - 1).map(Column::Permutation)) - .chain(if self.evals.range_check0_selector.is_some() { - Some(Column::Index(GateType::RangeCheck0)) - } else { - None - }) - .chain(if self.evals.range_check1_selector.is_some() { - Some(Column::Index(GateType::RangeCheck1)) - } else { - None - }) - .chain(if self.evals.foreign_field_add_selector.is_some() { - Some(Column::Index(GateType::ForeignFieldAdd)) - } else { - None - }) - .chain(if self.evals.foreign_field_mul_selector.is_some() { - Some(Column::Index(GateType::ForeignFieldMul)) - } else { - None - }) - .chain(if self.evals.xor_selector.is_some() { - Some(Column::Index(GateType::Xor16)) - } else { - None - }) - .chain(if self.evals.rot_selector.is_some() { - Some(Column::Index(GateType::Rot64)) - } else { - None - }) - .chain( - index - .lookup_index - .as_ref() - .map(|li| { - (0..li.lookup_info.max_per_row + 1) - .map(Column::LookupSorted) - .chain([Column::LookupAggreg, Column::LookupTable].into_iter()) - .chain( - li.runtime_tables_selector - .as_ref() - .map(|_| [Column::LookupRuntimeTable].into_iter()) - .into_iter() - .flatten(), - ) - .chain(if self.evals.runtime_lookup_table_selector.is_some() { - Some(Column::LookupRuntimeSelector) - } else { - None - }) - .chain(if self.evals.xor_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Xor)) - } else { - None - }) - .chain(if self.evals.lookup_gate_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Lookup)) - } else { - None - }) - .chain(if self.evals.range_check_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::RangeCheck)) - } else { - None - }) - .chain(if self.evals.foreign_field_mul_lookup_selector.is_some() { - Some(Column::LookupKindIndex(LookupPattern::ForeignFieldMul)) - } else { - None - }) - }) - .into_iter() - .flatten(), - ) { - es.push(( - { - let evals = self - .evals - .get_column(col) - .ok_or(VerifyError::MissingEvaluation(col))?; - vec![evals.zeta.clone(), evals.zeta_omega.clone()] - }, - None, - )) - } + let combined_inner_product = + { + let ft_eval0 = vec![ft_eval0]; + let ft_eval1 = vec![self.ft_eval1]; + + #[allow(clippy::type_complexity)] + let mut es: Vec<(Vec>, Option)> = + polys.iter().map(|(_, e)| (e.clone(), None)).collect(); + es.push((public_evals.to_vec(), None)); + es.push((vec![ft_eval0, ft_eval1], None)); + for col in [ + Column::Z, + Column::Index(GateType::Generic), + Column::Index(GateType::Poseidon), + Column::Index(GateType::CompleteAdd), + Column::Index(GateType::VarBaseMul), + Column::Index(GateType::EndoMul), + Column::Index(GateType::EndoMulScalar), + ] + .into_iter() + .chain((0..COLUMNS).map(Column::Witness)) + .chain((0..COLUMNS).map(Column::Coefficient)) + .chain((0..PERMUTS - 1).map(Column::Permutation)) + .chain(if self.evals.range_check0_selector.is_some() { + Some(Column::Index(GateType::RangeCheck0)) + } else { + None + }) + .chain(if self.evals.range_check1_selector.is_some() { + Some(Column::Index(GateType::RangeCheck1)) + } else { + None + }) + .chain(if self.evals.foreign_field_add_selector.is_some() { + Some(Column::Index(GateType::ForeignFieldAdd)) + } else { + None + }) + .chain(if self.evals.foreign_field_mul_selector.is_some() { + Some(Column::Index(GateType::ForeignFieldMul)) + } else { + None + }) + .chain(if self.evals.xor_selector.is_some() { + Some(Column::Index(GateType::Xor16)) + } else { + None + }) + .chain(if self.evals.rot_selector.is_some() { + Some(Column::Index(GateType::Rot64)) + } else { + None + }) + .chain( + index + .lookup_index + .as_ref() + .map(|li| { + (0..li.lookup_info.max_per_row + 1) + .map(Column::LookupSorted) + .chain([Column::LookupAggreg, Column::LookupTable].into_iter()) + .chain( + li.runtime_tables_selector + .as_ref() + .map(|_| [Column::LookupRuntimeTable].into_iter()) + .into_iter() + .flatten(), + ) + .chain( + self.evals + .runtime_lookup_table_selector + .as_ref() + .map(|_| Column::LookupRuntimeSelector), + ) + .chain( + self.evals + .xor_lookup_selector + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Xor)), + ) + .chain( + self.evals + .lookup_gate_lookup_selector + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Lookup)), + ) + .chain( + self.evals.range_check_lookup_selector.as_ref().map(|_| { + Column::LookupKindIndex(LookupPattern::RangeCheck) + }), + ) + .chain(self.evals.foreign_field_mul_lookup_selector.as_ref().map( + |_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul), + )) + }) + .into_iter() + .flatten(), + ) { + es.push(( + { + let evals = self + .evals + .get_column(col) + .ok_or(VerifyError::MissingEvaluation(col))?; + vec![evals.zeta.clone(), evals.zeta_omega.clone()] + }, + None, + )) + } - combined_inner_product(&evaluation_points, &v, &u, &es, index.srs().g.len()) - }; + combined_inner_product(&evaluation_points, &v, &u, &es, index.srs().g.len()) + }; let oracles = RandomOracles { joint_combiner, @@ -996,32 +998,34 @@ where .lookup_index .as_ref() .map(|li| { - (if li.runtime_tables_selector.is_some() { - Some(Column::LookupRuntimeSelector) - } else { - None - }) + (li.runtime_tables_selector + .as_ref() + .map(|_| Column::LookupRuntimeSelector)) .into_iter() - .chain(if li.lookup_selectors.xor.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Xor)) - } else { - None - }) - .chain(if li.lookup_selectors.lookup.is_some() { - Some(Column::LookupKindIndex(LookupPattern::Lookup)) - } else { - None - }) - .chain(if li.lookup_selectors.range_check.is_some() { - Some(Column::LookupKindIndex(LookupPattern::RangeCheck)) - } else { - None - }) - .chain(if li.lookup_selectors.ffmul.is_some() { - Some(Column::LookupKindIndex(LookupPattern::ForeignFieldMul)) - } else { - None - }) + .chain( + li.lookup_selectors + .xor + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Xor)), + ) + .chain( + li.lookup_selectors + .lookup + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::Lookup)), + ) + .chain( + li.lookup_selectors + .range_check + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::RangeCheck)), + ) + .chain( + li.lookup_selectors + .ffmul + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul)), + ) }) .into_iter() .flatten() From 00328293078068df48d2c9b0c734624cb69880ec Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 20 Jul 2023 21:40:16 +0200 Subject: [PATCH 117/242] Bump up actions/checkout to v3 Addressing https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/ --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3f3fcbdfdb..b32a3e8ee0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -24,7 +24,7 @@ jobs: # - name: Checkout PR - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up cargo/rust uses: actions-rs/toolchain@v1 From 8285412ddb96e1181cc87aef3651541f585740dd Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Aug 2023 11:54:34 +0200 Subject: [PATCH 118/242] Expose LookupInfo related structures with wasm_bindgen --- kimchi/src/circuits/lookup/lookups.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 8d9bec6169..b9168f34a0 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -42,6 +42,7 @@ fn max_lookups_per_row(kinds: LookupPatterns) -> usize { feature = "ocaml_types", derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct) )] +#[cfg_attr(feature = "wasm_types", wasm_bindgen::prelude::wasm_bindgen)] pub struct LookupPatterns { pub xor: bool, pub lookup: bool, @@ -133,6 +134,7 @@ impl LookupPatterns { feature = "ocaml_types", derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct) )] +#[cfg_attr(feature = "wasm_types", wasm_bindgen::prelude::wasm_bindgen)] pub struct LookupFeatures { /// A single lookup constraint is a vector of lookup constraints to be applied at a row. pub patterns: LookupPatterns, @@ -158,6 +160,7 @@ impl LookupFeatures { /// Describes the desired lookup configuration. #[derive(Clone, Serialize, Deserialize, Debug)] +#[cfg_attr(feature = "wasm_types", wasm_bindgen::prelude::wasm_bindgen)] pub struct LookupInfo { /// The maximum length of an element of `kinds`. This can be computed from `kinds`. pub max_per_row: usize, From 4fbc1becc3bee0958ab67830e405bffe0c53956c Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Aug 2023 18:45:28 +0200 Subject: [PATCH 119/242] LookupInfo: add copy trait for wasm bindings --- kimchi/src/circuits/lookup/lookups.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index b9168f34a0..6b6de6a517 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -159,7 +159,7 @@ impl LookupFeatures { } /// Describes the desired lookup configuration. -#[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Copy, Clone, Serialize, Deserialize, Debug)] #[cfg_attr(feature = "wasm_types", wasm_bindgen::prelude::wasm_bindgen)] pub struct LookupInfo { /// The maximum length of an element of `kinds`. This can be computed from `kinds`. From 28d2a8896ff12f69be9cc6c0aafea4c3a0148611 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 21 Aug 2023 15:19:10 +0200 Subject: [PATCH 120/242] Kimchi - verifier index: remove clone call to make clippy happy --- kimchi/src/verifier_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 9e3651ed4b..a7f7b28d14 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -176,7 +176,7 @@ impl ProverIndex { .as_ref() .map(|cs| LookupVerifierIndex { joint_lookup_used: cs.configuration.lookup_info.features.joint_lookup_used, - lookup_info: cs.configuration.lookup_info.clone(), + lookup_info: cs.configuration.lookup_info, lookup_selectors: cs .lookup_selectors .as_ref() From e0aae1c514063fc1a0de5e01a5f131c8142a9169 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 22 Aug 2023 20:13:04 +0200 Subject: [PATCH 121/242] Remove old TODO --- kimchi/src/tests/lookup.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/kimchi/src/tests/lookup.rs b/kimchi/src/tests/lookup.rs index 8fa4ac9723..9fd41dae1e 100644 --- a/kimchi/src/tests/lookup.rs +++ b/kimchi/src/tests/lookup.rs @@ -381,5 +381,3 @@ fn test_negative_test_runtime_table_prover_uses_undefined_id_in_index_and_witnes ); } -// TODO: add a test with a runtime table with ID 0 (it should panic) -// See https://github.com/MinaProtocol/mina/issues/13603 From 9f0b07a64336a41c4b9304191774d19e6472a7d6 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 22 Aug 2023 20:45:02 +0200 Subject: [PATCH 122/242] Add a negative test for runtime table One runtime table cfg and two runtime tables given by prover --- kimchi/src/tests/lookup.rs | 84 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/kimchi/src/tests/lookup.rs b/kimchi/src/tests/lookup.rs index 9fd41dae1e..933e350611 100644 --- a/kimchi/src/tests/lookup.rs +++ b/kimchi/src/tests/lookup.rs @@ -381,3 +381,87 @@ fn test_negative_test_runtime_table_prover_uses_undefined_id_in_index_and_witnes ); } +#[test] +fn test_runtime_table_with_more_than_one_runtime_table_data_given_by_prover() { + let mut rng = rand::thread_rng(); + + let first_column = [0, 1, 2, 3, 4]; + let len = first_column.len(); + + let cfg = RuntimeTableCfg { + id: 1, + first_column: first_column.into_iter().map(Into::into).collect(), + }; + + /* We want to simulate this + table ID | idx | v | v2 + 1 | 0 | 0 | 42 + 1 | 1 | 2 | 32 + 1 | 2 | 4 | 22 + 1 | 3 | 5 | 12 + 1 | 4 | 4 | 2 + */ + + let data_v: Vec = [0u32, 2, 3, 4, 5].into_iter().map(Into::into).collect(); + let data_v2: Vec = [42, 32, 22, 12, 2].into_iter().map(Into::into).collect(); + let runtime_tables: Vec> = vec![ + RuntimeTable { + id: 1, + data: data_v.clone(), + }, + RuntimeTable { + id: 1, + data: data_v2, + }, + ]; + + // circuit + let mut gates = vec![]; + for row in 0..20 { + gates.push(CircuitGate::new( + GateType::Lookup, + Wire::for_row(row), + vec![], + )); + } + + // witness + let witness = { + let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); + + // only the first 7 registers are used in the lookup gate + let (lookup_cols, _rest) = cols.split_at_mut(7); + + for row in 0..20 { + // the first register is the table id. + lookup_cols[0][row] = 1.into(); + + // create queries into our runtime lookup table. + // We will set [w1, w2], [w3, w4] and [w5, w6] to randon indexes and + // the corresponding values + let lookup_cols = &mut lookup_cols[1..]; + for chunk in lookup_cols.chunks_mut(2) { + let idx = rng.gen_range(0..len); + chunk[0][row] = first_column[idx].into(); + chunk[1][row] = data_v[idx]; + } + } + cols + }; + + print_witness(&witness, 0, 20); + + // run test + let err = TestFramework::::default() + .gates(gates) + .witness(witness) + .runtime_tables_setup(vec![cfg]) + .setup() + .runtime_tables(runtime_tables) + .prove_and_verify::() + .unwrap_err(); + assert_eq!( + err, + "the runtime tables provided did not match the index's configuration" + ); +} From 9a237c997ce2494be623244acac063bac76f0433 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 1 Sep 2023 17:03:32 +0100 Subject: [PATCH 123/242] Use the correct number of blinders for chunking --- kimchi/src/prover.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index b2fe288af9..6ec922bd63 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1244,22 +1244,22 @@ where polynomials.push(( evaluations_form(&index.column_evaluations.complete_add_selector4), None, - fixed_hiding(1), + fixed_hiding(num_chunks), )); polynomials.push(( evaluations_form(&index.column_evaluations.mul_selector8), None, - fixed_hiding(1), + fixed_hiding(num_chunks), )); polynomials.push(( evaluations_form(&index.column_evaluations.emul_selector8), None, - fixed_hiding(1), + fixed_hiding(num_chunks), )); polynomials.push(( evaluations_form(&index.column_evaluations.endomul_scalar_selector8), None, - fixed_hiding(1), + fixed_hiding(num_chunks), )); polynomials.extend( witness_poly @@ -1290,7 +1290,7 @@ where polynomials.push(( evaluations_form(range_check0_selector8), None, - non_hiding(1), + non_hiding(num_chunks), )); } if let Some(range_check1_selector8) = @@ -1299,7 +1299,7 @@ where polynomials.push(( evaluations_form(range_check1_selector8), None, - non_hiding(1), + non_hiding(num_chunks), )); } if let Some(foreign_field_add_selector8) = index @@ -1310,7 +1310,7 @@ where polynomials.push(( evaluations_form(foreign_field_add_selector8), None, - non_hiding(1), + non_hiding(num_chunks), )); } if let Some(foreign_field_mul_selector8) = index @@ -1321,14 +1321,22 @@ where polynomials.push(( evaluations_form(foreign_field_mul_selector8), None, - non_hiding(1), + non_hiding(num_chunks), )); } if let Some(xor_selector8) = index.column_evaluations.xor_selector8.as_ref() { - polynomials.push((evaluations_form(xor_selector8), None, non_hiding(1))); + polynomials.push(( + evaluations_form(xor_selector8), + None, + non_hiding(num_chunks), + )); } if let Some(rot_selector8) = index.column_evaluations.rot_selector8.as_ref() { - polynomials.push((evaluations_form(rot_selector8), None, non_hiding(1))); + polynomials.push(( + evaluations_form(rot_selector8), + None, + non_hiding(num_chunks), + )); } //~~ * optionally, the runtime table From 264ed4928cc71d8db6b3bf03a96875a1074e0f9e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 8 Sep 2023 15:17:00 +0200 Subject: [PATCH 124/242] Domain computation: runtime table cfg is given as option, not list iter() was applied on the option, not the list --- kimchi/src/circuits/constraints.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 238e725bc1..078c850650 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -668,8 +668,11 @@ impl Builder { }, ) .sum(); - for runtime_table in runtime_tables.iter() { - num_lookups += runtime_table.len(); + if runtime_tables.is_some() { + let runtime_tables = runtime_tables.as_ref().unwrap(); + for runtime_table in runtime_tables.iter() { + num_lookups += runtime_table.len(); + } } let LookupFeatures { patterns, .. } = &lookup_features; for pattern in patterns.into_iter() { From f280edd4b193b9cb675b357f8ffabb6212dc27ad Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 8 Sep 2023 15:30:44 +0200 Subject: [PATCH 125/242] Rename num_lookups in lookup_domain_size and add comments --- kimchi/src/circuits/constraints.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 078c850650..0897fcac18 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -655,8 +655,9 @@ impl Builder { let lookup_features = LookupFeatures::from_gates(&gates, runtime_tables.is_some()); - let num_lookups = { - let mut num_lookups: usize = lookup_tables + let lookup_domain_size = { + // First we sum over the lookup table size + let mut lookup_domain_size: usize = lookup_tables .iter() .map( |LookupTable { data, id: _ }| { @@ -668,26 +669,28 @@ impl Builder { }, ) .sum(); + // After that on the runtime tables if runtime_tables.is_some() { let runtime_tables = runtime_tables.as_ref().unwrap(); for runtime_table in runtime_tables.iter() { - num_lookups += runtime_table.len(); + lookup_domain_size += runtime_table.len(); } } + // And we add the built-in tables, depending on the features. let LookupFeatures { patterns, .. } = &lookup_features; for pattern in patterns.into_iter() { if let Some(gate_table) = pattern.table() { - num_lookups += gate_table.table_size(); + lookup_domain_size += gate_table.table_size(); } } - num_lookups + lookup_domain_size }; //~ 2. Create a domain for the circuit. That is, //~ compute the smallest subgroup of the field that //~ has order greater or equal to `n + ZK_ROWS` elements. let domain_size_lower_bound = - std::cmp::max(gates.len(), num_lookups + 1) + ZK_ROWS as usize; + std::cmp::max(gates.len(), lookup_domain_size + 1) + ZK_ROWS as usize; let domain = EvaluationDomains::::create(domain_size_lower_bound)?; assert!(domain.d1.size > ZK_ROWS); From 96f5ce704baa9cc6350118f077d42b866e69ba14 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 8 Sep 2023 17:59:11 +0200 Subject: [PATCH 126/242] Runtime tables: add tests regarding domain computation --- kimchi/src/circuits/constraints.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 0897fcac18..f11337be17 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -795,4 +795,32 @@ pub mod tests { Self::for_testing(gates) } } + + #[test] + pub fn test_domains_computation_with_runtime_tables() { + let dummy_gate = CircuitGate { + typ: GateType::Generic, + wires: [Wire::new(0, 0); PERMUTS], + coeffs: vec![Fp::zero()], + }; + // inputs + expected output + let data = [((10, 10), 128), ((0, 0), 8), ((5, 100), 512)]; + for ((number_of_rt_cfgs, size), expected_domain_size) in data.into_iter() { + let builder = ConstraintSystem::create(vec![dummy_gate.clone(), dummy_gate.clone()]); + let table_ids: Vec = (0..number_of_rt_cfgs).collect(); + let rt_cfgs: Vec> = table_ids + .into_iter() + .map(|table_id| { + let indexes: Vec = (0..size).collect(); + let first_column: Vec = indexes.into_iter().map(Fp::from).collect(); + RuntimeTableCfg { + id: table_id, + first_column, + } + }) + .collect(); + let res = builder.runtime(Some(rt_cfgs)).build().unwrap(); + assert_eq!(res.domain.d1.size, expected_domain_size) + } + } } From 58c9b33a7bde95f0cda4e06fc2a35b1dda752fc2 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 8 Sep 2023 18:03:11 +0200 Subject: [PATCH 127/242] Runtime tables: apply syntax shortcut --- kimchi/src/circuits/constraints.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index f11337be17..d140157dad 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -670,8 +670,7 @@ impl Builder { ) .sum(); // After that on the runtime tables - if runtime_tables.is_some() { - let runtime_tables = runtime_tables.as_ref().unwrap(); + if let Some(runtime_tables) = runtime_tables.as_ref() { for runtime_table in runtime_tables.iter() { lookup_domain_size += runtime_table.len(); } From 607e39fb2a55a64d1014eacb7fe49ea94273cdab Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 12 Sep 2023 11:39:24 +0200 Subject: [PATCH 128/242] Lookup tables: get length using method instead of relying on struct field --- kimchi/src/circuits/lookup/index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index e04816c41d..53ea80e304 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -348,7 +348,7 @@ impl LookupConstraintSystem { let mut has_table_id_0_with_zero_entry = false; for table in &lookup_tables { - let table_len = table.data[0].len(); + let table_len = table.len(); if table.id == 0 { has_table_id_0 = true; From 6d005b465aa408ffbac332c069e81ee644de1812 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 12 Sep 2023 11:44:00 +0200 Subject: [PATCH 129/242] Link to GH issue --- kimchi/src/circuits/lookup/index.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index e04816c41d..422941aec8 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -366,6 +366,7 @@ impl LookupConstraintSystem { //~~ * Copy the entries from the table to new rows in the corresponding columns of the concatenated table. for (i, col) in table.data.iter().enumerate() { + // See GH issue: https://github.com/MinaProtocol/mina/issues/14097 if col.len() != table_len { return Err(LookupError::InconsistentTableLength); } From bf135f5deba86b3a70a652154ae66b5c20f6e14d Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 12 Sep 2023 11:31:40 +0200 Subject: [PATCH 130/242] Lookup tables: introduce width method to get the width Using self.data.len() can be error-prone and an index is easily introduced. It is also always better to abstract with an API using methods. In the future, I would recommend to make the data field abstract. --- kimchi/src/circuits/lookup/index.rs | 4 ++-- kimchi/src/circuits/lookup/tables/mod.rs | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index e04816c41d..a81a1342b2 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -296,7 +296,7 @@ impl LookupConstraintSystem { //~ that a lookup table can have. let max_table_width = lookup_tables .iter() - .map(|table| table.data.len()) + .map(|table| table.width()) .max() .unwrap_or(0); @@ -373,7 +373,7 @@ impl LookupConstraintSystem { } //~~ * Fill in any unused columns with 0 (to match the dummy value) - for lookup_table in lookup_table.iter_mut().skip(table.data.len()) { + for lookup_table in lookup_table.iter_mut().skip(table.width()) { lookup_table.extend(repeat_n(F::zero(), table_len)); } } diff --git a/kimchi/src/circuits/lookup/tables/mod.rs b/kimchi/src/circuits/lookup/tables/mod.rs index 9d34012b97..ed2632aa9e 100644 --- a/kimchi/src/circuits/lookup/tables/mod.rs +++ b/kimchi/src/circuits/lookup/tables/mod.rs @@ -47,6 +47,13 @@ where false } + /// Returns the number of columns, i.e. the width of the table. + /// It is less error prone to introduce this method than using the public + /// field data. + pub fn width(&self) -> usize { + self.data.len() + } + /// Returns the length of the table. pub fn len(&self) -> usize { self.data[0].len() From fdb48ee30f94c48b48a66514fd3b61aa2a7e5d33 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 12 Sep 2023 11:50:00 +0200 Subject: [PATCH 131/242] Lookup table: use len instead of `data[0].len` --- kimchi/src/circuits/lookup/tables/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/lookup/tables/mod.rs b/kimchi/src/circuits/lookup/tables/mod.rs index 9d34012b97..c6b1b9f01f 100644 --- a/kimchi/src/circuits/lookup/tables/mod.rs +++ b/kimchi/src/circuits/lookup/tables/mod.rs @@ -35,7 +35,7 @@ where pub fn has_zero_entry(&self) -> bool { // reminder: a table is written as a list of columns, // not as a list of row entries. - for row in 0..self.data[0].len() { + for row in 0..self.len() { for col in &self.data { if !col[row].is_zero() { continue; From 3fc85ba263cd90b0c58cb64474cac2f6bf270c95 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 12 Sep 2023 12:48:49 +0200 Subject: [PATCH 132/242] Test runtime tables with ID zero --- kimchi/src/tests/lookup.rs | 138 ++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/kimchi/src/tests/lookup.rs b/kimchi/src/tests/lookup.rs index 933e350611..8fab3d1a96 100644 --- a/kimchi/src/tests/lookup.rs +++ b/kimchi/src/tests/lookup.rs @@ -8,7 +8,7 @@ use crate::circuits::{ polynomial::COLUMNS, wires::Wire, }; -use ark_ff::Zero; +use ark_ff::{UniformRand, Zero}; use mina_curves::pasta::{Fp, Vesta, VestaParameters}; use mina_poseidon::{ constants::PlonkSpongeConstantsKimchi, @@ -465,3 +465,139 @@ fn test_runtime_table_with_more_than_one_runtime_table_data_given_by_prover() { "the runtime tables provided did not match the index's configuration" ); } + +#[test] +fn test_runtime_table_only_one_table_with_id_zero_with_non_zero_entries_fixed_values() { + let mut rng = rand::thread_rng(); + + let first_column = [0, 1, 2, 3, 4, 5]; + let len = first_column.len(); + + let table_id = 0; + + let cfg = RuntimeTableCfg { + id: table_id, + first_column: first_column.into_iter().map(Into::into).collect(), + }; + + let data: Vec = [0u32, 1, 2, 3, 4, 5].into_iter().map(Into::into).collect(); + let runtime_table = RuntimeTable { + id: table_id, + data: data.clone(), + }; + + // circuit + let n_row = 20; + let mut gates = vec![]; + for row in 0..n_row { + gates.push(CircuitGate::new( + GateType::Lookup, + Wire::for_row(row), + vec![], + )); + } + + // witness + let witness = { + let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); + + // only the first 7 registers are used in the lookup gate + let (lookup_cols, _rest) = cols.split_at_mut(7); + + for row in 0..n_row { + // Lookup in table ID 0 + lookup_cols[0][row] = Fp::zero(); + + // create queries into our runtime lookup table. + // We will set [w1, w2], [w3, w4] and [w5, w6] to randon indexes and + // the corresponding values + let lookup_cols = &mut lookup_cols[1..]; + for chunk in lookup_cols.chunks_mut(2) { + let idx = rng.gen_range(0..len); + chunk[0][row] = first_column[idx].into(); + chunk[1][row] = data[idx]; + } + } + cols + }; + + // run test + TestFramework::::default() + .gates(gates) + .witness(witness) + .runtime_tables_setup(vec![cfg]) + .setup() + .runtime_tables(vec![runtime_table]) + .prove_and_verify::() + .unwrap(); +} + +#[test] +fn test_runtime_table_only_one_table_with_id_zero_with_non_zero_entries_random_values() { + let mut rng = rand::thread_rng(); + + let len = rng.gen_range(1usize..1000); + let first_column: Vec = (0..len as i32).collect(); + + let table_id = 0; + + let cfg = RuntimeTableCfg { + id: table_id, + first_column: first_column.clone().into_iter().map(Into::into).collect(), + }; + + let data: Vec = first_column + .clone() + .into_iter() + .map(|_| UniformRand::rand(&mut rng)) + .collect(); + let runtime_table = RuntimeTable { + id: table_id, + data: data.clone(), + }; + + // circuit + let n_row = 20; + let mut gates = vec![]; + for row in 0..n_row { + gates.push(CircuitGate::new( + GateType::Lookup, + Wire::for_row(row), + vec![], + )); + } + + // witness + let witness = { + let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); + + // only the first 7 registers are used in the lookup gate + let (lookup_cols, _rest) = cols.split_at_mut(7); + + for row in 0..n_row { + // Lookup in table ID 0 + lookup_cols[0][row] = Fp::zero(); + + // create queries into our runtime lookup table. + // We will set [w1, w2], [w3, w4] and [w5, w6] to randon indexes and + // the corresponding values + let lookup_cols = &mut lookup_cols[1..]; + for chunk in lookup_cols.chunks_mut(2) { + let idx = rng.gen_range(0..len); + chunk[0][row] = first_column[idx].into(); + chunk[1][row] = data[idx]; + } + } + cols + }; + + // run test + TestFramework::::default() + .gates(gates) + .witness(witness) + .runtime_tables_setup(vec![cfg]) + .setup() + .runtime_tables(vec![runtime_table]) + .prove_and_verify::() + .unwrap(); +} From 8193de769e55bf8f1e6da7be885a13b5f795b759 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 12 Sep 2023 16:42:22 +0200 Subject: [PATCH 133/242] Test: refactorize the runtime table tests when code can be shared --- kimchi/src/tests/lookup.rs | 170 ++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 99 deletions(-) diff --git a/kimchi/src/tests/lookup.rs b/kimchi/src/tests/lookup.rs index 8fab3d1a96..a674eba78f 100644 --- a/kimchi/src/tests/lookup.rs +++ b/kimchi/src/tests/lookup.rs @@ -126,6 +126,71 @@ fn lookup_gate_rejects_bad_lookups_multiple_tables() { setup_lookup_proof(false, 500, vec![100, 50, 50, 2, 2]) } +fn setup_successfull_runtime_table_test( + runtime_table_cfgs: Vec>, + runtime_tables: Vec>, + lookups: Vec, +) { + let mut rng = rand::thread_rng(); + let nb_lookups = lookups.len(); + + // circuit + let mut gates = vec![]; + for row in 0..nb_lookups { + gates.push(CircuitGate::new( + GateType::Lookup, + Wire::for_row(row), + vec![], + )); + } + + // witness + let witness = { + let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); + + // only the first 7 registers are used in the lookup gate + let (lookup_cols, _rest) = cols.split_at_mut(7); + + for (i, table_id) in lookups.into_iter().enumerate() { + lookup_cols[0][i] = Fp::from(table_id); + let rt = runtime_table_cfgs + .clone() + .into_iter() + .find(|rt_cfg| rt_cfg.id == table_id) + .unwrap(); + let len_rt = rt.len(); + let first_column = rt.first_column; + let data = runtime_tables + .clone() + .into_iter() + .find(|rt| rt.id == table_id) + .unwrap() + .data; + + // create queries into our runtime lookup table. + // We will set [w1, w2], [w3, w4] and [w5, w6] to randon indexes and + // the corresponding values + let lookup_cols = &mut lookup_cols[1..]; + for chunk in lookup_cols.chunks_mut(2) { + let idx = rng.gen_range(0..len_rt); + chunk[0][i] = first_column[idx]; + chunk[1][i] = data[idx]; + } + } + cols + }; + + // run test + TestFramework::::default() + .gates(gates) + .witness(witness) + .runtime_tables_setup(runtime_table_cfgs) + .setup() + .runtime_tables(runtime_tables) + .prove_and_verify::() + .unwrap(); +} + #[test] fn test_runtime_table() { let num = 5; @@ -468,11 +533,7 @@ fn test_runtime_table_with_more_than_one_runtime_table_data_given_by_prover() { #[test] fn test_runtime_table_only_one_table_with_id_zero_with_non_zero_entries_fixed_values() { - let mut rng = rand::thread_rng(); - let first_column = [0, 1, 2, 3, 4, 5]; - let len = first_column.len(); - let table_id = 0; let cfg = RuntimeTableCfg { @@ -481,55 +542,11 @@ fn test_runtime_table_only_one_table_with_id_zero_with_non_zero_entries_fixed_va }; let data: Vec = [0u32, 1, 2, 3, 4, 5].into_iter().map(Into::into).collect(); - let runtime_table = RuntimeTable { - id: table_id, - data: data.clone(), - }; - - // circuit - let n_row = 20; - let mut gates = vec![]; - for row in 0..n_row { - gates.push(CircuitGate::new( - GateType::Lookup, - Wire::for_row(row), - vec![], - )); - } - - // witness - let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); - - // only the first 7 registers are used in the lookup gate - let (lookup_cols, _rest) = cols.split_at_mut(7); + let runtime_table = RuntimeTable { id: table_id, data }; - for row in 0..n_row { - // Lookup in table ID 0 - lookup_cols[0][row] = Fp::zero(); + let lookups: Vec = [0; 20].into(); - // create queries into our runtime lookup table. - // We will set [w1, w2], [w3, w4] and [w5, w6] to randon indexes and - // the corresponding values - let lookup_cols = &mut lookup_cols[1..]; - for chunk in lookup_cols.chunks_mut(2) { - let idx = rng.gen_range(0..len); - chunk[0][row] = first_column[idx].into(); - chunk[1][row] = data[idx]; - } - } - cols - }; - - // run test - TestFramework::::default() - .gates(gates) - .witness(witness) - .runtime_tables_setup(vec![cfg]) - .setup() - .runtime_tables(vec![runtime_table]) - .prove_and_verify::() - .unwrap(); + setup_successfull_runtime_table_test(vec![cfg], vec![runtime_table], lookups); } #[test] @@ -547,57 +564,12 @@ fn test_runtime_table_only_one_table_with_id_zero_with_non_zero_entries_random_v }; let data: Vec = first_column - .clone() .into_iter() .map(|_| UniformRand::rand(&mut rng)) .collect(); - let runtime_table = RuntimeTable { - id: table_id, - data: data.clone(), - }; - - // circuit - let n_row = 20; - let mut gates = vec![]; - for row in 0..n_row { - gates.push(CircuitGate::new( - GateType::Lookup, - Wire::for_row(row), - vec![], - )); - } - - // witness - let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); - - // only the first 7 registers are used in the lookup gate - let (lookup_cols, _rest) = cols.split_at_mut(7); + let runtime_table = RuntimeTable { id: table_id, data }; - for row in 0..n_row { - // Lookup in table ID 0 - lookup_cols[0][row] = Fp::zero(); + let lookups: Vec = [0; 20].into(); - // create queries into our runtime lookup table. - // We will set [w1, w2], [w3, w4] and [w5, w6] to randon indexes and - // the corresponding values - let lookup_cols = &mut lookup_cols[1..]; - for chunk in lookup_cols.chunks_mut(2) { - let idx = rng.gen_range(0..len); - chunk[0][row] = first_column[idx].into(); - chunk[1][row] = data[idx]; - } - } - cols - }; - - // run test - TestFramework::::default() - .gates(gates) - .witness(witness) - .runtime_tables_setup(vec![cfg]) - .setup() - .runtime_tables(vec![runtime_table]) - .prove_and_verify::() - .unwrap(); + setup_successfull_runtime_table_test(vec![cfg], vec![runtime_table], lookups); } From e3b19ac25f29af828716939b302591d68161e092 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 18 Sep 2023 15:44:35 +0100 Subject: [PATCH 134/242] Flip inverted comments --- poly-commitment/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 89b975cbf3..5e0b05320d 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -41,14 +41,14 @@ pub trait SRS { rng: &mut (impl RngCore + CryptoRng), ) -> BlindedCommitment; - /// Turns a non-hiding polynomial commitment into a hidding polynomial commitment. Transforms each given `` into `( + wH, w)` with a random `w` per commitment. + /// Same as [SRS::mask] except that you can pass the blinders manually. fn mask_custom( &self, com: PolyComm, blinders: &PolyComm, ) -> Result, CommitmentError>; - /// Same as [SRS::mask] except that you can pass the blinders manually. + /// Turns a non-hiding polynomial commitment into a hidding polynomial commitment. Transforms each given `` into `( + wH, w)` with a random `w` per commitment. fn mask( &self, comm: PolyComm, From 5ccfaa463f2f6204d7d9156972a28461a80cd5c2 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 18 Sep 2023 17:02:31 +0100 Subject: [PATCH 135/242] Ignore too-many-arguments --- poly-commitment/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 5e0b05320d..a075d7ed6d 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -88,6 +88,7 @@ pub trait SRS { pub trait OpenProof: Sized { type SRS: SRS; + #[allow(clippy::too_many_arguments)] fn open::ScalarField>>( srs: &Self::SRS, group_map: &::Map, From 37d2a05a765c6eabcd5f34bbe5cfe47966168578 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 18 Sep 2023 17:06:02 +0100 Subject: [PATCH 136/242] cargo clippy --fix --- kimchi/src/verifier.rs | 2 +- poly-commitment/src/commitment.rs | 2 +- poly-commitment/src/pairing_proof.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index a8e37f263e..715dc59f04 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -782,7 +782,7 @@ where .get_lagrange_basis(verifier_index.domain.size()) .expect("pre-computed committed lagrange bases not found"); let com: Vec<_> = lgr_comm.iter().take(verifier_index.public).collect(); - if public_input.len() == 0 { + if public_input.is_empty() { PolyComm::new( vec![verifier_index.srs().blinding_commitment(); chunk_size], None, diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 0001844d60..ab62314532 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -571,7 +571,7 @@ pub fn combine_evaluations( ) -> Vec { let mut xi_i = G::ScalarField::one(); let mut acc = { - let num_evals = if evaluations.len() > 0 { + let num_evals = if !evaluations.is_empty() { evaluations[0].evaluations.len() } else { 0 diff --git a/poly-commitment/src/pairing_proof.rs b/poly-commitment/src/pairing_proof.rs index 1f12673d32..5f234a3561 100644 --- a/poly-commitment/src/pairing_proof.rs +++ b/poly-commitment/src/pairing_proof.rs @@ -37,8 +37,8 @@ impl Default for PairingProof { impl Clone for PairingProof { fn clone(&self) -> Self { Self { - quotient: self.quotient.clone(), - blinding: self.blinding.clone(), + quotient: self.quotient, + blinding: self.blinding, } } } @@ -277,7 +277,7 @@ impl< let divisor_polynomial = divisor_polynomial(elm); let numerator_polynomial = &p - &eval_polynomial; let (quotient, remainder) = DenseOrSparsePolynomial::divide_with_q_and_r( - &numerator_polynomial.clone().into(), + &numerator_polynomial.into(), &divisor_polynomial.into(), )?; if !remainder.is_zero() { From b1c92b75e279e77e5c49453fec71970e396de0b1 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 18 Sep 2023 17:18:17 +0100 Subject: [PATCH 137/242] Fixup more annoying clippy junk --- kimchi/src/bench.rs | 1 + poly-commitment/src/commitment.rs | 2 +- poly-commitment/src/evaluation_proof.rs | 10 +++------- poly-commitment/src/lib.rs | 15 +++++++++------ poly-commitment/src/pairing_proof.rs | 12 ++++-------- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/kimchi/src/bench.rs b/kimchi/src/bench.rs index a77d9d34cf..ccf4808c84 100644 --- a/kimchi/src/bench.rs +++ b/kimchi/src/bench.rs @@ -96,6 +96,7 @@ impl BenchmarkCtx { ) } + #[allow(clippy::type_complexity)] pub fn batch_verification(&self, batch: &[(ProverProof>, Vec)]) { // verify the proof let batch: Vec<_> = batch diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index ab62314532..3d6cdf2411 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -527,7 +527,7 @@ where } pub fn combine_commitments( - evaluations: &Vec>, + evaluations: &[Evaluation], scalars: &mut Vec, points: &mut Vec, polyscale: G::ScalarField, diff --git a/poly-commitment/src/evaluation_proof.rs b/poly-commitment/src/evaluation_proof.rs index 18fff9a896..0b15615b66 100644 --- a/poly-commitment/src/evaluation_proof.rs +++ b/poly-commitment/src/evaluation_proof.rs @@ -1,5 +1,5 @@ use crate::{commitment::*, srs::endos}; -use crate::{srs::SRS, SRS as _}; +use crate::{srs::SRS, PolynomialsToCombine, SRS as _}; use ark_ec::{msm::VariableBaseMSM, AffineCurve, ProjectiveCurve}; use ark_ff::{FftField, Field, One, PrimeField, UniformRand, Zero}; use ark_poly::{univariate::DensePolynomial, UVPolynomial}; @@ -73,12 +73,8 @@ impl<'a, F: Field> ScaledChunkedPolynomial { /// Combine the polynomials using `polyscale`, creating a single unified polynomial to open. pub fn combine_polys>( - plnms: &[( - DensePolynomialOrEvaluations, - Option, - PolyComm, - )], // vector of polynomial with optional degree bound and commitment randomness - polyscale: G::ScalarField, // scaling factor for polynoms + plnms: PolynomialsToCombine, // vector of polynomial with optional degree bound and commitment randomness + polyscale: G::ScalarField, // scaling factor for polynoms srs_length: usize, ) -> (DensePolynomial, G::ScalarField) { let mut plnm = ScaledChunkedPolynomial::::default(); diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index a075d7ed6d..4d7bac7913 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -85,6 +85,13 @@ pub trait SRS { ) -> BlindedCommitment; } +#[allow(type_alias_bounds)] +type PolynomialsToCombine<'a, G: CommitmentCurve, D: EvaluationDomain> = &'a [( + DensePolynomialOrEvaluations<'a, G::ScalarField, D>, + Option, + PolyComm, +)]; + pub trait OpenProof: Sized { type SRS: SRS; @@ -92,15 +99,11 @@ pub trait OpenProof: Sized { fn open::ScalarField>>( srs: &Self::SRS, group_map: &::Map, - plnms: &[( - DensePolynomialOrEvaluations<::ScalarField, D>, - Option, - PolyComm<::ScalarField>, - )], // vector of polynomial with optional degree bound and commitment randomness + plnms: PolynomialsToCombine, // vector of polynomial with optional degree bound and commitment randomness elm: &[::ScalarField], // vector of evaluation points polyscale: ::ScalarField, // scaling factor for polynoms evalscale: ::ScalarField, // scaling factor for evaluation point powers - sponge: EFqSponge, // sponge + sponge: EFqSponge, // sponge rng: &mut RNG, ) -> Self where diff --git a/poly-commitment/src/pairing_proof.rs b/poly-commitment/src/pairing_proof.rs index 5f234a3561..6c38a2ddbe 100644 --- a/poly-commitment/src/pairing_proof.rs +++ b/poly-commitment/src/pairing_proof.rs @@ -1,7 +1,7 @@ use crate::commitment::*; use crate::evaluation_proof::{combine_polys, DensePolynomialOrEvaluations}; use crate::srs::SRS; -use crate::{CommitmentError, SRS as SRSTrait}; +use crate::{CommitmentError, PolynomialsToCombine, SRS as SRSTrait}; use ark_ec::{msm::VariableBaseMSM, AffineCurve, PairingEngine}; use ark_ff::{PrimeField, Zero}; use ark_poly::{ @@ -261,13 +261,9 @@ impl< { pub fn create>( srs: &PairingSRS, - plnms: &[( - DensePolynomialOrEvaluations, - Option, - PolyComm, - )], // vector of polynomial with optional degree bound and commitment randomness - elm: &[G::ScalarField], // vector of evaluation points - polyscale: G::ScalarField, // scaling factor for polynoms + plnms: PolynomialsToCombine, // vector of polynomial with optional degree bound and commitment randomness + elm: &[G::ScalarField], // vector of evaluation points + polyscale: G::ScalarField, // scaling factor for polynoms ) -> Option { let (p, blinding_factor) = combine_polys::(plnms, polyscale, srs.full_srs.g.len()); let evals: Vec<_> = elm.iter().map(|pt| p.evaluate(pt)).collect(); From 7e3ad5ac134a21dc83e8a699a9f1e92d0a20d9ed Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 19 Sep 2023 18:05:38 +0100 Subject: [PATCH 138/242] Fixup incorrect `num_chunks` parameters --- poly-commitment/src/pairing_proof.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poly-commitment/src/pairing_proof.rs b/poly-commitment/src/pairing_proof.rs index 6c38a2ddbe..720a3a4fb7 100644 --- a/poly-commitment/src/pairing_proof.rs +++ b/poly-commitment/src/pairing_proof.rs @@ -284,7 +284,7 @@ impl< let quotient = srs .full_srs - .commit_non_hiding("ient_poly, srs.full_srs.g.len(), None) + .commit_non_hiding("ient_poly, 1, None) .unshifted[0]; Some(PairingProof { @@ -317,11 +317,11 @@ impl< let blinding_commitment = srs.full_srs.h.mul(self.blinding); let divisor_commitment = srs .verifier_srs - .commit_non_hiding(&divisor_polynomial(elm), srs.full_srs.g.len(), None) + .commit_non_hiding(&divisor_polynomial(elm), 1, None) .unshifted[0]; let eval_commitment = srs .full_srs - .commit_non_hiding(&eval_polynomial(elm, &evals), srs.full_srs.g.len(), None) + .commit_non_hiding(&eval_polynomial(elm, &evals), 1, None) .unshifted[0] .into_projective(); let numerator_commitment = { poly_commitment - eval_commitment - blinding_commitment }; @@ -380,7 +380,7 @@ mod tests { let comms: Vec<_> = polynomials .iter() - .map(|p| srs.full_srs.commit(p, srs.full_srs.g.len(), None, rng)) + .map(|p| srs.full_srs.commit(p, 1, None, rng)) .collect(); let polynomials_and_blinders: Vec<(DensePolynomialOrEvaluations<_, D<_>>, _, _)> = From d3f346583fa7dd6c4b5a188005bbe16f12595f94 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 27 Sep 2023 17:05:58 +0200 Subject: [PATCH 139/242] Bump up rust to 1.71 and 1.72 --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d99986aa59..bbe83c4fa0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -18,7 +18,7 @@ jobs: run_checks: strategy: matrix: - rust_toolchain_version: [1.67, 1.68, 1.69] + rust_toolchain_version: [1.71, 1.72] # FIXME: currently not available for 5.0.0. # It might be related to boxroot dependency, and we would need to bump # up the ocaml-rs dependency From d93da74cd332f6e3f6ef5e7994fad56694ebe3e3 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 27 Sep 2023 17:06:55 +0200 Subject: [PATCH 140/242] Use 1.71 in benches --- .github/workflows/benches.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benches.yml b/.github/workflows/benches.yml index f957eda17c..e8ac86e6b9 100644 --- a/.github/workflows/benches.yml +++ b/.github/workflows/benches.yml @@ -7,7 +7,7 @@ on: env: OCAML_VERSION: "4.14.0" - RUST_TOOLCHAIN_VERSION: "1.67" + RUST_TOOLCHAIN_VERSION: "1.71" jobs: From 8fb41e4b04744c7737d1862d8899e138a3135ec7 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 27 Sep 2023 17:08:01 +0200 Subject: [PATCH 141/242] Use double quotes for versions --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index bbe83c4fa0..2fd96e8a07 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -18,11 +18,11 @@ jobs: run_checks: strategy: matrix: - rust_toolchain_version: [1.71, 1.72] + rust_toolchain_version: ["1.71", "1.72"] # FIXME: currently not available for 5.0.0. # It might be related to boxroot dependency, and we would need to bump # up the ocaml-rs dependency - ocaml_version: [4.14] + ocaml_version: ["4.14"] runs-on: ubuntu-latest name: Run some basic checks and tests From 2fd3041aa1cae64642a2c5082391a57f87816d79 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 27 Sep 2023 17:08:44 +0200 Subject: [PATCH 142/242] Remove condition simply on master --- .github/workflows/rust.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2fd96e8a07..3490171728 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,8 +2,6 @@ name: CI on: push: - branches: - - master pull_request: env: From 2cf82ef0234bb0501e8ca1d499ce88fe2a85e634 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 27 Sep 2023 17:14:09 +0200 Subject: [PATCH 143/242] poly-commitment: fix comment in combine --- poly-commitment/src/combine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poly-commitment/src/combine.rs b/poly-commitment/src/combine.rs index 7c6ad08c5e..52f7e19f95 100644 --- a/poly-commitment/src/combine.rs +++ b/poly-commitment/src/combine.rs @@ -339,7 +339,7 @@ fn affine_window_combine_one_endo_base( points } -///! Double an array of curve points in-place. +/// Double an array of curve points in-place. fn batch_double_in_place( denominators: &mut Vec, points: &mut [SWJAffine

], From 30c60a15845f9aa68f458fb0ec806343dd842fea Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 27 Sep 2023 17:18:40 +0200 Subject: [PATCH 144/242] Use take instead of mem --- kimchi/src/tests/framework.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index b42d368d68..d95e768a40 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -29,7 +29,7 @@ use num_bigint::BigUint; use poly_commitment::{ commitment::CommitmentCurve, evaluation_proof::OpeningProof as DlogOpeningProof, OpenProof, }; -use std::{fmt::Write, mem, time::Instant}; +use std::{fmt::Write, time::Instant}; // aliases @@ -123,7 +123,7 @@ where let start = Instant::now(); let lookup_tables = std::mem::take(&mut self.lookup_tables); - let runtime_tables_setup = mem::replace(&mut self.runtime_tables_setup, None); + let runtime_tables_setup = self.runtime_tables_setup.take(); let index = new_index_for_test_with_lookups_and_custom_srs( self.gates.take().unwrap(), @@ -156,7 +156,7 @@ where let start = Instant::now(); let lookup_tables = std::mem::take(&mut self.lookup_tables); - let runtime_tables_setup = mem::replace(&mut self.runtime_tables_setup, None); + let runtime_tables_setup = self.runtime_tables_setup.take(); let index = new_index_for_test_with_lookups::( self.gates.take().unwrap(), From f88556f3f40e2227403aab503c2dfe85e1aa1643 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 27 Sep 2023 17:22:19 +0200 Subject: [PATCH 145/242] Make clippy happy for 1.72 --- kimchi/src/circuits/lookup/index.rs | 2 +- kimchi/src/tests/turshi.rs | 4 ++-- poly-commitment/src/pairing_proof.rs | 2 +- turshi/src/memory.rs | 2 +- turshi/src/runner.rs | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index b9e2bd3dc6..80cc6073e4 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -224,7 +224,7 @@ impl LookupConstraintSystem { //~ 3. Concatenate runtime lookup tables with the ones used by gates let mut lookup_tables: Vec<_> = gate_lookup_tables .into_iter() - .chain(lookup_tables.into_iter()) + .chain(lookup_tables) .collect(); let mut has_table_id_0 = false; diff --git a/kimchi/src/tests/turshi.rs b/kimchi/src/tests/turshi.rs index 2162ba7fb6..7a6e1f0775 100644 --- a/kimchi/src/tests/turshi.rs +++ b/kimchi/src/tests/turshi.rs @@ -7,7 +7,7 @@ use turshi::{CairoMemory, CairoProgram}; #[test] fn test_cairo_should_fail() { - let instrs = vec![0x480680017fff8000, 10, 0x208b7fff7fff7ffe] + let instrs = [0x480680017fff8000, 10, 0x208b7fff7fff7ffe] .iter() .map(|&i: &i64| F::from(i)) .collect(); @@ -30,7 +30,7 @@ fn test_cairo_should_fail() { #[test] fn test_cairo_gate() { - let instrs = vec![ + let instrs = [ 0x400380007ffc7ffd, 0x482680017ffc8000, 1, diff --git a/poly-commitment/src/pairing_proof.rs b/poly-commitment/src/pairing_proof.rs index 720a3a4fb7..913cf15d0f 100644 --- a/poly-commitment/src/pairing_proof.rs +++ b/poly-commitment/src/pairing_proof.rs @@ -397,7 +397,7 @@ mod tests { let evaluations: Vec<_> = polynomials .iter() - .zip(comms.into_iter()) + .zip(comms) .map(|(p, commitment)| { let evaluations = evaluation_points .iter() diff --git a/turshi/src/memory.rs b/turshi/src/memory.rs index dc515380a5..9e4c7bb1e2 100644 --- a/turshi/src/memory.rs +++ b/turshi/src/memory.rs @@ -115,7 +115,7 @@ mod tests { // end // And checks that memory writing and reading works as expected by completing // the total memory of executing the program - let instrs = vec![0x480680017fff8000, 10, 0x208b7fff7fff7ffe] + let instrs = [0x480680017fff8000, 10, 0x208b7fff7fff7ffe] .iter() .map(|&i: &i64| F::from(i)) .collect(); diff --git a/turshi/src/runner.rs b/turshi/src/runner.rs index d669243883..adc7724f24 100644 --- a/turshi/src/runner.rs +++ b/turshi/src/runner.rs @@ -582,7 +582,7 @@ mod tests { fn test_cairo_step() { // This tests that CairoStep works for a 2 word instruction // tempvar x = 10; - let instrs = vec![0x480680017fff8000, 10, 0x208b7fff7fff7ffe] + let instrs = [0x480680017fff8000, 10, 0x208b7fff7fff7ffe] .iter() .map(|&i: &i64| F::from(i)) .collect(); @@ -604,7 +604,7 @@ mod tests { #[test] fn test_cairo_program() { - let instrs = vec![0x480680017fff8000, 10, 0x208b7fff7fff7ffe] + let instrs = [0x480680017fff8000, 10, 0x208b7fff7fff7ffe] .iter() .map(|&i: &i64| F::from(i)) .collect(); @@ -634,7 +634,7 @@ mod tests { return () end */ - let instrs = vec![ + let instrs = [ 0x400380007ffc7ffd, 0x482680017ffc8000, 1, From 9be01f795e0d198cf2210861ef085da8b5a946ad Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 29 Sep 2023 22:07:44 +0200 Subject: [PATCH 146/242] Remove snarky --- book/src/SUMMARY.md | 11 -- book/src/snarky/api.md | 2 - book/src/snarky/booleans.md | 73 -------- book/src/snarky/circuit-generation.md | 29 ---- book/src/snarky/kimchi-backend.md | 234 -------------------------- book/src/snarky/overview.md | 32 ---- book/src/snarky/snarky-wrapper.md | 70 -------- book/src/snarky/vars.md | 135 --------------- book/src/snarky/witness-generation.md | 21 --- 9 files changed, 607 deletions(-) delete mode 100644 book/src/snarky/api.md delete mode 100644 book/src/snarky/booleans.md delete mode 100644 book/src/snarky/circuit-generation.md delete mode 100644 book/src/snarky/kimchi-backend.md delete mode 100644 book/src/snarky/overview.md delete mode 100644 book/src/snarky/snarky-wrapper.md delete mode 100644 book/src/snarky/vars.md delete mode 100644 book/src/snarky/witness-generation.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 8b6e482e3e..f39f655421 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -58,17 +58,6 @@ - [Permutation](./kimchi/permut.md) - [Lookup](./kimchi/lookup.md) -# Snarky - -- [Overview](./snarky/overview.md) -- [API](./snarky/api.md) -- [snarky wrapper](./snarky/snarky-wrapper.md) -- [Kimchi backend](./snarky/kimchi-backend.md) -- [Vars](./snarky/vars.md) -- [Booleans](./snarky/booleans.md) -- [Circuit generation](./snarky/circuit-generation.md) -- [Witness generation](./snarky/witness-generation.md) - # Pickles & Inductive Proof Systems - [Overview](./fundamentals/zkbook_ips.md) diff --git a/book/src/snarky/api.md b/book/src/snarky/api.md deleted file mode 100644 index e8b981a474..0000000000 --- a/book/src/snarky/api.md +++ /dev/null @@ -1,2 +0,0 @@ -# API of Snarky - diff --git a/book/src/snarky/booleans.md b/book/src/snarky/booleans.md deleted file mode 100644 index 7b503f0580..0000000000 --- a/book/src/snarky/booleans.md +++ /dev/null @@ -1,73 +0,0 @@ -# Booleans - -Booleans are a good example of a [snarky variable](./vars.md#snarky-vars). - -```rust -pub struct Boolean(CVar); - -impl SnarkyType for Boolean -where - F: PrimeField, -{ - type Auxiliary = (); - - type OutOfCircuit = bool; - - const SIZE_IN_FIELD_ELEMENTS: usize = 1; - - fn to_cvars(&self) -> (Vec>, Self::Auxiliary) { - (vec![self.0.clone()], ()) - } - - fn from_cvars_unsafe(cvars: Vec>, _aux: Self::Auxiliary) -> Self { - assert_eq!(cvars.len(), Self::SIZE_IN_FIELD_ELEMENTS); - Self(cvars[0].clone()) - } - - fn check(&self, cs: &mut RunState) { - // TODO: annotation? - cs.assert_(Some("boolean check"), vec![BasicSnarkyConstraint::Boolean(self.0.clone())]); - } - - fn deserialize(&self) -> (Self::OutOfCircuit, Self::Auxiliary) { - todo!() - } - - fn serialize(out_of_circuit: Self::OutOfCircuit, aux: Self::Auxiliary) -> Self { - todo!() - } - - fn constraint_system_auxiliary() -> Self::Auxiliary { - todo!() - } - - fn value_to_field_elements(x: &Self::OutOfCircuit) -> (Vec, Self::Auxiliary) { - todo!() - } - - fn value_of_field_elements(x: (Vec, Self::Auxiliary)) -> Self::OutOfCircuit { - todo!() - } -} -``` - -## Check - -The `check()` function is simply constraining the `CVar` $x$ to be either $0$ or $1$ using the following constraint: - -$$x ( x - 1) = 0$$ - -It is trivial to use the [double generic gate](../specs/kimchi.md#double-generic-gate) for this. - -## And - -$$x \land y = x \times y$$ - -## Not - -$$\sim x = 1 - x$$ - -## Or - -* $\sim x \land \sim y = b$ -* $x \lor y = \sim b$ diff --git a/book/src/snarky/circuit-generation.md b/book/src/snarky/circuit-generation.md deleted file mode 100644 index e81793aa03..0000000000 --- a/book/src/snarky/circuit-generation.md +++ /dev/null @@ -1,29 +0,0 @@ -# Circuit generation - -In circuit generation mode, the `has_witness` field of `RunState` is set to the default `CircuitGeneration`, and the program of the user is ran to completion. - -During the execution, the different snarky functions called on `RunState` will create [internal variables](./vars.md) as well as constraints. - -## Creation of variables - -[Variables](./vars.md) can be created via the `compute()` function, which takes two arguments: - -* A `TypeCreation` toggle, which is either set to `Checked` or `Unsafe`. We will describe this below. -* A closure representing the actual computation behind the variable. This computation will only take place when real values are computed, and can be non-deterministic (e.g. random, or external values provided by the user). Note that the closure takes one argument: a `WitnessGeneration`, a structure that allows you to read the runtime values of any variables that were previously created in your program. - -The `compute()` function also needs a type hint to understand what type of [snarky type](./vars.md#snarky-vars) it is creating. - -It then performs the following steps: - -* creates enough [`CVar`](./vars#circuit-vars) to hold the value to be created -* retrieves the auxiliary data needed to create the snarky type (TODO: explain auxiliary data) and create the [`snarky variable`](./vars.md#snarky-vars) out of the `CVar`s and the auxiliary data -* if the `TypeCreation` is set to `Checked`, call the `check()` function on the snarky type (which will constrain the value created), if it is set to `Unsafe` do nothing (in which case we're trusting that the value cannot be malformed, this is mostly used internally and it is highly-likely that users directly making use of `Unsafe` are writing bugs) - -```admonish -At this point we only created variables to hold future values, and made sure that they are constrained. -The actual values will fill the room created by the `CVar` only during the [witness generation](./witness-generation.md). -``` - -## Constraints - -All other functions exposed by the API are basically here to operate on variables and create constraints in doing so. diff --git a/book/src/snarky/kimchi-backend.md b/book/src/snarky/kimchi-backend.md deleted file mode 100644 index 2d2ebf789a..0000000000 --- a/book/src/snarky/kimchi-backend.md +++ /dev/null @@ -1,234 +0,0 @@ -# Kimchi Backend - -![](https://i.imgur.com/KmKU5Pl.jpg) - -Underneath the snarky wrapper (in `snarky/checked_runner.rs`) lies what we used to call the `plonk_constraint_system` or `kimchi_backend` in `snarky/constraint_systen.rs`. - -```admonish -It is good to note that we're planning on removing this abstract separation between the snarky wrapper and the constraint system. -``` - -The logic in the kimchi backend serves two purposes: - -* **Circuit generation**. It is the logic that adds gates to our list of gates (representing the circuit). For most of these gates, the variables used are passed to the backend by the snarky wrapper, but some of them are created by the backend itself (see more in the [variables section](#variables)). -* **Witness generation**. It is the logic that creates the witness - -One can also perform two additional operations once the constraint system has been compiled: - -* Generate the prover and verifier index for the system. -* Get a hash of the constraint system (this includes the circuit, the number of public input) (TODO: verify that this is true) (TODO: what else should be in that hash? a version of snarky and a version of kimchi?). - -## A circuit - -A circuit is either being built, or has been contructed during a circuit generation phase: - -```rust -enum Circuit -where - F: PrimeField, -{ - /** A circuit still being written. */ - Unfinalized(Vec>), - /** Once finalized, a circuit is represented as a digest - and a list of gates that corresponds to the circuit. - */ - Compiled([u8; 32], Vec>), -} -``` - -## State - -The state of the kimchi backend looks like this: - -```rust -where - Field: PrimeField, -{ - /// A counter used to track variables - /// (similar to the one in the snarky wrapper) - next_internal_var: usize, - - /// Instruction on how to compute each internal variable - /// (as a linear combination of other variables). - /// Used during witness generation. - internal_vars: HashMap, Option)>, - - /// The symbolic execution trace table. - /// Each cell is a variable that takes a value during witness generation. - /// (if not set, it will take the value 0). - rows: Vec>>, - - /// The circuit once compiled - gates: Circuit, - - /// The row to use the next time we add a constraint. - // TODO: I think we can delete this - next_row: usize, - - /// The size of the public input - /// (which fills the first rows of our constraint system. - public_input_size: Option, - - // omitted values... -} -``` - -## Variables - -In the backend, there's two types of variables: - -```rust -enum V { - /// An external variable - /// (generated by snarky, via [exists]). - External(usize), - - /// An internal variable is generated to hold an intermediate value, - /// (e.g. in reducing linear combinations to single PLONK positions). - Internal(InternalVar), -} -``` - -Internal variables are basically a `usize` pointing to a hashmap in the state. - -That hashmap tells you how to compute the internal variable during witness generation: it is always a linear combination of other variables (and a constant). - -## Circuit generation - -During circuit generation, the snarky wrapper will make calls to the `add_constraint()` or `add_basic_snarky_constraint` function of the kimchi backend, specifying what gate to use and what variables to use in that gate. - -At this point, the snarky wrapper might have some variables that are not yet tracked as such (with a counter). -Rather, they are constants, or they are a combination of other variables. -You can see that as a small AST representing how to compute a variable. -(See the [variables section](./vars.md#circuit-vars) for more details). - -For this reason, they can hide a number of operations that haven't been constrained yet. -It is the role of the `add_constrain` logic to enforce that at this point constants, as well as linear combinations or scalings of variables, are encoded in the circuit. -This is done by adding enough generic gates (using the `reduce_lincom()` or `reduce_to_var()` functions). - -```admonish -This is a remnant of an optimization targetting R1CS (in which additions are for free). -An issue with this approach is the following: imagine that two circuit variables are created from the same circuit variable, imagine also that the original circuit variable contained a long AST, then both variables might end up creating the same constraints to convert that AST. -Currently, snarkyjs and pickles expose a `seal()` function that allows you to reduce this issue, at the cost of some manual work and mental tracking on the developer. -We should probably get rid of this, while making sure that we can continue to optimize generic gates -(in some cases you can merge two generic gates in one (TODO: give an example of where that can happen)). -Another solution is to keep track of what was reduced, and reuse previous reductions (similar to how we handle constants). -``` - -It is during this "reducing" step that internal variables (known only to the kimchi backend) are created. - -```admonish -The process is quite safe, as the kimchi backend cannot use the snarky wrapper variables directly (which are of type `CVar`). -Since the expected format (see the [variables section](#variables) is a number (of type `usize`), the only way to convert a non-tracked variable (constant, or scale, or linear combination) is to reduce it (and in the process constraining its value). -``` - -Depending on the gate being used, several constraints might be added via the `add_row()` function which does three things: - -1. figure out if there's any wiring to be done -2. add a gate to our list of gates (representing the circuit) -3. add the variables to our _symbolic_ execution trace table (symbolic in the sense that nothing has values yet) - -This process happens as the circuit is "parsed" and the constraint functions of the kimchi backend are called. - -This does not lead to a finalized circuit, see the next section to see how that is done. - -(TODO: ideally this should happen in the same step) - -## Finalization of the circuit. - -So far we've only talked about adding specific constraints to the circuit, but not about how public input are handled. - -The `finalization()` function of the kimchi backend does the following: - -* add as many generic rows as there are public inputs. -* construct the permutation -* computes a cache of the circuit (TODO: this is so unecessary) -* and other things that are not that important - -## Witness generation - -Witness generation happens by taking the finalized state (in the `compute_witness()` function) with a callback that can be used to retrieve the values of external variables (public input and public output). - -The algorithm follows these steps using the symbolic execution table we built during circuit generation: - -1. it initializes the execution trace table with zeros -2. go through the rows related to the public input and set the most-left column values to the ones obtained by the callback. -3. go through the other rows and compute the value of the variables left in the table - -Variables in step 3. should either: - -* be absent (`None`) and evaluated to the default value 0 -* point to an external variable, in which case the closure passed can be used to retrieve the value -* be an internal variable, in which case the value is computed by evaluating the AST that was used to create it. - -## Permutation - -The permutation is used to wire cells of the execution trace table (specifically, cells belonging to the first 7 columns). -It is also known as "copy constraints". - -```admonish -In snarky, the permutation is represented differently from kimchi, and thus needs to be converted to the kimchi's format before a proof can be created. -TODO: merge the representations -``` - -We use the permutation in ingenious ways to optimize circuits. -For example, we use it to encode each constants once, and wire it to places where it is used. -Another example, is that we use it to assert equality between two cells. - -## Implementation details - -There's two aspect of the implementation of the permutation, the first one is a hashmap of equivalence classes, which is used to track all the positions of a variable, the second one is making use of a [union find]() data structure to link variables that are equivalent (we'll talk about that after). - -The two data structures are in the kimchi backend's state: - -```rust -pub struct SnarkyConstraintSystem -where - Field: PrimeField, -{ - equivalence_classes: HashMap>>, - union_finds: disjoint_set::DisjointSet, - // omitted fields... -} -``` - -### equivalence classes - -As said previously, during circuit generation a symbolic execution trace table is created. It should look a bit like this (if there were only 3 columns and 4 rows): - -| | 0 | 1 | 2 | -| :-: | :-: | :-: | :-:| -| 0 | v1 | v1 | | -| 1 | | v2 | | -| 2 | | v2 | | -| 3 | | | v1 | - -From that, it should be clear that all the cells containing the variable `v1` should be connected, -and all the cells containing the variable `v2` should be as well. - -The format that the permutation expects is a [cycle](https://en.wikipedia.org/wiki/Cyclic_permutation): a list of cells where each cell is linked to the next, the last one wrapping around and linking to the first one. - -For example, a cycle for the `v1` variable could be: - -``` -(0, 0) -> (0, 1) -(0, 1) -> (3, 2) -(3, 2) -> (0, 0) -``` - -During circuit generation, a hashmap (called `equivalence_classes`) is used to track all the positions (row and column) of each variable. - -During finalization, all the different cycles are created by looking at all the variables existing in the hashmap. - -### Union finds - -Sometimes, we know that two variables will have equivalent values due to an `assert_equal()` being called to link them. -Since we link two variables together, they need to be part of the same cycle, and as such we need to be able to detect that to construct correct cycles. - -To do this, we use a [union find]() data structure, which allows us to easily find the unions of equivalent variables. - -When an `assert_equal()` is called, we link the two variables together using the `union_finds` data structure. - -During finalization, when we create the cycles, we use the `union_finds` data structure to find the equivalent variables. -We then create a new equivalence classes hashmap to merge the keys (variables) that are in the same set. -This is done before using the equivalence classes hashmap to construct the cycles. diff --git a/book/src/snarky/overview.md b/book/src/snarky/overview.md deleted file mode 100644 index b67c1fa30b..0000000000 --- a/book/src/snarky/overview.md +++ /dev/null @@ -1,32 +0,0 @@ -# Snarky - -Snarky is a frontend to the [kimchi proof system](../kimchi/overview.md). - -It allows users to write circuits that can be proven using kimchi. - -This part of the Mina book documents both how to use snarky, and how its internals work. - -```admonish -Snarky was originally an OCaml library. It also is known as a typescript library: SnarkyJS. -This documentation talks about the Rust implementation, which one can refer to as snarky-rs (but we will just say snarky from now on). -``` - -## High-level design - -Snarky is divided into two parts: - -* **Circuit-generation**: which is also called the setup or compilation phase. It is when snarky turn code written using its library, to a circuit that kimchi can understand. This can later be used by kimchi to produce prover and verifier keys. -* **Witness-generation**: which is also called the proving, or runtime phase. It is when snarky executes the written program and records its state at various point in time to create an execution trace of the program (which we call witness here). This can later be used by kimchi, with a proving key, to produce a zero-knowledge proof. - -A snarky program is constructed using functions exposed by the library. -The API of snarky that one can use to design circuits can be split in three categories: - -* creation of snarky variables (via `compute()`) -* creation of constraints (via `assert` type-functions) -* manipulation of snarky variables (which can sometimes create constraints) - -Snarky itself is divided into three parts: - -* [The high-level API](./api.md) that you can find in `api.rs` and `traits.rs` -* [The snarky wrapper](./snarky-wrapper.md), which contains the logic for creating user variables and composed types (see the section on [Snarky vars](./vars.md#snarky-vars)). -* [The kimchi backend](./kimchi-backend.md), which contains the logic for constructing the circuit as well as the witness. diff --git a/book/src/snarky/snarky-wrapper.md b/book/src/snarky/snarky-wrapper.md deleted file mode 100644 index 725f7c35ec..0000000000 --- a/book/src/snarky/snarky-wrapper.md +++ /dev/null @@ -1,70 +0,0 @@ -# Snarky wrapper - -Snarky, as of today, is constructed as two parts: - -* a snarky wrapper, which is explained in this document -* a backend underneath that wrapper, explained in the [kimchi backend section](./kimchi-backend.md) - -```admonish -This separation exists for legacy reasons, and ideally we should merge the two into a single library. -``` - -The snarky wrapper mostly exists in `checked_runner.rs`, and has the following state: - -```rust -where - F: PrimeField, -{ - /// The constraint system used to build the circuit. - /// If not set, the constraint system is not built. - system: Option>, - - /// The public input of the circuit used in witness generation. - // TODO: can we merge public_input and private_input? - public_input: Vec, - - // TODO: we could also just store `usize` here - pub(crate) public_output: Vec>, - - /// The private input of the circuit used in witness generation. Still not sure what that is, or why we care about this. - private_input: Vec, - - /// If set, the witness generation will check if the constraints are satisfied. - /// This is useful to simulate running the circuit and return an error if an assertion fails. - eval_constraints: bool, - - /// The number of public inputs. - num_public_inputs: usize, - - /// A counter used to track variables (this includes public inputs) as they're being created. - next_var: usize, - - /// Indication that we're running the witness generation (as opposed to the circuit creation). - mode: Mode, -} -``` - -The wrapper is designed to be used in different ways, depending on the fields set. - -```admonish -Ideally, we would like to only run this once and obtain a result that's an immutable compiled artifact. -Currently, `public_input`, `private_input`, `eval_constriants`, `next_var`, and `mode` all need to be mutable. -In the future these should be passed as arguments to functions, and should not exist in the state. -``` - -## Public output - -The support for public output is implemented as kind of a hack. - -When the developer writes a circuit, they have to specify the type of the public output. - -This allows the API to save enough room at the end of the public input, and store the variables used in the public output in the state. - -When the API calls the circuit written by the developer, it expects the public output (as a snarky type) to be returned by the function. -The compilation or proving API that ends up calling that function, can thus obtain the variables of the public output. -With that in hand, the API can continue to write the circuit to enforce an equality constraint between these variables being returned and the public output variable that it had previously stored in the state. - -Essentially, the kimchi backend will turn this into as many wiring as there are `CVar` in the public output. - -During witness generation, we need a way to modify the witness once we know the values of the public output. -As the public output `CVar`s were generated from the snarky wrapper (and not from the kimchi backend), the snarky wrapper should know their values after running the given circuit. diff --git a/book/src/snarky/vars.md b/book/src/snarky/vars.md deleted file mode 100644 index 7a1e3a3be7..0000000000 --- a/book/src/snarky/vars.md +++ /dev/null @@ -1,135 +0,0 @@ -# Vars - -In this section we will introduce two types of variables: - -* Circuit vars, or `CVar`s, which are low-level variables representing field elements. -* Snarky vars, which are high-level variables that user can use to create more meaningful programs. - -## Circuit vars - -In snarky, we first define circuit variables (TODO: rename Field variable?) which represent field elements in a circuit. -These circuit variables, or cvars, can be represented differently in the system: - -```rust -pub enum CVar -where - F: PrimeField, -{ - /// A constant. - Constant(F), - - /// A variable that can be refered to via a `usize`. - Var(usize), - - /// The addition of two other [CVar]s. - Add(Box>, Box>), - - /// Scaling of a [CVar]. - Scale(F, Box>), -} -``` - -One can see a CVar as an AST, where two atoms exist: a `Var(usize)` which represents a private input, an a `Constant(F)` which represents a constant. -Anything else represents combinations of these two atoms. - -### Constants - -Note that a circuit variable does not represent a value that has been constrained in the circuit (yet). -This is why we need to know if a cvar is a constant, so that we can avoid constraining it too early. -For example, the following code does not encode 2 or 1 in the circuit, but will encode 3: - -```rust -let x: CVar = state.exists(|_| 2) + state.exists(|_| 3); -state.assert_eq(x, y); // 3 and y will be encoded in the circuit -``` - -whereas the following code will encode all variables: - -```rust -let x = y + y; -let one: CVar = state.exists(|_| 1); -assert_eq(x, one); -``` - -### Non-constants - -Right after being created, a `CVar` is not constrained yet, and needs to be constrained by the application. -That is unless the application wants the `CVar` to be a constant that will not need to be constrained (see previous example) or because the application wants the `CVar` to be a random value (unlikely) (TODO: we should add a "rand" function for that). - -In any case, a circuit variable which is not a constant has a value that is not known yet at circuit-generation time. -In some situations, we might not want to constrain the - - -### When do variables get constrained? - -In general, a circuit variable only gets constrained by an assertion call like `assert` or `assert_equals`. - -When variables are added together, or scaled, they do not directly get constrained. -This is due to optimizations targetting R1CS (which we don't support anymore) that were implemented in the original snarky library, and that we have kept in snarky-rs. - -Imagine the following example: - -```rust -let y = x1 + x2 + x3 +.... ; -let z = y + 3; -assert_eq(y, 6); -assert_eq(z, 7); -``` - -The first two lines will not create constraints, but simply create minimal ASTs that track all of the additions. - -Both assert calls will then reduce the variables to a single circuit variable, creating the same constraints twice. - -For this reason, there's a function `seal()` defined in pickles and snarkyjs. (TODO: more about `seal()`, and why is it not in snarky?) (TODO: remove the R1CS optimization) - -## Snarky vars - -Handling `CVar`s can be cumbersome, as they can only represent a single field element. -We might want to represent values that are either in a smaller range (e.g. [booleans](./booleans.md)) or that are made out of several `CVar`s. - -For this, snarky's API exposes the following trait, which allows users to define their own types: - -```rust -pub trait SnarkyType: Sized -where - F: PrimeField, -{ - /// ? - type Auxiliary; - - /// The equivalent type outside of the circuit. - type OutOfCircuit; - - const SIZE_IN_FIELD_ELEMENTS: usize; - - fn to_cvars(&self) -> (Vec>, Self::Auxiliary); - - fn from_cvars_unsafe(cvars: Vec>, aux: Self::Auxiliary) -> Self; - - fn check(&self, cs: &mut RunState); - - fn deserialize(&self) -> (Self::OutOfCircuit, Self::Auxiliary); - - fn serialize(out_of_circuit: Self::OutOfCircuit, aux: Self::Auxiliary) -> Self; - - fn constraint_system_auxiliary() -> Self::Auxiliary; - - fn value_to_field_elements(x: &Self::OutOfCircuit) -> (Vec, Self::Auxiliary); - - fn value_of_field_elements(x: (Vec, Self::Auxiliary)) -> Self::OutOfCircuit; -} -``` - -Such types are always handled as `OutOfCircuit` types (e.g. `bool`) by the users, and as a type implementing `SnarkyType` by snarky (e.g. [`Boolean`](./booleans.md)). -Thus, the user can pass them to snarky in two ways: - -**As public inputs**. In this case they will be serialized into field elements for snarky before [witness-generation](./witness-generation.md) (via the `value_to_field_elements()` function) - -**As private inputs**. In this case, they must be created using the `compute()` function with a closure returning an `OutOfCircuit` value by the user. -The call to `compute()` will need to have some type hint, for snarky to understand what `SnarkyType` it is creating. -This is because the relationship is currently only one-way: a `SnarkyType` knows what out-of-circuit type it relates to, but not the other way is not true. -(TODO: should we implement that though?) - -A `SnarkyType` always implements a `check()` function, which is called by snarky when `compute()` is called to create such a type. -The `check()` function is responsible for creating the constraints that sanitize the newly-created `SnarkyType` (and its underlying `CVar`s). -For example, creating a boolean would make sure that the underlying `CVar` is either 0 or 1. diff --git a/book/src/snarky/witness-generation.md b/book/src/snarky/witness-generation.md deleted file mode 100644 index 41fbc3b5f1..0000000000 --- a/book/src/snarky/witness-generation.md +++ /dev/null @@ -1,21 +0,0 @@ -# Witness generation - -In snarky, currently, the same code is run through again to generate the witness. - -That is, the `RunState` contains a few changes: - -* **`public_input: Vec`**: now contains concrete values (instead of being empty). -* **`has_witness`**: is set to `WitnessGeneration`. - -Additionaly, if we want to verify that the arguments are actually correct (and that the program implemented does not fail) we can also set `eval_constraints` to `true` (defaults to `false`) to verify that the program has a correct state at all point in time. - -If we do not do this, the user will only detect failure during proof generation (specifically when the [composition polynomial](../specs/kimchi.md#proof-creation) is divided by the [vanishing polynomial](../specs/kimchi.md#proof-creation)). - -```admonish -This is implemented by simply checking that each [generic gate](../specs/kimchi.md#double-generic-gate) encountered is correct, in relation to the witness values observed in that row. -In other words $c_0 l + c_1 r + c_2 o + c_3 l r + c_4 = 0$ (extrapolated to the [double generic gate](../specs/kimchi.md#double-generic-gate)). -Note that other custom gates are not checked, as they are wrapped by [gadgets](../specs/kimchi.md#gates) which fill in witness values instead of the user. -Thus there is no room for user error (i.e. the user entering a wrong private input). -``` - -Due to the `has_witness` variable set to `WitnessGeneration`, functions will behave differently and compute actual values instead of generating constraints. From 8e66d4258ad06e6dd983017fb59040d0a3bc93bd Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 3 Oct 2023 21:49:27 +0200 Subject: [PATCH 147/242] Default toolchain to 1.72 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 65ee095984..cc31fcd4f5 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.67.0 +1.72 From 2c8cc7df57b5e0d713b960c62fb31cb9224259aa Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 4 Oct 2023 19:57:10 +0100 Subject: [PATCH 148/242] Fixup test compilation --- kimchi/src/tests/framework.rs | 3 ++- kimchi/src/tests/generic.rs | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index 05fff61cb9..b0b79dbdbd 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -123,7 +123,7 @@ where /// creates the indexes #[must_use] - pub(crate) fn setup_with_custom_srs) -> OpeningProof::SRS>( + pub(crate) fn setup_with_custom_srs, usize) -> OpeningProof::SRS>( mut self, get_srs: F, ) -> TestRunner { @@ -139,6 +139,7 @@ where lookup_tables, runtime_tables_setup, self.disable_gates_checks, + self.override_srs_size, get_srs, ); println!( diff --git a/kimchi/src/tests/generic.rs b/kimchi/src/tests/generic.rs index b3d923e67b..f9efc83341 100644 --- a/kimchi/src/tests/generic.rs +++ b/kimchi/src/tests/generic.rs @@ -96,7 +96,6 @@ fn test_generic_gate_pairing() { type ScalarSponge = DefaultFrSponge; use ark_ff::UniformRand; - use ark_poly::EvaluationDomain; let public = vec![Fp::from(3u8); 5]; let gates = create_circuit(0, public.len()); @@ -116,8 +115,8 @@ fn test_generic_gate_pairing() { .gates(gates) .witness(witness) .public_inputs(public) - .setup_with_custom_srs(|d1| { - let mut srs = poly_commitment::pairing_proof::PairingSRS::create(x, d1.size()); + .setup_with_custom_srs(|d1, usize| { + let mut srs = poly_commitment::pairing_proof::PairingSRS::create(x, usize); srs.full_srs.add_lagrange_basis(d1); srs }) From 6d6574b3454214979865a5467ffd5a74a3afafb3 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 4 Oct 2023 20:10:57 +0100 Subject: [PATCH 149/242] Disable a clippy warning --- kimchi/src/prover_index.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 34b7a309e3..4672c75bd6 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -144,6 +144,7 @@ pub mod testing { use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as D}; use poly_commitment::{evaluation_proof::OpeningProof, srs::SRS, OpenProof}; + #[allow(clippy::too_many_arguments)] pub fn new_index_for_test_with_lookups_and_custom_srs< G: KimchiCurve, OpeningProof: OpenProof, From 02fd510b5f3390dd3b58017a3186a2e1ccc22276 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 4 Oct 2023 22:52:12 +0100 Subject: [PATCH 150/242] Add missing function call --- kimchi/src/prover_index.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index ae5424fc31..44ee0f6266 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -171,6 +171,7 @@ pub mod testing { .public(public) .prev_challenges(prev_challenges) .disable_gates_checks(disable_gates_checks) + .max_poly_size(override_srs_size) .build() .unwrap(); From b1023b6a7644e33e3f842d9f70ef200d4e15b207 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 9 Oct 2023 05:41:50 +0100 Subject: [PATCH 151/242] Remove noisy debug_sponge --- poseidon/Cargo.toml | 1 - poseidon/src/poseidon.rs | 10 ------- poseidon/src/sponge.rs | 59 ---------------------------------------- 3 files changed, 70 deletions(-) diff --git a/poseidon/Cargo.toml b/poseidon/Cargo.toml index 10b44ec4d4..7a122051e4 100644 --- a/poseidon/Cargo.toml +++ b/poseidon/Cargo.toml @@ -37,4 +37,3 @@ ark-serialize = "0.3.0" [features] default = [] ocaml_types = [ "ocaml", "ocaml-gen", ] -debug_sponge = [] diff --git a/poseidon/src/poseidon.rs b/poseidon/src/poseidon.rs index 0ee363edc9..ff06022910 100644 --- a/poseidon/src/poseidon.rs +++ b/poseidon/src/poseidon.rs @@ -1,8 +1,5 @@ //! This module implements Poseidon Hash Function primitive -#[cfg(feature = "debug_sponge")] -use std::sync::atomic::{AtomicU64, Ordering::SeqCst}; - use crate::constants::SpongeConstants; use crate::permutation::{full_round, poseidon_block_cipher}; use ark_ff::Field; @@ -52,8 +49,6 @@ pub struct ArithmeticSponge { pub state: Vec, params: &'static ArithmeticSpongeParams, pub constants: std::marker::PhantomData, - #[cfg(feature = "debug_sponge")] - pub id: u64, } impl ArithmeticSponge { @@ -77,17 +72,12 @@ impl Sponge for ArithmeticSponge { state.push(F::zero()); } - #[cfg(feature = "debug_sponge")] - static COUNTER: AtomicU64 = AtomicU64::new(0); - ArithmeticSponge { state, rate, sponge_state: SpongeState::Absorbed(0), params, constants: std::marker::PhantomData, - #[cfg(feature = "debug_sponge")] - id: COUNTER.fetch_add(1, SeqCst), } } diff --git a/poseidon/src/sponge.rs b/poseidon/src/sponge.rs index 385afbf539..ff7f00a412 100644 --- a/poseidon/src/sponge.rs +++ b/poseidon/src/sponge.rs @@ -3,9 +3,6 @@ use crate::poseidon::{ArithmeticSponge, ArithmeticSpongeParams, Sponge}; use ark_ec::{short_weierstrass_jacobian::GroupAffine, SWModelParameters}; use ark_ff::{BigInteger, Field, FpParameters, One, PrimeField, Zero}; -#[cfg(feature = "debug_sponge")] -use o1_utils::FieldHelpers; - pub use crate::FqSponge; pub const CHALLENGE_LENGTH_IN_LIMBS: usize = 2; @@ -132,49 +129,6 @@ where } } -// Debugging macros -- these only insert code when non-release build and -// "debug_sponge" feature is enabled. -macro_rules! debug_sponge { - ($name:expr, $sponge:expr) => { - #[cfg(feature = "debug_sponge")] - { - // No input - debug_sponge_print_state!($name, $sponge); - } - }; - ($name:expr, $input:expr, $sponge:expr) => { - #[cfg(feature = "debug_sponge")] - { - // Field input - debug_sponge_print_state!($name, $sponge); - - println!( - "debug_sponge: id{} {} input {}", - $sponge.id, - $name, - $input.to_hex() - ); - } - }; -} -#[cfg(feature = "debug_sponge")] -macro_rules! debug_sponge_print_state { - ($name:expr, $sponge:expr) => { - println!( - "debug_sponge: id{} {} state {:?} {}", - $sponge.id, - $name, - $sponge.sponge_state, - $sponge - .state - .iter() - .map(|f| { f.to_hex() }) - .collect::>() - .join(" "), - ); - }; -} - impl FqSponge, P::ScalarField> for DefaultFqSponge where @@ -183,7 +137,6 @@ where { fn new(params: &'static ArithmeticSpongeParams) -> DefaultFqSponge { let sponge = ArithmeticSponge::new(params); - debug_sponge!("new", sponge); DefaultFqSponge { sponge, last_squeezed: vec![], @@ -196,14 +149,10 @@ where if g.infinity { // absorb a fake point (0, 0) let zero = P::BaseField::zero(); - debug_sponge!("absorb", zero, self.sponge); self.sponge.absorb(&[zero]); - debug_sponge!("absorb", zero, self.sponge); self.sponge.absorb(&[zero]); } else { - debug_sponge!("absorb", g.x, self.sponge); self.sponge.absorb(&[g.x]); - debug_sponge!("absorb", g.y, self.sponge); self.sponge.absorb(&[g.y]); } } @@ -213,7 +162,6 @@ where self.last_squeezed = vec![]; for fe in x { - debug_sponge!("absorb", fe, self.sponge); self.sponge.absorb(&[*fe]) } } @@ -232,7 +180,6 @@ where ::BigInt::from_bits_le(&bits), ) .expect("padding code has a bug"); - debug_sponge!("absorb", fe, self.sponge); self.sponge.absorb(&[fe]); } else { let low_bit = if bits[0] { @@ -246,16 +193,13 @@ where ) .expect("padding code has a bug"); - debug_sponge!("absorb", high_bits, self.sponge); self.sponge.absorb(&[high_bits]); - debug_sponge!("absorb", low_bit, self.sponge); self.sponge.absorb(&[low_bit]); } }); } fn digest(mut self) -> P::ScalarField { - debug_sponge!("squeeze", self.sponge); let x: ::BigInt = self.squeeze_field().into_repr(); // Returns zero for values that are too large. // This means that there is a bias for the value zero (in one of the curve). @@ -267,17 +211,14 @@ where } fn digest_fq(mut self) -> P::BaseField { - debug_sponge!("squeeze", self.sponge); self.squeeze_field() } fn challenge(&mut self) -> P::ScalarField { - debug_sponge!("squeeze", self.sponge); self.squeeze(CHALLENGE_LENGTH_IN_LIMBS) } fn challenge_fq(&mut self) -> P::BaseField { - debug_sponge!("squeeze", self.sponge); self.squeeze_field() } } From 8071b0f03aae6fce71af505d553220ad82d1b148 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 9 Oct 2023 05:44:44 +0100 Subject: [PATCH 152/242] Remove kimchi-asm --- Cargo.lock | 17 ----------------- Cargo.toml | 1 - tools/kimchi-asm/CHANGELOG.md | 13 ------------- tools/kimchi-asm/Cargo.toml | 24 ----------------------- tools/kimchi-asm/README.md | 34 --------------------------------- tools/kimchi-asm/src/main.rs | 36 ----------------------------------- 6 files changed, 125 deletions(-) delete mode 100644 tools/kimchi-asm/CHANGELOG.md delete mode 100644 tools/kimchi-asm/Cargo.toml delete mode 100644 tools/kimchi-asm/README.md delete mode 100644 tools/kimchi-asm/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index e622691862..c8b7f9249a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1142,23 +1142,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kimchi-asm" -version = "0.1.0" -dependencies = [ - "ark-ec", - "ark-ff", - "kimchi", - "mina-curves", - "mina-poseidon", - "o1-utils", - "poly-commitment", - "serde", - "serde_json", - "serde_with", - "tinytemplate", -] - [[package]] name = "kimchi-visu" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 473e37d933..c50da37068 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ members = [ "poseidon/export_test_vectors", "poly-commitment", "signer", - "tools/kimchi-asm", "tools/kimchi-visu", "utils", "internal-tracing", diff --git a/tools/kimchi-asm/CHANGELOG.md b/tools/kimchi-asm/CHANGELOG.md deleted file mode 100644 index 56773f1e6a..0000000000 --- a/tools/kimchi-asm/CHANGELOG.md +++ /dev/null @@ -1,13 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - - -## 0.1.0 (2023-03-09) - -- Initial release diff --git a/tools/kimchi-asm/Cargo.toml b/tools/kimchi-asm/Cargo.toml deleted file mode 100644 index 4bd69deaef..0000000000 --- a/tools/kimchi-asm/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "kimchi-asm" -version = "0.1.0" -description = "A tool to read circuits" -repository = "https://github.com/o1-labs/proof-systems" -homepage = "https://o1-labs.github.io/proof-systems/" -documentation = "https://o1-labs.github.io/proof-systems/rustdoc/" -readme = "README.md" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -ark-ec = "0.3.0" -ark-ff = "0.3.0" -serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" -serde_with = "1.10.0" -tinytemplate = "1.1" - -mina-curves = { path = "../../curves", version = "0.1.0" } -kimchi = { path = "../../kimchi", version = "0.1.0" } -o1-utils = { path = "../../utils", version = "0.1.0" } -mina-poseidon = { path = "../../poseidon", version = "0.1.0" } -poly-commitment = { path = "../../poly-commitment", version = "0.1.0" } diff --git a/tools/kimchi-asm/README.md b/tools/kimchi-asm/README.md deleted file mode 100644 index b55767c23f..0000000000 --- a/tools/kimchi-asm/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Kimchi ASM - -Allows you to deserialize a circuit in JSON format and print it using some pseudo-assembly language. - -Simple pipe your JSON to this binary. For example: - -```console -$ cargo run --bin kimchi-asm < examples/circuits/poseidon.json -``` - -You will get an output like: - -```asm -row0.pub.Generic<1,0,0,0,0> -.l1 -> row4.l1 - -row1.pub.Generic<1,0,0,0,0> -.l1 -> row2.l1 - -row2.Generic<-1,0,0,1,0><-1,0,0,1,0> -.l1 -> row4.r1, .r1 -> row1.l1 -.l2 -> row0.l1, .r2 -> row2.l2 - -row3.Generic<-1,0,0,1,0><-1,0,0,1,0> -.l1 -> row4.r2, .r1 -> row3.l1 -.l2 -> row4.l2, .r2 -> row3.l2 - -row4.Generic<0,0,1,-1,0><0,0,1,-1,0> -.l1 -> row2.r2, .r1 -> row2.r1, .o1 -> row5.l1 -.l2 -> row3.r2, .r2 -> row3.r1, .o2 -> row4.o1 - -row5.Generic<1,0,0,0,-1> -.l1 -> row4.o2 -``` diff --git a/tools/kimchi-asm/src/main.rs b/tools/kimchi-asm/src/main.rs deleted file mode 100644 index 257146dc83..0000000000 --- a/tools/kimchi-asm/src/main.rs +++ /dev/null @@ -1,36 +0,0 @@ -use ark_ff::PrimeField; -use kimchi::circuits::gate::{Circuit, CircuitGate}; -use mina_curves::pasta::Fp; -use serde::de::DeserializeOwned; - -#[derive(serde::Deserialize)] -pub struct DeserializableCircuit -where - F: PrimeField, -{ - pub public_input_size: usize, - #[serde(bound = "CircuitGate: DeserializeOwned")] - pub gates: Vec>, -} - -impl<'a, F> From<&'a DeserializableCircuit> for Circuit<'a, F> -where - F: PrimeField, -{ - fn from(circuit: &'a DeserializableCircuit) -> Self { - Circuit::new(circuit.public_input_size, &circuit.gates) - } -} - -fn main() { - // get what was piped to this binary - let stdin = std::io::stdin(); - - // deserialize it to JSON - let circuit: DeserializableCircuit = - serde_json::from_reader(stdin).expect("couldn't deserialize the circuit"); - - let circuit: Circuit<_> = (&circuit).into(); - - println!("{}", circuit.generate_asm()); -} From e154fa449875b3b0e411a2fc939814dbf730820a Mon Sep 17 00:00:00 2001 From: Richard Bonichon Date: Wed, 13 Sep 2023 16:50:25 +0200 Subject: [PATCH 153/242] Lookups: add wasm-related creation functions with wasm constructors --- kimchi/src/circuits/lookup/lookups.rs | 55 +++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 6b6de6a517..b126e1be00 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -550,3 +550,58 @@ fn lookup_pattern_constants_correct() { assert_eq!((pat, pat.max_joint_size()), (pat, max_joint_size as u32)); } } + +#[cfg(feature = "wasm_types")] +pub mod wasm { + use super::*; + + #[wasm_bindgen::prelude::wasm_bindgen] + impl LookupPatterns { + #[wasm_bindgen::prelude::wasm_bindgen(constructor)] + pub fn new( + xor: bool, + lookup: bool, + range_check: bool, + foreign_field_mul: bool, + ) -> LookupPatterns { + LookupPatterns { + xor, + lookup, + range_check, + foreign_field_mul, + } + } + } + + #[wasm_bindgen::prelude::wasm_bindgen] + impl LookupFeatures { + #[wasm_bindgen::prelude::wasm_bindgen(constructor)] + pub fn new( + patterns: LookupPatterns, + joint_lookup_used: bool, + uses_runtime_tables: bool, + ) -> LookupFeatures { + LookupFeatures { + patterns, + joint_lookup_used, + uses_runtime_tables, + } + } + } + + #[wasm_bindgen::prelude::wasm_bindgen] + impl LookupInfo { + #[wasm_bindgen::prelude::wasm_bindgen(constructor)] + pub fn new( + max_per_row: usize, + max_joint_size: u32, + features: LookupFeatures, + ) -> LookupInfo { + LookupInfo { + max_per_row, + max_joint_size, + features, + } + } + } +} From 6cac18b42a0c4f48133a9f518cfa0e3e11613554 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 10 Oct 2023 08:08:08 +0100 Subject: [PATCH 154/242] Improve errors around domain creation --- kimchi/src/circuits/constraints.rs | 7 ++++--- kimchi/src/circuits/domains.rs | 29 ++++++++++++++++------------- kimchi/src/error.rs | 12 +++++++++++- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 48c88cc0cc..01ab9cca39 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -11,7 +11,7 @@ use crate::{ wires::*, }, curve::KimchiCurve, - error::SetupError, + error::{DomainCreationError, SetupError}, prover_index::ProverIndex, }; use ark_ff::{PrimeField, SquareRootField, Zero}; @@ -752,7 +752,7 @@ impl Builder { while { let domain_size = D::::compute_size_of_domain(domain_size_lower_bound) .ok_or(SetupError::DomainCreation( - "could not compute size of domain", + DomainCreationError::DomainSizeFailed(domain_size_lower_bound), ))?; let num_chunks = domain_size / max_poly_size; zk_rows = (zk_rows_strict_lower_bound(num_chunks) + 1) as u64; @@ -766,7 +766,8 @@ impl Builder { //~ 1. Create a domain for the circuit. That is, //~ compute the smallest subgroup of the field that //~ has order greater or equal to `n + zk_rows` elements. - let domain = EvaluationDomains::::create(domain_size_lower_bound)?; + let domain = EvaluationDomains::::create(domain_size_lower_bound) + .map_err(SetupError::DomainCreation)?; assert!(domain.d1.size > zk_rows); diff --git a/kimchi/src/circuits/domains.rs b/kimchi/src/circuits/domains.rs index 7f32dd6e12..89251bea5f 100644 --- a/kimchi/src/circuits/domains.rs +++ b/kimchi/src/circuits/domains.rs @@ -3,7 +3,7 @@ use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as Domain}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::error::SetupError; +use crate::error::DomainCreationError; #[serde_as] #[derive(Debug, Clone, Copy, Serialize, Deserialize)] @@ -22,26 +22,29 @@ impl EvaluationDomains { /// Creates 4 evaluation domains `d1` (of size `n`), `d2` (of size `2n`), `d4` (of size `4n`), /// and `d8` (of size `8n`). If generator of `d8` is `g`, the generator /// of `d4` is `g^2`, the generator of `d2` is `g^4`, and the generator of `d1` is `g^8`. - pub fn create(n: usize) -> Result { - let n = Domain::::compute_size_of_domain(n).ok_or(SetupError::DomainCreation( - "could not compute size of domain", - ))?; + pub fn create(n: usize) -> Result { + let n = Domain::::compute_size_of_domain(n) + .ok_or(DomainCreationError::DomainSizeFailed(n))?; - let d1 = Domain::::new(n).ok_or(SetupError::DomainCreation( - "construction of domain d1 did not work as intended", + let d1 = Domain::::new(n).ok_or(DomainCreationError::DomainConstructionFailed( + "d1".to_string(), + n, ))?; // we also create domains of larger sizes // to efficiently operate on polynomials in evaluation form. // (in evaluation form, the domain needs to grow as the degree of a polynomial grows) - let d2 = Domain::::new(2 * n).ok_or(SetupError::DomainCreation( - "construction of domain d2 did not work as intended", + let d2 = Domain::::new(2 * n).ok_or(DomainCreationError::DomainConstructionFailed( + "d2".to_string(), + 2 * n, ))?; - let d4 = Domain::::new(4 * n).ok_or(SetupError::DomainCreation( - "construction of domain d4 did not work as intended", + let d4 = Domain::::new(4 * n).ok_or(DomainCreationError::DomainConstructionFailed( + "d4".to_string(), + 4 * n, ))?; - let d8 = Domain::::new(8 * n).ok_or(SetupError::DomainCreation( - "construction of domain d8 did not work as intended", + let d8 = Domain::::new(8 * n).ok_or(DomainCreationError::DomainConstructionFailed( + "d8".to_string(), + 8 * n, ))?; // ensure the relationship between the three domains in case the library's behavior changes diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 5e4a8817b7..8c801fd38f 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -82,6 +82,16 @@ pub enum VerifyError { MissingCommitment(crate::circuits::expr::Column), } +/// Errors that can arise when preparing the setup +#[derive(Error, Debug, Clone)] +pub enum DomainCreationError { + #[error("could not compute the size of domain for {0}")] + DomainSizeFailed(usize), + + #[error("construction of domain {0} for size {1} failed")] + DomainConstructionFailed(String, usize), +} + /// Errors that can arise when preparing the setup #[derive(Error, Debug, Clone)] pub enum SetupError { @@ -89,7 +99,7 @@ pub enum SetupError { ConstraintSystem(String), #[error("the domain could not be constructed: {0}")] - DomainCreation(&'static str), + DomainCreation(DomainCreationError), } /// Errors that can arise when creating a verifier index From 0467bcec00792b590239e15107718dabfc84d10a Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 10 Oct 2023 08:28:39 +0100 Subject: [PATCH 155/242] Fixup edge-case around chunking in constraint system --- kimchi/src/circuits/constraints.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 48c88cc0cc..ee9443368a 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -754,7 +754,11 @@ impl Builder { .ok_or(SetupError::DomainCreation( "could not compute size of domain", ))?; - let num_chunks = domain_size / max_poly_size; + let num_chunks = if domain_size < max_poly_size { + 1 + } else { + domain_size / max_poly_size + }; zk_rows = (zk_rows_strict_lower_bound(num_chunks) + 1) as u64; domain_size_lower_bound = get_domain_size_lower_bound(zk_rows); domain_size < domain_size_lower_bound From b1bc089560a049a1d447b6678436247c1857de09 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 10 Oct 2023 19:02:58 +0100 Subject: [PATCH 156/242] Clippy :') --- kimchi/src/circuits/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 4da1339206..fb0e660695 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -2609,7 +2609,7 @@ where if *i > 0 { format!("unnormalized_lagrange_basis(zk_rows + {})", *i) } else if *i == 0 { - format!("unnormalized_lagrange_basis(zk_rows)") + "unnormalized_lagrange_basis(zk_rows)".to_string() } else { format!("unnormalized_lagrange_basis(zk_rows - {})", (-*i)) } From 6ec48aa1590bc6d6cfff9b4903cff6076a06387c Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 12 Oct 2023 18:06:45 +0100 Subject: [PATCH 157/242] More opinionated clippy changes --- kimchi/src/circuits/expr.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index fb0e660695..4c742ac5b5 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -2605,15 +2605,11 @@ where UnnormalizedLagrangeBasis(RowOffset { zk_rows: true, offset: i, - }) => { - if *i > 0 { - format!("unnormalized_lagrange_basis(zk_rows + {})", *i) - } else if *i == 0 { - "unnormalized_lagrange_basis(zk_rows)".to_string() - } else { - format!("unnormalized_lagrange_basis(zk_rows - {})", (-*i)) - } - } + }) => match i.cmp(&0) { + Ordering::Greater => format!("unnormalized_lagrange_basis(zk_rows + {})", *i), + Ordering::Equal => "unnormalized_lagrange_basis(zk_rows)".to_string(), + Ordering::Less => format!("unnormalized_lagrange_basis(zk_rows - {})", (-*i)), + }, UnnormalizedLagrangeBasis(RowOffset { zk_rows: false, offset: i, From a2e577cd98ae4b7b54d0945f46e45a240b510426 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 12 Oct 2023 18:41:06 +0100 Subject: [PATCH 158/242] Fixup compilation after clippy's 'help' --- kimchi/src/circuits/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 4c742ac5b5..f331d96b1b 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -21,11 +21,11 @@ use o1_utils::{foreign_field::ForeignFieldHelpers, FieldHelpers}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign, Mul, Neg, Sub}; +use std::{cmp::Ordering, fmt, iter::FromIterator}; use std::{ collections::{HashMap, HashSet}, ops::MulAssign, }; -use std::{fmt, iter::FromIterator}; use thiserror::Error; use CurrOrNext::{Curr, Next}; From fe78e3550ad1b92608b769d3a862008e346bdb92 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 12 Oct 2023 20:38:29 +0100 Subject: [PATCH 159/242] Fixup test --- kimchi/src/alphas.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/kimchi/src/alphas.rs b/kimchi/src/alphas.rs index 2dbef2aaf3..27a35f7bd8 100644 --- a/kimchi/src/alphas.rs +++ b/kimchi/src/alphas.rs @@ -326,7 +326,6 @@ mod tests { let (_linearization, powers_of_alpha) = expr_linearization::( Some(&index.cs.feature_flags), true, - index.cs.zk_rows as usize, ); // make sure this is present in the specification let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); From 09ba6e26cb614adb437a30213d45f055ffeb58ce Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 14 Oct 2023 18:35:50 +0100 Subject: [PATCH 160/242] cargo fmt --- kimchi/src/alphas.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kimchi/src/alphas.rs b/kimchi/src/alphas.rs index 27a35f7bd8..0eaa047114 100644 --- a/kimchi/src/alphas.rs +++ b/kimchi/src/alphas.rs @@ -323,10 +323,8 @@ mod tests { fn get_alphas_for_spec() { let gates = vec![CircuitGate::::zero(Wire::for_row(0)); 2]; let index = new_index_for_test::(gates, 0); - let (_linearization, powers_of_alpha) = expr_linearization::( - Some(&index.cs.feature_flags), - true, - ); + let (_linearization, powers_of_alpha) = + expr_linearization::(Some(&index.cs.feature_flags), true); // make sure this is present in the specification let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let spec_path = Path::new(&manifest_dir) From abd91eae176fdfb686644dd630bb2bb0e517f86f Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 29 Sep 2023 22:07:44 +0200 Subject: [PATCH 161/242] Remove snarky --- book/src/SUMMARY.md | 11 -- book/src/snarky/api.md | 2 - book/src/snarky/booleans.md | 73 -------- book/src/snarky/circuit-generation.md | 29 ---- book/src/snarky/kimchi-backend.md | 234 -------------------------- book/src/snarky/overview.md | 32 ---- book/src/snarky/snarky-wrapper.md | 70 -------- book/src/snarky/vars.md | 135 --------------- book/src/snarky/witness-generation.md | 21 --- 9 files changed, 607 deletions(-) delete mode 100644 book/src/snarky/api.md delete mode 100644 book/src/snarky/booleans.md delete mode 100644 book/src/snarky/circuit-generation.md delete mode 100644 book/src/snarky/kimchi-backend.md delete mode 100644 book/src/snarky/overview.md delete mode 100644 book/src/snarky/snarky-wrapper.md delete mode 100644 book/src/snarky/vars.md delete mode 100644 book/src/snarky/witness-generation.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 95d99267d6..aeccb68783 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -58,17 +58,6 @@ - [Permutation](./kimchi/permut.md) - [Lookup](./kimchi/lookup.md) -# Snarky - -- [Overview](./snarky/overview.md) -- [API](./snarky/api.md) -- [snarky wrapper](./snarky/snarky-wrapper.md) -- [Kimchi backend](./snarky/kimchi-backend.md) -- [Vars](./snarky/vars.md) -- [Booleans](./snarky/booleans.md) -- [Circuit generation](./snarky/circuit-generation.md) -- [Witness generation](./snarky/witness-generation.md) - # Pickles & Inductive Proof Systems - [Overview](./fundamentals/zkbook_ips.md) diff --git a/book/src/snarky/api.md b/book/src/snarky/api.md deleted file mode 100644 index e8b981a474..0000000000 --- a/book/src/snarky/api.md +++ /dev/null @@ -1,2 +0,0 @@ -# API of Snarky - diff --git a/book/src/snarky/booleans.md b/book/src/snarky/booleans.md deleted file mode 100644 index 7b503f0580..0000000000 --- a/book/src/snarky/booleans.md +++ /dev/null @@ -1,73 +0,0 @@ -# Booleans - -Booleans are a good example of a [snarky variable](./vars.md#snarky-vars). - -```rust -pub struct Boolean(CVar); - -impl SnarkyType for Boolean -where - F: PrimeField, -{ - type Auxiliary = (); - - type OutOfCircuit = bool; - - const SIZE_IN_FIELD_ELEMENTS: usize = 1; - - fn to_cvars(&self) -> (Vec>, Self::Auxiliary) { - (vec![self.0.clone()], ()) - } - - fn from_cvars_unsafe(cvars: Vec>, _aux: Self::Auxiliary) -> Self { - assert_eq!(cvars.len(), Self::SIZE_IN_FIELD_ELEMENTS); - Self(cvars[0].clone()) - } - - fn check(&self, cs: &mut RunState) { - // TODO: annotation? - cs.assert_(Some("boolean check"), vec![BasicSnarkyConstraint::Boolean(self.0.clone())]); - } - - fn deserialize(&self) -> (Self::OutOfCircuit, Self::Auxiliary) { - todo!() - } - - fn serialize(out_of_circuit: Self::OutOfCircuit, aux: Self::Auxiliary) -> Self { - todo!() - } - - fn constraint_system_auxiliary() -> Self::Auxiliary { - todo!() - } - - fn value_to_field_elements(x: &Self::OutOfCircuit) -> (Vec, Self::Auxiliary) { - todo!() - } - - fn value_of_field_elements(x: (Vec, Self::Auxiliary)) -> Self::OutOfCircuit { - todo!() - } -} -``` - -## Check - -The `check()` function is simply constraining the `CVar` $x$ to be either $0$ or $1$ using the following constraint: - -$$x ( x - 1) = 0$$ - -It is trivial to use the [double generic gate](../specs/kimchi.md#double-generic-gate) for this. - -## And - -$$x \land y = x \times y$$ - -## Not - -$$\sim x = 1 - x$$ - -## Or - -* $\sim x \land \sim y = b$ -* $x \lor y = \sim b$ diff --git a/book/src/snarky/circuit-generation.md b/book/src/snarky/circuit-generation.md deleted file mode 100644 index e81793aa03..0000000000 --- a/book/src/snarky/circuit-generation.md +++ /dev/null @@ -1,29 +0,0 @@ -# Circuit generation - -In circuit generation mode, the `has_witness` field of `RunState` is set to the default `CircuitGeneration`, and the program of the user is ran to completion. - -During the execution, the different snarky functions called on `RunState` will create [internal variables](./vars.md) as well as constraints. - -## Creation of variables - -[Variables](./vars.md) can be created via the `compute()` function, which takes two arguments: - -* A `TypeCreation` toggle, which is either set to `Checked` or `Unsafe`. We will describe this below. -* A closure representing the actual computation behind the variable. This computation will only take place when real values are computed, and can be non-deterministic (e.g. random, or external values provided by the user). Note that the closure takes one argument: a `WitnessGeneration`, a structure that allows you to read the runtime values of any variables that were previously created in your program. - -The `compute()` function also needs a type hint to understand what type of [snarky type](./vars.md#snarky-vars) it is creating. - -It then performs the following steps: - -* creates enough [`CVar`](./vars#circuit-vars) to hold the value to be created -* retrieves the auxiliary data needed to create the snarky type (TODO: explain auxiliary data) and create the [`snarky variable`](./vars.md#snarky-vars) out of the `CVar`s and the auxiliary data -* if the `TypeCreation` is set to `Checked`, call the `check()` function on the snarky type (which will constrain the value created), if it is set to `Unsafe` do nothing (in which case we're trusting that the value cannot be malformed, this is mostly used internally and it is highly-likely that users directly making use of `Unsafe` are writing bugs) - -```admonish -At this point we only created variables to hold future values, and made sure that they are constrained. -The actual values will fill the room created by the `CVar` only during the [witness generation](./witness-generation.md). -``` - -## Constraints - -All other functions exposed by the API are basically here to operate on variables and create constraints in doing so. diff --git a/book/src/snarky/kimchi-backend.md b/book/src/snarky/kimchi-backend.md deleted file mode 100644 index 2d2ebf789a..0000000000 --- a/book/src/snarky/kimchi-backend.md +++ /dev/null @@ -1,234 +0,0 @@ -# Kimchi Backend - -![](https://i.imgur.com/KmKU5Pl.jpg) - -Underneath the snarky wrapper (in `snarky/checked_runner.rs`) lies what we used to call the `plonk_constraint_system` or `kimchi_backend` in `snarky/constraint_systen.rs`. - -```admonish -It is good to note that we're planning on removing this abstract separation between the snarky wrapper and the constraint system. -``` - -The logic in the kimchi backend serves two purposes: - -* **Circuit generation**. It is the logic that adds gates to our list of gates (representing the circuit). For most of these gates, the variables used are passed to the backend by the snarky wrapper, but some of them are created by the backend itself (see more in the [variables section](#variables)). -* **Witness generation**. It is the logic that creates the witness - -One can also perform two additional operations once the constraint system has been compiled: - -* Generate the prover and verifier index for the system. -* Get a hash of the constraint system (this includes the circuit, the number of public input) (TODO: verify that this is true) (TODO: what else should be in that hash? a version of snarky and a version of kimchi?). - -## A circuit - -A circuit is either being built, or has been contructed during a circuit generation phase: - -```rust -enum Circuit -where - F: PrimeField, -{ - /** A circuit still being written. */ - Unfinalized(Vec>), - /** Once finalized, a circuit is represented as a digest - and a list of gates that corresponds to the circuit. - */ - Compiled([u8; 32], Vec>), -} -``` - -## State - -The state of the kimchi backend looks like this: - -```rust -where - Field: PrimeField, -{ - /// A counter used to track variables - /// (similar to the one in the snarky wrapper) - next_internal_var: usize, - - /// Instruction on how to compute each internal variable - /// (as a linear combination of other variables). - /// Used during witness generation. - internal_vars: HashMap, Option)>, - - /// The symbolic execution trace table. - /// Each cell is a variable that takes a value during witness generation. - /// (if not set, it will take the value 0). - rows: Vec>>, - - /// The circuit once compiled - gates: Circuit, - - /// The row to use the next time we add a constraint. - // TODO: I think we can delete this - next_row: usize, - - /// The size of the public input - /// (which fills the first rows of our constraint system. - public_input_size: Option, - - // omitted values... -} -``` - -## Variables - -In the backend, there's two types of variables: - -```rust -enum V { - /// An external variable - /// (generated by snarky, via [exists]). - External(usize), - - /// An internal variable is generated to hold an intermediate value, - /// (e.g. in reducing linear combinations to single PLONK positions). - Internal(InternalVar), -} -``` - -Internal variables are basically a `usize` pointing to a hashmap in the state. - -That hashmap tells you how to compute the internal variable during witness generation: it is always a linear combination of other variables (and a constant). - -## Circuit generation - -During circuit generation, the snarky wrapper will make calls to the `add_constraint()` or `add_basic_snarky_constraint` function of the kimchi backend, specifying what gate to use and what variables to use in that gate. - -At this point, the snarky wrapper might have some variables that are not yet tracked as such (with a counter). -Rather, they are constants, or they are a combination of other variables. -You can see that as a small AST representing how to compute a variable. -(See the [variables section](./vars.md#circuit-vars) for more details). - -For this reason, they can hide a number of operations that haven't been constrained yet. -It is the role of the `add_constrain` logic to enforce that at this point constants, as well as linear combinations or scalings of variables, are encoded in the circuit. -This is done by adding enough generic gates (using the `reduce_lincom()` or `reduce_to_var()` functions). - -```admonish -This is a remnant of an optimization targetting R1CS (in which additions are for free). -An issue with this approach is the following: imagine that two circuit variables are created from the same circuit variable, imagine also that the original circuit variable contained a long AST, then both variables might end up creating the same constraints to convert that AST. -Currently, snarkyjs and pickles expose a `seal()` function that allows you to reduce this issue, at the cost of some manual work and mental tracking on the developer. -We should probably get rid of this, while making sure that we can continue to optimize generic gates -(in some cases you can merge two generic gates in one (TODO: give an example of where that can happen)). -Another solution is to keep track of what was reduced, and reuse previous reductions (similar to how we handle constants). -``` - -It is during this "reducing" step that internal variables (known only to the kimchi backend) are created. - -```admonish -The process is quite safe, as the kimchi backend cannot use the snarky wrapper variables directly (which are of type `CVar`). -Since the expected format (see the [variables section](#variables) is a number (of type `usize`), the only way to convert a non-tracked variable (constant, or scale, or linear combination) is to reduce it (and in the process constraining its value). -``` - -Depending on the gate being used, several constraints might be added via the `add_row()` function which does three things: - -1. figure out if there's any wiring to be done -2. add a gate to our list of gates (representing the circuit) -3. add the variables to our _symbolic_ execution trace table (symbolic in the sense that nothing has values yet) - -This process happens as the circuit is "parsed" and the constraint functions of the kimchi backend are called. - -This does not lead to a finalized circuit, see the next section to see how that is done. - -(TODO: ideally this should happen in the same step) - -## Finalization of the circuit. - -So far we've only talked about adding specific constraints to the circuit, but not about how public input are handled. - -The `finalization()` function of the kimchi backend does the following: - -* add as many generic rows as there are public inputs. -* construct the permutation -* computes a cache of the circuit (TODO: this is so unecessary) -* and other things that are not that important - -## Witness generation - -Witness generation happens by taking the finalized state (in the `compute_witness()` function) with a callback that can be used to retrieve the values of external variables (public input and public output). - -The algorithm follows these steps using the symbolic execution table we built during circuit generation: - -1. it initializes the execution trace table with zeros -2. go through the rows related to the public input and set the most-left column values to the ones obtained by the callback. -3. go through the other rows and compute the value of the variables left in the table - -Variables in step 3. should either: - -* be absent (`None`) and evaluated to the default value 0 -* point to an external variable, in which case the closure passed can be used to retrieve the value -* be an internal variable, in which case the value is computed by evaluating the AST that was used to create it. - -## Permutation - -The permutation is used to wire cells of the execution trace table (specifically, cells belonging to the first 7 columns). -It is also known as "copy constraints". - -```admonish -In snarky, the permutation is represented differently from kimchi, and thus needs to be converted to the kimchi's format before a proof can be created. -TODO: merge the representations -``` - -We use the permutation in ingenious ways to optimize circuits. -For example, we use it to encode each constants once, and wire it to places where it is used. -Another example, is that we use it to assert equality between two cells. - -## Implementation details - -There's two aspect of the implementation of the permutation, the first one is a hashmap of equivalence classes, which is used to track all the positions of a variable, the second one is making use of a [union find]() data structure to link variables that are equivalent (we'll talk about that after). - -The two data structures are in the kimchi backend's state: - -```rust -pub struct SnarkyConstraintSystem -where - Field: PrimeField, -{ - equivalence_classes: HashMap>>, - union_finds: disjoint_set::DisjointSet, - // omitted fields... -} -``` - -### equivalence classes - -As said previously, during circuit generation a symbolic execution trace table is created. It should look a bit like this (if there were only 3 columns and 4 rows): - -| | 0 | 1 | 2 | -| :-: | :-: | :-: | :-:| -| 0 | v1 | v1 | | -| 1 | | v2 | | -| 2 | | v2 | | -| 3 | | | v1 | - -From that, it should be clear that all the cells containing the variable `v1` should be connected, -and all the cells containing the variable `v2` should be as well. - -The format that the permutation expects is a [cycle](https://en.wikipedia.org/wiki/Cyclic_permutation): a list of cells where each cell is linked to the next, the last one wrapping around and linking to the first one. - -For example, a cycle for the `v1` variable could be: - -``` -(0, 0) -> (0, 1) -(0, 1) -> (3, 2) -(3, 2) -> (0, 0) -``` - -During circuit generation, a hashmap (called `equivalence_classes`) is used to track all the positions (row and column) of each variable. - -During finalization, all the different cycles are created by looking at all the variables existing in the hashmap. - -### Union finds - -Sometimes, we know that two variables will have equivalent values due to an `assert_equal()` being called to link them. -Since we link two variables together, they need to be part of the same cycle, and as such we need to be able to detect that to construct correct cycles. - -To do this, we use a [union find]() data structure, which allows us to easily find the unions of equivalent variables. - -When an `assert_equal()` is called, we link the two variables together using the `union_finds` data structure. - -During finalization, when we create the cycles, we use the `union_finds` data structure to find the equivalent variables. -We then create a new equivalence classes hashmap to merge the keys (variables) that are in the same set. -This is done before using the equivalence classes hashmap to construct the cycles. diff --git a/book/src/snarky/overview.md b/book/src/snarky/overview.md deleted file mode 100644 index b67c1fa30b..0000000000 --- a/book/src/snarky/overview.md +++ /dev/null @@ -1,32 +0,0 @@ -# Snarky - -Snarky is a frontend to the [kimchi proof system](../kimchi/overview.md). - -It allows users to write circuits that can be proven using kimchi. - -This part of the Mina book documents both how to use snarky, and how its internals work. - -```admonish -Snarky was originally an OCaml library. It also is known as a typescript library: SnarkyJS. -This documentation talks about the Rust implementation, which one can refer to as snarky-rs (but we will just say snarky from now on). -``` - -## High-level design - -Snarky is divided into two parts: - -* **Circuit-generation**: which is also called the setup or compilation phase. It is when snarky turn code written using its library, to a circuit that kimchi can understand. This can later be used by kimchi to produce prover and verifier keys. -* **Witness-generation**: which is also called the proving, or runtime phase. It is when snarky executes the written program and records its state at various point in time to create an execution trace of the program (which we call witness here). This can later be used by kimchi, with a proving key, to produce a zero-knowledge proof. - -A snarky program is constructed using functions exposed by the library. -The API of snarky that one can use to design circuits can be split in three categories: - -* creation of snarky variables (via `compute()`) -* creation of constraints (via `assert` type-functions) -* manipulation of snarky variables (which can sometimes create constraints) - -Snarky itself is divided into three parts: - -* [The high-level API](./api.md) that you can find in `api.rs` and `traits.rs` -* [The snarky wrapper](./snarky-wrapper.md), which contains the logic for creating user variables and composed types (see the section on [Snarky vars](./vars.md#snarky-vars)). -* [The kimchi backend](./kimchi-backend.md), which contains the logic for constructing the circuit as well as the witness. diff --git a/book/src/snarky/snarky-wrapper.md b/book/src/snarky/snarky-wrapper.md deleted file mode 100644 index 725f7c35ec..0000000000 --- a/book/src/snarky/snarky-wrapper.md +++ /dev/null @@ -1,70 +0,0 @@ -# Snarky wrapper - -Snarky, as of today, is constructed as two parts: - -* a snarky wrapper, which is explained in this document -* a backend underneath that wrapper, explained in the [kimchi backend section](./kimchi-backend.md) - -```admonish -This separation exists for legacy reasons, and ideally we should merge the two into a single library. -``` - -The snarky wrapper mostly exists in `checked_runner.rs`, and has the following state: - -```rust -where - F: PrimeField, -{ - /// The constraint system used to build the circuit. - /// If not set, the constraint system is not built. - system: Option>, - - /// The public input of the circuit used in witness generation. - // TODO: can we merge public_input and private_input? - public_input: Vec, - - // TODO: we could also just store `usize` here - pub(crate) public_output: Vec>, - - /// The private input of the circuit used in witness generation. Still not sure what that is, or why we care about this. - private_input: Vec, - - /// If set, the witness generation will check if the constraints are satisfied. - /// This is useful to simulate running the circuit and return an error if an assertion fails. - eval_constraints: bool, - - /// The number of public inputs. - num_public_inputs: usize, - - /// A counter used to track variables (this includes public inputs) as they're being created. - next_var: usize, - - /// Indication that we're running the witness generation (as opposed to the circuit creation). - mode: Mode, -} -``` - -The wrapper is designed to be used in different ways, depending on the fields set. - -```admonish -Ideally, we would like to only run this once and obtain a result that's an immutable compiled artifact. -Currently, `public_input`, `private_input`, `eval_constriants`, `next_var`, and `mode` all need to be mutable. -In the future these should be passed as arguments to functions, and should not exist in the state. -``` - -## Public output - -The support for public output is implemented as kind of a hack. - -When the developer writes a circuit, they have to specify the type of the public output. - -This allows the API to save enough room at the end of the public input, and store the variables used in the public output in the state. - -When the API calls the circuit written by the developer, it expects the public output (as a snarky type) to be returned by the function. -The compilation or proving API that ends up calling that function, can thus obtain the variables of the public output. -With that in hand, the API can continue to write the circuit to enforce an equality constraint between these variables being returned and the public output variable that it had previously stored in the state. - -Essentially, the kimchi backend will turn this into as many wiring as there are `CVar` in the public output. - -During witness generation, we need a way to modify the witness once we know the values of the public output. -As the public output `CVar`s were generated from the snarky wrapper (and not from the kimchi backend), the snarky wrapper should know their values after running the given circuit. diff --git a/book/src/snarky/vars.md b/book/src/snarky/vars.md deleted file mode 100644 index 7a1e3a3be7..0000000000 --- a/book/src/snarky/vars.md +++ /dev/null @@ -1,135 +0,0 @@ -# Vars - -In this section we will introduce two types of variables: - -* Circuit vars, or `CVar`s, which are low-level variables representing field elements. -* Snarky vars, which are high-level variables that user can use to create more meaningful programs. - -## Circuit vars - -In snarky, we first define circuit variables (TODO: rename Field variable?) which represent field elements in a circuit. -These circuit variables, or cvars, can be represented differently in the system: - -```rust -pub enum CVar -where - F: PrimeField, -{ - /// A constant. - Constant(F), - - /// A variable that can be refered to via a `usize`. - Var(usize), - - /// The addition of two other [CVar]s. - Add(Box>, Box>), - - /// Scaling of a [CVar]. - Scale(F, Box>), -} -``` - -One can see a CVar as an AST, where two atoms exist: a `Var(usize)` which represents a private input, an a `Constant(F)` which represents a constant. -Anything else represents combinations of these two atoms. - -### Constants - -Note that a circuit variable does not represent a value that has been constrained in the circuit (yet). -This is why we need to know if a cvar is a constant, so that we can avoid constraining it too early. -For example, the following code does not encode 2 or 1 in the circuit, but will encode 3: - -```rust -let x: CVar = state.exists(|_| 2) + state.exists(|_| 3); -state.assert_eq(x, y); // 3 and y will be encoded in the circuit -``` - -whereas the following code will encode all variables: - -```rust -let x = y + y; -let one: CVar = state.exists(|_| 1); -assert_eq(x, one); -``` - -### Non-constants - -Right after being created, a `CVar` is not constrained yet, and needs to be constrained by the application. -That is unless the application wants the `CVar` to be a constant that will not need to be constrained (see previous example) or because the application wants the `CVar` to be a random value (unlikely) (TODO: we should add a "rand" function for that). - -In any case, a circuit variable which is not a constant has a value that is not known yet at circuit-generation time. -In some situations, we might not want to constrain the - - -### When do variables get constrained? - -In general, a circuit variable only gets constrained by an assertion call like `assert` or `assert_equals`. - -When variables are added together, or scaled, they do not directly get constrained. -This is due to optimizations targetting R1CS (which we don't support anymore) that were implemented in the original snarky library, and that we have kept in snarky-rs. - -Imagine the following example: - -```rust -let y = x1 + x2 + x3 +.... ; -let z = y + 3; -assert_eq(y, 6); -assert_eq(z, 7); -``` - -The first two lines will not create constraints, but simply create minimal ASTs that track all of the additions. - -Both assert calls will then reduce the variables to a single circuit variable, creating the same constraints twice. - -For this reason, there's a function `seal()` defined in pickles and snarkyjs. (TODO: more about `seal()`, and why is it not in snarky?) (TODO: remove the R1CS optimization) - -## Snarky vars - -Handling `CVar`s can be cumbersome, as they can only represent a single field element. -We might want to represent values that are either in a smaller range (e.g. [booleans](./booleans.md)) or that are made out of several `CVar`s. - -For this, snarky's API exposes the following trait, which allows users to define their own types: - -```rust -pub trait SnarkyType: Sized -where - F: PrimeField, -{ - /// ? - type Auxiliary; - - /// The equivalent type outside of the circuit. - type OutOfCircuit; - - const SIZE_IN_FIELD_ELEMENTS: usize; - - fn to_cvars(&self) -> (Vec>, Self::Auxiliary); - - fn from_cvars_unsafe(cvars: Vec>, aux: Self::Auxiliary) -> Self; - - fn check(&self, cs: &mut RunState); - - fn deserialize(&self) -> (Self::OutOfCircuit, Self::Auxiliary); - - fn serialize(out_of_circuit: Self::OutOfCircuit, aux: Self::Auxiliary) -> Self; - - fn constraint_system_auxiliary() -> Self::Auxiliary; - - fn value_to_field_elements(x: &Self::OutOfCircuit) -> (Vec, Self::Auxiliary); - - fn value_of_field_elements(x: (Vec, Self::Auxiliary)) -> Self::OutOfCircuit; -} -``` - -Such types are always handled as `OutOfCircuit` types (e.g. `bool`) by the users, and as a type implementing `SnarkyType` by snarky (e.g. [`Boolean`](./booleans.md)). -Thus, the user can pass them to snarky in two ways: - -**As public inputs**. In this case they will be serialized into field elements for snarky before [witness-generation](./witness-generation.md) (via the `value_to_field_elements()` function) - -**As private inputs**. In this case, they must be created using the `compute()` function with a closure returning an `OutOfCircuit` value by the user. -The call to `compute()` will need to have some type hint, for snarky to understand what `SnarkyType` it is creating. -This is because the relationship is currently only one-way: a `SnarkyType` knows what out-of-circuit type it relates to, but not the other way is not true. -(TODO: should we implement that though?) - -A `SnarkyType` always implements a `check()` function, which is called by snarky when `compute()` is called to create such a type. -The `check()` function is responsible for creating the constraints that sanitize the newly-created `SnarkyType` (and its underlying `CVar`s). -For example, creating a boolean would make sure that the underlying `CVar` is either 0 or 1. diff --git a/book/src/snarky/witness-generation.md b/book/src/snarky/witness-generation.md deleted file mode 100644 index 41fbc3b5f1..0000000000 --- a/book/src/snarky/witness-generation.md +++ /dev/null @@ -1,21 +0,0 @@ -# Witness generation - -In snarky, currently, the same code is run through again to generate the witness. - -That is, the `RunState` contains a few changes: - -* **`public_input: Vec`**: now contains concrete values (instead of being empty). -* **`has_witness`**: is set to `WitnessGeneration`. - -Additionaly, if we want to verify that the arguments are actually correct (and that the program implemented does not fail) we can also set `eval_constraints` to `true` (defaults to `false`) to verify that the program has a correct state at all point in time. - -If we do not do this, the user will only detect failure during proof generation (specifically when the [composition polynomial](../specs/kimchi.md#proof-creation) is divided by the [vanishing polynomial](../specs/kimchi.md#proof-creation)). - -```admonish -This is implemented by simply checking that each [generic gate](../specs/kimchi.md#double-generic-gate) encountered is correct, in relation to the witness values observed in that row. -In other words $c_0 l + c_1 r + c_2 o + c_3 l r + c_4 = 0$ (extrapolated to the [double generic gate](../specs/kimchi.md#double-generic-gate)). -Note that other custom gates are not checked, as they are wrapped by [gadgets](../specs/kimchi.md#gates) which fill in witness values instead of the user. -Thus there is no room for user error (i.e. the user entering a wrong private input). -``` - -Due to the `has_witness` variable set to `WitnessGeneration`, functions will behave differently and compute actual values instead of generating constraints. From b16635c5fbf731a24a211554ceec7124155d7160 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 23 Oct 2023 17:27:55 +0100 Subject: [PATCH 162/242] Initial optimism layout --- Cargo.lock | 115 ++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + optimism/Cargo.toml | 29 +++++++++++ optimism/src/lib.rs | 0 optimism/src/main.rs | 6 +++ 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 optimism/Cargo.toml create mode 100644 optimism/src/lib.rs create mode 100644 optimism/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index c8b7f9249a..8028b4f6d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,6 +46,54 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "ark-algebra-test-templates" version = "0.3.0" @@ -417,7 +465,7 @@ dependencies = [ "atty", "bitflags 1.3.2", "clap_derive", - "clap_lex", + "clap_lex 0.2.4", "indexmap", "once_cell", "strsim 0.10.0", @@ -425,6 +473,27 @@ dependencies = [ "textwrap 0.16.0", ] +[[package]] +name = "clap" +version = "4.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +dependencies = [ + "anstream", + "anstyle", + "clap_lex 0.5.1", + "strsim 0.10.0", +] + [[package]] name = "clap_derive" version = "3.2.25" @@ -447,6 +516,18 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "colored" version = "2.0.4" @@ -727,6 +808,12 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "elf" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6e7d85896690fe195447717af8eceae0593ac2196fd42fe88c184e904406ce" + [[package]] name = "entities" version = "1.0.1" @@ -1159,6 +1246,26 @@ dependencies = [ "tinytemplate", ] +[[package]] +name = "kimchi_optimism" +version = "0.1.0" +dependencies = [ + "ark-ff", + "ark-poly", + "clap 4.4.6", + "elf", + "groupmap", + "hex", + "kimchi", + "mina-curves", + "mina-poseidon", + "poly-commitment", + "rmp-serde", + "serde", + "serde_json", + "serde_with", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -2636,6 +2743,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index c50da37068..851713bf6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "groupmap", "hasher", "kimchi", + "optimism", "poseidon", "poseidon/export_test_vectors", "poly-commitment", diff --git a/optimism/Cargo.toml b/optimism/Cargo.toml new file mode 100644 index 0000000000..9b45ab1d29 --- /dev/null +++ b/optimism/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "kimchi_optimism" +version = "0.1.0" +description = "MIPS demo" +repository = "https://github.com/o1-labs/proof-systems" +homepage = "https://o1-labs.github.io/proof-systems/" +documentation = "https://o1-labs.github.io/proof-systems/rustdoc/" +readme = "README.md" +edition = "2021" +license = "Apache-2.0" + +[lib] +path = "src/lib.rs" + +[dependencies] +kimchi = { path = "../kimchi", version = "0.1.0" } +poly-commitment = { path = "../poly-commitment", version = "0.1.0" } +groupmap = { path = "../groupmap", version = "0.1.0" } +mina-curves = { path = "../curves", version = "0.1.0" } +mina-poseidon = { path = "../poseidon", version = "0.1.0" } +elf = "0.7.2" +rmp-serde = "1.1.1" +serde_json = "1.0.91" +serde = "1.0.130" +serde_with = "1.10.0" +ark-poly = { version = "0.3.0", features = [ "parallel" ] } +ark-ff = { version = "0.3.0", features = [ "parallel" ] } +clap = "4.4.6" +hex = "0.4.3" diff --git a/optimism/src/lib.rs b/optimism/src/lib.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/optimism/src/main.rs b/optimism/src/main.rs new file mode 100644 index 0000000000..9301ced20f --- /dev/null +++ b/optimism/src/main.rs @@ -0,0 +1,6 @@ +use std:: process::ExitCode; + +pub fn main() -> ExitCode { + // TODO: Logic + ExitCode::FAILURE +} From eac8542b0bf7da2235bab978618f15df2433fa9a Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 23 Oct 2023 17:35:43 +0100 Subject: [PATCH 163/242] Checkout optimism v1.1.6 --- .gitmodules | 3 +++ optimism/ethereum-optimism | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 optimism/ethereum-optimism diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..5b1dec4f59 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "optimism/ethereum-optimism"] + path = optimism/ethereum-optimism + url = https://github.com/ethereum-optimism/optimism.git diff --git a/optimism/ethereum-optimism b/optimism/ethereum-optimism new file mode 160000 index 0000000000..c83cd947d4 --- /dev/null +++ b/optimism/ethereum-optimism @@ -0,0 +1 @@ +Subproject commit c83cd947d419aa2c213583a32872bc350a69e566 From e55460bbc025a73addd1f199d56e81f85ae9ad7a Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 23 Oct 2023 18:02:56 +0100 Subject: [PATCH 164/242] Check-in runner --- optimism/.gitignore | 1 + optimism/run-code.sh | 63 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 optimism/.gitignore create mode 100755 optimism/run-code.sh diff --git a/optimism/.gitignore b/optimism/.gitignore new file mode 100644 index 0000000000..53df36bb78 --- /dev/null +++ b/optimism/.gitignore @@ -0,0 +1 @@ +rpcs.sh diff --git a/optimism/run-code.sh b/optimism/run-code.sh new file mode 100755 index 0000000000..1452f2933f --- /dev/null +++ b/optimism/run-code.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -euo pipefail + +make -C ./ethereum-optimism/op-program op-program + +source rpcs.sh + +# L2 output oracle on Goerli +# L2_OUTPUT_ORACLE=0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0 +# L2 output oracle on Sepolia +L2_OUTPUT_ORACLE=0x90E9c4f8a994a250F6aEfd61CAFb4F2e895D458F + +L2_FINALIZED_NUMBER=$(cast block finalized --rpc-url "${L2RPC}" -f number) +echo "Finalize number: ${L2_FINALIZED_NUMBER}" +L2_FINALIZED_HASH=$(cast block "${L2_FINALIZED_NUMBER}" --rpc-url "${L2RPC}" -f hash) + +L1_FINALIZED_NUMBER=$(cast block finalized --rpc-url "${L1RPC}" -f number) +L1_FINALIZED_HASH=$(cast block "${L1_FINALIZED_NUMBER}" --rpc-url "${L1RPC}" -f hash) + +OUTPUT_INDEX=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2OutputIndexAfter(uint256) returns(uint256)' "${L2_FINALIZED_NUMBER}") +OUTPUT_INDEX=$((OUTPUT_INDEX-1)) + +OUTPUT=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2Output(uint256) returns(bytes32,uint128,uint128)' "${OUTPUT_INDEX}") +OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) +OUTPUT_TIMESTAMP=$(echo ${OUTPUT} | cut -d' ' -f 2) +OUTPUT_L2BLOCK_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) + +L1_HEAD=$L1_FINALIZED_HASH +L2_CLAIM=$OUTPUT_ROOT +L2_BLOCK_NUMBER=$OUTPUT_L2BLOCK_NUMBER + +STARTING_L2BLOCK_NUMBER=$((L2_BLOCK_NUMBER-100)) +STARTING_OUTPUT_INDEX=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2OutputIndexAfter(uint256) returns(uint256)' "${STARTING_L2BLOCK_NUMBER}") +STARTING_OUTPUT=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2Output(uint256) returns(bytes32,uint128,uint128)' "${STARTING_OUTPUT_INDEX}") +STARTING_OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) +L2_HEAD_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) +L2_HEAD=$(cast block "${L2_HEAD_NUMBER}" --rpc-url "${L2RPC}" -f hash) + +TODAY=$(date +"%Y-%m-%d-%H-%M-%S") +FILENAME=${TODAY}-op-program-data-log.sh +OP_PROGRAM_DATA_DIR=$(pwd)/op-program-db-sepolia-${TODAY} + +echo "L1_HEAD=${L1_HEAD}" >> ${FILENAME} +echo "L2_HEAD=${L2_HEAD}" >> ${FILENAME} +echo "L2_BLOCK_NUMBER=${L2_BLOCK_NUMBER}" >> ${FILENAME} +echo "STARTING_OUTPUT_ROOT=${STARTING_OUTPUT_ROOT}" >> ${FILENAME} +echo "L2_CLAIM=${L2_CLAIM}" >> ${FILENAME} +echo "OP_PROGRAM_DATA_DIR=${OP_PROGRAM_DATA_DIR}" >> ${FILENAME} +echo "L1RPC=${L1RPC}" >> ${FILENAME} +echo "L2RPC=${L2RPC}" >> ${FILENAME} + +set -x +./ethereum-optimism/op-program/bin/op-program \ + --log.level DEBUG \ + --l1 $L1RPC \ + --l2 $L2RPC \ + --network sepolia \ + --datadir ${OP_PROGRAM_DATA_DIR} \ + --l1.head $L1_HEAD \ + --l2.head $L2_HEAD \ + --l2.outputroot $STARTING_OUTPUT_ROOT \ + --l2.claim $L2_CLAIM \ + --l2.blocknumber $L2_BLOCK_NUMBER From 4fc60e939ed2ca457ff37fbc64c9b0b0c048d085 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 23 Oct 2023 18:07:27 +0100 Subject: [PATCH 165/242] Split out op-program runner --- optimism/run-code.sh | 47 ++++++++++++++------------------------ optimism/run-op-program.sh | 17 ++++++++++++++ 2 files changed, 34 insertions(+), 30 deletions(-) create mode 100755 optimism/run-op-program.sh diff --git a/optimism/run-code.sh b/optimism/run-code.sh index 1452f2933f..43cd300fe2 100755 --- a/optimism/run-code.sh +++ b/optimism/run-code.sh @@ -1,8 +1,6 @@ #!/usr/bin/env bash set -euo pipefail -make -C ./ethereum-optimism/op-program op-program - source rpcs.sh # L2 output oracle on Goerli @@ -25,39 +23,28 @@ OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) OUTPUT_TIMESTAMP=$(echo ${OUTPUT} | cut -d' ' -f 2) OUTPUT_L2BLOCK_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) -L1_HEAD=$L1_FINALIZED_HASH -L2_CLAIM=$OUTPUT_ROOT -L2_BLOCK_NUMBER=$OUTPUT_L2BLOCK_NUMBER +export L1_HEAD=$L1_FINALIZED_HASH +export L2_CLAIM=$OUTPUT_ROOT +export L2_BLOCK_NUMBER=$OUTPUT_L2BLOCK_NUMBER STARTING_L2BLOCK_NUMBER=$((L2_BLOCK_NUMBER-100)) STARTING_OUTPUT_INDEX=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2OutputIndexAfter(uint256) returns(uint256)' "${STARTING_L2BLOCK_NUMBER}") STARTING_OUTPUT=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2Output(uint256) returns(bytes32,uint128,uint128)' "${STARTING_OUTPUT_INDEX}") -STARTING_OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) +export STARTING_OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) L2_HEAD_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) -L2_HEAD=$(cast block "${L2_HEAD_NUMBER}" --rpc-url "${L2RPC}" -f hash) +export L2_HEAD=$(cast block "${L2_HEAD_NUMBER}" --rpc-url "${L2RPC}" -f hash) TODAY=$(date +"%Y-%m-%d-%H-%M-%S") FILENAME=${TODAY}-op-program-data-log.sh -OP_PROGRAM_DATA_DIR=$(pwd)/op-program-db-sepolia-${TODAY} - -echo "L1_HEAD=${L1_HEAD}" >> ${FILENAME} -echo "L2_HEAD=${L2_HEAD}" >> ${FILENAME} -echo "L2_BLOCK_NUMBER=${L2_BLOCK_NUMBER}" >> ${FILENAME} -echo "STARTING_OUTPUT_ROOT=${STARTING_OUTPUT_ROOT}" >> ${FILENAME} -echo "L2_CLAIM=${L2_CLAIM}" >> ${FILENAME} -echo "OP_PROGRAM_DATA_DIR=${OP_PROGRAM_DATA_DIR}" >> ${FILENAME} -echo "L1RPC=${L1RPC}" >> ${FILENAME} -echo "L2RPC=${L2RPC}" >> ${FILENAME} - -set -x -./ethereum-optimism/op-program/bin/op-program \ - --log.level DEBUG \ - --l1 $L1RPC \ - --l2 $L2RPC \ - --network sepolia \ - --datadir ${OP_PROGRAM_DATA_DIR} \ - --l1.head $L1_HEAD \ - --l2.head $L2_HEAD \ - --l2.outputroot $STARTING_OUTPUT_ROOT \ - --l2.claim $L2_CLAIM \ - --l2.blocknumber $L2_BLOCK_NUMBER +export OP_PROGRAM_DATA_DIR=$(pwd)/op-program-db-sepolia-${TODAY} + +echo "export L1_HEAD=${L1_HEAD}" >> ${FILENAME} +echo "export L2_HEAD=${L2_HEAD}" >> ${FILENAME} +echo "export L2_BLOCK_NUMBER=${L2_BLOCK_NUMBER}" >> ${FILENAME} +echo "export STARTING_OUTPUT_ROOT=${STARTING_OUTPUT_ROOT}" >> ${FILENAME} +echo "export L2_CLAIM=${L2_CLAIM}" >> ${FILENAME} +echo "export OP_PROGRAM_DATA_DIR=${OP_PROGRAM_DATA_DIR}" >> ${FILENAME} +echo "export L1RPC=${L1RPC}" >> ${FILENAME} +echo "export L2RPC=${L2RPC}" >> ${FILENAME} + +./run-op-program.sh diff --git a/optimism/run-op-program.sh b/optimism/run-op-program.sh new file mode 100755 index 0000000000..f7936fee6e --- /dev/null +++ b/optimism/run-op-program.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +make -C ./ethereum-optimism/op-program op-program + +set -x +./ethereum-optimism/op-program/bin/op-program \ + --log.level DEBUG \ + --l1 $L1RPC \ + --l2 $L2RPC \ + --network sepolia \ + --datadir ${OP_PROGRAM_DATA_DIR} \ + --l1.head $L1_HEAD \ + --l2.head $L2_HEAD \ + --l2.outputroot $STARTING_OUTPUT_ROOT \ + --l2.claim $L2_CLAIM \ + --l2.blocknumber $L2_BLOCK_NUMBER From 0a715b74ff609e14a980aca2bf4e2bb5f9865dfd Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 23 Oct 2023 18:16:23 +0100 Subject: [PATCH 166/242] Separate out runner --- optimism/generate-config.sh | 50 +++++++++++++++++++++++++++++++++++++ optimism/run-code.sh | 44 ++------------------------------ 2 files changed, 52 insertions(+), 42 deletions(-) create mode 100755 optimism/generate-config.sh diff --git a/optimism/generate-config.sh b/optimism/generate-config.sh new file mode 100755 index 0000000000..e71f8a90ed --- /dev/null +++ b/optimism/generate-config.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -euo pipefail + +source rpcs.sh + +# L2 output oracle on Goerli +# L2_OUTPUT_ORACLE=0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0 +# L2 output oracle on Sepolia +L2_OUTPUT_ORACLE=0x90E9c4f8a994a250F6aEfd61CAFb4F2e895D458F + +L2_FINALIZED_NUMBER=$(cast block finalized --rpc-url "${L2RPC}" -f number) +echo "Finalize number: ${L2_FINALIZED_NUMBER}" 1>&2 +L2_FINALIZED_HASH=$(cast block "${L2_FINALIZED_NUMBER}" --rpc-url "${L2RPC}" -f hash) + +L1_FINALIZED_NUMBER=$(cast block finalized --rpc-url "${L1RPC}" -f number) +L1_FINALIZED_HASH=$(cast block "${L1_FINALIZED_NUMBER}" --rpc-url "${L1RPC}" -f hash) + +OUTPUT_INDEX=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2OutputIndexAfter(uint256) returns(uint256)' "${L2_FINALIZED_NUMBER}") +OUTPUT_INDEX=$((OUTPUT_INDEX-1)) + +OUTPUT=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2Output(uint256) returns(bytes32,uint128,uint128)' "${OUTPUT_INDEX}") +OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) +OUTPUT_TIMESTAMP=$(echo ${OUTPUT} | cut -d' ' -f 2) +OUTPUT_L2BLOCK_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) + +L1_HEAD=$L1_FINALIZED_HASH +L2_CLAIM=$OUTPUT_ROOT +L2_BLOCK_NUMBER=$OUTPUT_L2BLOCK_NUMBER + +STARTING_L2BLOCK_NUMBER=$((L2_BLOCK_NUMBER-100)) +STARTING_OUTPUT_INDEX=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2OutputIndexAfter(uint256) returns(uint256)' "${STARTING_L2BLOCK_NUMBER}") +STARTING_OUTPUT=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2Output(uint256) returns(bytes32,uint128,uint128)' "${STARTING_OUTPUT_INDEX}") +STARTING_OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) +L2_HEAD_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) +L2_HEAD=$(cast block "${L2_HEAD_NUMBER}" --rpc-url "${L2RPC}" -f hash) + +TODAY=$(date +"%Y-%m-%d-%H-%M-%S") +FILENAME=${TODAY}-op-program-data-log.sh +OP_PROGRAM_DATA_DIR=$(pwd)/op-program-db-sepolia-${TODAY} + +echo "export L1_HEAD=${L1_HEAD}" >> ${FILENAME} +echo "export L2_HEAD=${L2_HEAD}" >> ${FILENAME} +echo "export L2_BLOCK_NUMBER=${L2_BLOCK_NUMBER}" >> ${FILENAME} +echo "export STARTING_OUTPUT_ROOT=${STARTING_OUTPUT_ROOT}" >> ${FILENAME} +echo "export L2_CLAIM=${L2_CLAIM}" >> ${FILENAME} +echo "export OP_PROGRAM_DATA_DIR=${OP_PROGRAM_DATA_DIR}" >> ${FILENAME} +echo "export L1RPC=${L1RPC}" >> ${FILENAME} +echo "export L2RPC=${L2RPC}" >> ${FILENAME} + +echo "${FILENAME}" diff --git a/optimism/run-code.sh b/optimism/run-code.sh index 43cd300fe2..1af79e85d9 100755 --- a/optimism/run-code.sh +++ b/optimism/run-code.sh @@ -3,48 +3,8 @@ set -euo pipefail source rpcs.sh -# L2 output oracle on Goerli -# L2_OUTPUT_ORACLE=0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0 -# L2 output oracle on Sepolia -L2_OUTPUT_ORACLE=0x90E9c4f8a994a250F6aEfd61CAFb4F2e895D458F +FILENAME="$(./generate-config.sh)" -L2_FINALIZED_NUMBER=$(cast block finalized --rpc-url "${L2RPC}" -f number) -echo "Finalize number: ${L2_FINALIZED_NUMBER}" -L2_FINALIZED_HASH=$(cast block "${L2_FINALIZED_NUMBER}" --rpc-url "${L2RPC}" -f hash) - -L1_FINALIZED_NUMBER=$(cast block finalized --rpc-url "${L1RPC}" -f number) -L1_FINALIZED_HASH=$(cast block "${L1_FINALIZED_NUMBER}" --rpc-url "${L1RPC}" -f hash) - -OUTPUT_INDEX=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2OutputIndexAfter(uint256) returns(uint256)' "${L2_FINALIZED_NUMBER}") -OUTPUT_INDEX=$((OUTPUT_INDEX-1)) - -OUTPUT=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2Output(uint256) returns(bytes32,uint128,uint128)' "${OUTPUT_INDEX}") -OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) -OUTPUT_TIMESTAMP=$(echo ${OUTPUT} | cut -d' ' -f 2) -OUTPUT_L2BLOCK_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) - -export L1_HEAD=$L1_FINALIZED_HASH -export L2_CLAIM=$OUTPUT_ROOT -export L2_BLOCK_NUMBER=$OUTPUT_L2BLOCK_NUMBER - -STARTING_L2BLOCK_NUMBER=$((L2_BLOCK_NUMBER-100)) -STARTING_OUTPUT_INDEX=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2OutputIndexAfter(uint256) returns(uint256)' "${STARTING_L2BLOCK_NUMBER}") -STARTING_OUTPUT=$(cast call --rpc-url "${L1RPC}" "${L2_OUTPUT_ORACLE}" 'getL2Output(uint256) returns(bytes32,uint128,uint128)' "${STARTING_OUTPUT_INDEX}") -export STARTING_OUTPUT_ROOT=$(echo ${OUTPUT} | cut -d' ' -f 1) -L2_HEAD_NUMBER=$(echo ${OUTPUT} | cut -d' ' -f 3) -export L2_HEAD=$(cast block "${L2_HEAD_NUMBER}" --rpc-url "${L2RPC}" -f hash) - -TODAY=$(date +"%Y-%m-%d-%H-%M-%S") -FILENAME=${TODAY}-op-program-data-log.sh -export OP_PROGRAM_DATA_DIR=$(pwd)/op-program-db-sepolia-${TODAY} - -echo "export L1_HEAD=${L1_HEAD}" >> ${FILENAME} -echo "export L2_HEAD=${L2_HEAD}" >> ${FILENAME} -echo "export L2_BLOCK_NUMBER=${L2_BLOCK_NUMBER}" >> ${FILENAME} -echo "export STARTING_OUTPUT_ROOT=${STARTING_OUTPUT_ROOT}" >> ${FILENAME} -echo "export L2_CLAIM=${L2_CLAIM}" >> ${FILENAME} -echo "export OP_PROGRAM_DATA_DIR=${OP_PROGRAM_DATA_DIR}" >> ${FILENAME} -echo "export L1RPC=${L1RPC}" >> ${FILENAME} -echo "export L2RPC=${L2RPC}" >> ${FILENAME} +source $FILENAME ./run-op-program.sh From 7af8026becbf24924e4a27a79004ec68fe55731f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 23 Oct 2023 18:24:29 +0100 Subject: [PATCH 167/242] Add cannon to runner --- optimism/run-op-program.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/optimism/run-op-program.sh b/optimism/run-op-program.sh index f7936fee6e..c16072e8c9 100755 --- a/optimism/run-op-program.sh +++ b/optimism/run-op-program.sh @@ -2,6 +2,7 @@ set -euo pipefail make -C ./ethereum-optimism/op-program op-program +make -C ./ethereum-optimism/cannon cannon set -x ./ethereum-optimism/op-program/bin/op-program \ @@ -15,3 +16,24 @@ set -x --l2.outputroot $STARTING_OUTPUT_ROOT \ --l2.claim $L2_CLAIM \ --l2.blocknumber $L2_BLOCK_NUMBER + +./ethereum-optimism/cannon/bin/cannon load-elf --path=./ethereum-optimism/op-program/bin/op-program-client.elf + +./ethereum-optimism/cannon/bin/cannon run \ + --pprof.cpu \ + --info-at '%10000000' \ + --proof-at never \ + --input ./state.json \ + -- \ + ./ethereum-optimism/op-program/bin/op-program \ + --log.level DEBUG \ + --l1 ${L1RPC} \ + --l2 ${L2RPC} \ + --network sepolia \ + --datadir ${OP_PROGRAM_DATA_DIR} \ + --l1.head ${L1_HEAD} \ + --l2.head ${L2_HEAD} \ + --l2.outputroot ${STARTING_OUTPUT_ROOT} \ + --l2.claim ${L2_CLAIM} \ + --l2.blocknumber ${L2_BLOCK_NUMBER} \ + --server From 85841b02ac2b08b17bb66a86ef5293148ea3fadf Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Mon, 23 Oct 2023 18:27:30 +0100 Subject: [PATCH 168/242] Allow an explicit filename to override --- optimism/run-code.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/optimism/run-code.sh b/optimism/run-code.sh index 1af79e85d9..a07555070f 100755 --- a/optimism/run-code.sh +++ b/optimism/run-code.sh @@ -3,7 +3,11 @@ set -euo pipefail source rpcs.sh -FILENAME="$(./generate-config.sh)" +set +u +if [ -z "${FILENAME}" ]; then + FILENAME="$(./generate-config.sh)" +fi +set -u source $FILENAME From d2aac11e5582a26bb7b26c68f721ddef0ccad09b Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 15:22:51 +0100 Subject: [PATCH 169/242] Import parsing for CLI --- Cargo.lock | 21 ++++---- optimism/Cargo.toml | 1 + optimism/src/cannon.rs | 118 ++++++++++++++++++++++++++++++++++++++++ optimism/src/lib.rs | 1 + optimism/src/main.rs | 119 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 249 insertions(+), 11 deletions(-) create mode 100644 optimism/src/cannon.rs diff --git a/Cargo.lock b/Cargo.lock index 8028b4f6d9..03396e2f2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1260,6 +1260,7 @@ dependencies = [ "mina-curves", "mina-poseidon", "poly-commitment", + "regex", "rmp-serde", "serde", "serde_json", @@ -1325,9 +1326,9 @@ checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -2100,25 +2101,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.7.3", + "regex-syntax 0.8.2", ] [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.3", + "regex-syntax 0.8.2", ] [[package]] @@ -2129,9 +2130,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rmp" diff --git a/optimism/Cargo.toml b/optimism/Cargo.toml index 9b45ab1d29..f1edb563cd 100644 --- a/optimism/Cargo.toml +++ b/optimism/Cargo.toml @@ -27,3 +27,4 @@ ark-poly = { version = "0.3.0", features = [ "parallel" ] } ark-ff = { version = "0.3.0", features = [ "parallel" ] } clap = "4.4.6" hex = "0.4.3" +regex = "1.10.2" diff --git a/optimism/src/cannon.rs b/optimism/src/cannon.rs new file mode 100644 index 0000000000..c7693f3cab --- /dev/null +++ b/optimism/src/cannon.rs @@ -0,0 +1,118 @@ +// Data structure and stuff for compatibility with Cannon + +use regex::Regex; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +pub struct Page { + pub index: u32, + pub data: String, +} + +// The renaming below keeps compatibility with OP Cannon's state format +#[derive(Serialize, Deserialize, Debug)] +pub struct State { + pub memory: Vec, + #[serde(rename = "preimageKey")] + pub preimage_key: String, + #[serde(rename = "preimageOffset")] + pub preimage_offset: u32, + pub pc: u32, + #[serde(rename = "nextPC")] + next_pc: u32, // + pub lo: u32, + pub hi: u32, + pub heap: u32, + exit: u8, + pub exited: bool, + pub step: u64, + pub registers: [u32; 32], + pub last_hint: Option>, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum StepFrequency { + Never, + Always, + Exactly(u64), + Every(u64), +} + +// Simple parser for Cannon's "frequency format" +// A frequency input is either +// - never/always +// - = (only at step n) +// - % (every steps multiple of n) +pub fn step_frequency_parser(s: &str) -> std::result::Result { + use StepFrequency::*; + + let mod_re = Regex::new(r"%([0-9]+)").unwrap(); + let eq_re = Regex::new(r"=([0-9]+)").unwrap(); + + match s { + "never" => Ok(Never), + "always" => Ok(Always), + s => { + if let Some(m) = mod_re.captures(s) { + Ok(Every(m[1].parse::().unwrap())) + } else if let Some(m) = eq_re.captures(s) { + Ok(Exactly(m[1].parse::().unwrap())) + } else { + Err(format!("Unknown frequency format {}", s)) + } + } + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn sp_parser() { + use StepFrequency::*; + assert_eq!(step_frequency_parser("never"), Ok(Never)); + assert_eq!(step_frequency_parser("always"), Ok(Always)); + assert_eq!(step_frequency_parser("=123"), Ok(Exactly(123))); + assert_eq!(step_frequency_parser("%123"), Ok(Every(123))); + assert!(step_frequency_parser("@123").is_err()); + } +} + +impl ToString for State { + // A very debatable and incomplete, but serviceable, `to_string` implementation. + fn to_string(&self) -> String { + format!( + "memory_size (length): {}\nfirst page size: {}\npreimage key: {}\npreimage offset:{}\npc: {}\nlo: {}\nhi: {}\nregisters:{:#?} ", + self.memory.len(), + self.memory[0].data.len(), + self.preimage_key, + self.preimage_offset, + self.pc, + self.lo, + self.hi, + self.registers + ) + } +} + +#[derive(Debug)] +pub struct HostProgram { + pub name: String, + pub arguments: Vec, +} + +#[derive(Debug)] +pub struct VmConfiguration { + pub input_state_file: String, + pub output_state_file: String, + pub metadata_file: String, + pub proof_at: StepFrequency, + pub stop_at: StepFrequency, + pub info_at: StepFrequency, + pub proof_fmt: String, + pub snapshot_fmt: String, + pub pprof_cpu: bool, + pub host: Option, +} diff --git a/optimism/src/lib.rs b/optimism/src/lib.rs index e69de29bb2..3bec498068 100644 --- a/optimism/src/lib.rs +++ b/optimism/src/lib.rs @@ -0,0 +1 @@ +pub mod cannon; diff --git a/optimism/src/main.rs b/optimism/src/main.rs index 9301ced20f..f7692547cf 100644 --- a/optimism/src/main.rs +++ b/optimism/src/main.rs @@ -1,6 +1,123 @@ -use std:: process::ExitCode; +use clap::{arg, value_parser, Arg, ArgAction, Command}; +use kimchi_optimism::cannon::VmConfiguration; +use std::process::ExitCode; + +fn cli() -> VmConfiguration { + use kimchi_optimism::cannon::*; + + let app_name = "zkvm"; + let cli = Command::new(app_name) + .version("0.1") + .about("MIPS-based zkvm") + .arg(arg!(--input "initial state file").default_value("state.json")) + .arg(arg!(--output "output state file").default_value("out.json")) + .arg(arg!(--meta "metadata file").default_value("meta.json")) + // The CLI arguments below this line are ignored at this point + .arg( + Arg::new("proof-at") + .short('p') + .long("proof-at") + .value_name("FREQ") + .default_value("never") + .value_parser(step_frequency_parser), + ) + .arg( + Arg::new("proof-fmt") + .long("proof-fmt") + .value_name("FORMAT") + .default_value("proof-%d.json"), + ) + .arg( + Arg::new("snapshot-fmt") + .long("snapshot-fmt") + .value_name("FORMAT") + .default_value("state-%d.json"), + ) + .arg( + Arg::new("stop-at") + .long("stop-at") + .value_name("FREQ") + .default_value("never") + .value_parser(step_frequency_parser), + ) + .arg( + Arg::new("info-at") + .long("info-at") + .value_name("FREQ") + .default_value("never") + .value_parser(step_frequency_parser), + ) + .arg( + Arg::new("pprof-cpu") + .long("pprof-cpu") + .action(ArgAction::SetTrue), + ) + .arg( + arg!(host: [HOST] "host program specification [host program arguments]") + .num_args(1..) + .last(true) + .value_parser(value_parser!(String)), + ); + + let cli = cli.get_matches(); + + let input_state_file = cli + .get_one::("input") + .expect("Default ensures there is always a value"); + + let output_state_file = cli + .get_one::("output") + .expect("Default ensures there is always a value"); + + let metadata_file = cli + .get_one::("meta") + .expect("Default ensures there is always a value"); + + let proof_at = cli.get_one::("proof-at").expect(""); + let info_at = cli.get_one::("info-at").expect(""); + let stop_at = cli.get_one::("stop-at").expect(""); + + let proof_fmt = cli.get_one::("proof-fmt").expect(""); + let snapshot_fmt = cli.get_one::("snapshot-fmt").expect(""); + let pprof_cpu = cli.get_one::("pprof-cpu").expect(""); + + let host_spec = cli + .get_many::("host") + .map(|vals| vals.collect::>()) + .unwrap_or_default(); + + let host = if host_spec.is_empty() { + None + } else { + Some(HostProgram { + name: host_spec[0].to_string(), + arguments: host_spec[1..] + .to_vec() + .iter() + .map(|x| x.to_string()) + .collect(), + }) + }; + + VmConfiguration { + input_state_file: input_state_file.to_string(), + output_state_file: output_state_file.to_string(), + metadata_file: metadata_file.to_string(), + proof_at: proof_at.clone(), + stop_at: stop_at.clone(), + info_at: info_at.clone(), + proof_fmt: proof_fmt.to_string(), + snapshot_fmt: snapshot_fmt.to_string(), + pprof_cpu: *pprof_cpu, + host, + } +} pub fn main() -> ExitCode { + let configuration = cli(); + + println!("configuration\n{:#?}", configuration); + // TODO: Logic ExitCode::FAILURE } From 1cd783279528a05bb1fea7d2756fc72bf745ca40 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 15:31:10 +0100 Subject: [PATCH 170/242] Load the state declared in the flags --- optimism/src/main.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/optimism/src/main.rs b/optimism/src/main.rs index f7692547cf..6989806a70 100644 --- a/optimism/src/main.rs +++ b/optimism/src/main.rs @@ -1,6 +1,6 @@ use clap::{arg, value_parser, Arg, ArgAction, Command}; -use kimchi_optimism::cannon::VmConfiguration; -use std::process::ExitCode; +use kimchi_optimism::cannon::{State, VmConfiguration}; +use std::{fs::File, io::BufReader, process::ExitCode}; fn cli() -> VmConfiguration { use kimchi_optimism::cannon::*; @@ -118,6 +118,23 @@ pub fn main() -> ExitCode { println!("configuration\n{:#?}", configuration); + let file = File::open(configuration.input_state_file).expect("file"); + + let reader = BufReader::new(file); + // Read the JSON contents of the file as an instance of `State`. + let state: State = serde_json::from_reader(reader).expect("Error reading input state file"); + + if let Some(host_program) = configuration.host { + println!("Launching host program {}", host_program.name); + + let _child = std::process::Command::new(host_program.name) + .args(host_program.arguments) + .spawn() + .expect("Could not spawn host process"); + }; + + println!("{}", state.to_string()); + // TODO: Logic ExitCode::FAILURE } From 391ea4e2b14d63da72a9fc2eddf812dfc47878a3 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 15:34:13 +0100 Subject: [PATCH 171/242] Run the VM CLI from the main script --- optimism/run-code.sh | 2 ++ optimism/run-vm.sh | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100755 optimism/run-vm.sh diff --git a/optimism/run-code.sh b/optimism/run-code.sh index a07555070f..c664e58025 100755 --- a/optimism/run-code.sh +++ b/optimism/run-code.sh @@ -12,3 +12,5 @@ set -u source $FILENAME ./run-op-program.sh + +./run-vm.sh diff --git a/optimism/run-vm.sh b/optimism/run-vm.sh new file mode 100755 index 0000000000..4f24506b4e --- /dev/null +++ b/optimism/run-vm.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +cargo run -p kimchi_optimism -- \ + --pprof-cpu \ + --info-at '%10000000' \ + --proof-at never \ + --input ./state.json \ + -- \ + ./ethereum-optimism/op-program/bin/op-program \ + --log.level DEBUG \ + --l1 ${L1RPC} \ + --l2 ${L2RPC} \ + --network sepolia \ + --datadir ${OP_PROGRAM_DATA_DIR} \ + --l1.head ${L1_HEAD} \ + --l2.head ${L2_HEAD} \ + --l2.outputroot ${STARTING_OUTPUT_ROOT} \ + --l2.claim ${L2_CLAIM} \ + --l2.blocknumber ${L2_BLOCK_NUMBER} \ + --server From 4a54b24d685a9f24cc20180a7b9077e51d11df17 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 00:20:48 +0100 Subject: [PATCH 172/242] Abstract ExprError over Column --- kimchi/src/circuits/expr.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index f331d96b1b..81ff2da386 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -21,7 +21,11 @@ use o1_utils::{foreign_field::ForeignFieldHelpers, FieldHelpers}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign, Mul, Neg, Sub}; -use std::{cmp::Ordering, fmt, iter::FromIterator}; +use std::{ + cmp::Ordering, + fmt::{self, Debug}, + iter::FromIterator, +}; use std::{ collections::{HashMap, HashSet}, ops::MulAssign, @@ -32,7 +36,7 @@ use CurrOrNext::{Curr, Next}; use self::constraints::ExprOps; #[derive(Debug, Error)] -pub enum ExprError { +pub enum ExprError { #[error("Empty stack")] EmptyStack, @@ -668,7 +672,7 @@ impl Variable { fn evaluate( &self, evals: &ProofEvaluations>, - ) -> Result { + ) -> Result> { let point_evaluations = { use Column::*; match self.col { @@ -745,7 +749,7 @@ impl PolishToken { pt: F, evals: &ProofEvaluations>, c: &Constants, - ) -> Result { + ) -> Result> { let mut stack = vec![]; let mut cache: Vec = vec![]; @@ -1562,7 +1566,7 @@ impl Expr> { pt: F, evals: &ProofEvaluations>, env: &Environment, - ) -> Result { + ) -> Result> { self.evaluate_(d, pt, evals, &env.constants) } @@ -1573,7 +1577,7 @@ impl Expr> { pt: F, evals: &ProofEvaluations>, c: &Constants, - ) -> Result { + ) -> Result> { use Expr::*; match self { Double(x) => x.evaluate_(d, pt, evals, c).map(|x| x.double()), @@ -1642,7 +1646,7 @@ impl Expr { pt: F, zk_rows: u64, evals: &ProofEvaluations>, - ) -> Result { + ) -> Result> { use Expr::*; match self { Constant(x) => Ok(*x), @@ -2145,7 +2149,7 @@ impl + Clone + One + Zero + PartialEq> Expr { pub fn linearize( &self, evaluated: HashSet, - ) -> Result>, ExprError> { + ) -> Result>, ExprError> { let mut res: HashMap> = HashMap::new(); let mut constant_term: Expr = Self::zero(); let monomials = self.monomials(&evaluated); From 163457bcf4440b38cd38db7684c0e76692a7d551 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 00:26:21 +0100 Subject: [PATCH 173/242] Abstract Variable over Column --- kimchi/src/circuits/expr.rs | 18 +++++++++--------- kimchi/src/circuits/polynomials/varbasemul.rs | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 81ff2da386..ee20be142b 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -50,7 +50,7 @@ pub enum ExprError { MissingIndexEvaluation(Column), #[error("Linearization failed (too many unevaluated columns: {0:?}")] - FailedLinearization(Vec), + FailedLinearization(Vec>), #[error("runtime table not available")] MissingRuntime, @@ -235,14 +235,14 @@ impl Column { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] /// A type representing a variable which can appear in a constraint. It specifies a column /// and a relative position (Curr or Next) -pub struct Variable { +pub struct Variable { /// The column of this variable pub col: Column, /// The row (Curr of Next) of this variable pub row: CurrOrNext, } -impl Variable { +impl Variable { fn ocaml(&self) -> String { format!("var({:?}, {:?})", self.col, self.row) } @@ -482,7 +482,7 @@ pub struct RowOffset { #[derive(Clone, Debug, PartialEq)] pub enum Expr { Constant(C), - Cell(Variable), + Cell(Variable), Double(Box>), Square(Box>), BinOp(Op2, Box>, Box>), @@ -652,7 +652,7 @@ pub enum PolishToken { col: usize, }, Literal(F), - Cell(Variable), + Cell(Variable), Dup, Pow(u64), Add, @@ -668,7 +668,7 @@ pub enum PolishToken { SkipIfNot(FeatureFlag, usize), } -impl Variable { +impl Variable { fn evaluate( &self, evals: &ProofEvaluations>, @@ -1983,7 +1983,7 @@ impl Expr { } } -type Monomials = HashMap, Expr>; +type Monomials = HashMap>, Expr>; fn mul_monomials + Clone + One + Zero + PartialEq>( e1: &Monomials, @@ -2024,8 +2024,8 @@ impl + Clone + One + Zero + PartialEq> Expr { } } - fn monomials(&self, ev: &HashSet) -> HashMap, Expr> { - let sing = |v: Vec, c: Expr| { + fn monomials(&self, ev: &HashSet) -> HashMap>, Expr> { + let sing = |v: Vec>, c: Expr| { let mut h = HashMap::new(); h.insert(v, c); h diff --git a/kimchi/src/circuits/polynomials/varbasemul.rs b/kimchi/src/circuits/polynomials/varbasemul.rs index 22b9522195..0ed90e711c 100644 --- a/kimchi/src/circuits/polynomials/varbasemul.rs +++ b/kimchi/src/circuits/polynomials/varbasemul.rs @@ -12,7 +12,7 @@ use crate::circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::{constraints::ExprOps, Cache, Column, Variable}, + expr::{constraints::ExprOps, Cache, Column, Variable as VariableGen}, gate::{CircuitGate, CurrOrNext, GateType}, wires::{GateWires, COLUMNS}, }; @@ -20,6 +20,8 @@ use ark_ff::{FftField, PrimeField}; use std::marker::PhantomData; use CurrOrNext::{Curr, Next}; +type Variable = VariableGen; + //~ We implement custom Plonk constraints for short Weierstrass curve variable base scalar multiplication. //~ //~ Given a finite field $\mathbb{F}_q$ of order $q$, if the order is not a multiple of 2 nor 3, then an From 7b5cc8fb3c174daa2bf5e4de50524f323193a3f6 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 00:51:42 +0100 Subject: [PATCH 174/242] Abstract Expr over Column --- kimchi/src/circuits/expr.rs | 130 +++++++++++++++++++----------------- kimchi/src/linearization.rs | 2 +- 2 files changed, 69 insertions(+), 63 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index ee20be142b..9c5d62aadc 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -480,24 +480,26 @@ pub struct RowOffset { /// the corresponding combination of the polynomials corresponding to /// the above variables should vanish on the PLONK domain. #[derive(Clone, Debug, PartialEq)] -pub enum Expr { +pub enum Expr { Constant(C), Cell(Variable), - Double(Box>), - Square(Box>), - BinOp(Op2, Box>, Box>), + Double(Box>), + Square(Box>), + BinOp(Op2, Box>, Box>), VanishesOnZeroKnowledgeAndPreviousRows, /// UnnormalizedLagrangeBasis(i) is /// (x^n - 1) / (x - omega^i) UnnormalizedLagrangeBasis(RowOffset), - Pow(Box>, u64), - Cache(CacheId, Box>), + Pow(Box>, u64), + Cache(CacheId, Box>), /// If the feature flag is enabled, return the first expression; otherwise, return the second. - IfFeature(FeatureFlag, Box>, Box>), + IfFeature(FeatureFlag, Box>, Box>), } -impl + PartialEq + Clone> Expr { - fn apply_feature_flags_inner(&self, features: &FeatureFlags) -> (Expr, bool) { +impl + PartialEq + Clone, Column: Clone + PartialEq> + Expr +{ + fn apply_feature_flags_inner(&self, features: &FeatureFlags) -> (Expr, bool) { use Expr::*; match self { Constant(_) @@ -631,7 +633,7 @@ impl + PartialEq + Clone> Expr { } } } - pub fn apply_feature_flags(&self, features: &FeatureFlags) -> Expr { + pub fn apply_feature_flags(&self, features: &FeatureFlags) -> Expr { let (res, _) = self.apply_feature_flags_inner(features); res } @@ -831,12 +833,14 @@ impl PolishToken { } } -impl Expr { +impl Expr { /// Convenience function for constructing cell variables. - pub fn cell(col: Column, row: CurrOrNext) -> Expr { + pub fn cell(col: Column, row: CurrOrNext) -> Expr { Expr::Cell(Variable { col, row }) } +} +impl Expr { pub fn double(self) -> Self { Expr::Double(Box::new(self)) } @@ -846,7 +850,7 @@ impl Expr { } /// Convenience function for constructing constant expressions. - pub fn constant(c: C) -> Expr { + pub fn constant(c: C) -> Expr { Expr::Constant(c) } @@ -872,7 +876,7 @@ impl Expr { } } -impl fmt::Display for Expr> +impl fmt::Display for Expr, Column> where F: PrimeField, { @@ -1428,7 +1432,7 @@ fn get_domain(d: Domain, env: &Environment) -> D { } } -impl Expr> { +impl Expr, Column> { /// Convenience function for constructing expressions from literal /// field elements. pub fn literal(x: F) -> Self { @@ -1438,7 +1442,7 @@ impl Expr> { /// Combines multiple constraints `[c0, ..., cn]` into a single constraint /// `alpha^alpha0 * c0 + alpha^{alpha0 + 1} * c1 + ... + alpha^{alpha0 + n} * cn`. pub fn combine_constraints(alphas: impl Iterator, cs: Vec) -> Self { - let zero = Expr::>::zero(); + let zero = Expr::, Column>::zero(); cs.into_iter() .zip_eq(alphas) .map(|(c, i)| Expr::Constant(ConstantExpr::Alpha.pow(i as u64)) * c) @@ -1446,7 +1450,7 @@ impl Expr> { } } -impl Expr> { +impl Expr, Column> { /// Compile an expression to an RPN expression. pub fn to_polish(&self) -> Vec> { let mut res = vec![]; @@ -1536,7 +1540,7 @@ impl Expr> { Expr::Constant(ConstantExpr::Beta) } - fn evaluate_constants_(&self, c: &Constants) -> Expr { + fn evaluate_constants_(&self, c: &Constants) -> Expr { use Expr::*; // TODO: Use cache match self { @@ -1623,7 +1627,7 @@ impl Expr> { } /// Evaluate the constant expressions in this expression down into field elements. - pub fn evaluate_constants(&self, env: &Environment) -> Expr { + pub fn evaluate_constants(&self, env: &Environment) -> Expr { self.evaluate_constants_(&env.constants) } @@ -1638,7 +1642,7 @@ enum Either { Right(B), } -impl Expr { +impl Expr { /// Evaluate an expression into a field element. pub fn evaluate( &self, @@ -1901,10 +1905,10 @@ impl Linearization { } } -impl Linearization>> { +impl Linearization, Column>> { /// Evaluate the constants in a linearization with `ConstantExpr` coefficients down /// to literal field elements. - pub fn evaluate_constants(&self, env: &Environment) -> Linearization> { + pub fn evaluate_constants(&self, env: &Environment) -> Linearization> { self.map(|e| e.evaluate_constants(env)) } } @@ -1939,7 +1943,7 @@ impl Linearization>> { } } -impl Linearization>> { +impl Linearization, Column>> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. pub fn to_polynomial( @@ -1971,7 +1975,7 @@ impl Linearization>> { } } -impl Expr { +impl Expr { /// Exponentiate an expression #[must_use] pub fn pow(self, p: u64) -> Self { @@ -1983,27 +1987,27 @@ impl Expr { } } -type Monomials = HashMap>, Expr>; +type Monomials = HashMap>, Expr>; fn mul_monomials + Clone + One + Zero + PartialEq>( e1: &Monomials, e2: &Monomials, ) -> Monomials { - let mut res: HashMap<_, Expr> = HashMap::new(); + let mut res: HashMap<_, Expr> = HashMap::new(); for (m1, c1) in e1.iter() { for (m2, c2) in e2.iter() { let mut m = m1.clone(); m.extend(m2); m.sort(); let c1c2 = c1.clone() * c2.clone(); - let v = res.entry(m).or_insert_with(Expr::::zero); + let v = res.entry(m).or_insert_with(Expr::::zero); *v = v.clone() + c1c2; } } res } -impl + Clone + One + Zero + PartialEq> Expr { +impl + Clone + One + Zero + PartialEq> Expr { // TODO: This function (which takes linear time) // is called repeatedly in monomials, yielding quadratic behavior for // that function. It's ok for now as we only call that function once on @@ -2024,13 +2028,13 @@ impl + Clone + One + Zero + PartialEq> Expr { } } - fn monomials(&self, ev: &HashSet) -> HashMap>, Expr> { - let sing = |v: Vec>, c: Expr| { + fn monomials(&self, ev: &HashSet) -> HashMap>, Expr> { + let sing = |v: Vec>, c: Expr| { let mut h = HashMap::new(); h.insert(v, c); h }; - let constant = |e: Expr| sing(vec![], e); + let constant = |e: Expr| sing(vec![], e); use Expr::*; if self.is_constant(ev) { @@ -2040,7 +2044,7 @@ impl + Clone + One + Zero + PartialEq> Expr { match self { Pow(x, d) => { // Run the multiplication logic with square and multiply - let mut acc = sing(vec![], Expr::::one()); + let mut acc = sing(vec![], Expr::::one()); let mut acc_is_one = true; let x = x.monomials(ev); @@ -2149,9 +2153,9 @@ impl + Clone + One + Zero + PartialEq> Expr { pub fn linearize( &self, evaluated: HashSet, - ) -> Result>, ExprError> { - let mut res: HashMap> = HashMap::new(); - let mut constant_term: Expr = Self::zero(); + ) -> Result>, ExprError> { + let mut res: HashMap> = HashMap::new(); + let mut constant_term: Expr = Self::zero(); let monomials = self.monomials(&evaluated); for (m, c) in monomials { @@ -2283,7 +2287,7 @@ impl Mul> for ConstantExpr { } } -impl Zero for Expr { +impl Zero for Expr { fn zero() -> Self { Expr::Constant(F::zero()) } @@ -2296,7 +2300,7 @@ impl Zero for Expr { } } -impl One for Expr { +impl One for Expr { fn one() -> Self { Expr::Constant(F::one()) } @@ -2309,10 +2313,10 @@ impl One for Expr { } } -impl> Neg for Expr { - type Output = Expr; +impl, Column> Neg for Expr { + type Output = Expr; - fn neg(self) -> Expr { + fn neg(self) -> Expr { match self { Expr::Constant(x) => Expr::Constant(x.neg()), e => Expr::BinOp( @@ -2324,8 +2328,8 @@ impl> Neg for Expr { } } -impl Add> for Expr { - type Output = Expr; +impl Add> for Expr { + type Output = Expr; fn add(self, other: Self) -> Self { if self.is_zero() { return other; @@ -2337,7 +2341,7 @@ impl Add> for Expr { } } -impl AddAssign> for Expr { +impl AddAssign> for Expr { fn add_assign(&mut self, other: Self) { if self.is_zero() { *self = other; @@ -2347,8 +2351,8 @@ impl AddAssign> for Expr { } } -impl Mul> for Expr { - type Output = Expr; +impl Mul> for Expr { + type Output = Expr; fn mul(self, other: Self) -> Self { if self.is_zero() || other.is_zero() { return Self::zero(); @@ -2364,9 +2368,10 @@ impl Mul> for Expr { } } -impl MulAssign> for Expr +impl MulAssign> for Expr where F: Zero + One + PartialEq + Clone, + Column: PartialEq + Clone, { fn mul_assign(&mut self, other: Self) { if self.is_zero() || other.is_zero() { @@ -2379,8 +2384,8 @@ where } } -impl Sub> for Expr { - type Output = Expr; +impl Sub> for Expr { + type Output = Expr; fn sub(self, other: Self) -> Self { if other.is_zero() { return self; @@ -2389,13 +2394,13 @@ impl Sub> for Expr { } } -impl From for Expr { +impl From for Expr { fn from(x: u64) -> Self { Expr::Constant(F::from(x)) } } -impl From for Expr> { +impl From for Expr, Column> { fn from(x: u64) -> Self { Expr::Constant(ConstantExpr::Literal(F::from(x))) } @@ -2407,8 +2412,8 @@ impl From for ConstantExpr { } } -impl Mul for Expr> { - type Output = Expr>; +impl Mul for Expr, Column> { + type Output = Expr, Column>; fn mul(self, y: F) -> Self::Output { Expr::Constant(ConstantExpr::Literal(y)) * self @@ -2484,7 +2489,7 @@ where } } -impl Expr> +impl Expr, Column> where F: PrimeField, { @@ -2511,7 +2516,7 @@ where /// Recursively print the expression, /// except for the cached expression that are stored in the `cache`. - fn ocaml(&self, cache: &mut HashMap>>) -> String { + fn ocaml(&self, cache: &mut HashMap, Column>>) -> String { use Expr::*; match self { Double(x) => format!("double({})", x.ocaml(cache)), @@ -2564,7 +2569,7 @@ where res } - fn latex(&self, cache: &mut HashMap>>) -> String { + fn latex(&self, cache: &mut HashMap, Column>>) -> String { use Expr::*; match self { Double(x) => format!("2 ({})", x.latex(cache)), @@ -2600,7 +2605,7 @@ where /// Recursively print the expression, /// except for the cached expression that are stored in the `cache`. - fn text(&self, cache: &mut HashMap>>) -> String { + fn text(&self, cache: &mut HashMap, Column>>) -> String { use Expr::*; match self { Double(x) => format!("double({})", x.text(cache)), @@ -2733,24 +2738,25 @@ pub mod constraints { fn cache(&self, cache: &mut Cache) -> Self; } - impl ExprOps for Expr> + impl ExprOps for Expr, Column> where F: PrimeField, + Expr, Column>: std::fmt::Display, { fn two_pow(pow: u64) -> Self { - Expr::>::literal(>::two_pow(pow)) + Expr::, Column>::literal(>::two_pow(pow)) } fn two_to_limb() -> Self { - Expr::>::literal(>::two_to_limb()) + Expr::, Column>::literal(>::two_to_limb()) } fn two_to_2limb() -> Self { - Expr::>::literal(>::two_to_2limb()) + Expr::, Column>::literal(>::two_to_2limb()) } fn two_to_3limb() -> Self { - Expr::>::literal(>::two_to_3limb()) + Expr::, Column>::literal(>::two_to_3limb()) } fn double(&self) -> Self { @@ -2886,7 +2892,7 @@ pub mod constraints { // /// An alias for the intended usage of the expression type in constructing constraints. -pub type E = Expr>; +pub type E = Expr, Column>; /// Convenience function to create a constant as [Expr]. pub fn constant(x: F) -> E { diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 566ef58216..1ed07bf53f 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -38,7 +38,7 @@ use ark_ff::{FftField, PrimeField, SquareRootField, Zero}; pub fn constraints_expr( feature_flags: Option<&FeatureFlags>, generic: bool, -) -> (Expr>, Alphas) { +) -> (Expr, Column>, Alphas) { // register powers of alpha so that we don't reuse them across mutually inclusive constraints let mut powers_of_alpha = Alphas::::default(); From 85c10bfed1ddb2a4c07d00ad919fe8ab746bf09d Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 00:58:49 +0100 Subject: [PATCH 175/242] Generalize PolishToken over Column --- book/src/specs/kimchi.md | 4 ++-- kimchi/src/circuits/expr.rs | 24 +++++++++++++++--------- kimchi/src/linearization.rs | 2 +- kimchi/src/prover_index.rs | 4 ++-- kimchi/src/verifier_index.rs | 4 ++-- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 4bd760e137..fc965cab55 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1710,7 +1710,7 @@ pub struct ProverIndex> { /// The symbolic linearization of our circuit, which can compile to concrete types once certain values are learned in the protocol. #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>>, /// The mapping between powers of alpha and constraints #[serde(skip)] @@ -1856,7 +1856,7 @@ pub struct VerifierIndex> { pub lookup_index: Option>, #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>>, /// The mapping between powers of alpha and constraints #[serde(skip)] pub powers_of_alpha: Alphas, diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 9c5d62aadc..a6713e5acb 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -290,7 +290,7 @@ pub enum ConstantExpr { } impl ConstantExpr { - fn to_polish_(&self, res: &mut Vec>) { + fn to_polish_(&self, res: &mut Vec>) { match self { ConstantExpr::Alpha => res.push(PolishToken::Alpha), ConstantExpr::Beta => res.push(PolishToken::Beta), @@ -425,7 +425,7 @@ pub enum Op2 { } impl Op2 { - fn to_polish(&self) -> PolishToken { + fn to_polish(&self) -> PolishToken { use Op2::*; match self { Add => PolishToken::Add, @@ -643,7 +643,7 @@ impl + PartialEq + Clone, Column: Clone + Partia /// [reverse Polish notation](https://en.wikipedia.org/wiki/Reverse_Polish_notation) /// expressions, which are vectors of the below tokens. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum PolishToken { +pub enum PolishToken { Alpha, Beta, Gamma, @@ -743,10 +743,10 @@ impl Variable { } } -impl PolishToken { +impl PolishToken { /// Evaluate an RPN expression to a field element. pub fn evaluate( - toks: &[PolishToken], + toks: &[PolishToken], d: D, pt: F, evals: &ProofEvaluations>, @@ -1450,16 +1450,20 @@ impl Expr, Column> { } } -impl Expr, Column> { +impl Expr, Column> { /// Compile an expression to an RPN expression. - pub fn to_polish(&self) -> Vec> { + pub fn to_polish(&self) -> Vec> { let mut res = vec![]; let mut cache = HashMap::new(); self.to_polish_(&mut cache, &mut res); res } - fn to_polish_(&self, cache: &mut HashMap, res: &mut Vec>) { + fn to_polish_( + &self, + cache: &mut HashMap, + res: &mut Vec>, + ) { match self { Expr::Double(x) => { x.to_polish_(cache, res); @@ -1539,7 +1543,9 @@ impl Expr, Column> { pub fn beta() -> Self { Expr::Constant(ConstantExpr::Beta) } +} +impl Expr, Column> { fn evaluate_constants_(&self, c: &Constants) -> Expr { use Expr::*; // TODO: Use cache @@ -1913,7 +1919,7 @@ impl Linearization, Column>> { } } -impl Linearization>> { +impl Linearization>> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. pub fn to_polynomial( diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 1ed07bf53f..34a68a6317 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -339,7 +339,7 @@ pub fn linearization_columns( pub fn expr_linearization( feature_flags: Option<&FeatureFlags>, generic: bool, -) -> (Linearization>>, Alphas) { +) -> (Linearization>>, Alphas) { let evaluated_cols = linearization_columns::(feature_flags); let (expr, powers_of_alpha) = constraints_expr(feature_flags, generic); diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 523d583e18..169abb335d 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -4,7 +4,7 @@ use crate::{ alphas::Alphas, circuits::{ constraints::{ColumnEvaluations, ConstraintSystem}, - expr::{Linearization, PolishToken}, + expr::{Column, Linearization, PolishToken}, }, curve::KimchiCurve, linearization::expr_linearization, @@ -28,7 +28,7 @@ pub struct ProverIndex> { /// The symbolic linearization of our circuit, which can compile to concrete types once certain values are learned in the protocol. #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>>, /// The mapping between powers of alpha and constraints #[serde(skip)] diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index d0e5f89172..37973e5fae 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -4,7 +4,7 @@ use crate::{ alphas::Alphas, circuits::{ - expr::{Linearization, PolishToken}, + expr::{Column, Linearization, PolishToken}, lookup::{index::LookupSelectors, lookups::LookupInfo}, polynomials::permutation::{vanishes_on_last_n_rows, zk_w}, wires::{COLUMNS, PERMUTS}, @@ -144,7 +144,7 @@ pub struct VerifierIndex> { pub lookup_index: Option>, #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>>, /// The mapping between powers of alpha and constraints #[serde(skip)] pub powers_of_alpha: Alphas, From 748269d50f886ba149a11630c0b852dbb4c66ddb Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 01:22:49 +0100 Subject: [PATCH 176/242] ColumnEnvironment trait --- kimchi/src/circuits/expr.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index a6713e5acb..6b80c759b5 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -119,7 +119,14 @@ pub struct Environment<'a, F: FftField> { pub lookup: Option>, } -impl<'a, F: FftField> Environment<'a, F> { +trait ColumnEnvironment<'a, F: FftField> { + type Column; + fn get_column(&self, col: &Column) -> Option<&'a Evaluations>>; +} + +impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { + type Column = Column; + fn get_column(&self, col: &Column) -> Option<&'a Evaluations>> { use Column::*; let lookup = self.lookup.as_ref(); From 21502a30264fe62403dff77c41fda115281fc28d Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 01:36:22 +0100 Subject: [PATCH 177/242] ColumnEvaluations trait --- kimchi/src/circuits/expr.rs | 130 +++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 61 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 6b80c759b5..c51310dfa2 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -677,72 +677,80 @@ pub enum PolishToken { SkipIfNot(FeatureFlag, usize), } +trait ColumnEvaluations { + type Column; + fn evaluate(&self, col: Self::Column) -> Result, ExprError>; +} + +impl ColumnEvaluations for ProofEvaluations> { + type Column = Column; + fn evaluate(&self, col: Self::Column) -> Result, ExprError> { + use Column::*; + match col { + Witness(i) => Ok(self.w[i]), + Z => Ok(self.z), + LookupSorted(i) => self.lookup_sorted[i].ok_or(ExprError::MissingIndexEvaluation(col)), + LookupAggreg => self + .lookup_aggregation + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupTable => self + .lookup_table + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupRuntimeTable => self + .runtime_lookup_table + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::Poseidon) => Ok(self.poseidon_selector), + Index(GateType::Generic) => Ok(self.generic_selector), + Index(GateType::CompleteAdd) => Ok(self.complete_add_selector), + Index(GateType::VarBaseMul) => Ok(self.mul_selector), + Index(GateType::EndoMul) => Ok(self.emul_selector), + Index(GateType::EndoMulScalar) => Ok(self.endomul_scalar_selector), + Index(GateType::RangeCheck0) => self + .range_check0_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::RangeCheck1) => self + .range_check1_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::ForeignFieldAdd) => self + .foreign_field_add_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::ForeignFieldMul) => self + .foreign_field_mul_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::Xor16) => self + .xor_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::Rot64) => self + .rot_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Permutation(i) => Ok(self.s[i]), + Coefficient(i) => Ok(self.coefficients[i]), + LookupKindIndex(LookupPattern::Xor) => self + .xor_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::Lookup) => self + .lookup_gate_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::RangeCheck) => self + .range_check_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::ForeignFieldMul) => self + .foreign_field_mul_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupRuntimeSelector => self + .runtime_lookup_table_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(_) => Err(ExprError::MissingIndexEvaluation(col)), + } + } +} + impl Variable { fn evaluate( &self, evals: &ProofEvaluations>, ) -> Result> { - let point_evaluations = { - use Column::*; - match self.col { - Witness(i) => Ok(evals.w[i]), - Z => Ok(evals.z), - LookupSorted(i) => { - evals.lookup_sorted[i].ok_or(ExprError::MissingIndexEvaluation(self.col)) - } - LookupAggreg => evals - .lookup_aggregation - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - LookupTable => evals - .lookup_table - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - LookupRuntimeTable => evals - .runtime_lookup_table - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Index(GateType::Poseidon) => Ok(evals.poseidon_selector), - Index(GateType::Generic) => Ok(evals.generic_selector), - Index(GateType::CompleteAdd) => Ok(evals.complete_add_selector), - Index(GateType::VarBaseMul) => Ok(evals.mul_selector), - Index(GateType::EndoMul) => Ok(evals.emul_selector), - Index(GateType::EndoMulScalar) => Ok(evals.endomul_scalar_selector), - Index(GateType::RangeCheck0) => evals - .range_check0_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Index(GateType::RangeCheck1) => evals - .range_check1_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Index(GateType::ForeignFieldAdd) => evals - .foreign_field_add_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Index(GateType::ForeignFieldMul) => evals - .foreign_field_mul_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Index(GateType::Xor16) => evals - .xor_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Index(GateType::Rot64) => evals - .rot_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Permutation(i) => Ok(evals.s[i]), - Coefficient(i) => Ok(evals.coefficients[i]), - Column::LookupKindIndex(LookupPattern::Xor) => evals - .xor_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Column::LookupKindIndex(LookupPattern::Lookup) => evals - .lookup_gate_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Column::LookupKindIndex(LookupPattern::RangeCheck) => evals - .range_check_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Column::LookupKindIndex(LookupPattern::ForeignFieldMul) => evals - .foreign_field_mul_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Column::LookupRuntimeSelector => evals - .runtime_lookup_table_selector - .ok_or(ExprError::MissingIndexEvaluation(self.col)), - Index(_) => Err(ExprError::MissingIndexEvaluation(self.col)), - } - }?; + let point_evaluations = evals.evaluate(self.col)?; match self.row { CurrOrNext::Curr => Ok(point_evaluations.zeta), CurrOrNext::Next => Ok(point_evaluations.zeta_omega), From 06b0137bf66dba6183dfa56d21d94af23be61729 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 01:40:05 +0100 Subject: [PATCH 178/242] Generalize PolishToken::evaluate --- kimchi/src/circuits/expr.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index c51310dfa2..367ccd81e3 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -677,7 +677,7 @@ pub enum PolishToken { SkipIfNot(FeatureFlag, usize), } -trait ColumnEvaluations { +pub trait ColumnEvaluations { type Column; fn evaluate(&self, col: Self::Column) -> Result, ExprError>; } @@ -745,10 +745,10 @@ impl ColumnEvaluations for ProofEvaluations> { } } -impl Variable { - fn evaluate( +impl Variable { + fn evaluate>( &self, - evals: &ProofEvaluations>, + evals: &Evaluations, ) -> Result> { let point_evaluations = evals.evaluate(self.col)?; match self.row { @@ -758,13 +758,13 @@ impl Variable { } } -impl PolishToken { +impl PolishToken { /// Evaluate an RPN expression to a field element. - pub fn evaluate( + pub fn evaluate>( toks: &[PolishToken], d: D, pt: F, - evals: &ProofEvaluations>, + evals: &Evaluations, c: &Constants, ) -> Result> { let mut stack = vec![]; From bf1a5a32fd94ce010a8ede8ca9f0f002a2a00658 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 01:41:10 +0100 Subject: [PATCH 179/242] Generalize Expr::cell --- kimchi/src/circuits/expr.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 367ccd81e3..9dd3e22aa6 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -848,14 +848,12 @@ impl PolishToken { } } -impl Expr { +impl Expr { /// Convenience function for constructing cell variables. pub fn cell(col: Column, row: CurrOrNext) -> Expr { Expr::Cell(Variable { col, row }) } -} -impl Expr { pub fn double(self) -> Self { Expr::Double(Box::new(self)) } From 04566d957cb94c75abb365fcae4f2a9532732c4f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Wed, 29 Mar 2023 06:07:00 +0100 Subject: [PATCH 180/242] Generalize to_polynomial --- kimchi/src/circuits/expr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 9dd3e22aa6..48842f5437 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -1932,14 +1932,14 @@ impl Linearization, Column>> { } } -impl Linearization>> { +impl Linearization>> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. - pub fn to_polynomial( + pub fn to_polynomial>( &self, env: &Environment, pt: F, - evals: &ProofEvaluations>, + evals: &ColEvaluations, ) -> (F, Evaluations>) { let cs = &env.constants; let n = env.domain.d1.size(); From ff637ad64720c9dda1392fbad0235d2c9b536353 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 02:53:49 +0100 Subject: [PATCH 181/242] Generalize evaluate_ --- kimchi/src/circuits/expr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 48842f5437..48af5ef9f7 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -1445,7 +1445,7 @@ fn get_domain(d: Domain, env: &Environment) -> D { } } -impl Expr, Column> { +impl Expr, Column> { /// Convenience function for constructing expressions from literal /// field elements. pub fn literal(x: F) -> Self { @@ -1594,11 +1594,11 @@ impl Expr, Column> { } /// Evaluate an expression as a field element against the constants. - pub fn evaluate_( + pub fn evaluate_>( &self, d: D, pt: F, - evals: &ProofEvaluations>, + evals: &Evaluations, c: &Constants, ) -> Result> { use Expr::*; From f8cb64b4a77842c45ec672eadf0ebf99fe59460e Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 03:01:48 +0100 Subject: [PATCH 182/242] Generalize remaining ProofEvaluations uses --- kimchi/src/circuits/expr.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 48af5ef9f7..395b2209ed 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -1583,11 +1583,11 @@ impl Expr, Column> { } /// Evaluate an expression as a field element against an environment. - pub fn evaluate( + pub fn evaluate>( &self, d: D, pt: F, - evals: &ProofEvaluations>, + evals: &Evaluations, env: &Environment, ) -> Result> { self.evaluate_(d, pt, evals, &env.constants) @@ -1663,12 +1663,12 @@ enum Either { impl Expr { /// Evaluate an expression into a field element. - pub fn evaluate( + pub fn evaluate>( &self, d: D, pt: F, zk_rows: u64, - evals: &ProofEvaluations>, + evals: &Evaluations, ) -> Result> { use Expr::*; match self { @@ -1965,11 +1965,11 @@ impl Linearization impl Linearization, Column>> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. - pub fn to_polynomial( + pub fn to_polynomial>( &self, env: &Environment, pt: F, - evals: &ProofEvaluations>, + evals: &ColEvaluations, ) -> (F, DensePolynomial) { let cs = &env.constants; let n = env.domain.d1.size(); From 50bb0ea9be4a9e7f7a0f2576c0fc14691d6c2baf Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 03:11:09 +0100 Subject: [PATCH 183/242] Move get_domain into ColumnEnvironment --- kimchi/src/circuits/expr.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 395b2209ed..12a1602413 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -122,6 +122,7 @@ pub struct Environment<'a, F: FftField> { trait ColumnEnvironment<'a, F: FftField> { type Column; fn get_column(&self, col: &Column) -> Option<&'a Evaluations>>; + fn get_domain(&self, d: Domain) -> D; } impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { @@ -147,6 +148,15 @@ impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { Permutation(_) => None, } } + + fn get_domain(&self, d: Domain) -> D { + match d { + Domain::D1 => self.domain.d1, + Domain::D2 => self.domain.d2, + Domain::D4 => self.domain.d4, + Domain::D8 => self.domain.d8, + } + } } // In this file, we define... @@ -984,7 +994,7 @@ fn unnormalized_lagrange_evals( Domain::D4 => 4, Domain::D8 => 8, }; - let res_domain = get_domain(res_domain, env); + let res_domain = env.get_domain(res_domain); let d1 = env.domain.d1; let n = d1.size; @@ -1436,15 +1446,6 @@ impl<'a, F: FftField> EvalResult<'a, F> { } } -fn get_domain(d: Domain, env: &Environment) -> D { - match d { - Domain::D1 => env.domain.d1, - Domain::D2 => env.domain.d2, - Domain::D4 => env.domain.d4, - Domain::D8 => env.domain.d8, - } -} - impl Expr, Column> { /// Convenience function for constructing expressions from literal /// field elements. @@ -1740,13 +1741,13 @@ impl Expr { assert_eq!(domain, d); evals } - EvalResult::Constant(x) => EvalResult::init_((d, get_domain(d, env)), |_| x), + EvalResult::Constant(x) => EvalResult::init_((d, env.get_domain(d)), |_| x), EvalResult::SubEvals { evals, domain: d_sub, shift: s, } => { - let res_domain = get_domain(d, env); + let res_domain = env.get_domain(d); let scale = (d_sub as usize) / (d as usize); assert!(scale != 0); EvalResult::init_((d, res_domain), |i| { @@ -1765,7 +1766,7 @@ impl Expr { where 'a: 'b, { - let dom = (d, get_domain(d, env)); + let dom = (d, env.get_domain(d)); let res: EvalResult<'a, F> = match self { Expr::Square(x) => match x.evaluations_helper(cache, d, env) { @@ -1827,9 +1828,9 @@ impl Expr { Expr::Pow(x, p) => { let x = x.evaluations_helper(cache, d, env); match x { - Either::Left(x) => x.pow(*p, (d, get_domain(d, env))), + Either::Left(x) => x.pow(*p, (d, env.get_domain(d))), Either::Right(id) => { - id.get_from(cache).unwrap().pow(*p, (d, get_domain(d, env))) + id.get_from(cache).unwrap().pow(*p, (d, env.get_domain(d))) } } } @@ -1864,7 +1865,7 @@ impl Expr { } } Expr::BinOp(op, e1, e2) => { - let dom = (d, get_domain(d, env)); + let dom = (d, env.get_domain(d)); let f = |x: EvalResult, y: EvalResult| match op { Op2::Mul => x.mul(y, dom), Op2::Add => x.add(y, dom), From accad129bda4fe3aeaa7b1e5802cbc8885455e9d Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 03:12:47 +0100 Subject: [PATCH 184/242] Generalize unnormalized_lagrange_evals over Environment --- kimchi/src/circuits/expr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 12a1602413..5dfa78613a 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -982,11 +982,11 @@ pub fn pows(x: F, n: usize) -> Vec { /// = (omega^{q n} omega_8^{r n} - 1) / (omega_8^k - omega^i) /// = ((omega_8^n)^r - 1) / (omega_8^k - omega^i) /// = ((omega_8^n)^r - 1) / (omega^q omega_8^r - omega^i) -fn unnormalized_lagrange_evals( +fn unnormalized_lagrange_evals<'a, F: FftField, Environment: ColumnEnvironment<'a, F>>( l0_1: F, i: i32, res_domain: Domain, - env: &Environment, + env: &Environment, ) -> Evaluations> { let k = match res_domain { Domain::D1 => 1, @@ -996,7 +996,7 @@ fn unnormalized_lagrange_evals( }; let res_domain = env.get_domain(res_domain); - let d1 = env.domain.d1; + let d1 = env.get_domain(Domain::D1); let n = d1.size; // Renormalize negative values to wrap around at domain size let i = if i < 0 { From f49371a9067bf35796f78d585d0b3b61c091c33e Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 03:54:50 +0100 Subject: [PATCH 185/242] Generalize to_polynomials over Environment --- kimchi/src/circuits/expr.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 5dfa78613a..8f8151275d 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -119,10 +119,11 @@ pub struct Environment<'a, F: FftField> { pub lookup: Option>, } -trait ColumnEnvironment<'a, F: FftField> { +pub trait ColumnEnvironment<'a, F: FftField> { type Column; fn get_column(&self, col: &Column) -> Option<&'a Evaluations>>; fn get_domain(&self, d: Domain) -> D; + fn get_constants(&self) -> &Constants; } impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { @@ -157,6 +158,10 @@ impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { Domain::D8 => self.domain.d8, } } + + fn get_constants(&self) -> &Constants { + &self.constants + } } // In this file, we define... @@ -909,7 +914,7 @@ where } #[derive(Clone, Copy, Debug, PartialEq, FromPrimitive, ToPrimitive)] -enum Domain { +pub enum Domain { D1 = 1, D2 = 2, D4 = 4, @@ -1936,17 +1941,22 @@ impl Linearization, Column>> { impl Linearization>> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. - pub fn to_polynomial>( + pub fn to_polynomial< + 'a, + ColEvaluations: ColumnEvaluations, + Environment: ColumnEnvironment<'a, F, Column = Column>, + >( &self, - env: &Environment, + env: &Environment, pt: F, evals: &ColEvaluations, ) -> (F, Evaluations>) { - let cs = &env.constants; - let n = env.domain.d1.size(); + let cs = env.get_constants(); + let d1 = env.get_domain(Domain::D1); + let n = d1.size(); let mut res = vec![F::zero(); n]; self.index_terms.iter().for_each(|(idx, c)| { - let c = PolishToken::evaluate(c, env.domain.d1, pt, evals, cs).unwrap(); + let c = PolishToken::evaluate(c, d1, pt, evals, cs).unwrap(); let e = env .get_column(idx) .unwrap_or_else(|| panic!("Index polynomial {idx:?} not found")); @@ -1955,9 +1965,9 @@ impl Linearization .enumerate() .for_each(|(i, r)| *r += c * e.evals[scale * i]); }); - let p = Evaluations::>::from_vec_and_domain(res, env.domain.d1); + let p = Evaluations::>::from_vec_and_domain(res, d1); ( - PolishToken::evaluate(&self.constant_term, env.domain.d1, pt, evals, cs).unwrap(), + PolishToken::evaluate(&self.constant_term, d1, pt, evals, cs).unwrap(), p, ) } From f02d1d0c7da06f9af3fc964983bb599266d06025 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 03:57:30 +0100 Subject: [PATCH 186/242] Generalize evaluate over Environment --- kimchi/src/circuits/expr.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 8f8151275d..7fd243b08c 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -1589,14 +1589,18 @@ impl Expr, Column> { } /// Evaluate an expression as a field element against an environment. - pub fn evaluate>( + pub fn evaluate< + 'a, + Evaluations: ColumnEvaluations, + Environment: ColumnEnvironment<'a, F, Column = Column>, + >( &self, d: D, pt: F, evals: &Evaluations, - env: &Environment, + env: &Environment, ) -> Result> { - self.evaluate_(d, pt, evals, &env.constants) + self.evaluate_(d, pt, evals, &env.get_constants()) } /// Evaluate an expression as a field element against the constants. @@ -1652,8 +1656,11 @@ impl Expr, Column> { } /// Evaluate the constant expressions in this expression down into field elements. - pub fn evaluate_constants(&self, env: &Environment) -> Expr { - self.evaluate_constants_(&env.constants) + pub fn evaluate_constants<'a, Environment: ColumnEnvironment<'a, F, Column = Column>>( + &self, + env: &Environment, + ) -> Expr { + self.evaluate_constants_(env.get_constants()) } /// Compute the polynomial corresponding to this expression, in evaluation form. From ba32966f5e145507d4f90a07e78e3c2acd08d8cc Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 04:04:56 +0100 Subject: [PATCH 187/242] Generalize to_polynomial --- kimchi/src/circuits/expr.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 7fd243b08c..fd78255c43 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -1983,17 +1983,22 @@ impl Linearization impl Linearization, Column>> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. - pub fn to_polynomial>( + pub fn to_polynomial< + 'a, + ColEvaluations: ColumnEvaluations, + Environment: ColumnEnvironment<'a, F, Column = Column>, + >( &self, - env: &Environment, + env: &Environment, pt: F, evals: &ColEvaluations, ) -> (F, DensePolynomial) { - let cs = &env.constants; - let n = env.domain.d1.size(); + let cs = env.get_constants(); + let d1 = env.get_domain(Domain::D1); + let n = d1.size(); let mut res = vec![F::zero(); n]; self.index_terms.iter().for_each(|(idx, c)| { - let c = c.evaluate_(env.domain.d1, pt, evals, cs).unwrap(); + let c = c.evaluate_(d1, pt, evals, cs).unwrap(); let e = env .get_column(idx) .unwrap_or_else(|| panic!("Index polynomial {idx:?} not found")); @@ -2002,13 +2007,8 @@ impl Linearization, Column>> { .enumerate() .for_each(|(i, r)| *r += c * e.evals[scale * i]) }); - let p = Evaluations::>::from_vec_and_domain(res, env.domain.d1).interpolate(); - ( - self.constant_term - .evaluate_(env.domain.d1, pt, evals, cs) - .unwrap(), - p, - ) + let p = Evaluations::>::from_vec_and_domain(res, d1).interpolate(); + (self.constant_term.evaluate_(d1, pt, evals, cs).unwrap(), p) } } From 840b18f29d3587bbfaabd5690e9b08c7a2c7fa01 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 04:09:16 +0100 Subject: [PATCH 188/242] Generalize evaluations_helper over Environment --- kimchi/src/circuits/expr.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index fd78255c43..ccfef79d47 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -124,6 +124,8 @@ pub trait ColumnEnvironment<'a, F: FftField> { fn get_column(&self, col: &Column) -> Option<&'a Evaluations>>; fn get_domain(&self, d: Domain) -> D; fn get_constants(&self) -> &Constants; + fn vanishes_on_zero_knowledge_and_previous_rows(&self) -> &'a Evaluations>; + fn l0_1(&self) -> F; } impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { @@ -162,6 +164,14 @@ impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { fn get_constants(&self) -> &Constants { &self.constants } + + fn vanishes_on_zero_knowledge_and_previous_rows(&self) -> &'a Evaluations> { + &self.vanishes_on_zero_knowledge_and_previous_rows + } + + fn l0_1(&self) -> F { + self.l0_1 + } } // In this file, we define... @@ -1769,11 +1779,11 @@ impl Expr { } } - fn evaluations_helper<'a, 'b>( + fn evaluations_helper<'a, 'b, Environment: ColumnEnvironment<'a, F, Column = Column>>( &self, cache: &'b mut HashMap>, d: Domain, - env: &Environment<'a, F>, + env: &Environment, ) -> Either, CacheId> where 'a: 'b, @@ -1849,18 +1859,18 @@ impl Expr { Expr::VanishesOnZeroKnowledgeAndPreviousRows => EvalResult::SubEvals { domain: Domain::D8, shift: 0, - evals: env.vanishes_on_zero_knowledge_and_previous_rows, + evals: env.vanishes_on_zero_knowledge_and_previous_rows(), }, Expr::Constant(x) => EvalResult::Constant(*x), Expr::UnnormalizedLagrangeBasis(i) => { let offset = if i.zk_rows { - -(env.constants.zk_rows as i32) + i.offset + -(env.get_constants().zk_rows as i32) + i.offset } else { i.offset }; EvalResult::Evals { domain: d, - evals: unnormalized_lagrange_evals(env.l0_1, offset, d, env), + evals: unnormalized_lagrange_evals(env.l0_1(), offset, d, env), } } Expr::Cell(Variable { col, row }) => { From 473c435cedaa080654e79e7abf1b758d300235c8 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 04:25:19 +0100 Subject: [PATCH 189/242] Generalize Linearization over column --- book/src/specs/kimchi.md | 4 +-- kimchi/src/circuits/expr.rs | 53 ++++++++++++++++++++++++------------ kimchi/src/linearization.rs | 5 +++- kimchi/src/prover_index.rs | 2 +- kimchi/src/verifier_index.rs | 2 +- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index fc965cab55..842ecbb171 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1710,7 +1710,7 @@ pub struct ProverIndex> { /// The symbolic linearization of our circuit, which can compile to concrete types once certain values are learned in the protocol. #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>, Column>, /// The mapping between powers of alpha and constraints #[serde(skip)] @@ -1856,7 +1856,7 @@ pub struct VerifierIndex> { pub lookup_index: Option>, #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>, Column>, /// The mapping between powers of alpha and constraints #[serde(skip)] pub powers_of_alpha: Alphas, diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index ccfef79d47..093bc972cb 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -121,7 +121,7 @@ pub struct Environment<'a, F: FftField> { pub trait ColumnEnvironment<'a, F: FftField> { type Column; - fn get_column(&self, col: &Column) -> Option<&'a Evaluations>>; + fn get_column(&self, col: &Self::Column) -> Option<&'a Evaluations>>; fn get_domain(&self, d: Domain) -> D; fn get_constants(&self) -> &Constants; fn vanishes_on_zero_knowledge_and_previous_rows(&self) -> &'a Evaluations>; @@ -131,7 +131,7 @@ pub trait ColumnEnvironment<'a, F: FftField> { impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { type Column = Column; - fn get_column(&self, col: &Column) -> Option<&'a Evaluations>> { + fn get_column(&self, col: &Self::Column) -> Option<&'a Evaluations>> { use Column::*; let lookup = self.lookup.as_ref(); match col { @@ -218,7 +218,11 @@ pub enum Column { Permutation(usize), } -impl Column { +pub trait GenericColumn { + fn domain(&self) -> Domain; +} + +impl GenericColumn for Column { fn domain(&self) -> Domain { match self { Column::Index(GateType::Generic) => Domain::D4, @@ -226,7 +230,9 @@ impl Column { _ => Domain::D8, } } +} +impl Column { fn latex(&self) -> String { match self { Column::Witness(i) => format!("w_{{{i}}}"), @@ -1574,7 +1580,7 @@ impl Expr, Column> { } } -impl Expr, Column> { +impl Expr, Column> { fn evaluate_constants_(&self, c: &Constants) -> Expr { use Expr::*; // TODO: Use cache @@ -1674,7 +1680,10 @@ impl Expr, Column> { } /// Compute the polynomial corresponding to this expression, in evaluation form. - pub fn evaluations(&self, env: &Environment<'_, F>) -> Evaluations> { + pub fn evaluations<'a, Environment: ColumnEnvironment<'a, F, Column = Column>>( + &self, + env: &Environment, + ) -> Evaluations> { self.evaluate_constants(env).evaluations(env) } } @@ -1684,7 +1693,7 @@ enum Either { Right(B), } -impl Expr { +impl Expr { /// Evaluate an expression into a field element. pub fn evaluate>( &self, @@ -1738,9 +1747,12 @@ impl Expr { } /// Compute the polynomial corresponding to this expression, in evaluation form. - pub fn evaluations(&self, env: &Environment<'_, F>) -> Evaluations> { - let d1_size = env.domain.d1.size; - let deg = self.degree(d1_size, env.constants.zk_rows); + pub fn evaluations<'a, Environment: ColumnEnvironment<'a, F, Column = Column>>( + &self, + env: &Environment, + ) -> Evaluations> { + let d1_size = env.get_domain(Domain::D1).size; + let deg = self.degree(d1_size, env.get_constants().zk_rows); let d = if deg <= d1_size { Domain::D1 } else if deg <= 4 * d1_size { @@ -1923,12 +1935,12 @@ impl Expr { #[derive(Clone, Debug, Serialize, Deserialize)] /// A "linearization", which is linear combination with `E` coefficients of /// columns. -pub struct Linearization { +pub struct Linearization { pub constant_term: E, pub index_terms: Vec<(Column, E)>, } -impl Default for Linearization { +impl Default for Linearization { fn default() -> Self { Linearization { constant_term: E::default(), @@ -1937,9 +1949,9 @@ impl Default for Linearization { } } -impl Linearization { +impl Linearization { /// Apply a function to all the coefficients in the linearization. - pub fn map B>(&self, f: F) -> Linearization { + pub fn map B>(&self, f: F) -> Linearization { Linearization { constant_term: f(&self.constant_term), index_terms: self.index_terms.iter().map(|(c, x)| (*c, f(x))).collect(), @@ -1947,15 +1959,20 @@ impl Linearization { } } -impl Linearization, Column>> { +impl + Linearization, Column>, Column> +{ /// Evaluate the constants in a linearization with `ConstantExpr` coefficients down /// to literal field elements. - pub fn evaluate_constants(&self, env: &Environment) -> Linearization> { + pub fn evaluate_constants<'a, Environment: ColumnEnvironment<'a, F, Column = Column>>( + &self, + env: &Environment, + ) -> Linearization, Column> { self.map(|e| e.evaluate_constants(env)) } } -impl Linearization>> { +impl Linearization>, Column> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. pub fn to_polynomial< @@ -1990,7 +2007,7 @@ impl Linearization } } -impl Linearization, Column>> { +impl Linearization, Column>, Column> { /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. pub fn to_polynomial< @@ -2200,7 +2217,7 @@ impl + Clone + One + Zero + PartialEq> Expr { pub fn linearize( &self, evaluated: HashSet, - ) -> Result>, ExprError> { + ) -> Result, Column>, ExprError> { let mut res: HashMap> = HashMap::new(); let mut constant_term: Expr = Self::zero(); let monomials = self.monomials(&evaluated); diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 34a68a6317..b9657adedc 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -339,7 +339,10 @@ pub fn linearization_columns( pub fn expr_linearization( feature_flags: Option<&FeatureFlags>, generic: bool, -) -> (Linearization>>, Alphas) { +) -> ( + Linearization>, Column>, + Alphas, +) { let evaluated_cols = linearization_columns::(feature_flags); let (expr, powers_of_alpha) = constraints_expr(feature_flags, generic); diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 169abb335d..42fe06c1e9 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -28,7 +28,7 @@ pub struct ProverIndex> { /// The symbolic linearization of our circuit, which can compile to concrete types once certain values are learned in the protocol. #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>, Column>, /// The mapping between powers of alpha and constraints #[serde(skip)] diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 37973e5fae..8f6b664974 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -144,7 +144,7 @@ pub struct VerifierIndex> { pub lookup_index: Option>, #[serde(skip)] - pub linearization: Linearization>>, + pub linearization: Linearization>, Column>, /// The mapping between powers of alpha and constraints #[serde(skip)] pub powers_of_alpha: Alphas, From 7a4f0e2335e9bf7a7a5ab1f580176d3eb824b225 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 04:30:39 +0100 Subject: [PATCH 190/242] Generalize to_polynomial over Column --- kimchi/src/circuits/expr.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 093bc972cb..32e3927c83 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -2007,7 +2007,9 @@ impl Linearization } } -impl Linearization, Column>, Column> { +impl + Linearization, Column>, Column> +{ /// Given a linearization and an environment, compute the polynomial corresponding to the /// linearization, in evaluation form. pub fn to_polynomial< From 1d700a346a5771c5adf69b01dba27d97e76d830d Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 04:37:23 +0100 Subject: [PATCH 191/242] Generalize Monomials over Column --- kimchi/src/circuits/expr.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 32e3927c83..4f2f96dfaa 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -2053,12 +2053,15 @@ impl Expr { } } -type Monomials = HashMap>, Expr>; - -fn mul_monomials + Clone + One + Zero + PartialEq>( - e1: &Monomials, - e2: &Monomials, -) -> Monomials { +type Monomials = HashMap>, Expr>; + +fn mul_monomials< + F: Neg + Clone + One + Zero + PartialEq, + Column: Ord + Copy + std::hash::Hash, +>( + e1: &Monomials, + e2: &Monomials, +) -> Monomials { let mut res: HashMap<_, Expr> = HashMap::new(); for (m1, c1) in e1.iter() { for (m2, c2) in e2.iter() { @@ -2073,7 +2076,9 @@ fn mul_monomials + Clone + One + Zero + PartialEq>( res } -impl + Clone + One + Zero + PartialEq> Expr { +impl + Clone + One + Zero + PartialEq, Column: Ord + Copy + std::hash::Hash> + Expr +{ // TODO: This function (which takes linear time) // is called repeatedly in monomials, yielding quadratic behavior for // that function. It's ok for now as we only call that function once on From 23614b61b4d778efd6b07cca56ab7874fedba23f Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 06:57:39 +0100 Subject: [PATCH 192/242] Move expr::Columns to berkeley_columns --- kimchi/src/circuits/berkeley_columns.rs | 93 ++++++++++++ kimchi/src/circuits/expr.rs | 143 +++++------------- kimchi/src/circuits/lookup/constraints.rs | 3 +- kimchi/src/circuits/lookup/runtime_tables.rs | 5 +- kimchi/src/circuits/mod.rs | 1 + kimchi/src/circuits/polynomials/turshi.rs | 3 +- kimchi/src/circuits/polynomials/varbasemul.rs | 3 +- kimchi/src/error.rs | 4 +- kimchi/src/linearization.rs | 3 +- kimchi/src/proof.rs | 2 +- kimchi/src/prover_index.rs | 3 +- kimchi/src/verifier.rs | 3 +- kimchi/src/verifier_index.rs | 3 +- 13 files changed, 150 insertions(+), 119 deletions(-) create mode 100644 kimchi/src/circuits/berkeley_columns.rs diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs new file mode 100644 index 0000000000..1224744a6b --- /dev/null +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -0,0 +1,93 @@ +use crate::circuits::{ + expr::{self, Domain, GenericColumn}, + gate::{CurrOrNext, GateType}, + lookup::lookups::LookupPattern, +}; +use serde::{Deserialize, Serialize}; +use CurrOrNext::{Curr, Next}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +/// A type representing one of the polynomials involved in the PLONK IOP. +pub enum Column { + Witness(usize), + Z, + LookupSorted(usize), + LookupAggreg, + LookupTable, + LookupKindIndex(LookupPattern), + LookupRuntimeSelector, + LookupRuntimeTable, + Index(GateType), + Coefficient(usize), + Permutation(usize), +} + +impl GenericColumn for Column { + fn domain(&self) -> Domain { + match self { + Column::Index(GateType::Generic) => Domain::D4, + Column::Index(GateType::CompleteAdd) => Domain::D4, + _ => Domain::D8, + } + } +} + +impl Column { + pub fn latex(&self) -> String { + match self { + Column::Witness(i) => format!("w_{{{i}}}"), + Column::Z => "Z".to_string(), + Column::LookupSorted(i) => format!("s_{{{i}}}"), + Column::LookupAggreg => "a".to_string(), + Column::LookupTable => "t".to_string(), + Column::LookupKindIndex(i) => format!("k_{{{i:?}}}"), + Column::LookupRuntimeSelector => "rts".to_string(), + Column::LookupRuntimeTable => "rt".to_string(), + Column::Index(gate) => { + format!("{gate:?}") + } + Column::Coefficient(i) => format!("c_{{{i}}}"), + Column::Permutation(i) => format!("sigma_{{{i}}}"), + } + } + + pub fn text(&self) -> String { + match self { + Column::Witness(i) => format!("w[{i}]"), + Column::Z => "Z".to_string(), + Column::LookupSorted(i) => format!("s[{i}]"), + Column::LookupAggreg => "a".to_string(), + Column::LookupTable => "t".to_string(), + Column::LookupKindIndex(i) => format!("k[{i:?}]"), + Column::LookupRuntimeSelector => "rts".to_string(), + Column::LookupRuntimeTable => "rt".to_string(), + Column::Index(gate) => { + format!("{gate:?}") + } + Column::Coefficient(i) => format!("c[{i}]"), + Column::Permutation(i) => format!("sigma_[{i}]"), + } + } +} + +impl expr::Variable { + pub fn ocaml(&self) -> String { + format!("var({:?}, {:?})", self.col, self.row) + } + + pub fn latex(&self) -> String { + let col = self.col.latex(); + match self.row { + Curr => col, + Next => format!("\\tilde{{{col}}}"), + } + } + + pub fn text(&self) -> String { + let col = self.col.text(); + match self.row { + Curr => format!("Curr({col})"), + Next => format!("Next({col})"), + } + } +} diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 4f2f96dfaa..d84512d5fe 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -1,5 +1,6 @@ use crate::{ circuits::{ + berkeley_columns, constraints::FeatureFlags, domains::EvaluationDomains, gate::{CurrOrNext, GateType}, @@ -129,10 +130,10 @@ pub trait ColumnEnvironment<'a, F: FftField> { } impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { - type Column = Column; + type Column = berkeley_columns::Column; fn get_column(&self, col: &Self::Column) -> Option<&'a Evaluations>> { - use Column::*; + use berkeley_columns::Column::*; let lookup = self.lookup.as_ref(); match col { Witness(i) => Some(&self.witness[*i]), @@ -202,74 +203,10 @@ fn unnormalized_lagrange_basis(domain: &D, i: i32, pt: &F) -> F domain.evaluate_vanishing_polynomial(*pt) / (*pt - omega_i) } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] -/// A type representing one of the polynomials involved in the PLONK IOP. -pub enum Column { - Witness(usize), - Z, - LookupSorted(usize), - LookupAggreg, - LookupTable, - LookupKindIndex(LookupPattern), - LookupRuntimeSelector, - LookupRuntimeTable, - Index(GateType), - Coefficient(usize), - Permutation(usize), -} - pub trait GenericColumn { fn domain(&self) -> Domain; } -impl GenericColumn for Column { - fn domain(&self) -> Domain { - match self { - Column::Index(GateType::Generic) => Domain::D4, - Column::Index(GateType::CompleteAdd) => Domain::D4, - _ => Domain::D8, - } - } -} - -impl Column { - fn latex(&self) -> String { - match self { - Column::Witness(i) => format!("w_{{{i}}}"), - Column::Z => "Z".to_string(), - Column::LookupSorted(i) => format!("s_{{{i}}}"), - Column::LookupAggreg => "a".to_string(), - Column::LookupTable => "t".to_string(), - Column::LookupKindIndex(i) => format!("k_{{{i:?}}}"), - Column::LookupRuntimeSelector => "rts".to_string(), - Column::LookupRuntimeTable => "rt".to_string(), - Column::Index(gate) => { - format!("{gate:?}") - } - Column::Coefficient(i) => format!("c_{{{i}}}"), - Column::Permutation(i) => format!("sigma_{{{i}}}"), - } - } - - fn text(&self) -> String { - match self { - Column::Witness(i) => format!("w[{i}]"), - Column::Z => "Z".to_string(), - Column::LookupSorted(i) => format!("s[{i}]"), - Column::LookupAggreg => "a".to_string(), - Column::LookupTable => "t".to_string(), - Column::LookupKindIndex(i) => format!("k[{i:?}]"), - Column::LookupRuntimeSelector => "rts".to_string(), - Column::LookupRuntimeTable => "rt".to_string(), - Column::Index(gate) => { - format!("{gate:?}") - } - Column::Coefficient(i) => format!("c[{i}]"), - Column::Permutation(i) => format!("sigma_[{i}]"), - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] /// A type representing a variable which can appear in a constraint. It specifies a column /// and a relative position (Curr or Next) @@ -280,28 +217,6 @@ pub struct Variable { pub row: CurrOrNext, } -impl Variable { - fn ocaml(&self) -> String { - format!("var({:?}, {:?})", self.col, self.row) - } - - fn latex(&self) -> String { - let col = self.col.latex(); - match self.row { - Curr => col, - Next => format!("\\tilde{{{col}}}"), - } - } - - fn text(&self) -> String { - let col = self.col.text(); - match self.row { - Curr => format!("Curr({col})"), - Next => format!("Next({col})"), - } - } -} - #[derive(Clone, Debug, PartialEq)] /// An arithmetic expression over /// @@ -714,9 +629,9 @@ pub trait ColumnEvaluations { } impl ColumnEvaluations for ProofEvaluations> { - type Column = Column; + type Column = berkeley_columns::Column; fn evaluate(&self, col: Self::Column) -> Result, ExprError> { - use Column::*; + use berkeley_columns::Column::*; match col { Witness(i) => Ok(self.w[i]), Z => Ok(self.z), @@ -920,7 +835,7 @@ impl Expr { } } -impl fmt::Display for Expr, Column> +impl fmt::Display for Expr, berkeley_columns::Column> where F: PrimeField, { @@ -2560,7 +2475,7 @@ where } } -impl Expr, Column> +impl Expr, berkeley_columns::Column> where F: PrimeField, { @@ -2587,7 +2502,10 @@ where /// Recursively print the expression, /// except for the cached expression that are stored in the `cache`. - fn ocaml(&self, cache: &mut HashMap, Column>>) -> String { + fn ocaml( + &self, + cache: &mut HashMap, berkeley_columns::Column>>, + ) -> String { use Expr::*; match self { Double(x) => format!("double({})", x.ocaml(cache)), @@ -2640,7 +2558,10 @@ where res } - fn latex(&self, cache: &mut HashMap, Column>>) -> String { + fn latex( + &self, + cache: &mut HashMap, berkeley_columns::Column>>, + ) -> String { use Expr::*; match self { Double(x) => format!("2 ({})", x.latex(cache)), @@ -2676,7 +2597,10 @@ where /// Recursively print the expression, /// except for the cached expression that are stored in the `cache`. - fn text(&self, cache: &mut HashMap, Column>>) -> String { + fn text( + &self, + cache: &mut HashMap, berkeley_columns::Column>>, + ) -> String { use Expr::*; match self { Double(x) => format!("double({})", x.text(cache)), @@ -2809,25 +2733,34 @@ pub mod constraints { fn cache(&self, cache: &mut Cache) -> Self; } - impl ExprOps for Expr, Column> + impl ExprOps for Expr, berkeley_columns::Column> where F: PrimeField, - Expr, Column>: std::fmt::Display, + Expr, berkeley_columns::Column>: std::fmt::Display, { fn two_pow(pow: u64) -> Self { - Expr::, Column>::literal(>::two_pow(pow)) + Expr::, berkeley_columns::Column>::literal(>::two_pow(pow)) } fn two_to_limb() -> Self { - Expr::, Column>::literal(>::two_to_limb()) + Expr::, berkeley_columns::Column>::literal(>::two_to_limb( + )) } fn two_to_2limb() -> Self { - Expr::, Column>::literal(>::two_to_2limb()) + Expr::, berkeley_columns::Column>::literal(>::two_to_2limb( + )) } fn two_to_3limb() -> Self { - Expr::, Column>::literal(>::two_to_3limb()) + Expr::, berkeley_columns::Column>::literal(>::two_to_3limb( + )) } fn double(&self) -> Self { @@ -2963,7 +2896,7 @@ pub mod constraints { // /// An alias for the intended usage of the expression type in constructing constraints. -pub type E = Expr, Column>; +pub type E = Expr, berkeley_columns::Column>; /// Convenience function to create a constant as [Expr]. pub fn constant(x: F) -> E { @@ -2972,7 +2905,7 @@ pub fn constant(x: F) -> E { /// Helper function to quickly create an expression for a witness. pub fn witness(i: usize, row: CurrOrNext) -> E { - E::::cell(Column::Witness(i), row) + E::::cell(berkeley_columns::Column::Witness(i), row) } /// Same as [witness] but for the current row. @@ -2987,11 +2920,11 @@ pub fn witness_next(i: usize) -> E { /// Handy function to quickly create an expression for a gate. pub fn index(g: GateType) -> E { - E::::cell(Column::Index(g), CurrOrNext::Curr) + E::::cell(berkeley_columns::Column::Index(g), CurrOrNext::Curr) } pub fn coeff(i: usize) -> E { - E::::cell(Column::Coefficient(i), CurrOrNext::Curr) + E::::cell(berkeley_columns::Column::Coefficient(i), CurrOrNext::Curr) } /// Auto clone macro - Helps make constraints more readable diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index 2ba98b08c4..3cbf3f34ad 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -1,6 +1,7 @@ use crate::{ circuits::{ - expr::{prologue::*, Column, ConstantExpr, RowOffset}, + berkeley_columns::Column, + expr::{prologue::*, ConstantExpr, RowOffset}, gate::{CircuitGate, CurrOrNext}, lookup::lookups::{ JointLookup, JointLookupSpec, JointLookupValue, LocalPosition, LookupInfo, diff --git a/kimchi/src/circuits/lookup/runtime_tables.rs b/kimchi/src/circuits/lookup/runtime_tables.rs index 98b018ed8a..f8123d75d8 100644 --- a/kimchi/src/circuits/lookup/runtime_tables.rs +++ b/kimchi/src/circuits/lookup/runtime_tables.rs @@ -2,10 +2,7 @@ //! The setup has to prepare for their presence using [`RuntimeTableCfg`]. //! At proving time, the prover can use [`RuntimeTable`] to specify the actual tables. -use crate::circuits::{ - expr::{prologue::*, Column}, - gate::CurrOrNext, -}; +use crate::circuits::{berkeley_columns::Column, expr::prologue::*, gate::CurrOrNext}; use ark_ff::Field; use serde::{Deserialize, Serialize}; diff --git a/kimchi/src/circuits/mod.rs b/kimchi/src/circuits/mod.rs index 83dbc91c63..7bad1cfd9f 100644 --- a/kimchi/src/circuits/mod.rs +++ b/kimchi/src/circuits/mod.rs @@ -2,6 +2,7 @@ pub mod macros; pub mod argument; +pub mod berkeley_columns; pub mod constraints; pub mod domain_constant_evaluation; pub mod domains; diff --git a/kimchi/src/circuits/polynomials/turshi.rs b/kimchi/src/circuits/polynomials/turshi.rs index da51465f92..645e5649c1 100644 --- a/kimchi/src/circuits/polynomials/turshi.rs +++ b/kimchi/src/circuits/polynomials/turshi.rs @@ -82,8 +82,9 @@ use crate::{ alphas::Alphas, circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, + berkeley_columns::Column, constraints::ConstraintSystem, - expr::{self, constraints::ExprOps, Cache, Column, E}, + expr::{self, constraints::ExprOps, Cache, E}, gate::{CircuitGate, GateType}, wires::{GateWires, Wire, COLUMNS}, }, diff --git a/kimchi/src/circuits/polynomials/varbasemul.rs b/kimchi/src/circuits/polynomials/varbasemul.rs index 0ed90e711c..c211fb1ef8 100644 --- a/kimchi/src/circuits/polynomials/varbasemul.rs +++ b/kimchi/src/circuits/polynomials/varbasemul.rs @@ -12,7 +12,8 @@ use crate::circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::{constraints::ExprOps, Cache, Column, Variable as VariableGen}, + berkeley_columns::Column, + expr::{constraints::ExprOps, Cache, Variable as VariableGen}, gate::{CircuitGate, CurrOrNext, GateType}, wires::{GateWires, COLUMNS}, }; diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 8c801fd38f..3c0b352eb7 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -73,13 +73,13 @@ pub enum VerifyError { IncorrectRuntimeProof, #[error("the evaluation for {0:?} is missing")] - MissingEvaluation(crate::circuits::expr::Column), + MissingEvaluation(crate::circuits::berkeley_columns::Column), #[error("the evaluation for PublicInput is missing")] MissingPublicInputEvaluation, #[error("the commitment for {0:?} is missing")] - MissingCommitment(crate::circuits::expr::Column), + MissingCommitment(crate::circuits::berkeley_columns::Column), } /// Errors that can arise when preparing the setup diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index b9657adedc..50218e1c05 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -23,8 +23,9 @@ use crate::circuits::polynomials::{ }; use crate::circuits::{ + berkeley_columns::Column, constraints::FeatureFlags, - expr::{Column, ConstantExpr, Expr, FeatureFlag, Linearization, PolishToken}, + expr::{ConstantExpr, Expr, FeatureFlag, Linearization, PolishToken}, gate::GateType, wires::COLUMNS, }; diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 5829178786..f7ace0c5fd 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -1,7 +1,7 @@ //! This module implements the data structures of a proof. use crate::circuits::{ - expr::Column, + berkeley_columns::Column, gate::GateType, lookup::lookups::LookupPattern, wires::{COLUMNS, PERMUTS}, diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index 42fe06c1e9..05db4f5b6b 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -3,8 +3,9 @@ use crate::{ alphas::Alphas, circuits::{ + berkeley_columns::Column, constraints::{ColumnEvaluations, ConstraintSystem}, - expr::{Column, Linearization, PolishToken}, + expr::{Linearization, PolishToken}, }, curve::KimchiCurve, linearization::expr_linearization, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 0c9cd4aef3..3a9fc386a1 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -3,8 +3,9 @@ use crate::{ circuits::{ argument::ArgumentType, + berkeley_columns::Column, constraints::ConstraintSystem, - expr::{Column, Constants, PolishToken}, + expr::{Constants, PolishToken}, gate::GateType, lookup::{lookups::LookupPattern, tables::combine_table}, polynomials::permutation, diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 8f6b664974..ff4aaca48a 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -4,7 +4,8 @@ use crate::{ alphas::Alphas, circuits::{ - expr::{Column, Linearization, PolishToken}, + berkeley_columns::Column, + expr::{Linearization, PolishToken}, lookup::{index::LookupSelectors, lookups::LookupInfo}, polynomials::permutation::{vanishes_on_last_n_rows, zk_w}, wires::{COLUMNS, PERMUTS}, From ce6fdfa17c459a3a4adc53bd71857c9ac3081c89 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Thu, 30 Mar 2023 07:02:33 +0100 Subject: [PATCH 193/242] Move ColumnEvaluations to berkeley_columns --- kimchi/src/circuits/berkeley_columns.rs | 74 +++++++++++++++++++++++-- kimchi/src/circuits/expr.rs | 65 +--------------------- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs index 1224744a6b..6558f4c367 100644 --- a/kimchi/src/circuits/berkeley_columns.rs +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -1,7 +1,10 @@ -use crate::circuits::{ - expr::{self, Domain, GenericColumn}, - gate::{CurrOrNext, GateType}, - lookup::lookups::LookupPattern, +use crate::{ + circuits::{ + expr::{self, ColumnEvaluations, Domain, ExprError, GenericColumn}, + gate::{CurrOrNext, GateType}, + lookup::lookups::LookupPattern, + }, + proof::{PointEvaluations, ProofEvaluations}, }; use serde::{Deserialize, Serialize}; use CurrOrNext::{Curr, Next}; @@ -91,3 +94,66 @@ impl expr::Variable { } } } + +impl ColumnEvaluations for ProofEvaluations> { + type Column = Column; + fn evaluate(&self, col: Self::Column) -> Result, ExprError> { + use Column::*; + match col { + Witness(i) => Ok(self.w[i]), + Z => Ok(self.z), + LookupSorted(i) => self.lookup_sorted[i].ok_or(ExprError::MissingIndexEvaluation(col)), + LookupAggreg => self + .lookup_aggregation + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupTable => self + .lookup_table + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupRuntimeTable => self + .runtime_lookup_table + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::Poseidon) => Ok(self.poseidon_selector), + Index(GateType::Generic) => Ok(self.generic_selector), + Index(GateType::CompleteAdd) => Ok(self.complete_add_selector), + Index(GateType::VarBaseMul) => Ok(self.mul_selector), + Index(GateType::EndoMul) => Ok(self.emul_selector), + Index(GateType::EndoMulScalar) => Ok(self.endomul_scalar_selector), + Index(GateType::RangeCheck0) => self + .range_check0_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::RangeCheck1) => self + .range_check1_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::ForeignFieldAdd) => self + .foreign_field_add_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::ForeignFieldMul) => self + .foreign_field_mul_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::Xor16) => self + .xor_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(GateType::Rot64) => self + .rot_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Permutation(i) => Ok(self.s[i]), + Coefficient(i) => Ok(self.coefficients[i]), + LookupKindIndex(LookupPattern::Xor) => self + .xor_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::Lookup) => self + .lookup_gate_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::RangeCheck) => self + .range_check_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::ForeignFieldMul) => self + .foreign_field_mul_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupRuntimeSelector => self + .runtime_lookup_table_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + Index(_) => Err(ExprError::MissingIndexEvaluation(col)), + } + } +} diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index d84512d5fe..defdae6b13 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -11,7 +11,7 @@ use crate::{ polynomials::permutation::eval_vanishes_on_last_n_rows, wires::COLUMNS, }, - proof::{PointEvaluations, ProofEvaluations}, + proof::PointEvaluations, }; use ark_ff::{FftField, Field, One, PrimeField, Zero}; use ark_poly::{ @@ -628,69 +628,6 @@ pub trait ColumnEvaluations { fn evaluate(&self, col: Self::Column) -> Result, ExprError>; } -impl ColumnEvaluations for ProofEvaluations> { - type Column = berkeley_columns::Column; - fn evaluate(&self, col: Self::Column) -> Result, ExprError> { - use berkeley_columns::Column::*; - match col { - Witness(i) => Ok(self.w[i]), - Z => Ok(self.z), - LookupSorted(i) => self.lookup_sorted[i].ok_or(ExprError::MissingIndexEvaluation(col)), - LookupAggreg => self - .lookup_aggregation - .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupTable => self - .lookup_table - .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupRuntimeTable => self - .runtime_lookup_table - .ok_or(ExprError::MissingIndexEvaluation(col)), - Index(GateType::Poseidon) => Ok(self.poseidon_selector), - Index(GateType::Generic) => Ok(self.generic_selector), - Index(GateType::CompleteAdd) => Ok(self.complete_add_selector), - Index(GateType::VarBaseMul) => Ok(self.mul_selector), - Index(GateType::EndoMul) => Ok(self.emul_selector), - Index(GateType::EndoMulScalar) => Ok(self.endomul_scalar_selector), - Index(GateType::RangeCheck0) => self - .range_check0_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - Index(GateType::RangeCheck1) => self - .range_check1_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - Index(GateType::ForeignFieldAdd) => self - .foreign_field_add_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - Index(GateType::ForeignFieldMul) => self - .foreign_field_mul_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - Index(GateType::Xor16) => self - .xor_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - Index(GateType::Rot64) => self - .rot_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - Permutation(i) => Ok(self.s[i]), - Coefficient(i) => Ok(self.coefficients[i]), - LookupKindIndex(LookupPattern::Xor) => self - .xor_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupKindIndex(LookupPattern::Lookup) => self - .lookup_gate_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupKindIndex(LookupPattern::RangeCheck) => self - .range_check_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupKindIndex(LookupPattern::ForeignFieldMul) => self - .foreign_field_mul_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupRuntimeSelector => self - .runtime_lookup_table_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - Index(_) => Err(ExprError::MissingIndexEvaluation(col)), - } - } -} - impl Variable { fn evaluate>( &self, From 5ab1b2d6a990dc06f6b630d7d832eb60ba4af630 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 17:41:16 +0100 Subject: [PATCH 194/242] Use unwrap instead of empty string expects --- optimism/src/main.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/optimism/src/main.rs b/optimism/src/main.rs index 6989806a70..32c86b9f9e 100644 --- a/optimism/src/main.rs +++ b/optimism/src/main.rs @@ -61,25 +61,19 @@ fn cli() -> VmConfiguration { let cli = cli.get_matches(); - let input_state_file = cli - .get_one::("input") - .expect("Default ensures there is always a value"); + let input_state_file = cli.get_one::("input").unwrap(); - let output_state_file = cli - .get_one::("output") - .expect("Default ensures there is always a value"); + let output_state_file = cli.get_one::("output").unwrap(); - let metadata_file = cli - .get_one::("meta") - .expect("Default ensures there is always a value"); + let metadata_file = cli.get_one::("meta").unwrap(); - let proof_at = cli.get_one::("proof-at").expect(""); - let info_at = cli.get_one::("info-at").expect(""); - let stop_at = cli.get_one::("stop-at").expect(""); + let proof_at = cli.get_one::("proof-at").unwrap(); + let info_at = cli.get_one::("info-at").unwrap(); + let stop_at = cli.get_one::("stop-at").unwrap(); - let proof_fmt = cli.get_one::("proof-fmt").expect(""); - let snapshot_fmt = cli.get_one::("snapshot-fmt").expect(""); - let pprof_cpu = cli.get_one::("pprof-cpu").expect(""); + let proof_fmt = cli.get_one::("proof-fmt").unwrap(); + let snapshot_fmt = cli.get_one::("snapshot-fmt").unwrap(); + let pprof_cpu = cli.get_one::("pprof-cpu").unwrap(); let host_spec = cli .get_many::("host") @@ -118,7 +112,7 @@ pub fn main() -> ExitCode { println!("configuration\n{:#?}", configuration); - let file = File::open(configuration.input_state_file).expect("file"); + let file = File::open(configuration.input_state_file).expect("Error opening input state file "); let reader = BufReader::new(file); // Read the JSON contents of the file as an instance of `State`. From a5f48d1dab3d23a4d26369697814cc05f3248307 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 17:48:06 +0100 Subject: [PATCH 195/242] Mini readme --- optimism/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 optimism/README.md diff --git a/optimism/README.md b/optimism/README.md new file mode 100644 index 0000000000..2dbf25c375 --- /dev/null +++ b/optimism/README.md @@ -0,0 +1,18 @@ +To run the demo: +* create an executable file `rpcs.sh` that looks like + ```bash + #!/usr/bin/env bash + export L1RPC=http://xxxxxxxxx + export L2RPC=http://xxxxxxxxx + ``` +* run the `run-code.sh` script. + +This will +* generate the initial state, +* execute the OP program, +* execute the OP program through the cannon MIPS VM, +* execute the OP program through the kimchi MIPS VM prover. + +The initial state will be output to a file with format `YYYY-MM-DD-HH-MM-SS-op-program-data-log.sh`. + +If you want to re-run against an existing state, pass the environment variable `FILENAME=YYYY-MM-DD-HH-MM-SS-op-program-data-log.sh` to the `run-code.sh` script. From c7254f725b5a802d53853232cc0680f8d03c44d1 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 17:49:01 +0100 Subject: [PATCH 196/242] Update script to use env --- optimism/generate-config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optimism/generate-config.sh b/optimism/generate-config.sh index e71f8a90ed..3e8dae0221 100755 --- a/optimism/generate-config.sh +++ b/optimism/generate-config.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail source rpcs.sh From cbf3b56c834b6232d9da4c19fe337b0c18d50ebf Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 17:55:37 +0100 Subject: [PATCH 197/242] Clippy!!!!! --- kimchi/src/circuits/expr.rs | 4 ++-- kimchi/src/linearization.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index defdae6b13..cd0e5ec2ef 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -167,7 +167,7 @@ impl<'a, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, F> { } fn vanishes_on_zero_knowledge_and_previous_rows(&self) -> &'a Evaluations> { - &self.vanishes_on_zero_knowledge_and_previous_rows + self.vanishes_on_zero_knowledge_and_previous_rows } fn l0_1(&self) -> F { @@ -1468,7 +1468,7 @@ impl Expr evals: &Evaluations, env: &Environment, ) -> Result> { - self.evaluate_(d, pt, evals, &env.get_constants()) + self.evaluate_(d, pt, evals, env.get_constants()) } /// Evaluate an expression as a field element against the constants. diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 50218e1c05..65ffe41284 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -337,6 +337,7 @@ pub fn linearization_columns( /// # Panics /// /// Will panic if the `linearization` process fails. +#[allow(clippy::type_complexity)] pub fn expr_linearization( feature_flags: Option<&FeatureFlags>, generic: bool, From 0a0b8b33b7cf75fd0fba5c20a46716c1d2c734b8 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 24 Oct 2023 20:13:28 +0200 Subject: [PATCH 198/242] Implement deserializer --- optimism/Cargo.toml | 2 ++ optimism/src/cannon.rs | 20 ++++++++++++++++++-- optimism/src/main.rs | 4 +--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/optimism/Cargo.toml b/optimism/Cargo.toml index f1edb563cd..55fe049a9a 100644 --- a/optimism/Cargo.toml +++ b/optimism/Cargo.toml @@ -28,3 +28,5 @@ ark-ff = { version = "0.3.0", features = [ "parallel" ] } clap = "4.4.6" hex = "0.4.3" regex = "1.10.2" +libflate = "2" +base64 = "0.21.5" diff --git a/optimism/src/cannon.rs b/optimism/src/cannon.rs index c7693f3cab..3ccd9a152f 100644 --- a/optimism/src/cannon.rs +++ b/optimism/src/cannon.rs @@ -1,12 +1,28 @@ // Data structure and stuff for compatibility with Cannon +use base64::{engine::general_purpose, Engine as _}; +use libflate::zlib::Decoder; use regex::Regex; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; +use std::io::Read; #[derive(Serialize, Deserialize, Debug)] pub struct Page { pub index: u32, - pub data: String, + #[serde(deserialize_with = "from_base64")] + pub data: Vec, +} + +fn from_base64<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let s: String = Deserialize::deserialize(deserializer)?; + let b64_decoded = general_purpose::STANDARD.decode(s).unwrap(); + let mut decoder = Decoder::new(&b64_decoded[..]).unwrap(); + let mut data = Vec::new(); + decoder.read_to_end(&mut data).unwrap(); + Ok(data) } // The renaming below keeps compatibility with OP Cannon's state format diff --git a/optimism/src/main.rs b/optimism/src/main.rs index 32c86b9f9e..78f9d837d6 100644 --- a/optimism/src/main.rs +++ b/optimism/src/main.rs @@ -116,7 +116,7 @@ pub fn main() -> ExitCode { let reader = BufReader::new(file); // Read the JSON contents of the file as an instance of `State`. - let state: State = serde_json::from_reader(reader).expect("Error reading input state file"); + let _state: State = serde_json::from_reader(reader).expect("Error reading input state file"); if let Some(host_program) = configuration.host { println!("Launching host program {}", host_program.name); @@ -127,8 +127,6 @@ pub fn main() -> ExitCode { .expect("Could not spawn host process"); }; - println!("{}", state.to_string()); - // TODO: Logic ExitCode::FAILURE } From 9d714610a85174fbb298e145046a87c1cd95e7ad Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 24 Oct 2023 20:13:41 +0200 Subject: [PATCH 199/242] Update cargo.lock --- Cargo.lock | 174 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 134 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03396e2f2a..1a8d682020 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "ahash" version = "0.7.6" @@ -28,6 +34,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.0.2" @@ -204,7 +222,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd4e5f0bf8285d5ed538d27fab7411f3e297908fd93c62195de8bee3f199e82" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", ] @@ -238,7 +256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87bf87e6e8b47264efa9bde63d6225c6276a52e05e91bf37eaa8afd0032d6b71" dependencies = [ "askama_shared", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "syn 1.0.109", ] @@ -261,7 +279,7 @@ dependencies = [ "nom", "num-traits", "percent-encoding", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "serde", "syn 1.0.109", @@ -302,9 +320,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bcs" @@ -502,7 +520,7 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", ] @@ -590,6 +608,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.9" @@ -748,7 +775,7 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "strsim 0.10.0", "syn 1.0.109", @@ -765,13 +792,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dary_heap" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" + [[package]] name = "derivative" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", ] @@ -890,9 +923,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", @@ -994,7 +1027,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash", + "ahash 0.7.6", ] [[package]] @@ -1003,7 +1036,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.5", ] [[package]] @@ -1252,11 +1294,13 @@ version = "0.1.0" dependencies = [ "ark-ff", "ark-poly", + "base64", "clap 4.4.6", "elf", "groupmap", "hex", "kimchi", + "libflate", "mina-curves", "mina-poseidon", "poly-commitment", @@ -1285,6 +1329,30 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libflate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7d5654ae1795afc7ff76f4365c2c8791b0feb18e8996a96adad8ffd7c3b2bf" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5f52fb8c451576ec6b79d3f4deb327398bc05bbdbd99021a6e77a4c855d524" +dependencies = [ + "core2", + "hashbrown 0.13.2", + "rle-decode-fast", +] + [[package]] name = "libm" version = "0.2.7" @@ -1365,7 +1433,7 @@ version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b5bc45b761bcf1b5e6e6c4128cd93b84c218721a8d9b894aa0aff4ed180174c" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", ] @@ -1572,7 +1640,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", ] @@ -1667,7 +1735,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40aa99a001268b85eb18414ecd190dc21fceaeaf81214ca28233b6feb25a998" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", "synstructure", @@ -1692,7 +1760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1894efdef5c9d83d17932c5f5db16d16eb5c8ae1a625ce44d9d1715e85d9d8dc" dependencies = [ "convert_case", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", ] @@ -1803,9 +1871,9 @@ checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", - "syn 2.0.25", + "syn 2.0.38", ] [[package]] @@ -1909,7 +1977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", "version_check", @@ -1921,7 +1989,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "version_check", ] @@ -1943,9 +2011,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -2011,7 +2079,7 @@ version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", ] [[package]] @@ -2134,6 +2202,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + [[package]] name = "rmp" version = "0.8.11" @@ -2304,9 +2378,9 @@ version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", - "syn 2.0.25", + "syn 2.0.38", ] [[package]] @@ -2337,7 +2411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", ] @@ -2405,7 +2479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "rustversion", "syn 1.0.109", @@ -2462,18 +2536,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.25" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "unicode-ident", ] @@ -2484,7 +2558,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", "syn 1.0.109", "unicode-xid 0.2.4", @@ -2593,9 +2667,9 @@ version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", - "syn 2.0.25", + "syn 2.0.38", ] [[package]] @@ -2806,9 +2880,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", - "syn 2.0.25", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -2828,9 +2902,9 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", - "syn 2.0.25", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2997,6 +3071,26 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "zerocopy" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8db0ac2df3d060f81ec0380ccc5b71c2a7c092cfced671feeee1320e95559c87" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b6093bc6d5265ff40b479c834cdd25d8e20784781a2a29a8106327393d0a9ff" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.29", + "syn 2.0.38", +] + [[package]] name = "zeroize" version = "1.6.0" @@ -3012,7 +3106,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.64", + "proc-macro2 1.0.69", "quote 1.0.29", - "syn 2.0.25", + "syn 2.0.38", ] From 44891fb8dd28a3b86de81bd179f1f7e5b1bd9825 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 24 Oct 2023 20:35:27 +0200 Subject: [PATCH 200/242] Check page size --- optimism/src/cannon.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/optimism/src/cannon.rs b/optimism/src/cannon.rs index 3ccd9a152f..6b0049c040 100644 --- a/optimism/src/cannon.rs +++ b/optimism/src/cannon.rs @@ -6,6 +6,8 @@ use regex::Regex; use serde::{Deserialize, Deserializer, Serialize}; use std::io::Read; +pub const PAGE_SIZE: usize = 4096; + #[derive(Serialize, Deserialize, Debug)] pub struct Page { pub index: u32, @@ -22,6 +24,7 @@ where let mut decoder = Decoder::new(&b64_decoded[..]).unwrap(); let mut data = Vec::new(); decoder.read_to_end(&mut data).unwrap(); + assert_eq!(data.len(), PAGE_SIZE); Ok(data) } From fafd2a4992eb0a0157cb6bd76ecad670ab23e367 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Tue, 24 Oct 2023 19:34:33 +0100 Subject: [PATCH 201/242] Add initial witness::Env --- Cargo.lock | 1 + optimism/Cargo.toml | 3 +- optimism/src/lib.rs | 1 + optimism/src/main.rs | 15 +++++- optimism/src/mips/mod.rs | 2 + optimism/src/mips/registers.rs | 47 ++++++++++++++++ optimism/src/mips/witness.rs | 99 ++++++++++++++++++++++++++++++++++ 7 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 optimism/src/mips/mod.rs create mode 100644 optimism/src/mips/registers.rs create mode 100644 optimism/src/mips/witness.rs diff --git a/Cargo.lock b/Cargo.lock index 1a8d682020..77da43c308 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1292,6 +1292,7 @@ dependencies = [ name = "kimchi_optimism" version = "0.1.0" dependencies = [ + "ark-bn254", "ark-ff", "ark-poly", "base64", diff --git a/optimism/Cargo.toml b/optimism/Cargo.toml index 55fe049a9a..da634f3030 100644 --- a/optimism/Cargo.toml +++ b/optimism/Cargo.toml @@ -13,7 +13,8 @@ license = "Apache-2.0" path = "src/lib.rs" [dependencies] -kimchi = { path = "../kimchi", version = "0.1.0" } +ark-bn254 = { version = "0.3.0" } +kimchi = { path = "../kimchi", version = "0.1.0", features = [ "bn254" ] } poly-commitment = { path = "../poly-commitment", version = "0.1.0" } groupmap = { path = "../groupmap", version = "0.1.0" } mina-curves = { path = "../curves", version = "0.1.0" } diff --git a/optimism/src/lib.rs b/optimism/src/lib.rs index 3bec498068..da4f2ad95d 100644 --- a/optimism/src/lib.rs +++ b/optimism/src/lib.rs @@ -1 +1,2 @@ pub mod cannon; +pub mod mips; diff --git a/optimism/src/main.rs b/optimism/src/main.rs index 78f9d837d6..732ceddb3d 100644 --- a/optimism/src/main.rs +++ b/optimism/src/main.rs @@ -1,5 +1,8 @@ use clap::{arg, value_parser, Arg, ArgAction, Command}; -use kimchi_optimism::cannon::{State, VmConfiguration}; +use kimchi_optimism::{ + cannon::{State, VmConfiguration}, + mips::witness, +}; use std::{fs::File, io::BufReader, process::ExitCode}; fn cli() -> VmConfiguration { @@ -116,7 +119,7 @@ pub fn main() -> ExitCode { let reader = BufReader::new(file); // Read the JSON contents of the file as an instance of `State`. - let _state: State = serde_json::from_reader(reader).expect("Error reading input state file"); + let state: State = serde_json::from_reader(reader).expect("Error reading input state file"); if let Some(host_program) = configuration.host { println!("Launching host program {}", host_program.name); @@ -127,6 +130,14 @@ pub fn main() -> ExitCode { .expect("Could not spawn host process"); }; + let page_size = 1 << 12; + + let mut env = witness::Env::::create(page_size, state); + + while !env.halt { + env.step(); + } + // TODO: Logic ExitCode::FAILURE } diff --git a/optimism/src/mips/mod.rs b/optimism/src/mips/mod.rs new file mode 100644 index 0000000000..2499222bb4 --- /dev/null +++ b/optimism/src/mips/mod.rs @@ -0,0 +1,2 @@ +pub mod registers; +pub mod witness; diff --git a/optimism/src/mips/registers.rs b/optimism/src/mips/registers.rs new file mode 100644 index 0000000000..89a1ee23b8 --- /dev/null +++ b/optimism/src/mips/registers.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; +use std::ops::{Index, IndexMut}; + +pub const NUM_REGISTERS: usize = 34; + +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +pub struct Registers { + pub general_purpose: [T; 32], + pub hi: T, + pub lo: T, +} + +impl Registers { + pub fn iter(&self) -> impl Iterator { + self.general_purpose.iter().chain([&self.hi, &self.lo]) + } +} + +impl Index for Registers { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + if index < 32 { + &self.general_purpose[index] + } else if index == 32 { + &self.hi + } else if index == 33 { + &self.lo + } else { + panic!("Index out of bounds"); + } + } +} + +impl IndexMut for Registers { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + if index < 32 { + &mut self.general_purpose[index] + } else if index == 32 { + &mut self.hi + } else if index == 33 { + &mut self.lo + } else { + panic!("Index out of bounds"); + } + } +} diff --git a/optimism/src/mips/witness.rs b/optimism/src/mips/witness.rs new file mode 100644 index 0000000000..dbaa7b30a8 --- /dev/null +++ b/optimism/src/mips/witness.rs @@ -0,0 +1,99 @@ +use crate::{cannon::State, mips::registers::Registers}; +use ark_ff::Field; +use std::array; + +pub const NUM_GLOBAL_LOOKUP_TERMS: usize = 1; +pub const NUM_DECODING_LOOKUP_TERMS: usize = 2; +pub const NUM_INSTRUCTION_LOOKUP_TERMS: usize = 5; +pub const NUM_LOOKUP_TERMS: usize = + NUM_GLOBAL_LOOKUP_TERMS + NUM_DECODING_LOOKUP_TERMS + NUM_INSTRUCTION_LOOKUP_TERMS; +pub const SCRATCH_SIZE: usize = 25; + +#[derive(Clone)] +pub struct SyscallEnv { + pub heap: u32, // Heap pointer (actually unused in Cannon as of [2023-10-18]) + pub preimage_offset: u32, + pub preimage_key: Vec, + pub last_hint: Option>, +} + +impl SyscallEnv { + pub fn create(state: &State) -> Self { + SyscallEnv { + heap: state.heap, + preimage_key: state.preimage_key.as_bytes().to_vec(), // Might not be correct + preimage_offset: state.preimage_offset, + last_hint: state.last_hint.clone(), + } + } +} + +#[derive(Clone)] +pub struct Env { + pub instruction_counter: usize, + pub memory: Vec<(u32, Vec)>, + pub memory_write_index: Vec<(u32, Vec)>, + pub registers: Registers, + pub registers_write_index: Registers, + pub instruction_pointer: u32, + pub scratch_state_idx: usize, + pub scratch_state: [Fp; SCRATCH_SIZE], + pub halt: bool, + pub syscall_env: SyscallEnv, +} + +fn fresh_scratch_state() -> [Fp; N] { + array::from_fn(|_| Fp::zero()) +} + +impl Env { + pub fn create(page_size: usize, state: State) -> Self { + let initial_instruction_pointer = state.pc; + + let syscall_env = SyscallEnv::create(&state); + + let mut initial_memory: Vec<(u32, Vec)> = state + .memory + .into_iter() + // Check that the conversion from page data is correct + .map(|page| (page.index, page.data)) + .collect(); + + for (_address, initial_memory) in initial_memory.iter_mut() { + initial_memory.extend((0..(page_size - initial_memory.len())).map(|_| 0u8)); + assert_eq!(initial_memory.len(), page_size); + } + + let memory_offsets = initial_memory + .iter() + .map(|(offset, _)| *offset) + .collect::>(); + + let initial_registers = Registers { + lo: state.lo, + hi: state.hi, + general_purpose: state.registers, + }; + + Env { + instruction_counter: state.step as usize, + memory: initial_memory.clone(), + memory_write_index: memory_offsets + .iter() + .map(|offset| (*offset, vec![0usize; page_size])) + .collect(), + registers: initial_registers.clone(), + registers_write_index: Registers::default(), + instruction_pointer: initial_instruction_pointer, + scratch_state_idx: 0, + scratch_state: fresh_scratch_state(), + halt: state.exited, + syscall_env, + } + } + + pub fn step(&mut self) { + // TODO + self.halt = true; + } +} From bd2e00960999b0deee8164789b8c5eaab68e7c03 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 25 Oct 2023 11:21:15 +0200 Subject: [PATCH 202/242] add support for trivial rotation by 0 and 64 --- kimchi/src/circuits/polynomials/rot.rs | 6 ++---- kimchi/src/tests/rot.rs | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/kimchi/src/circuits/polynomials/rot.rs b/kimchi/src/circuits/polynomials/rot.rs index d529670d13..9683d765d5 100644 --- a/kimchi/src/circuits/polynomials/rot.rs +++ b/kimchi/src/circuits/polynomials/rot.rs @@ -328,8 +328,6 @@ pub fn extend_rot( rot: u32, side: RotMode, ) { - assert!(rot < 64, "Rotation value must be less than 64"); - assert_ne!(rot, 0, "Rotation value must be non-zero"); let rot = if side == RotMode::Right { 64 - rot } else { @@ -343,8 +341,8 @@ pub fn extend_rot( // shifted [------] * 2^rot // rot = [------|000] // + [---] excess - let shifted = (word as u128 * 2u128.pow(rot) % 2u128.pow(64)) as u64; - let excess = word / 2u64.pow(64 - rot); + let shifted = (word as u128) * 2u128.pow(rot) % 2u128.pow(64); + let excess = (word as u128) / 2u128.pow(64 - rot); let rotated = shifted + excess; // Value for the added value for the bound // Right input of the "FFAdd" for the bound equation diff --git a/kimchi/src/tests/rot.rs b/kimchi/src/tests/rot.rs index 8d8ee17f97..0b037cc15e 100644 --- a/kimchi/src/tests/rot.rs +++ b/kimchi/src/tests/rot.rs @@ -169,22 +169,20 @@ fn test_rot_random() { test_rot::(word, rot, RotMode::Right); } -#[should_panic] #[test] // Test that a bad rotation fails as expected fn test_zero_rot() { let rng = &mut StdRng::from_seed(RNG_SEED); let word = rng.gen_range(0..2u128.pow(64)) as u64; - create_rot_witness::(word, 0, RotMode::Left); + test_rot::(word, 0, RotMode::Left); } -#[should_panic] #[test] // Test that a bad rotation fails as expected fn test_large_rot() { let rng = &mut StdRng::from_seed(RNG_SEED); let word = rng.gen_range(0..2u128.pow(64)) as u64; - create_rot_witness::(word, 64, RotMode::Left); + test_rot::(word, 64, RotMode::Left); } #[test] From 5eb5fcc7b6368c5ee517d457b67fe6eaa3fbb68d Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 11:01:49 +0200 Subject: [PATCH 203/242] update assert to force <= 64 rotation offset --- kimchi/src/circuits/polynomials/rot.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kimchi/src/circuits/polynomials/rot.rs b/kimchi/src/circuits/polynomials/rot.rs index 9683d765d5..f7cae6c7eb 100644 --- a/kimchi/src/circuits/polynomials/rot.rs +++ b/kimchi/src/circuits/polynomials/rot.rs @@ -328,6 +328,8 @@ pub fn extend_rot( rot: u32, side: RotMode, ) { + assert!(rot <= 64, "Rotation value must be less or equal than 64"); + let rot = if side == RotMode::Right { 64 - rot } else { From facc966c2e4bd68dbcaee783270a375e404cd934 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 18:59:17 +0200 Subject: [PATCH 204/242] make WitnessCell variable generic to be F by default --- .../circuits/polynomials/foreign_field_add/witness.rs | 4 ++-- .../circuits/polynomials/foreign_field_mul/witness.rs | 2 +- kimchi/src/circuits/polynomials/range_check/witness.rs | 4 ++-- kimchi/src/circuits/polynomials/rot.rs | 4 ++-- kimchi/src/circuits/polynomials/xor.rs | 9 +++------ kimchi/src/circuits/witness/constant_cell.rs | 2 +- kimchi/src/circuits/witness/copy_bits_cell.rs | 2 +- kimchi/src/circuits/witness/copy_cell.rs | 2 +- kimchi/src/circuits/witness/copy_shift_cell.rs | 2 +- kimchi/src/circuits/witness/mod.rs | 9 +++++---- kimchi/src/circuits/witness/variable_bits_cell.rs | 2 +- kimchi/src/circuits/witness/variable_cell.rs | 2 +- 12 files changed, 21 insertions(+), 23 deletions(-) diff --git a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs index 57af9b6ff0..40f08e013b 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs @@ -185,7 +185,7 @@ fn init_ffadd_row( overflow: F, carry: F, ) { - let layout: [Vec>>; 1] = [ + let layout: [Vec>>; 1] = [ // ForeignFieldAdd row vec![ VariableCell::create("left_lo"), @@ -221,7 +221,7 @@ fn init_bound_rows( bound: &[F; 3], carry: &F, ) { - let layout: [Vec>>; 2] = [ + let layout: [Vec>>; 2] = [ vec![ // ForeignFieldAdd row VariableCell::create("result_lo"), diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs index 50fb4d2305..ef0fc02a26 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs @@ -41,7 +41,7 @@ use super::circuitgates; // // so that most significant limb, q2, is in W[2][0]. // -fn create_layout() -> [Vec>>; 2] { +fn create_layout() -> [Vec>>; 2] { [ // ForeignFieldMul row vec![ diff --git a/kimchi/src/circuits/polynomials/range_check/witness.rs b/kimchi/src/circuits/polynomials/range_check/witness.rs index e6fd60987f..55d99b2b7f 100644 --- a/kimchi/src/circuits/polynomials/range_check/witness.rs +++ b/kimchi/src/circuits/polynomials/range_check/witness.rs @@ -29,7 +29,7 @@ use o1_utils::foreign_field::BigUintForeignFieldHelpers; /// For example, we can convert the `RangeCheck0` circuit gate into /// a 64-bit lookup by adding two copy constraints to constrain /// columns 1 and 2 to zero. -fn layout() -> [Vec>>; 4] { +fn layout() -> [Vec>>; 4] { [ /* row 1, RangeCheck0 row */ range_check_0_row("v0", 0), @@ -86,7 +86,7 @@ fn layout() -> [Vec>>; 4] { pub fn range_check_0_row( limb_name: &'static str, row: usize, -) -> Vec>> { +) -> Vec>> { vec![ VariableCell::create(limb_name), /* 12-bit copies */ diff --git a/kimchi/src/circuits/polynomials/rot.rs b/kimchi/src/circuits/polynomials/rot.rs index a0bc442a24..8b72a94e95 100644 --- a/kimchi/src/circuits/polynomials/rot.rs +++ b/kimchi/src/circuits/polynomials/rot.rs @@ -266,7 +266,7 @@ where // ROTATION WITNESS COMPUTATION -fn layout_rot64(curr_row: usize) -> [Vec>>; 3] { +fn layout_rot64(curr_row: usize) -> [Vec>>; 3] { [ rot_row(), range_check_0_row("shifted", curr_row + 1), @@ -274,7 +274,7 @@ fn layout_rot64(curr_row: usize) -> [Vec() -> Vec>> { +fn rot_row() -> Vec>> { vec![ VariableCell::create("word"), VariableCell::create("rotated"), diff --git a/kimchi/src/circuits/polynomials/xor.rs b/kimchi/src/circuits/polynomials/xor.rs index a7913f92a7..d7276cee12 100644 --- a/kimchi/src/circuits/polynomials/xor.rs +++ b/kimchi/src/circuits/polynomials/xor.rs @@ -172,7 +172,7 @@ where fn layout( curr_row: usize, bits: usize, -) -> Vec>>> { +) -> Vec>>> { let num_xor = num_xors(bits); let mut layout = (0..num_xor) .map(|i| xor_row(i, curr_row + i)) @@ -181,10 +181,7 @@ fn layout( layout } -fn xor_row( - nybble: usize, - curr_row: usize, -) -> Vec>> { +fn xor_row(nybble: usize, curr_row: usize) -> Vec>> { let start = nybble * 16; vec![ VariableBitsCell::create("in1", start, None), @@ -205,7 +202,7 @@ fn xor_row( ] } -fn zero_row() -> Vec>> { +fn zero_row() -> Vec>> { vec![ ConstantCell::create(F::zero()), ConstantCell::create(F::zero()), diff --git a/kimchi/src/circuits/witness/constant_cell.rs b/kimchi/src/circuits/witness/constant_cell.rs index ea14b5de8c..1ec69d797c 100644 --- a/kimchi/src/circuits/witness/constant_cell.rs +++ b/kimchi/src/circuits/witness/constant_cell.rs @@ -13,7 +13,7 @@ impl ConstantCell { } } -impl WitnessCell for ConstantCell { +impl WitnessCell for ConstantCell { fn value(&self, _witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { self.value } diff --git a/kimchi/src/circuits/witness/copy_bits_cell.rs b/kimchi/src/circuits/witness/copy_bits_cell.rs index 964e2f26bf..e97eed7940 100644 --- a/kimchi/src/circuits/witness/copy_bits_cell.rs +++ b/kimchi/src/circuits/witness/copy_bits_cell.rs @@ -23,7 +23,7 @@ impl CopyBitsCell { } } -impl WitnessCell for CopyBitsCell { +impl WitnessCell for CopyBitsCell { fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { F::from_bits(&witness[self.col][self.row].to_bits()[self.start..self.end]) .expect("failed to deserialize field bits for copy bits cell") diff --git a/kimchi/src/circuits/witness/copy_cell.rs b/kimchi/src/circuits/witness/copy_cell.rs index ffa8339094..f5b75ad829 100644 --- a/kimchi/src/circuits/witness/copy_cell.rs +++ b/kimchi/src/circuits/witness/copy_cell.rs @@ -15,7 +15,7 @@ impl CopyCell { } } -impl WitnessCell for CopyCell { +impl WitnessCell for CopyCell { fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { witness[self.col][self.row] } diff --git a/kimchi/src/circuits/witness/copy_shift_cell.rs b/kimchi/src/circuits/witness/copy_shift_cell.rs index b0ed5d055a..e151d0cd57 100644 --- a/kimchi/src/circuits/witness/copy_shift_cell.rs +++ b/kimchi/src/circuits/witness/copy_shift_cell.rs @@ -15,7 +15,7 @@ impl CopyShiftCell { } } -impl WitnessCell for CopyShiftCell { +impl WitnessCell for CopyShiftCell { fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { F::from(2u32).pow([self.shift]) * witness[self.col][self.row] } diff --git a/kimchi/src/circuits/witness/mod.rs b/kimchi/src/circuits/witness/mod.rs index 8dad3a2a40..daea8be7fa 100644 --- a/kimchi/src/circuits/witness/mod.rs +++ b/kimchi/src/circuits/witness/mod.rs @@ -20,10 +20,11 @@ pub use self::{ variables::{variable_map, variables, Variables}, }; -/// Witness cell interface -pub trait WitnessCell { +/// Witness cell interface. By default, the witness cell is a single element of type F. +pub trait WitnessCell { fn value(&self, witness: &mut [Vec; W], variables: &Variables, index: usize) -> F; + // Length is 1 by default (T is single F element) unless overridden fn length(&self) -> usize { 1 } @@ -97,7 +98,7 @@ mod tests { #[test] fn zero_layout() { - let layout: Vec>>> = vec![vec![ + let layout: Vec>>> = vec![vec![ ConstantCell::create(PallasField::zero()), ConstantCell::create(PallasField::zero()), ConstantCell::create(PallasField::zero()), @@ -140,7 +141,7 @@ mod tests { #[test] fn mixed_layout() { - let layout: Vec>>> = vec![ + let layout: Vec>>> = vec![ vec![ ConstantCell::create(PallasField::from(12u32)), ConstantCell::create(PallasField::from(0xa5a3u32)), diff --git a/kimchi/src/circuits/witness/variable_bits_cell.rs b/kimchi/src/circuits/witness/variable_bits_cell.rs index 1fef513607..cef394cfb9 100644 --- a/kimchi/src/circuits/witness/variable_bits_cell.rs +++ b/kimchi/src/circuits/witness/variable_bits_cell.rs @@ -18,7 +18,7 @@ impl<'a> VariableBitsCell<'a> { } } -impl<'a, const W: usize, F: Field> WitnessCell for VariableBitsCell<'a> { +impl<'a, const W: usize, F: Field> WitnessCell for VariableBitsCell<'a> { fn value(&self, _witness: &mut [Vec; W], variables: &Variables, _index: usize) -> F { let bits = if let Some(end) = self.end { F::from_bits(&variables[self.name].to_bits()[self.start..end]) diff --git a/kimchi/src/circuits/witness/variable_cell.rs b/kimchi/src/circuits/witness/variable_cell.rs index c24ce57d42..88b17ccf9f 100644 --- a/kimchi/src/circuits/witness/variable_cell.rs +++ b/kimchi/src/circuits/witness/variable_cell.rs @@ -14,7 +14,7 @@ impl<'a> VariableCell<'a> { } } -impl<'a, const W: usize, F: Field> WitnessCell for VariableCell<'a> { +impl<'a, const W: usize, F: Field> WitnessCell for VariableCell<'a> { fn value(&self, _witness: &mut [Vec; W], variables: &Variables, _index: usize) -> F { variables[self.name] } From 95bfeb5ae9d524d87362ff205480baa06ee00d49 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 19:11:20 +0200 Subject: [PATCH 205/242] making column width generic in witness cell by default, smaller diff, cleaner interface --- .../polynomials/foreign_field_add/witness.rs | 4 ++-- .../polynomials/foreign_field_mul/witness.rs | 2 +- .../polynomials/range_check/witness.rs | 4 ++-- kimchi/src/circuits/polynomials/rot.rs | 4 ++-- kimchi/src/circuits/polynomials/xor.rs | 9 +++------ kimchi/src/circuits/witness/constant_cell.rs | 2 +- kimchi/src/circuits/witness/copy_bits_cell.rs | 2 +- kimchi/src/circuits/witness/copy_cell.rs | 2 +- .../src/circuits/witness/copy_shift_cell.rs | 2 +- kimchi/src/circuits/witness/index_cell.rs | 2 +- kimchi/src/circuits/witness/mod.rs | 20 ++++++++++--------- .../circuits/witness/variable_bits_cell.rs | 2 +- kimchi/src/circuits/witness/variable_cell.rs | 2 +- 13 files changed, 28 insertions(+), 29 deletions(-) diff --git a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs index 40f08e013b..950f7a265d 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs @@ -185,7 +185,7 @@ fn init_ffadd_row( overflow: F, carry: F, ) { - let layout: [Vec>>; 1] = [ + let layout: [Vec>>; 1] = [ // ForeignFieldAdd row vec![ VariableCell::create("left_lo"), @@ -221,7 +221,7 @@ fn init_bound_rows( bound: &[F; 3], carry: &F, ) { - let layout: [Vec>>; 2] = [ + let layout: [Vec>>; 2] = [ vec![ // ForeignFieldAdd row VariableCell::create("result_lo"), diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs index ef0fc02a26..2c1e0e328d 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs @@ -41,7 +41,7 @@ use super::circuitgates; // // so that most significant limb, q2, is in W[2][0]. // -fn create_layout() -> [Vec>>; 2] { +fn create_layout() -> [Vec>>; 2] { [ // ForeignFieldMul row vec![ diff --git a/kimchi/src/circuits/polynomials/range_check/witness.rs b/kimchi/src/circuits/polynomials/range_check/witness.rs index 55d99b2b7f..459c95435f 100644 --- a/kimchi/src/circuits/polynomials/range_check/witness.rs +++ b/kimchi/src/circuits/polynomials/range_check/witness.rs @@ -29,7 +29,7 @@ use o1_utils::foreign_field::BigUintForeignFieldHelpers; /// For example, we can convert the `RangeCheck0` circuit gate into /// a 64-bit lookup by adding two copy constraints to constrain /// columns 1 and 2 to zero. -fn layout() -> [Vec>>; 4] { +fn layout() -> [Vec>>; 4] { [ /* row 1, RangeCheck0 row */ range_check_0_row("v0", 0), @@ -86,7 +86,7 @@ fn layout() -> [Vec>>; 4] { pub fn range_check_0_row( limb_name: &'static str, row: usize, -) -> Vec>> { +) -> Vec>> { vec![ VariableCell::create(limb_name), /* 12-bit copies */ diff --git a/kimchi/src/circuits/polynomials/rot.rs b/kimchi/src/circuits/polynomials/rot.rs index 8b72a94e95..1df1376cb6 100644 --- a/kimchi/src/circuits/polynomials/rot.rs +++ b/kimchi/src/circuits/polynomials/rot.rs @@ -266,7 +266,7 @@ where // ROTATION WITNESS COMPUTATION -fn layout_rot64(curr_row: usize) -> [Vec>>; 3] { +fn layout_rot64(curr_row: usize) -> [Vec>>; 3] { [ rot_row(), range_check_0_row("shifted", curr_row + 1), @@ -274,7 +274,7 @@ fn layout_rot64(curr_row: usize) -> [Vec() -> Vec>> { +fn rot_row() -> Vec>> { vec![ VariableCell::create("word"), VariableCell::create("rotated"), diff --git a/kimchi/src/circuits/polynomials/xor.rs b/kimchi/src/circuits/polynomials/xor.rs index d7276cee12..6750a511bc 100644 --- a/kimchi/src/circuits/polynomials/xor.rs +++ b/kimchi/src/circuits/polynomials/xor.rs @@ -169,10 +169,7 @@ where } // Witness layout -fn layout( - curr_row: usize, - bits: usize, -) -> Vec>>> { +fn layout(curr_row: usize, bits: usize) -> Vec>>> { let num_xor = num_xors(bits); let mut layout = (0..num_xor) .map(|i| xor_row(i, curr_row + i)) @@ -181,7 +178,7 @@ fn layout( layout } -fn xor_row(nybble: usize, curr_row: usize) -> Vec>> { +fn xor_row(nybble: usize, curr_row: usize) -> Vec>> { let start = nybble * 16; vec![ VariableBitsCell::create("in1", start, None), @@ -202,7 +199,7 @@ fn xor_row(nybble: usize, curr_row: usize) -> Vec() -> Vec>> { +fn zero_row() -> Vec>> { vec![ ConstantCell::create(F::zero()), ConstantCell::create(F::zero()), diff --git a/kimchi/src/circuits/witness/constant_cell.rs b/kimchi/src/circuits/witness/constant_cell.rs index 1ec69d797c..cbc7aaa7c8 100644 --- a/kimchi/src/circuits/witness/constant_cell.rs +++ b/kimchi/src/circuits/witness/constant_cell.rs @@ -13,7 +13,7 @@ impl ConstantCell { } } -impl WitnessCell for ConstantCell { +impl WitnessCell for ConstantCell { fn value(&self, _witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { self.value } diff --git a/kimchi/src/circuits/witness/copy_bits_cell.rs b/kimchi/src/circuits/witness/copy_bits_cell.rs index e97eed7940..a61ca183a8 100644 --- a/kimchi/src/circuits/witness/copy_bits_cell.rs +++ b/kimchi/src/circuits/witness/copy_bits_cell.rs @@ -23,7 +23,7 @@ impl CopyBitsCell { } } -impl WitnessCell for CopyBitsCell { +impl WitnessCell for CopyBitsCell { fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { F::from_bits(&witness[self.col][self.row].to_bits()[self.start..self.end]) .expect("failed to deserialize field bits for copy bits cell") diff --git a/kimchi/src/circuits/witness/copy_cell.rs b/kimchi/src/circuits/witness/copy_cell.rs index f5b75ad829..d3fad71654 100644 --- a/kimchi/src/circuits/witness/copy_cell.rs +++ b/kimchi/src/circuits/witness/copy_cell.rs @@ -15,7 +15,7 @@ impl CopyCell { } } -impl WitnessCell for CopyCell { +impl WitnessCell for CopyCell { fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { witness[self.col][self.row] } diff --git a/kimchi/src/circuits/witness/copy_shift_cell.rs b/kimchi/src/circuits/witness/copy_shift_cell.rs index e151d0cd57..b0c87587d1 100644 --- a/kimchi/src/circuits/witness/copy_shift_cell.rs +++ b/kimchi/src/circuits/witness/copy_shift_cell.rs @@ -15,7 +15,7 @@ impl CopyShiftCell { } } -impl WitnessCell for CopyShiftCell { +impl WitnessCell for CopyShiftCell { fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { F::from(2u32).pow([self.shift]) * witness[self.col][self.row] } diff --git a/kimchi/src/circuits/witness/index_cell.rs b/kimchi/src/circuits/witness/index_cell.rs index 9d6ebefea5..fd2628a316 100644 --- a/kimchi/src/circuits/witness/index_cell.rs +++ b/kimchi/src/circuits/witness/index_cell.rs @@ -18,7 +18,7 @@ impl<'a> IndexCell<'a> { } } -impl<'a, const W: usize, F: Field> WitnessCell> for IndexCell<'a> { +impl<'a, F: Field, const W: usize> WitnessCell, W> for IndexCell<'a> { fn value(&self, _witness: &mut [Vec; W], variables: &Variables>, index: usize) -> F { assert!(index < self.length, "index out of bounds of `IndexCell`"); variables[self.name][index] diff --git a/kimchi/src/circuits/witness/mod.rs b/kimchi/src/circuits/witness/mod.rs index daea8be7fa..830e2af5e7 100644 --- a/kimchi/src/circuits/witness/mod.rs +++ b/kimchi/src/circuits/witness/mod.rs @@ -20,8 +20,10 @@ pub use self::{ variables::{variable_map, variables, Variables}, }; +use super::polynomial::COLUMNS; + /// Witness cell interface. By default, the witness cell is a single element of type F. -pub trait WitnessCell { +pub trait WitnessCell { fn value(&self, witness: &mut [Vec; W], variables: &Variables, index: usize) -> F; // Length is 1 by default (T is single F element) unless overridden @@ -41,25 +43,25 @@ pub trait WitnessCell { /// - layout: the partial layout to initialize from /// - variables: the hashmap of variables to get the values from #[allow(clippy::too_many_arguments)] -pub fn init_cell( +pub fn init_cell( witness: &mut [Vec; W], offset: usize, row: usize, col: usize, cell: usize, index: usize, - layout: &[Vec>>], + layout: &[Vec>>], variables: &Variables, ) { witness[col][row + offset] = layout[row][cell].value(witness, variables, index); } /// Initialize a witness row based on layout and computed variables -pub fn init_row( +pub fn init_row( witness: &mut [Vec; W], offset: usize, row: usize, - layout: &[Vec>>], + layout: &[Vec>>], variables: &Variables, ) { let mut col = 0; @@ -73,10 +75,10 @@ pub fn init_row( } /// Initialize a witness based on layout and computed variables -pub fn init( +pub fn init( witness: &mut [Vec; W], offset: usize, - layout: &[Vec>>], + layout: &[Vec>>], variables: &Variables, ) { for row in 0..layout.len() { @@ -98,7 +100,7 @@ mod tests { #[test] fn zero_layout() { - let layout: Vec>>> = vec![vec![ + let layout: Vec>>> = vec![vec![ ConstantCell::create(PallasField::zero()), ConstantCell::create(PallasField::zero()), ConstantCell::create(PallasField::zero()), @@ -141,7 +143,7 @@ mod tests { #[test] fn mixed_layout() { - let layout: Vec>>> = vec![ + let layout: Vec>>> = vec![ vec![ ConstantCell::create(PallasField::from(12u32)), ConstantCell::create(PallasField::from(0xa5a3u32)), diff --git a/kimchi/src/circuits/witness/variable_bits_cell.rs b/kimchi/src/circuits/witness/variable_bits_cell.rs index cef394cfb9..584920592d 100644 --- a/kimchi/src/circuits/witness/variable_bits_cell.rs +++ b/kimchi/src/circuits/witness/variable_bits_cell.rs @@ -18,7 +18,7 @@ impl<'a> VariableBitsCell<'a> { } } -impl<'a, const W: usize, F: Field> WitnessCell for VariableBitsCell<'a> { +impl<'a, F: Field, const W: usize> WitnessCell for VariableBitsCell<'a> { fn value(&self, _witness: &mut [Vec; W], variables: &Variables, _index: usize) -> F { let bits = if let Some(end) = self.end { F::from_bits(&variables[self.name].to_bits()[self.start..end]) diff --git a/kimchi/src/circuits/witness/variable_cell.rs b/kimchi/src/circuits/witness/variable_cell.rs index 88b17ccf9f..fcb6ee9f21 100644 --- a/kimchi/src/circuits/witness/variable_cell.rs +++ b/kimchi/src/circuits/witness/variable_cell.rs @@ -14,7 +14,7 @@ impl<'a> VariableCell<'a> { } } -impl<'a, const W: usize, F: Field> WitnessCell for VariableCell<'a> { +impl<'a, F: Field, const W: usize> WitnessCell for VariableCell<'a> { fn value(&self, _witness: &mut [Vec; W], variables: &Variables, _index: usize) -> F { variables[self.name] } From 71fe4aa7a5e18ac7d17f9ffc772900ca1856756c Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 19:20:25 +0200 Subject: [PATCH 206/242] fix serialization of generic const array in coefficients_comm suggested by Matthew :D --- book/src/specs/kimchi.md | 4 ++-- kimchi/src/verifier_index.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 31db5ddc0c..a680d81c2c 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1761,8 +1761,8 @@ pub struct VerifierIndex { #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub sigma_comm: [PolyComm; PERMUTS], /// coefficient commitment array - #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] - pub coefficients_comm: Vec>, + #[serde_as(as = "[_; W]")] + pub coefficients_comm: [PolyComm; W], /// coefficient commitment array #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub generic_comm: PolyComm, diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 7b00ffe018..5832c0b268 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -75,8 +75,8 @@ pub struct VerifierIndex { #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub sigma_comm: [PolyComm; PERMUTS], /// coefficient commitment array - #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] - pub coefficients_comm: Vec>, + #[serde_as(as = "[_; W]")] + pub coefficients_comm: [PolyComm; W], /// coefficient commitment array #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub generic_comm: PolyComm, @@ -215,12 +215,12 @@ impl ProverIndex { &self.column_evaluations.permutation_coefficients8[i], ) }), - coefficients_comm: self - .column_evaluations - .coefficients8 - .iter() - .map(|c| self.srs.commit_evaluations_non_hiding(domain, c)) - .collect::>(), + coefficients_comm: array::from_fn(|i| { + self.srs.commit_evaluations_non_hiding( + domain, + &self.column_evaluations.coefficients8[i], + ) + }), generic_comm: mask_fixed( self.srs.commit_evaluations_non_hiding( domain, From b0b3458aea1b6306a87e3b86d379dc02ae064671 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 30 Oct 2023 18:17:14 +0100 Subject: [PATCH 207/242] make width 15 by default --- book/src/specs/kimchi.md | 20 +-- kimchi/src/alphas.rs | 4 +- kimchi/src/bench.rs | 10 +- kimchi/src/circuits/berkeley_columns.rs | 2 +- kimchi/src/circuits/constraints.rs | 18 +-- kimchi/src/circuits/expr.rs | 12 +- kimchi/src/circuits/gate.rs | 24 ++-- kimchi/src/circuits/lookup/constraints.rs | 4 +- kimchi/src/circuits/lookup/index.rs | 2 +- kimchi/src/circuits/lookup/lookups.rs | 2 +- kimchi/src/circuits/polynomial.rs | 14 +-- kimchi/src/circuits/polynomials/and.rs | 6 +- .../circuits/polynomials/endomul_scalar.rs | 2 +- kimchi/src/circuits/polynomials/endosclmul.rs | 4 +- .../polynomials/foreign_field_mul/gadget.rs | 2 +- kimchi/src/circuits/polynomials/generic.rs | 8 +- .../src/circuits/polynomials/permutation.rs | 14 +-- kimchi/src/circuits/polynomials/poseidon.rs | 2 +- .../polynomials/range_check/gadget.rs | 2 +- kimchi/src/circuits/polynomials/turshi.rs | 26 ++-- kimchi/src/circuits/polynomials/varbasemul.rs | 6 +- kimchi/src/circuits/polynomials/xor.rs | 14 +-- kimchi/src/linearization.rs | 12 +- kimchi/src/plonk_sponge.rs | 9 +- kimchi/src/proof.rs | 31 ++--- kimchi/src/prover.rs | 18 +-- kimchi/src/prover_index.rs | 31 ++--- kimchi/src/snarky/constraint_system.rs | 4 +- kimchi/src/tests/and.rs | 16 +-- kimchi/src/tests/chunked.rs | 2 +- kimchi/src/tests/ec.rs | 2 +- kimchi/src/tests/endomul.rs | 2 +- kimchi/src/tests/endomul_scalar.rs | 2 +- kimchi/src/tests/foreign_field_add.rs | 42 +++---- kimchi/src/tests/foreign_field_mul.rs | 10 +- kimchi/src/tests/framework.rs | 38 +++--- kimchi/src/tests/generic.rs | 20 +-- kimchi/src/tests/lookup.rs | 14 +-- kimchi/src/tests/not.rs | 18 +-- kimchi/src/tests/poseidon.rs | 2 +- kimchi/src/tests/range_check.rs | 114 +++++++++--------- kimchi/src/tests/recursion.rs | 4 +- kimchi/src/tests/rot.rs | 36 +++--- kimchi/src/tests/serde.rs | 13 +- kimchi/src/tests/turshi.rs | 4 +- kimchi/src/tests/varbasemul.rs | 2 +- kimchi/src/tests/xor.rs | 22 ++-- kimchi/src/verifier.rs | 48 ++++---- kimchi/src/verifier_index.rs | 12 +- tools/kimchi-visu/src/lib.rs | 4 +- tools/kimchi-visu/src/main.rs | 2 +- 51 files changed, 366 insertions(+), 366 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 9131dd0d9a..57cb70363d 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1703,7 +1703,7 @@ Both the prover and the verifier index, besides the common parts described above These pre-computations are optimizations, in the context of normal proofs, but they are necessary for recursion. ```rs -pub struct ProverIndex> { +pub struct ProverIndex, const W: usize=COLUMNS> { /// constraints system polynomials #[serde(bound = "ConstraintSystem: Serialize + DeserializeOwned")] pub cs: ConstraintSystem, @@ -1724,12 +1724,12 @@ pub struct ProverIndex, + #[serde(bound = "ColumnEvaluations: Serialize + DeserializeOwned")] + pub column_evaluations: ColumnEvaluations, /// The verifier index corresponding to this prover index #[serde(skip)] - pub verifier_index: Option>, + pub verifier_index: Option>, /// The verifier index digest corresponding to this prover index #[serde_as(as = "Option")] @@ -1767,7 +1767,7 @@ pub struct LookupVerifierIndex { #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VerifierIndex> { +pub struct VerifierIndex, const W: usize = COLUMNS> { /// evaluation domain #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub domain: D, @@ -1963,7 +1963,7 @@ pub struct PointEvaluations { /// - **Non chunked evaluations** `Field` is instantiated with a field, so they are single-sized#[serde_as] #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ProofEvaluations { +pub struct ProofEvaluations { /// public input polynomials pub public: Option, /// witness polynomials @@ -2042,7 +2042,7 @@ pub struct LookupCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverCommitments { +pub struct ProverCommitments { /// The commitments to the witness (execution trace) pub w_comm: Vec>, /// The commitment to the permutation polynomial @@ -2057,9 +2057,9 @@ pub struct ProverCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverProof { +pub struct ProverProof { /// All the polynomial commitments required in the proof - pub commitments: ProverCommitments, + pub commitments: ProverCommitments, /// batched commitment opening proof #[serde(bound( @@ -2069,7 +2069,7 @@ pub struct ProverProof { pub proof: OpeningProof, /// Two evaluations over a number of committed polynomials - pub evals: ProofEvaluations>>, + pub evals: ProofEvaluations>, W>, /// Required evaluation for [Maller's optimization](https://o1-labs.github.io/mina-book/crypto/plonk/maller_15.html#the-evaluation-of-l) #[serde_as(as = "o1_utils::serialization::SerdeAs")] diff --git a/kimchi/src/alphas.rs b/kimchi/src/alphas.rs index e41c494fea..031c01e20a 100644 --- a/kimchi/src/alphas.rs +++ b/kimchi/src/alphas.rs @@ -322,9 +322,9 @@ mod tests { #[test] fn get_alphas_for_spec() { let gates = vec![CircuitGate::::zero(Wire::for_row(0)); 2]; - let index = new_index_for_test::(gates, 0); + let index = new_index_for_test::(gates, 0); let (_linearization, powers_of_alpha) = - expr_linearization::(Some(&index.cs.feature_flags), true); + expr_linearization::(Some(&index.cs.feature_flags), true); // make sure this is present in the specification let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let spec_path = Path::new(&manifest_dir) diff --git a/kimchi/src/bench.rs b/kimchi/src/bench.rs index 39d89598cb..00fe661706 100644 --- a/kimchi/src/bench.rs +++ b/kimchi/src/bench.rs @@ -28,8 +28,8 @@ type ScalarSponge = DefaultFrSponge; pub struct BenchmarkCtx { num_gates: usize, group_map: BWParameters, - index: ProverIndex>, - verifier_index: VerifierIndex>, + index: ProverIndex>, + verifier_index: VerifierIndex>, } impl BenchmarkCtx { @@ -77,7 +77,7 @@ impl BenchmarkCtx { } /// Produces a proof - pub fn create_proof(&self) -> (ProverProof>, Vec) { + pub fn create_proof(&self) -> (ProverProof, COLUMNS>, Vec) { // create witness let witness: [Vec; COLUMNS] = array::from_fn(|_| vec![1u32.into(); self.num_gates]); @@ -99,7 +99,7 @@ impl BenchmarkCtx { #[allow(clippy::type_complexity)] pub fn batch_verification( &self, - batch: &[(ProverProof>, Vec)], + batch: &[(ProverProof, COLUMNS>, Vec)], ) { // verify the proof let batch: Vec<_> = batch @@ -110,7 +110,7 @@ impl BenchmarkCtx { public_input: public, }) .collect(); - batch_verify::>( + batch_verify::, COLUMNS>( &self.group_map, &batch, ) diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs index b5a2fc0ca1..454ba186b8 100644 --- a/kimchi/src/circuits/berkeley_columns.rs +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -95,7 +95,7 @@ impl expr::Variable { } } -impl ColumnEvaluations for ProofEvaluations> { +impl ColumnEvaluations for ProofEvaluations, W> { type Column = Column; fn evaluate(&self, col: Self::Column) -> Result, ExprError> { use Column::*; diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index dd0aa5e19b..64ee13ef75 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -53,7 +53,7 @@ pub struct FeatureFlags { /// The polynomials representing evaluated columns, in coefficient form. #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] -pub struct EvaluatedColumnCoefficients { +pub struct EvaluatedColumnCoefficients { /// permutation coefficients #[serde_as(as = "[o1_utils::serialization::SerdeAs; PERMUTS]")] pub permutation_coefficients: [DP; PERMUTS], @@ -75,7 +75,7 @@ pub struct EvaluatedColumnCoefficients { /// The evaluations are expanded to the domain size required for their constraints. #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] -pub struct ColumnEvaluations { +pub struct ColumnEvaluations { /// permutation coefficients over domain d8 #[serde_as(as = "[o1_utils::serialization::SerdeAs; PERMUTS]")] pub permutation_coefficients8: [E>; PERMUTS], @@ -270,11 +270,11 @@ impl ConstraintSystem { } impl< - const W: usize, F: PrimeField + SquareRootField, G: KimchiCurve, OpeningProof: OpenProof, - > ProverIndex + const W: usize, + > ProverIndex { /// This function verifies the consistency of the wire /// assignments (witness) against the constraints @@ -319,7 +319,7 @@ impl< } // check the gate's satisfiability - gate.verify::(row, &witness, self, public) + gate.verify::(row, &witness, self, public) .map_err(|err| GateError::Custom { row, err })?; } @@ -330,7 +330,7 @@ impl< impl ConstraintSystem { /// evaluate witness polynomials over domains - pub fn evaluate(&self, w: &[DP; W], z: &DP) -> WitnessOverDomains { + pub fn evaluate(&self, w: &[DP; W], z: &DP) -> WitnessOverDomains { // compute shifted witness polynomials let w8: [E>; W] = array::from_fn(|i| w[i].evaluate_over_domain_by_ref(self.domain.d8)); @@ -370,7 +370,7 @@ impl ConstraintSystem { pub(crate) fn evaluated_column_coefficients( &self, - ) -> EvaluatedColumnCoefficients { + ) -> EvaluatedColumnCoefficients { // compute permutation polynomials let shifts = Shifts::new(&self.domain.d1); @@ -452,8 +452,8 @@ impl ConstraintSystem { pub(crate) fn column_evaluations( &self, - evaluated_column_coefficients: &EvaluatedColumnCoefficients, - ) -> ColumnEvaluations { + evaluated_column_coefficients: &EvaluatedColumnCoefficients, + ) -> ColumnEvaluations { let permutation_coefficients8 = array::from_fn(|i| { evaluated_column_coefficients.permutation_coefficients[i] .evaluate_over_domain_by_ref(self.domain.d8) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index f89827ea08..149c96efb1 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -97,7 +97,7 @@ pub struct LookupEnvironment<'a, F: FftField> { /// required to evaluate an expression as a polynomial. /// /// All are evaluations. -pub struct Environment<'a, const W: usize, F: FftField> { +pub struct Environment<'a, F: FftField, const W: usize = COLUMNS> { /// The witness column polynomials pub witness: &'a [Evaluations>; W], /// The coefficient column polynomials @@ -128,7 +128,7 @@ pub trait ColumnEnvironment<'a, F: FftField> { fn l0_1(&self) -> F; } -impl<'a, const W: usize, F: FftField> ColumnEnvironment<'a, F> for Environment<'a, W, F> { +impl<'a, F: FftField, const W: usize> ColumnEnvironment<'a, F> for Environment<'a, F, W> { type Column = berkeley_columns::Column; fn get_column(&self, col: &Self::Column) -> Option<&'a Evaluations>> { @@ -2890,6 +2890,8 @@ macro_rules! auto_clone_array { pub use auto_clone; pub use auto_clone_array; +use super::wires::COLUMNS; + /// You can import this module like `use kimchi::circuits::expr::prologue::*` to obtain a number of handy aliases and helpers pub mod prologue { pub use super::{coeff, constant, index, witness, witness_curr, witness_next, FeatureFlag, E}; @@ -2961,11 +2963,7 @@ pub mod test { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::>::create( - constraint_system, - endo_q, - srs, - ) + ProverIndex::>::create(constraint_system, endo_q, srs) }; let witness_cols: [_; COLUMNS] = array::from_fn(|_| DensePolynomial::zero()); diff --git a/kimchi/src/circuits/gate.rs b/kimchi/src/circuits/gate.rs index bbc312a451..1772b6309b 100644 --- a/kimchi/src/circuits/gate.rs +++ b/kimchi/src/circuits/gate.rs @@ -195,47 +195,47 @@ impl CircuitGate { /// # Errors /// /// Will give error if verify process returns error. - pub fn verify, OpeningProof: OpenProof>( + pub fn verify, OpeningProof: OpenProof, const W: usize>( &self, row: usize, witness: &[Vec; W], - index: &ProverIndex, + index: &ProverIndex, public: &[F], ) -> Result<(), String> { use GateType::*; match self.typ { Zero => Ok(()), Generic => self.verify_generic(row, witness, public), - Poseidon => self.verify_poseidon::(row, witness), + Poseidon => self.verify_poseidon::(row, witness), CompleteAdd => self.verify_complete_add(row, witness), VarBaseMul => self.verify_vbmul(row, witness), - EndoMul => self.verify_endomul::(row, witness, &index.cs), - EndoMulScalar => self.verify_endomul_scalar::(row, witness, &index.cs), + EndoMul => self.verify_endomul::(row, witness, &index.cs), + EndoMulScalar => self.verify_endomul_scalar::(row, witness, &index.cs), // TODO: implement the verification for the lookup gate Lookup => Ok(()), CairoClaim | CairoInstruction | CairoFlags | CairoTransition => { - self.verify_cairo_gate::(row, witness, &index.cs) + self.verify_cairo_gate::(row, witness, &index.cs) } RangeCheck0 | RangeCheck1 => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), ForeignFieldAdd => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), ForeignFieldMul => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), Xor16 => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), Rot64 => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), } } /// Verify the witness against the constraints - pub fn verify_witness>( + pub fn verify_witness, const W: usize>( &self, row: usize, witness: &[Vec; W], diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index 13d286692b..fbc464e068 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -83,7 +83,7 @@ pub fn zk_patch( /// /// Will panic if `value(s)` are missing from the `table`. #[allow(clippy::too_many_arguments)] -pub fn sorted( +pub fn sorted( dummy_lookup_value: F, joint_lookup_table_d8: &Evaluations>, d1: D, @@ -225,7 +225,7 @@ pub fn sorted( /// /// Will panic if final evaluation is not 1. #[allow(clippy::too_many_arguments)] -pub fn aggregation( +pub fn aggregation( dummy_lookup_value: F, joint_lookup_table_d8: &Evaluations>, d1: D, diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index 2b5826be5d..6ba2c80ba4 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -219,7 +219,7 @@ impl LookupConstraintSystem { //~ 2. Get the lookup selectors and lookup tables (TODO: how?) let (lookup_selectors, gate_lookup_tables) = - lookup_info.selector_polynomials_and_tables::(domain, gates); + lookup_info.selector_polynomials_and_tables::(domain, gates); //~ 3. Concatenate runtime lookup tables with the ones used by gates let mut lookup_tables: Vec<_> = gate_lookup_tables diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 1231faf446..84c835363e 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -200,7 +200,7 @@ impl LookupInfo { /// Each entry in `kinds` has a corresponding selector polynomial that controls whether that /// lookup kind should be enforced at a given row. This computes those selector polynomials. - pub fn selector_polynomials_and_tables( + pub fn selector_polynomials_and_tables( &self, domain: &EvaluationDomains, gates: &[CircuitGate], diff --git a/kimchi/src/circuits/polynomial.rs b/kimchi/src/circuits/polynomial.rs index 15e78da80a..23de59fe2a 100644 --- a/kimchi/src/circuits/polynomial.rs +++ b/kimchi/src/circuits/polynomial.rs @@ -8,7 +8,7 @@ use ark_poly::{univariate::DensePolynomial, Evaluations, Radix2EvaluationDomain /// Evaluations of the wires and permutation #[derive(Clone)] -pub struct WitnessEvals { +pub struct WitnessEvals { /// wire evaluations pub w: [Evaluations>; W], /// permutation evaluations @@ -16,19 +16,19 @@ pub struct WitnessEvals { } #[derive(Clone)] -pub struct WitnessShifts { +pub struct WitnessShifts { /// this wire evaluations - pub this: WitnessEvals, + pub this: WitnessEvals, /// next wire evaluations - pub next: WitnessEvals, + pub next: WitnessEvals, } #[derive(Clone)] -pub struct WitnessOverDomains { +pub struct WitnessOverDomains { /// evaluations over domain d4 - pub d4: WitnessShifts, + pub d4: WitnessShifts, /// evaluations over domain d8 - pub d8: WitnessShifts, + pub d8: WitnessShifts, } // PLOOKUP diff --git a/kimchi/src/circuits/polynomials/and.rs b/kimchi/src/circuits/polynomials/and.rs index 6c52e95442..fbaf6047fa 100644 --- a/kimchi/src/circuits/polynomials/and.rs +++ b/kimchi/src/circuits/polynomials/and.rs @@ -133,7 +133,7 @@ pub fn lookup_table() -> LookupTable { /// Create a And for inputs as field elements starting at row 0 /// Input: first input, second input, and desired byte length /// Panics if the input is too large for the chosen number of bytes -pub fn create_and_witness( +pub fn create_and_witness( input1: F, input2: F, bytes: usize, @@ -170,13 +170,13 @@ pub fn create_and_witness( /// Extends an AND witness to the whole witness /// Input: first input, second input, and desired byte length /// Panics if the input is too large for the chosen number of bytes -pub fn extend_and_witness( +pub fn extend_and_witness( witness: &mut [Vec; W], input1: F, input2: F, bytes: usize, ) { - let and_witness = create_and_witness::(input1, input2, bytes); + let and_witness = create_and_witness::(input1, input2, bytes); for col in 0..W { witness[col].extend(and_witness[col].iter()); } diff --git a/kimchi/src/circuits/polynomials/endomul_scalar.rs b/kimchi/src/circuits/polynomials/endomul_scalar.rs index 24a8486e6e..ad3a1324af 100644 --- a/kimchi/src/circuits/polynomials/endomul_scalar.rs +++ b/kimchi/src/circuits/polynomials/endomul_scalar.rs @@ -21,7 +21,7 @@ impl CircuitGate { /// # Errors /// /// Will give error if `self.typ` is not `GateType::EndoMulScalar`, or there are errors in gate values. - pub fn verify_endomul_scalar>( + pub fn verify_endomul_scalar, const W: usize>( &self, row: usize, witness: &[Vec; W], diff --git a/kimchi/src/circuits/polynomials/endosclmul.rs b/kimchi/src/circuits/polynomials/endosclmul.rs index fce7b126da..3039b04c46 100644 --- a/kimchi/src/circuits/polynomials/endosclmul.rs +++ b/kimchi/src/circuits/polynomials/endosclmul.rs @@ -125,7 +125,7 @@ impl CircuitGate { /// # Errors /// /// Will give error if `self.typ` is not `GateType::EndoMul`, or `constraint evaluation` fails. - pub fn verify_endomul>( + pub fn verify_endomul, const W: usize>( &self, row: usize, witness: &[Vec; W], @@ -148,7 +148,7 @@ impl CircuitGate { zk_rows: cs.zk_rows, }; - let evals: ProofEvaluations> = + let evals: ProofEvaluations, W> = ProofEvaluations::dummy_with_witness_evaluations(this, next); let constraints = EndosclMul::::constraints(&mut Cache::default()); diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs index abf81cfcbc..421c81e766 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs @@ -96,7 +96,7 @@ pub fn circuit_gates() -> [GateType; GATE_COUNT] { } /// Get combined constraints for a given foreign field multiplication circuit gate -pub fn circuit_gate_constraints( +pub fn circuit_gate_constraints( typ: GateType, alphas: &Alphas, cache: &mut Cache, diff --git a/kimchi/src/circuits/polynomials/generic.rs b/kimchi/src/circuits/polynomials/generic.rs index de6781a35c..63cbc0a096 100644 --- a/kimchi/src/circuits/polynomials/generic.rs +++ b/kimchi/src/circuits/polynomials/generic.rs @@ -308,11 +308,11 @@ pub mod testing { } impl< - const W: usize, F: PrimeField, G: KimchiCurve, OpeningProof: OpenProof, - > ProverIndex + const W: usize, + > ProverIndex { /// Function to verify the generic polynomials with a witness. pub fn verify_generic( @@ -370,7 +370,7 @@ pub mod testing { /// # Panics /// /// Will panic if `gates_row` is None. - pub fn create_circuit( + pub fn create_circuit( start_row: usize, public: usize, ) -> Vec> { @@ -429,7 +429,7 @@ pub mod testing { /// # Panics /// /// Will panic if `witness_row` is None. - pub fn fill_in_witness( + pub fn fill_in_witness( start_row: usize, witness: &mut [Vec; W], public: &[F], diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index 88cd06c548..dffd84e65d 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -195,11 +195,11 @@ where } impl< - const W: usize, F: PrimeField, G: KimchiCurve, OpeningProof: OpenProof, - > ProverIndex + const W: usize, + > ProverIndex { /// permutation quotient poly contribution computation /// @@ -213,7 +213,7 @@ impl< #[allow(clippy::type_complexity)] pub fn perm_quot( &self, - lagrange: &WitnessOverDomains, + lagrange: &WitnessOverDomains, beta: F, gamma: F, z: &DensePolynomial, @@ -336,7 +336,7 @@ impl< /// permutation linearization poly contribution computation pub fn perm_lnrz( &self, - e: &ProofEvaluations>, + e: &ProofEvaluations, W>, zeta: F, beta: F, gamma: F, @@ -366,7 +366,7 @@ impl< impl ConstraintSystem { pub fn perm_scalars( - e: &ProofEvaluations>, + e: &ProofEvaluations, W>, beta: F, gamma: F, mut alphas: impl Iterator, @@ -407,11 +407,11 @@ impl ConstraintSystem { } impl< - const W: usize, F: PrimeField, G: KimchiCurve, OpeningProof: OpenProof, - > ProverIndex + const W: usize, + > ProverIndex { /// permutation aggregation polynomial computation /// diff --git a/kimchi/src/circuits/polynomials/poseidon.rs b/kimchi/src/circuits/polynomials/poseidon.rs index ef5d010dc9..3187afa215 100644 --- a/kimchi/src/circuits/polynomials/poseidon.rs +++ b/kimchi/src/circuits/polynomials/poseidon.rs @@ -137,7 +137,7 @@ impl CircuitGate { /// # Errors /// /// Will give error if `self.typ` is not `Poseidon` gate, or `state` does not match after `permutation`. - pub fn verify_poseidon>( + pub fn verify_poseidon, const W: usize>( &self, row: usize, // TODO(mimoo): we should just pass two rows instead of the whole witness diff --git a/kimchi/src/circuits/polynomials/range_check/gadget.rs b/kimchi/src/circuits/polynomials/range_check/gadget.rs index 3b787b0ff2..cd5a6b0b92 100644 --- a/kimchi/src/circuits/polynomials/range_check/gadget.rs +++ b/kimchi/src/circuits/polynomials/range_check/gadget.rs @@ -149,7 +149,7 @@ pub fn circuit_gate_constraints( } /// Get the combined constraints for all range check circuit gate types -pub fn combined_constraints( +pub fn combined_constraints( alphas: &Alphas, cache: &mut Cache, ) -> E { diff --git a/kimchi/src/circuits/polynomials/turshi.rs b/kimchi/src/circuits/polynomials/turshi.rs index 2c2f345d54..bb441bafbd 100644 --- a/kimchi/src/circuits/polynomials/turshi.rs +++ b/kimchi/src/circuits/polynomials/turshi.rs @@ -177,7 +177,7 @@ impl CircuitGate { /// # Panics /// /// Will panic if `constraint linearization` fails. - pub fn verify_cairo_gate>( + pub fn verify_cairo_gate, const W: usize>( &self, row: usize, witness: &[Vec; W], @@ -210,7 +210,7 @@ impl CircuitGate { // Get constraints for this circuit gate let constraints = - circuit_gate_combined_constraints::(self.typ, &alphas, &mut Cache::default()); + circuit_gate_combined_constraints::(self.typ, &alphas, &mut Cache::default()); // Linearize let linearized = constraints.linearize(polys).unwrap(); @@ -256,7 +256,7 @@ pub mod witness { use super::*; /// Returns the witness of an execution of a Cairo program in `CircuitGate` format - pub fn cairo_witness(prog: &CairoProgram) -> [Vec; W] { + pub fn cairo_witness(prog: &CairoProgram) -> [Vec; W] { // 0: 1 row for final check CairoClaim gate // 4i+1: 1 row per instruction for CairoInstruction gate // 4i+2: 1 row per instruction for Flags argument @@ -274,14 +274,14 @@ pub mod witness { let claim_wit = claim_witness(prog); table[i] = claim_wit; } - let ins_wit = instruction_witness::(inst); - let flg_wit = flag_witness::(inst); + let ins_wit = instruction_witness::(inst); + let flg_wit = flag_witness::(inst); table[4 * i + 1] = ins_wit; table[4 * i + 2] = flg_wit; if i != n - 1 { // all but last instruction - let tra_wit = transition_witness::(inst, &prog.trace()[i + 1]); - let aux_wit = auxiliary_witness::(&prog.trace()[i + 1]); + let tra_wit = transition_witness::(inst, &prog.trace()[i + 1]); + let aux_wit = auxiliary_witness::(&prog.trace()[i + 1]); table[4 * i + 3] = tra_wit; table[4 * i + 4] = aux_wit; } @@ -320,7 +320,7 @@ pub mod witness { ] } - fn instruction_witness(inst: &CairoInstruction) -> Vec { + fn instruction_witness(inst: &CairoInstruction) -> Vec { vec![ inst.pc(), inst.ap(), @@ -340,7 +340,7 @@ pub mod witness { ] } - fn flag_witness(inst: &CairoInstruction) -> Vec { + fn flag_witness(inst: &CairoInstruction) -> Vec { vec![ inst.f_dst_fp(), inst.f_op0_fp(), @@ -360,7 +360,7 @@ pub mod witness { ] } - fn transition_witness( + fn transition_witness( curr: &CairoInstruction, next: &CairoInstruction, ) -> Vec { @@ -383,7 +383,7 @@ pub mod witness { ] } - fn auxiliary_witness(next: &CairoInstruction) -> Vec { + fn auxiliary_witness(next: &CairoInstruction) -> Vec { vec![ next.pc(), next.ap(), @@ -412,7 +412,7 @@ pub mod testing { /// # Errors /// /// Will give error if `gate` is not `Cairo`-related gate or `zero` gate. - pub fn ensure_cairo_gate( + pub fn ensure_cairo_gate( gate: &CircuitGate, row: usize, witness: &[Vec; W], @@ -741,7 +741,7 @@ fn two>() -> T { /// # Panics /// /// Will panic if the `typ` is not `Cairo`-related gate type or `zero` gate type. -pub fn circuit_gate_combined_constraints( +pub fn circuit_gate_combined_constraints( typ: GateType, alphas: &Alphas, cache: &mut Cache, diff --git a/kimchi/src/circuits/polynomials/varbasemul.rs b/kimchi/src/circuits/polynomials/varbasemul.rs index 2242e8dcbb..454cb8bf2f 100644 --- a/kimchi/src/circuits/polynomials/varbasemul.rs +++ b/kimchi/src/circuits/polynomials/varbasemul.rs @@ -181,7 +181,7 @@ impl Point { } } -fn set(w: &mut [Vec; W], row0: usize, var: Variable, x: F) { +fn set(w: &mut [Vec; W], row0: usize, var: Variable, x: F) { match var.col { Column::Witness(i) => w[i][row0 + var.row.shift()] = x, _ => panic!("Can only set witness columns"), @@ -189,7 +189,7 @@ fn set(w: &mut [Vec; W], row0: usize, var: Variable, x: F) } #[allow(clippy::too_many_arguments)] -fn single_bit_witness( +fn single_bit_witness( w: &mut [Vec; W], row: usize, b: Variable, @@ -364,7 +364,7 @@ pub struct VarbaseMulResult { /// # Panics /// /// Will panic if `bits chunk` length validation fails. -pub fn witness( +pub fn witness( w: &mut [Vec; W], row0: usize, base: (F, F), diff --git a/kimchi/src/circuits/polynomials/xor.rs b/kimchi/src/circuits/polynomials/xor.rs index 5be63d1d45..3ecc8390c5 100644 --- a/kimchi/src/circuits/polynomials/xor.rs +++ b/kimchi/src/circuits/polynomials/xor.rs @@ -168,7 +168,7 @@ where } // Witness layout -fn layout( +fn layout( curr_row: usize, bits: usize, ) -> Vec>>> { @@ -180,7 +180,7 @@ fn layout( layout } -fn xor_row( +fn xor_row( nybble: usize, curr_row: usize, ) -> Vec>> { @@ -204,7 +204,7 @@ fn xor_row( ] } -fn zero_row() -> Vec>> { +fn zero_row() -> Vec>> { vec![ ConstantCell::create(F::zero()), ConstantCell::create(F::zero()), @@ -224,7 +224,7 @@ fn zero_row() -> Vec ] } -pub(crate) fn init_xor( +pub(crate) fn init_xor( witness: &mut [Vec; W], curr_row: usize, bits: usize, @@ -242,13 +242,13 @@ pub(crate) fn init_xor( /// Extends the Xor rows to the full witness /// Panics if the words are larger than the desired bits -pub fn extend_xor_witness( +pub fn extend_xor_witness( witness: &mut [Vec; W], input1: F, input2: F, bits: usize, ) { - let xor_witness = create_xor_witness::(input1, input2, bits); + let xor_witness = create_xor_witness::(input1, input2, bits); for col in 0..W { witness[col].extend(xor_witness[col].iter()); } @@ -257,7 +257,7 @@ pub fn extend_xor_witness( /// Create a Xor for up to the native length starting at row 0 /// Input: first input and second input, bits length, current row /// Panics if the desired bits is smaller than the inputs length -pub fn create_xor_witness( +pub fn create_xor_witness( input1: F, input2: F, bits: usize, diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 728816a3dd..0b5ae39ae7 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -35,7 +35,7 @@ use ark_ff::{FftField, PrimeField, SquareRootField, Zero}; /// # Panics /// /// Will panic if `generic_gate` is not associate with `alpha^0`. -pub fn constraints_expr( +pub fn constraints_expr( feature_flags: Option<&FeatureFlags>, generic: bool, ) -> (Expr, Column>, Alphas) { @@ -220,7 +220,7 @@ pub fn constraints_expr( // flags. if cfg!(feature = "check_feature_flags") { if let Some(feature_flags) = feature_flags { - let (feature_flagged_expr, _) = constraints_expr::(None, generic); + let (feature_flagged_expr, _) = constraints_expr::(None, generic); let feature_flagged_expr = feature_flagged_expr.apply_feature_flags(feature_flags); assert_eq!(expr, feature_flagged_expr); } @@ -232,7 +232,7 @@ pub fn constraints_expr( /// Adds the polynomials that are evaluated as part of the proof /// for the linearization to work. -pub fn linearization_columns( +pub fn linearization_columns( feature_flags: Option<&FeatureFlags>, ) -> std::collections::HashSet { let mut h = std::collections::HashSet::new(); @@ -335,16 +335,16 @@ pub fn linearization_columns( /// /// Will panic if the `linearization` process fails. #[allow(clippy::type_complexity)] -pub fn expr_linearization( +pub fn expr_linearization( feature_flags: Option<&FeatureFlags>, generic: bool, ) -> ( Linearization>, Column>, Alphas, ) { - let evaluated_cols = linearization_columns::(feature_flags); + let evaluated_cols = linearization_columns::(feature_flags); - let (expr, powers_of_alpha) = constraints_expr::(feature_flags, generic); + let (expr, powers_of_alpha) = constraints_expr::(feature_flags, generic); let linearization = expr .linearize(evaluated_cols) diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index b1763211b1..67ae88dd29 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -5,9 +5,10 @@ use mina_poseidon::{ poseidon::{ArithmeticSponge, ArithmeticSpongeParams, Sponge}, }; +use crate::circuits::wires::COLUMNS; use crate::proof::{PointEvaluations, ProofEvaluations}; -pub trait FrSponge { +pub trait FrSponge { /// Creates a new Fr-Sponge. fn new(p: &'static ArithmeticSpongeParams) -> Self; @@ -25,10 +26,10 @@ pub trait FrSponge { /// Absorbs the given evaluations into the sponge. // TODO: IMO this function should be inlined in prover/verifier - fn absorb_evaluations(&mut self, e: &ProofEvaluations>>); + fn absorb_evaluations(&mut self, e: &ProofEvaluations>, W>); } -impl FrSponge for DefaultFrSponge { +impl FrSponge for DefaultFrSponge { fn new(params: &'static ArithmeticSpongeParams) -> DefaultFrSponge { DefaultFrSponge { sponge: ArithmeticSponge::new(params), @@ -56,7 +57,7 @@ impl FrSponge for DefaultFrSponge } // We absorb all evaluations of the same polynomial at the same time - fn absorb_evaluations(&mut self, e: &ProofEvaluations>>) { + fn absorb_evaluations(&mut self, e: &ProofEvaluations>, W>) { self.last_squeezed = vec![]; let ProofEvaluations { diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 5cc1adf4aa..3a9bfc8aeb 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -1,7 +1,10 @@ //! This module implements the data structures of a proof. use crate::circuits::{ - berkeley_columns::Column, gate::GateType, lookup::lookups::LookupPattern, wires::PERMUTS, + berkeley_columns::Column, + gate::GateType, + lookup::lookups::LookupPattern, + wires::{COLUMNS, PERMUTS}, }; use ark_ec::AffineCurve; use ark_ff::{FftField, One, Zero}; @@ -39,7 +42,7 @@ pub struct PointEvaluations { /// - **Non chunked evaluations** `Field` is instantiated with a field, so they are single-sized#[serde_as] #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ProofEvaluations { +pub struct ProofEvaluations { /// public input polynomials pub public: Option, /// witness polynomials @@ -118,7 +121,7 @@ pub struct LookupCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverCommitments { +pub struct ProverCommitments { /// The commitments to the witness (execution trace) pub w_comm: Vec>, /// The commitment to the permutation polynomial @@ -133,9 +136,9 @@ pub struct ProverCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverProof { +pub struct ProverProof { /// All the polynomial commitments required in the proof - pub commitments: ProverCommitments, + pub commitments: ProverCommitments, /// batched commitment opening proof #[serde(bound( @@ -145,7 +148,7 @@ pub struct ProverProof { pub proof: OpeningProof, /// Two evaluations over a number of committed polynomials - pub evals: ProofEvaluations>>, + pub evals: ProofEvaluations>, W>, /// Required evaluation for [Maller's optimization](https://o1-labs.github.io/mina-book/crypto/plonk/maller_15.html#the-evaluation-of-l) #[serde_as(as = "o1_utils::serialization::SerdeAs")] @@ -190,8 +193,8 @@ impl PointEvaluations { } } -impl ProofEvaluations { - pub fn map Eval2>(self, f: &FN) -> ProofEvaluations { +impl ProofEvaluations { + pub fn map Eval2>(self, f: &FN) -> ProofEvaluations { let ProofEvaluations { public, w, @@ -250,7 +253,7 @@ impl ProofEvaluations { } } - pub fn map_ref Eval2>(&self, f: &FN) -> ProofEvaluations { + pub fn map_ref Eval2>(&self, f: &FN) -> ProofEvaluations { let ProofEvaluations { public, w, @@ -357,11 +360,11 @@ impl RecursionChallenge { } } -impl ProofEvaluations> { +impl ProofEvaluations, W> { pub fn dummy_with_witness_evaluations( curr: [F; W], next: [F; W], - ) -> ProofEvaluations> { + ) -> ProofEvaluations, W> { let pt = |curr, next| PointEvaluations { zeta: curr, zeta_omega: next, @@ -397,8 +400,8 @@ impl ProofEvaluations> { } } -impl ProofEvaluations>> { - pub fn combine(&self, pt: &PointEvaluations) -> ProofEvaluations> { +impl ProofEvaluations>, W> { + pub fn combine(&self, pt: &PointEvaluations) -> ProofEvaluations, W> { self.map_ref(&|evals| PointEvaluations { zeta: DensePolynomial::eval_polynomial(&evals.zeta, pt.zeta), zeta_omega: DensePolynomial::eval_polynomial(&evals.zeta_omega, pt.zeta_omega), @@ -406,7 +409,7 @@ impl ProofEvaluations>> } } -impl ProofEvaluations { +impl ProofEvaluations { pub fn get_column(&self, col: Column) -> Option<&F> { match col { Column::Witness(i) => Some(&self.w[i]), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index a3f77c45ff..8062081963 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -122,7 +122,7 @@ where runtime_second_col_d8: Option>>, } -impl> ProverProof +impl, const W: usize> ProverProof where G::BaseField: PrimeField, { @@ -133,15 +133,15 @@ where /// Will give error if `create_recursive` process fails. pub fn create< EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, >( groupmap: &G::Map, witness: [Vec; W], runtime_tables: &[RuntimeTable], - index: &ProverIndex, + index: &ProverIndex, ) -> Result where - VerifierIndex: Clone, + VerifierIndex: Clone, { Self::create_recursive::( groupmap, @@ -164,17 +164,17 @@ where /// Will panic if `lookup_context.joint_lookup_table_d8` is None. pub fn create_recursive< EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, >( group_map: &G::Map, mut witness: [Vec; W], runtime_tables: &[RuntimeTable], - index: &ProverIndex, + index: &ProverIndex, prev_challenges: Vec>, blinders: Option<[Option>; W]>, ) -> Result where - VerifierIndex: Clone, + VerifierIndex: Clone, { internal_tracing::checkpoint!(internal_traces; create_recursive); let d1_size = index.cs.domain.d1.size(); @@ -567,7 +567,7 @@ where //~~ * Compute the lookup aggregation polynomial. let joint_lookup_table_d8 = lookup_context.joint_lookup_table_d8.as_ref().unwrap(); - let aggreg = lookup::constraints::aggregation::( + let aggreg = lookup::constraints::aggregation::<_, G::ScalarField, W>( lookup_context.dummy_lookup_value.unwrap(), joint_lookup_table_d8, index.cs.domain.d1, @@ -971,7 +971,7 @@ where }; internal_tracing::checkpoint!(internal_traces; chunk_eval_zeta_omega_poly); - let chunked_evals = ProofEvaluations::>> { + let chunked_evals = ProofEvaluations::>, W> { public: { let chunked = public_poly.to_chunked_polynomial(num_chunks, index.max_poly_size); Some(PointEvaluations { diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index c57c199f73..b4e624b116 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -6,6 +6,7 @@ use crate::{ berkeley_columns::Column, constraints::{ColumnEvaluations, ConstraintSystem}, expr::{Linearization, PolishToken}, + wires::COLUMNS, }, curve::KimchiCurve, linearization::expr_linearization, @@ -22,7 +23,7 @@ use std::sync::Arc; #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] //~spec:startcode -pub struct ProverIndex> { +pub struct ProverIndex, const W: usize = COLUMNS> { /// constraints system polynomials #[serde(bound = "ConstraintSystem: Serialize + DeserializeOwned")] pub cs: ConstraintSystem, @@ -43,12 +44,12 @@ pub struct ProverIndex, + #[serde(bound = "ColumnEvaluations: Serialize + DeserializeOwned")] + pub column_evaluations: ColumnEvaluations, /// The verifier index corresponding to this prover index #[serde(skip)] - pub verifier_index: Option>, + pub verifier_index: Option>, /// The verifier index digest corresponding to this prover index #[serde_as(as = "Option")] @@ -56,7 +57,7 @@ pub struct ProverIndex> ProverIndex +impl, const W: usize> ProverIndex where G::BaseField: PrimeField, { @@ -71,7 +72,7 @@ where // pre-compute the linearization let (linearization, powers_of_alpha) = - expr_linearization::(Some(&cs.feature_flags), true); + expr_linearization::(Some(&cs.feature_flags), true); let evaluated_column_coefficients = cs.evaluated_column_coefficients(); @@ -97,7 +98,7 @@ where &mut self, ) -> G::BaseField where - VerifierIndex: Clone, + VerifierIndex: Clone, { if let Some(verifier_index_digest) = self.verifier_index_digest { return verifier_index_digest; @@ -117,7 +118,7 @@ where &self, ) -> G::BaseField where - VerifierIndex: Clone, + VerifierIndex: Clone, { if let Some(verifier_index_digest) = self.verifier_index_digest { return verifier_index_digest; @@ -148,9 +149,9 @@ pub mod testing { #[allow(clippy::too_many_arguments)] pub fn new_index_for_test_with_lookups_and_custom_srs< - const W: usize, G: KimchiCurve, OpeningProof: OpenProof, + const W: usize, F: FnMut(D, usize) -> OpeningProof::SRS, >( gates: Vec>, @@ -161,7 +162,7 @@ pub mod testing { disable_gates_checks: bool, override_srs_size: Option, mut get_srs: F, - ) -> ProverIndex + ) -> ProverIndex where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, @@ -190,7 +191,7 @@ pub mod testing { /// # Panics /// /// Will panic if `constraint system` is not built with `gates` input. - pub fn new_index_for_test_with_lookups( + pub fn new_index_for_test_with_lookups( gates: Vec>, public: usize, prev_challenges: usize, @@ -198,7 +199,7 @@ pub mod testing { runtime_tables: Option>>, disable_gates_checks: bool, override_srs_size: Option, - ) -> ProverIndex> + ) -> ProverIndex, W> where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, @@ -227,14 +228,14 @@ pub mod testing { ) } - pub fn new_index_for_test( + pub fn new_index_for_test( gates: Vec>, public: usize, - ) -> ProverIndex> + ) -> ProverIndex, W> where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, { - new_index_for_test_with_lookups::(gates, public, 0, vec![], None, false, None) + new_index_for_test_with_lookups::(gates, public, 0, vec![], None, false, None) } } diff --git a/kimchi/src/snarky/constraint_system.rs b/kimchi/src/snarky/constraint_system.rs index ddf94409f8..1b9e42e558 100644 --- a/kimchi/src/snarky/constraint_system.rs +++ b/kimchi/src/snarky/constraint_system.rs @@ -194,7 +194,7 @@ enum V { while it is being written. */ #[derive(Clone)] -enum Circuit +enum Circuit where F: PrimeField, { @@ -225,7 +225,7 @@ where A gate is finalized once [finalize_and_get_gates](SnarkyConstraintSystem::finalize_and_get_gates) is called. The finalized tag contains the digest of the circuit. */ - gates: Circuit, + gates: Circuit, /** The row to use the next time we add a constraint. */ next_row: usize, /** The size of the public input (which fills the first rows of our constraint system. */ diff --git a/kimchi/src/tests/and.rs b/kimchi/src/tests/and.rs index 2c35d5ae2c..94ed8a7295 100644 --- a/kimchi/src/tests/and.rs +++ b/kimchi/src/tests/and.rs @@ -107,7 +107,7 @@ where for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -125,7 +125,7 @@ fn prove_and_verify(bytes: usize) where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let rng = &mut StdRng::from_seed(RNG_SEED); @@ -140,7 +140,7 @@ where // Create witness let witness = and::create_and_witness(input1, input2, bytes); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() @@ -251,7 +251,7 @@ fn verify_bad_and_decomposition( // Update copy constraints of generic gate if col < 2 { assert_eq!( - cs.gates[0].verify_witness::( + cs.gates[0].verify_witness::( 0, witness, &cs, @@ -267,7 +267,7 @@ fn verify_bad_and_decomposition( } if col == 2 { assert_eq!( - cs.gates[0].verify_witness::( + cs.gates[0].verify_witness::( 0, witness, &cs, @@ -285,7 +285,7 @@ fn verify_bad_and_decomposition( witness[4][and_row] += G::ScalarField::one(); } assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::Xor16, bad)) ); witness[col][xor_row] -= G::ScalarField::one(); @@ -298,7 +298,7 @@ fn verify_bad_and_decomposition( } // undo changes assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), Ok(()) ); } @@ -333,7 +333,7 @@ fn test_bad_and() { witness[4][2] = PallasField::zero(); assert_eq!( - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/chunked.rs b/kimchi/src/tests/chunked.rs index c044054bb3..7e00d715aa 100644 --- a/kimchi/src/tests/chunked.rs +++ b/kimchi/src/tests/chunked.rs @@ -76,7 +76,7 @@ fn test_generic_gate_with_srs_override( } // create and verify proof based on the witness - let framework = TestFramework::::default() + let framework = TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(public); diff --git a/kimchi/src/tests/ec.rs b/kimchi/src/tests/ec.rs index 565a5e81db..9deec7a32a 100644 --- a/kimchi/src/tests/ec.rs +++ b/kimchi/src/tests/ec.rs @@ -145,7 +145,7 @@ fn ec_test() { witness[14].push(F::zero()); } - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/endomul.rs b/kimchi/src/tests/endomul.rs index bdfb0e2d8e..5a4fa08246 100644 --- a/kimchi/src/tests/endomul.rs +++ b/kimchi/src/tests/endomul.rs @@ -110,7 +110,7 @@ fn endomul_test() { assert_eq!(x.into_repr(), res.n.into_repr()); } - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/endomul_scalar.rs b/kimchi/src/tests/endomul_scalar.rs index 338df87e7a..f39c0bf236 100644 --- a/kimchi/src/tests/endomul_scalar.rs +++ b/kimchi/src/tests/endomul_scalar.rs @@ -64,7 +64,7 @@ fn endomul_scalar_test() { ); } - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/foreign_field_add.rs b/kimchi/src/tests/foreign_field_add.rs index bd3b2ba0db..f0911ba0a6 100644 --- a/kimchi/src/tests/foreign_field_add.rs +++ b/kimchi/src/tests/foreign_field_add.rs @@ -316,7 +316,7 @@ fn create_test_constraint_system_ffadd( opcodes: &[FFOps], foreign_field_modulus: BigUint, full: bool, -) -> ProverIndex> { +) -> ProverIndex> { let (_next_row, gates) = if full { full_circuit(opcodes, &foreign_field_modulus) } else { @@ -332,7 +332,7 @@ fn create_test_constraint_system_ffadd( let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::>::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) } // helper to reduce lines of code in repetitive test structure @@ -343,7 +343,7 @@ fn test_ffadd( full: bool, ) -> ( [Vec; COLUMNS], - ProverIndex>, + ProverIndex>, ) { let index = create_test_constraint_system_ffadd(opcodes, foreign_field_modulus.clone(), full); @@ -357,7 +357,7 @@ fn test_ffadd( for row in 0..all_rows { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -761,7 +761,7 @@ fn test_wrong_sum() { witness[0][12] = all_ones_limb; assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -785,7 +785,7 @@ fn test_wrong_dif() { witness[0][12] = PallasField::zero(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1072,7 +1072,7 @@ fn test_bad_bound() { // Modify overflow to check first the copy constraint and then the ovf constraint witness[6][2] = -PallasField::one(); assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1086,7 +1086,7 @@ fn test_bad_bound() { ); witness[0][0] = -PallasField::one(); assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1097,7 +1097,7 @@ fn test_bad_bound() { witness[6][2] = PallasField::one(); witness[0][0] = PallasField::one(); assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1126,7 +1126,7 @@ fn test_random_bad_input() { // First modify left input only to cause an invalid copy constraint witness[0][1] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1141,7 +1141,7 @@ fn test_random_bad_input() { // then modify the value in the range check to cause an invalid FFAdd constraint witness[0][4] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1170,7 +1170,7 @@ fn test_random_bad_parameters() { // Modify bot carry witness[7][1] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1182,7 +1182,7 @@ fn test_random_bad_parameters() { // Modify overflow witness[6][1] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1194,7 +1194,7 @@ fn test_random_bad_parameters() { // Modify sign index.cs.gates[1].coeffs[3] = PallasField::zero() - index.cs.gates[1].coeffs[3]; assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1205,7 +1205,7 @@ fn test_random_bad_parameters() { index.cs.gates[1].coeffs[3] = PallasField::zero() - index.cs.gates[1].coeffs[3]; // Check back to normal assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1272,7 +1272,7 @@ fn prove_and_verify(operation_count: usize) { // Create witness let witness = short_witness(&inputs, &operations, foreign_field_modulus); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(vec![PallasField::one()]) @@ -1347,7 +1347,7 @@ fn test_ffadd_no_rc() { for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -1421,7 +1421,7 @@ where // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return (result, witness); } @@ -1511,12 +1511,12 @@ fn test_ffadd_finalization() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::>::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; for row in 0..witness[0].len() { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -1526,7 +1526,7 @@ fn test_ffadd_finalization() { ); } - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness.clone()) .public_inputs(vec![witness[0][0]]) diff --git a/kimchi/src/tests/foreign_field_mul.rs b/kimchi/src/tests/foreign_field_mul.rs index eb77101018..631c94fed5 100644 --- a/kimchi/src/tests/foreign_field_mul.rs +++ b/kimchi/src/tests/foreign_field_mul.rs @@ -79,7 +79,7 @@ fn run_test( where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { // Create foreign field multiplication gates let (mut next_row, mut gates) = @@ -191,7 +191,7 @@ where let runner = if full { // Create prover index with test framework Some( - TestFramework::::default() + TestFramework::::default() .disable_gates_checks(disable_gates_checks) .gates(gates.clone()) .setup(), @@ -212,7 +212,7 @@ where // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return (result, witness); } @@ -246,7 +246,7 @@ where // When targeting the plookup constraints the invalidated values would cause custom constraint // failures, so we want to suppress these witness verification checks when doing plookup tests. for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { - let result = gate.verify_witness::( + let result = gate.verify_witness::( row, &witness, &cs, @@ -295,7 +295,7 @@ fn test_custom_constraints(foreign_field_m where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let rng = &mut StdRng::from_seed(RNG_SEED); diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index 67ecfb18af..e1e4fd52f0 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -35,13 +35,13 @@ use std::{fmt::Write, time::Instant}; #[derive(Default, Clone)] pub(crate) struct TestFramework< - const W: usize, G: KimchiCurve, + const W: usize = COLUMNS, OpeningProof: OpenProof = DlogOpeningProof, > where G::BaseField: PrimeField, OpeningProof::SRS: Clone, - VerifierIndex: Clone, + VerifierIndex: Clone, { gates: Option>>, witness: Option<[Vec; W]>, @@ -54,26 +54,26 @@ pub(crate) struct TestFramework< disable_gates_checks: bool, override_srs_size: Option, - prover_index: Option>, - verifier_index: Option>, + prover_index: Option>, + verifier_index: Option>, } #[derive(Clone)] pub(crate) struct TestRunner< - const W: usize, G: KimchiCurve, + const W: usize = COLUMNS, OpeningProof: OpenProof = DlogOpeningProof, ->(TestFramework) +>(TestFramework) where G::BaseField: PrimeField, OpeningProof::SRS: Clone, - VerifierIndex: Clone; + VerifierIndex: Clone; -impl> TestFramework +impl> TestFramework where G::BaseField: PrimeField, OpeningProof::SRS: Clone, - VerifierIndex: Clone, + VerifierIndex: Clone, { #[must_use] pub(crate) fn gates(mut self, gates: Vec>) -> Self { @@ -131,7 +131,7 @@ where pub(crate) fn setup_with_custom_srs, usize) -> OpeningProof::SRS>( mut self, get_srs: F, - ) -> TestRunner { + ) -> TestRunner { let start = Instant::now(); let lookup_tables = std::mem::take(&mut self.lookup_tables); @@ -159,19 +159,19 @@ where } } -impl TestFramework +impl TestFramework where G::BaseField: PrimeField, { /// creates the indexes #[must_use] - pub(crate) fn setup(mut self) -> TestRunner { + pub(crate) fn setup(mut self) -> TestRunner { let start = Instant::now(); let lookup_tables = std::mem::take(&mut self.lookup_tables); let runtime_tables_setup = self.runtime_tables_setup.take(); - let index = new_index_for_test_with_lookups::( + let index = new_index_for_test_with_lookups::( self.gates.take().unwrap(), self.public_inputs.len(), self.num_prev_challenges, @@ -192,12 +192,12 @@ where } } -impl> TestRunner +impl> TestRunner where G::ScalarField: PrimeField + Clone, G::BaseField: PrimeField + Clone, OpeningProof::SRS: Clone, - VerifierIndex: Clone, + VerifierIndex: Clone, { #[must_use] pub(crate) fn runtime_tables( @@ -220,7 +220,7 @@ where self } - pub(crate) fn prover_index(&self) -> &ProverIndex { + pub(crate) fn prover_index(&self) -> &ProverIndex { self.0.prover_index.as_ref().unwrap() } @@ -229,7 +229,7 @@ where pub(crate) fn prove(self) -> Result<(), String> where EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let prover = self.0.prover_index.unwrap(); let witness = self.0.witness.unwrap(); @@ -260,7 +260,7 @@ where pub(crate) fn prove_and_verify(self) -> Result<(), String> where EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let prover = self.0.prover_index.unwrap(); let witness = self.0.witness.unwrap(); @@ -291,7 +291,7 @@ where // verify the proof (propagate any errors) let start = Instant::now(); - verify::( + verify::( &group_map, &self.0.verifier_index.unwrap(), &proof, diff --git a/kimchi/src/tests/generic.rs b/kimchi/src/tests/generic.rs index 5fcb1e6022..ac1b785a29 100644 --- a/kimchi/src/tests/generic.rs +++ b/kimchi/src/tests/generic.rs @@ -15,14 +15,14 @@ type ScalarSponge = DefaultFrSponge; #[test] fn test_generic_gate() { - let gates = create_circuit::(0, 0); + let gates = create_circuit::(0, 0); // create witness let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &[]); // create and verify proof based on the witness - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() @@ -33,14 +33,14 @@ fn test_generic_gate() { #[test] fn test_generic_gate_pub() { let public = vec![Fp::from(3u8); 5]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); // create and verify proof based on the witness - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(public) @@ -52,14 +52,14 @@ fn test_generic_gate_pub() { #[test] fn test_generic_gate_pub_all_zeros() { let public = vec![Fp::from(0u8); 5]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); // create and verify proof based on the witness - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(public) @@ -71,14 +71,14 @@ fn test_generic_gate_pub_all_zeros() { #[test] fn test_generic_gate_pub_empty() { let public = vec![]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); // create and verify proof based on the witness - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(public) @@ -98,7 +98,7 @@ fn test_generic_gate_pairing() { use ark_ff::UniformRand; let public = vec![Fp::from(3u8); 5]; - let gates = create_circuit(0, public.len()); + let gates = create_circuit::(0, public.len()); let rng = &mut rand::rngs::OsRng; let x = Fp::rand(rng); @@ -109,8 +109,8 @@ fn test_generic_gate_pairing() { // create and verify proof based on the witness >, > as Default>::default() .gates(gates) diff --git a/kimchi/src/tests/lookup.rs b/kimchi/src/tests/lookup.rs index 0e26a8a551..a674eba78f 100644 --- a/kimchi/src/tests/lookup.rs +++ b/kimchi/src/tests/lookup.rs @@ -95,7 +95,7 @@ fn setup_lookup_proof(use_values_from_table: bool, num_lookups: usize, table_siz ] }; - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .lookup_tables(lookup_tables) @@ -181,7 +181,7 @@ fn setup_successfull_runtime_table_test( }; // run test - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .runtime_tables_setup(runtime_table_cfgs) @@ -254,7 +254,7 @@ fn test_runtime_table() { print_witness(&witness, 0, 20); // run test - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .runtime_tables_setup(runtime_tables_setup) @@ -310,7 +310,7 @@ fn test_negative_test_runtime_table_value_not_in_table() { }; // run prover only as the error should be raised while creating the proof. - let err = TestFramework::::default() + let err = TestFramework::::default() .gates(gates) .witness(witness) .runtime_tables_setup(vec![cfg]) @@ -372,7 +372,7 @@ fn test_negative_test_runtime_table_prover_with_undefined_id_in_index_and_witnes }; // We only run the prover. No need to verify. - let err = TestFramework::::default() + let err = TestFramework::::default() .gates(gates) .witness(witness) .runtime_tables_setup(vec![cfg]) @@ -432,7 +432,7 @@ fn test_negative_test_runtime_table_prover_uses_undefined_id_in_index_and_witnes }; // We only run the prover. No need to verify. - let err = TestFramework::::default() + let err = TestFramework::::default() .gates(gates) .witness(witness) .runtime_tables_setup(vec![cfg]) @@ -517,7 +517,7 @@ fn test_runtime_table_with_more_than_one_runtime_table_data_given_by_prover() { print_witness(&witness, 0, 20); // run test - let err = TestFramework::::default() + let err = TestFramework::::default() .gates(gates) .witness(witness) .runtime_tables_setup(vec![cfg]) diff --git a/kimchi/src/tests/not.rs b/kimchi/src/tests/not.rs index 6cf3c093a1..072f185643 100644 --- a/kimchi/src/tests/not.rs +++ b/kimchi/src/tests/not.rs @@ -157,7 +157,7 @@ where for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -218,7 +218,7 @@ where // test public input and not generic gate for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -290,7 +290,7 @@ fn test_prove_and_verify_not_xor() { let witness = create_not_witness_checked_length::(rng.gen_field_with_bits(bits), Some(bits)); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(vec![ @@ -326,7 +326,7 @@ fn test_prove_and_verify_five_not_gnrc() { bits, ); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(vec![ @@ -408,7 +408,7 @@ fn test_bad_not_gnrc() { // modify public input row to make sure the copy constraint fails and the generic gate also fails witness[0][0] += PallasField::one(); assert_eq!( - cs.gates[0].verify_witness::(0, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::CopyConstraint { typ: GateType::Generic, src: Wire { row: 0, col: 0 }, @@ -426,7 +426,7 @@ fn test_bad_not_gnrc() { None, ); assert_eq!( - index.cs.gates[1].verify::>(1, &witness, &index, &[]), + index.cs.gates[1].verify::, COLUMNS>(1, &witness, &index, &[]), Err(("generic: incorrect gate").to_string()) ); } @@ -438,7 +438,7 @@ fn test_bad_not_xor() { // modify public input row to make sure the copy constraint fails and the XOR gate also fails witness[0][0] += PallasField::one(); assert_eq!( - cs.gates[0].verify_witness::(0, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::CopyConstraint { typ: GateType::Generic, src: Wire { row: 0, col: 0 }, @@ -448,7 +448,7 @@ fn test_bad_not_xor() { witness[1][1] += PallasField::one(); // decomposition of xor fails assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::Xor16, 2)) ); // Make the second input zero with correct decomposition to make sure XOR table fails @@ -460,7 +460,7 @@ fn test_bad_not_xor() { witness[10][1] = PallasField::zero(); assert_eq!( - TestFramework::::default() + TestFramework::::default() .gates(cs.gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/poseidon.rs b/kimchi/src/tests/poseidon.rs index dfaff7393f..f5f31e0f49 100644 --- a/kimchi/src/tests/poseidon.rs +++ b/kimchi/src/tests/poseidon.rs @@ -81,7 +81,7 @@ fn test_poseidon() { ); } - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/range_check.rs b/kimchi/src/tests/range_check.rs index b9ba9ded01..c4c21af35b 100644 --- a/kimchi/src/tests/range_check.rs +++ b/kimchi/src/tests/range_check.rs @@ -57,7 +57,7 @@ const RNG_SEED: [u8; 32] = [ fn create_test_prover_index( public_size: usize, compact: bool, -) -> ProverIndex> { +) -> ProverIndex> { let (_next_row, gates) = if compact { CircuitGate::::create_compact_multi_range_check(0) } else { @@ -82,7 +82,7 @@ fn verify_range_check0_zero_valid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -93,7 +93,7 @@ fn verify_range_check0_zero_valid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -110,7 +110,7 @@ fn verify_range_check0_one_invalid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -121,7 +121,7 @@ fn verify_range_check0_one_invalid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -146,7 +146,7 @@ fn verify_range_check0_valid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -157,7 +157,7 @@ fn verify_range_check0_valid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -177,7 +177,7 @@ fn verify_range_check0_valid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -188,7 +188,7 @@ fn verify_range_check0_valid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -216,7 +216,7 @@ fn verify_range_check0_invalid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -234,7 +234,7 @@ fn verify_range_check0_invalid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -261,7 +261,7 @@ fn verify_range_check0_invalid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -275,7 +275,7 @@ fn verify_range_check0_invalid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -297,7 +297,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -314,7 +314,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -331,7 +331,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -348,7 +348,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -370,7 +370,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -387,7 +387,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -404,7 +404,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -421,7 +421,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -443,7 +443,7 @@ fn verify_range_check0_invalid_v0_not_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -460,7 +460,7 @@ fn verify_range_check0_invalid_v0_not_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -482,7 +482,7 @@ fn verify_range_check0_invalid_v1_not_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -499,7 +499,7 @@ fn verify_range_check0_invalid_v1_not_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -524,7 +524,7 @@ fn verify_range_check0_test_copy_constraints() { // Positive test case (gates[row] is a RangeCheck0 circuit gate) assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -537,7 +537,7 @@ fn verify_range_check0_test_copy_constraints() { assert_ne!(witness[col][row], PallasField::zero()); witness[col][row] = PallasField::zero(); assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -569,7 +569,7 @@ fn verify_range_check0_v0_test_lookups() { // Positive test // gates[0] is RangeCheck0 and constrains some of v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -578,7 +578,7 @@ fn verify_range_check0_v0_test_lookups() { Ok(()) ); - let test_runner = TestFramework::::default() + let test_runner = TestFramework::::default() .gates(index.cs.gates) .setup(); @@ -622,7 +622,7 @@ fn verify_range_check0_v1_test_lookups() { // Positive test // gates[1] is RangeCheck0 and constrains some of v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -631,7 +631,7 @@ fn verify_range_check0_v1_test_lookups() { Ok(()) ); - let test_runner = TestFramework::::default() + let test_runner = TestFramework::::default() .gates(index.cs.gates) .setup(); @@ -669,7 +669,7 @@ fn verify_range_check1_zero_valid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -686,7 +686,7 @@ fn verify_range_check1_one_invalid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -711,7 +711,7 @@ fn verify_range_check1_valid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -731,7 +731,7 @@ fn verify_range_check1_valid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -759,7 +759,7 @@ fn verify_range_check1_invalid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -782,7 +782,7 @@ fn verify_range_check1_invalid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -804,7 +804,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -821,7 +821,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -838,7 +838,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -855,7 +855,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -877,7 +877,7 @@ fn verify_range_check1_invalid_v2_not_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -894,7 +894,7 @@ fn verify_range_check1_invalid_v2_not_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -919,7 +919,7 @@ fn verify_range_check1_test_copy_constraints() { // Positive test case (gates[2] is a RangeCheck1 circuit gate) assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -934,7 +934,7 @@ fn verify_range_check1_test_copy_constraints() { // RangeCheck1's current row doesn't have any copy constraints assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -945,7 +945,7 @@ fn verify_range_check1_test_copy_constraints() { // RangeCheck1's next row has copy constraints, but it's a Zero gate assert_eq!( - index.cs.gates[3].verify_witness::( + index.cs.gates[3].verify_witness::( 3, &witness, &index.cs, @@ -976,7 +976,7 @@ fn verify_range_check1_test_curr_row_lookups() { // Positive test // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -985,7 +985,7 @@ fn verify_range_check1_test_curr_row_lookups() { Ok(()) ); - let test_runner = TestFramework::::default() + let test_runner = TestFramework::::default() .gates(index.cs.gates) .setup(); @@ -1025,7 +1025,7 @@ fn verify_range_check1_test_next_row_lookups() { // Positive test case (gates[2] is RangeCheck1 and constrains // both v0's and v1's lookups that are deferred to 4th row) assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1034,7 +1034,7 @@ fn verify_range_check1_test_next_row_lookups() { Ok(()) ); - let test_runner = TestFramework::::default() + let test_runner = TestFramework::::default() .gates(index.cs.gates) .setup(); @@ -1096,7 +1096,7 @@ fn verify_64_bit_range_check() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::>::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; // Witness layout (positive test case) @@ -1113,7 +1113,7 @@ fn verify_64_bit_range_check() { // Positive test case assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1136,7 +1136,7 @@ fn verify_64_bit_range_check() { // Negative test case assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1168,7 +1168,7 @@ fn compact_multi_range_check() { // Positive test assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1182,7 +1182,7 @@ fn compact_multi_range_check() { // Negative test assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1222,7 +1222,7 @@ fn verify_range_check_valid_proof1() { let verifier_index = prover_index.verifier_index(); // Verify proof - let res = verify::>( + let res = verify::, COLUMNS>( &group_map, &verifier_index, &proof, @@ -1245,7 +1245,7 @@ fn verify_compact_multi_range_check_proof() { let (_next_row, gates) = CircuitGate::::create_compact_multi_range_check(0); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/recursion.rs b/kimchi/src/tests/recursion.rs index 7e788f7d5f..60ef234e7c 100644 --- a/kimchi/src/tests/recursion.rs +++ b/kimchi/src/tests/recursion.rs @@ -21,14 +21,14 @@ type ScalarSponge = DefaultFrSponge; #[test] fn test_recursion() { - let gates = create_circuit::(0, 0); + let gates = create_circuit::(0, 0); // create witness let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &[]); // setup - let test_runner = TestFramework::::default() + let test_runner = TestFramework::::default() .num_prev_challenges(1) .gates(gates) .witness(witness) diff --git a/kimchi/src/tests/rot.rs b/kimchi/src/tests/rot.rs index 2c392f06ca..a92ca36b57 100644 --- a/kimchi/src/tests/rot.rs +++ b/kimchi/src/tests/rot.rs @@ -94,7 +94,7 @@ fn prove_and_verify() where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let rng = &mut StdRng::from_seed(RNG_SEED); let rot = rng.gen_range(1..64); @@ -107,7 +107,7 @@ where // Create witness let witness = create_rot_witness::(word, rot, RotMode::Left); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() @@ -129,7 +129,7 @@ where let (witness, cs) = setup_rot::(word, rot, side); for row in 0..=2 { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -207,7 +207,7 @@ fn test_bad_constraints() { witness[i + 7][1] += PallasField::from(4u32); // Decomposition constraint fails assert_eq!( - cs.gates[1].verify_witness::( + cs.gates[1].verify_witness::( 1, &witness, &cs, @@ -224,7 +224,7 @@ fn test_bad_constraints() { witness[0][1] += PallasField::one(); // Decomposition constraint fails assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::Rot64, 9)) ); // undo @@ -235,7 +235,7 @@ fn test_bad_constraints() { witness[1][1] += PallasField::one(); // Rotated word is wrong assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::Rot64, 10)) ); // undo @@ -248,7 +248,7 @@ fn test_bad_constraints() { witness[i + 3][1] += PallasField::one(); // Bound constraint fails assert_eq!( - cs.gates[1].verify_witness::( + cs.gates[1].verify_witness::( 1, &witness, &cs, @@ -264,11 +264,11 @@ fn test_bad_constraints() { witness[2][1] += PallasField::one(); witness[0][3] += PallasField::one(); assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::Rot64, 9)) ); assert_eq!( - cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); witness[2][1] -= PallasField::one(); @@ -277,11 +277,11 @@ fn test_bad_constraints() { // modify shifted witness[0][2] += PallasField::one(); assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::Rot64, 9)) ); assert_eq!( - cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); witness[0][2] -= PallasField::one(); @@ -289,14 +289,14 @@ fn test_bad_constraints() { // modify value of shifted to be more than 64 bits witness[0][2] += PallasField::two_pow(64); assert_eq!( - cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); // Update decomposition witness[2][2] += PallasField::one(); // Make sure the 64-bit check fails assert_eq!( - cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::CopyConstraint { typ: GateType::RangeCheck0, src: Wire { row: 2, col: 2 }, @@ -310,14 +310,14 @@ fn test_bad_constraints() { witness[0][3] += PallasField::two_pow(64); witness[2][1] += PallasField::two_pow(64); assert_eq!( - cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); // Update decomposition witness[2][3] += PallasField::one(); // Make sure the 64-bit check fails assert_eq!( - cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::CopyConstraint { typ: GateType::RangeCheck0, src: Wire { row: 3, col: 2 }, @@ -377,12 +377,12 @@ fn test_rot_finalization() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::>::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; for row in 0..witness[0].len() { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -392,7 +392,7 @@ fn test_rot_finalization() { ); } - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness.clone()) .public_inputs(vec![witness[0][0], witness[0][1]]) diff --git a/kimchi/src/tests/serde.rs b/kimchi/src/tests/serde.rs index bf087d5c88..1a1735a406 100644 --- a/kimchi/src/tests/serde.rs +++ b/kimchi/src/tests/serde.rs @@ -41,7 +41,7 @@ mod tests { println!("proof size: {} bytes", ser_pf.len()); // deserialize the proof - let de_pf: ProverProof> = + let de_pf: ProverProof> = rmp_serde::from_slice(&ser_pf).unwrap(); // verify the deserialized proof (must accept the proof) @@ -51,7 +51,7 @@ mod tests { #[test] pub fn test_serialization() { let public = vec![Fp::from(3u8); 5]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); @@ -73,11 +73,8 @@ mod tests { .unwrap(); // deserialize the verifier index - let mut verifier_index_deserialize: VerifierIndex< - COLUMNS, - GroupAffine, - _, - > = serde_json::from_str(&verifier_index_serialize).unwrap(); + let mut verifier_index_deserialize: VerifierIndex, _> = + serde_json::from_str(&verifier_index_serialize).unwrap(); // add srs with lagrange bases let mut srs = SRS::>::create(verifier_index.max_poly_size); @@ -88,7 +85,7 @@ mod tests { // verify the proof let start = Instant::now(); - verify::>( + verify::, COLUMNS>( &group_map, &verifier_index_deserialize, &proof, diff --git a/kimchi/src/tests/turshi.rs b/kimchi/src/tests/turshi.rs index 971bc86a71..25b1d311b1 100644 --- a/kimchi/src/tests/turshi.rs +++ b/kimchi/src/tests/turshi.rs @@ -22,7 +22,7 @@ fn test_cairo_should_fail() { let inirow = 0; let (circuit, _) = CircuitGate::::create_cairo_gadget(inirow, ninstr); - let mut witness = cairo_witness::(&prog); + let mut witness = cairo_witness::(&prog); // break a witness witness[0][0] += F::from(1u32); let res_ensure = ensure_cairo_gate(&circuit[0], 0, &witness); @@ -68,7 +68,7 @@ fn test_cairo_gate() { mem.write(F::from(23u32), F::from(44u32)); //end of program let prog = CairoProgram::new(&mut mem, 5); - let witness = cairo_witness::(&prog); + let witness = cairo_witness::(&prog); // Create the Cairo circuit let ninstr = prog.trace().len(); diff --git a/kimchi/src/tests/varbasemul.rs b/kimchi/src/tests/varbasemul.rs index df46e12f7d..91eed12b78 100644 --- a/kimchi/src/tests/varbasemul.rs +++ b/kimchi/src/tests/varbasemul.rs @@ -89,7 +89,7 @@ fn varbase_mul_test() { start.elapsed() ); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() diff --git a/kimchi/src/tests/xor.rs b/kimchi/src/tests/xor.rs index 570908035a..f520a56cab 100644 --- a/kimchi/src/tests/xor.rs +++ b/kimchi/src/tests/xor.rs @@ -143,7 +143,7 @@ where let (cs, witness) = setup_xor::(in1, in2, bits); for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -171,7 +171,7 @@ fn test_prove_and_verify_xor() { // Create witness and random inputs let witness = xor::create_xor_witness(input1, input2, bits); - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() @@ -258,14 +258,14 @@ fn verify_bad_xor_decomposition( let bad = if col < 3 { col + 1 } else { (col - 3) / 4 + 1 }; witness[col][0] += G::ScalarField::one(); assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), Err(CircuitGateError::Constraint(GateType::Xor16, bad)) ); witness[col][0] -= G::ScalarField::one(); } // undo changes assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), Ok(()) ); } @@ -313,11 +313,11 @@ fn test_extend_xor() { let mut witness: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); 2]); witness[0][0] = input1; witness[0][1] = input2; - xor::extend_xor_witness::(&mut witness, input1, input2, bits); + xor::extend_xor_witness::(&mut witness, input1, input2, bits); for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -354,7 +354,7 @@ fn test_bad_xor() { } assert_eq!( - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .setup() @@ -399,7 +399,7 @@ fn test_xor_finalization() { cols[0][0] = input1; cols[0][1] = input2; - xor::extend_xor_witness::(&mut cols, input1, input2, 128); + xor::extend_xor_witness(&mut cols, input1, input2, 128); cols }; @@ -414,12 +414,12 @@ fn test_xor_finalization() { let srs = Arc::new(srs); let (endo_q, _endo_r) = endos::(); - ProverIndex::>::create(cs, endo_q, srs) + ProverIndex::>::create(cs, endo_q, srs) }; for row in 0..witness[0].len() { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -429,7 +429,7 @@ fn test_xor_finalization() { ); } - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness.clone()) .public_inputs(vec![witness[0][0], witness[0][1]]) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 13d94e76a3..8e5837f0b2 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -10,7 +10,7 @@ use crate::{ lookup::{lookups::LookupPattern, tables::combine_table}, polynomials::permutation, scalars::RandomOracles, - wires::PERMUTS, + wires::{COLUMNS, PERMUTS}, }, curve::KimchiCurve, error::VerifyError, @@ -35,19 +35,19 @@ use rand::thread_rng; /// The result of a proof verification. pub type Result = std::result::Result; -pub struct Context<'a, const W: usize, G: KimchiCurve, OpeningProof: OpenProof> { +pub struct Context<'a, G: KimchiCurve, OpeningProof: OpenProof, const W: usize = COLUMNS> { /// The [VerifierIndex] associated to the proof - pub verifier_index: &'a VerifierIndex, + pub verifier_index: &'a VerifierIndex, /// The proof to verify - pub proof: &'a ProverProof, + pub proof: &'a ProverProof, /// The public input used in the creation of the proof pub public_input: &'a [G::ScalarField], } -impl<'a, const W: usize, G: KimchiCurve, OpeningProof: OpenProof> - Context<'a, W, G, OpeningProof> +impl<'a, G: KimchiCurve, OpeningProof: OpenProof, const W: usize> + Context<'a, G, OpeningProof, W> { pub fn get_column(&self, col: Column) -> Option<&'a PolyComm> { use Column::*; @@ -94,7 +94,7 @@ impl<'a, const W: usize, G: KimchiCurve, OpeningProof: OpenProof> } } -impl> ProverProof +impl, const W: usize> ProverProof where G::BaseField: PrimeField, { @@ -109,10 +109,10 @@ where /// Will panic if `PolishToken` evaluation is invalid. pub fn oracles< EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, >( &self, - index: &VerifierIndex, + index: &VerifierIndex, public_comm: &PolyComm, public_input: Option<&[G::ScalarField]>, ) -> Result> { @@ -601,8 +601,8 @@ where /// Enforce the length of evaluations inside [`Proof`]. /// Atm, the length of evaluations(both `zeta` and `zeta_omega`) SHOULD be 1. /// The length value is prone to future change. -fn check_proof_evals_len( - proof: &ProverProof, +fn check_proof_evals_len( + proof: &ProverProof, expected_size: usize, ) -> Result<()> where @@ -741,16 +741,16 @@ where Ok(()) } -fn to_batch<'a, const W: usize, G, EFqSponge, EFrSponge, OpeningProof: OpenProof>( - verifier_index: &VerifierIndex, - proof: &'a ProverProof, +fn to_batch<'a, G, EFqSponge, EFrSponge, OpeningProof: OpenProof, const W: usize>( + verifier_index: &VerifierIndex, + proof: &'a ProverProof, public_input: &'a [::ScalarField], ) -> Result> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { //~ //~ #### Partial verification @@ -1150,24 +1150,24 @@ where /// # Errors /// /// Will give error if `proof(s)` are not verified as valid. -pub fn verify>( +pub fn verify, const W: usize>( group_map: &G::Map, - verifier_index: &VerifierIndex, - proof: &ProverProof, + verifier_index: &VerifierIndex, + proof: &ProverProof, public_input: &[G::ScalarField], ) -> Result<()> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let proofs = vec![Context { verifier_index, proof, public_input, }]; - batch_verify::(group_map, &proofs) + batch_verify::(group_map, &proofs) } /// This function verifies the batch of zk-proofs @@ -1177,15 +1177,15 @@ where /// # Errors /// /// Will give error if `srs` of `proof` is invalid or `verify` process fails. -pub fn batch_verify>( +pub fn batch_verify, const W: usize>( group_map: &G::Map, - proofs: &[Context], + proofs: &[Context], ) -> Result<()> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { //~ #### Batch verification of proofs //~ @@ -1216,7 +1216,7 @@ where public_input, } in proofs { - batch.push(to_batch::( + batch.push(to_batch::( verifier_index, proof, public_input, diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index ad7e230a34..9ddd318c2a 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -8,7 +8,7 @@ use crate::{ expr::{Linearization, PolishToken}, lookup::{index::LookupSelectors, lookups::LookupInfo}, polynomials::permutation::{vanishes_on_last_n_rows, zk_w}, - wires::PERMUTS, + wires::{COLUMNS, PERMUTS}, }, curve::KimchiCurve, prover_index::ProverIndex, @@ -56,7 +56,7 @@ pub struct LookupVerifierIndex { #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VerifierIndex> { +pub struct VerifierIndex, const W: usize = COLUMNS> { /// evaluation domain #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub domain: D, @@ -152,7 +152,7 @@ pub struct VerifierIndex> ProverIndex +impl, const W: usize> ProverIndex where G::BaseField: PrimeField, { @@ -161,9 +161,9 @@ where /// # Panics /// /// Will panic if `srs` cannot be in `cell`. - pub fn verifier_index(&self) -> VerifierIndex + pub fn verifier_index(&self) -> VerifierIndex where - VerifierIndex: Clone, + VerifierIndex: Clone, { if let Some(verifier_index) = &self.verifier_index { return verifier_index.clone(); @@ -315,7 +315,7 @@ where } } -impl> VerifierIndex { +impl, const W: usize> VerifierIndex { /// Gets srs from [`VerifierIndex`] lazily pub fn srs(&self) -> &Arc where diff --git a/tools/kimchi-visu/src/lib.rs b/tools/kimchi-visu/src/lib.rs index 11495ed3ce..ece3ffad0d 100644 --- a/tools/kimchi-visu/src/lib.rs +++ b/tools/kimchi-visu/src/lib.rs @@ -75,8 +75,8 @@ where /// # Panics /// /// Will panic if `TinyTemplate::render()` returns `Error` or `std::fs::File::create()` returns `Error`. -pub fn visu( - index: &ProverIndex>, +pub fn visu( + index: &ProverIndex, W>, witness: Option>, ) where G::BaseField: PrimeField, diff --git a/tools/kimchi-visu/src/main.rs b/tools/kimchi-visu/src/main.rs index afcf8a988a..b8c1636f09 100644 --- a/tools/kimchi-visu/src/main.rs +++ b/tools/kimchi-visu/src/main.rs @@ -59,7 +59,7 @@ fn main() { }; // create the index - let index = new_index_for_test::(gates, public); + let index = new_index_for_test::(gates, public); // create the witness let mut witness = Witness::new(row + 1).inner(); From 399d5f824498d54a03085d01af0496940e4face1 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 30 Oct 2023 18:50:34 +0100 Subject: [PATCH 208/242] replace generic W for COLUMNS and now KIMCHI_COLS means 15 --- book/src/specs/kimchi.md | 36 ++++-- kimchi/src/alphas.rs | 6 +- kimchi/src/bench.rs | 18 ++- kimchi/src/circuits/berkeley_columns.rs | 4 +- kimchi/src/circuits/constraints.rs | 59 +++++---- kimchi/src/circuits/expr.rs | 18 +-- kimchi/src/circuits/gate.rs | 44 ++++--- kimchi/src/circuits/lookup/constraints.rs | 12 +- kimchi/src/circuits/lookup/index.rs | 4 +- kimchi/src/circuits/lookup/lookups.rs | 2 +- kimchi/src/circuits/polynomial.rs | 18 +-- kimchi/src/circuits/polynomials/and.rs | 14 +- .../src/circuits/polynomials/complete_add.rs | 4 +- .../circuits/polynomials/endomul_scalar.rs | 8 +- kimchi/src/circuits/polynomials/endosclmul.rs | 14 +- .../polynomials/foreign_field_add/witness.rs | 12 +- .../polynomials/foreign_field_mul/gadget.rs | 2 +- .../polynomials/foreign_field_mul/witness.rs | 19 +-- kimchi/src/circuits/polynomials/generic.rs | 20 +-- kimchi/src/circuits/polynomials/keccak.rs | 6 +- kimchi/src/circuits/polynomials/not.rs | 14 +- .../src/circuits/polynomials/permutation.rs | 18 +-- kimchi/src/circuits/polynomials/poseidon.rs | 10 +- .../polynomials/range_check/circuitgates.rs | 14 +- .../polynomials/range_check/gadget.rs | 2 +- .../polynomials/range_check/witness.rs | 47 +++---- kimchi/src/circuits/polynomials/rot.rs | 14 +- kimchi/src/circuits/polynomials/turshi.rs | 61 +++++---- kimchi/src/circuits/polynomials/varbasemul.rs | 14 +- kimchi/src/circuits/polynomials/xor.rs | 29 +++-- kimchi/src/circuits/wires.rs | 4 +- kimchi/src/circuits/witness/constant_cell.rs | 9 +- kimchi/src/circuits/witness/copy_bits_cell.rs | 9 +- kimchi/src/circuits/witness/copy_cell.rs | 9 +- .../src/circuits/witness/copy_shift_cell.rs | 9 +- kimchi/src/circuits/witness/index_cell.rs | 9 +- kimchi/src/circuits/witness/mod.rs | 32 ++--- .../circuits/witness/variable_bits_cell.rs | 9 +- kimchi/src/circuits/witness/variable_cell.rs | 9 +- kimchi/src/linearization.rs | 16 +-- kimchi/src/oracles.rs | 8 +- kimchi/src/plonk_sponge.rs | 10 +- kimchi/src/proof.rs | 48 ++++--- kimchi/src/prover.rs | 55 ++++---- kimchi/src/prover_index.rs | 39 +++--- kimchi/src/snarky/constraint_system.rs | 4 +- kimchi/src/tests/and.rs | 35 +++-- kimchi/src/tests/chunked.rs | 4 +- kimchi/src/tests/ec.rs | 2 +- kimchi/src/tests/endomul.rs | 2 +- kimchi/src/tests/endomul_scalar.rs | 2 +- kimchi/src/tests/foreign_field_add.rs | 69 +++++----- kimchi/src/tests/foreign_field_mul.rs | 14 +- kimchi/src/tests/framework.rs | 50 +++---- kimchi/src/tests/generic.rs | 28 ++-- kimchi/src/tests/lookup.rs | 14 +- kimchi/src/tests/not.rs | 58 ++++++--- kimchi/src/tests/poseidon.rs | 4 +- kimchi/src/tests/range_check.rs | 122 +++++++++--------- kimchi/src/tests/recursion.rs | 6 +- kimchi/src/tests/rot.rs | 96 ++++++++++---- kimchi/src/tests/serde.rs | 8 +- kimchi/src/tests/turshi.rs | 6 +- kimchi/src/tests/varbasemul.rs | 2 +- kimchi/src/tests/xor.rs | 43 +++--- kimchi/src/verifier.rs | 62 +++++---- kimchi/src/verifier_index.rs | 23 ++-- tools/kimchi-visu/src/lib.rs | 4 +- tools/kimchi-visu/src/main.rs | 4 +- tools/kimchi-visu/src/witness.rs | 14 +- 70 files changed, 848 insertions(+), 646 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 57cb70363d..d80a376832 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1703,7 +1703,11 @@ Both the prover and the verifier index, besides the common parts described above These pre-computations are optimizations, in the context of normal proofs, but they are necessary for recursion. ```rs -pub struct ProverIndex, const W: usize=COLUMNS> { +pub struct ProverIndex< + G: KimchiCurve, + OpeningProof: OpenProof, + const COLUMNS: usize = KIMCHI_COLS, +> { /// constraints system polynomials #[serde(bound = "ConstraintSystem: Serialize + DeserializeOwned")] pub cs: ConstraintSystem, @@ -1724,12 +1728,12 @@ pub struct ProverIndex, const W: usiz /// maximal size of polynomial section pub max_poly_size: usize, - #[serde(bound = "ColumnEvaluations: Serialize + DeserializeOwned")] - pub column_evaluations: ColumnEvaluations, + #[serde(bound = "ColumnEvaluations: Serialize + DeserializeOwned")] + pub column_evaluations: ColumnEvaluations, /// The verifier index corresponding to this prover index #[serde(skip)] - pub verifier_index: Option>, + pub verifier_index: Option>, /// The verifier index digest corresponding to this prover index #[serde_as(as = "Option")] @@ -1767,7 +1771,11 @@ pub struct LookupVerifierIndex { #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VerifierIndex, const W: usize = COLUMNS> { +pub struct VerifierIndex< + G: KimchiCurve, + OpeningProof: OpenProof, + const COLUMNS: usize = KIMCHI_COLS, +> { /// evaluation domain #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub domain: D, @@ -1789,8 +1797,8 @@ pub struct VerifierIndex, const W: us #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub sigma_comm: [PolyComm; PERMUTS], /// coefficient commitment array - #[serde_as(as = "[_; W]")] - pub coefficients_comm: [PolyComm; W], + #[serde_as(as = "[_; COLUMNS]")] + pub coefficients_comm: [PolyComm; COLUMNS], /// coefficient commitment array #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub generic_comm: PolyComm, @@ -1963,7 +1971,7 @@ pub struct PointEvaluations { /// - **Non chunked evaluations** `Field` is instantiated with a field, so they are single-sized#[serde_as] #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ProofEvaluations { +pub struct ProofEvaluations { /// public input polynomials pub public: Option, /// witness polynomials @@ -2042,7 +2050,7 @@ pub struct LookupCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverCommitments { +pub struct ProverCommitments { /// The commitments to the witness (execution trace) pub w_comm: Vec>, /// The commitment to the permutation polynomial @@ -2057,9 +2065,9 @@ pub struct ProverCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverProof { +pub struct ProverProof { /// All the polynomial commitments required in the proof - pub commitments: ProverCommitments, + pub commitments: ProverCommitments, /// batched commitment opening proof #[serde(bound( @@ -2069,7 +2077,7 @@ pub struct ProverProof { pub proof: OpeningProof, /// Two evaluations over a number of committed polynomials - pub evals: ProofEvaluations>, W>, + pub evals: ProofEvaluations>, COLUMNS>, /// Required evaluation for [Maller's optimization](https://o1-labs.github.io/mina-book/crypto/plonk/maller_15.html#the-evaluation-of-l) #[serde_as(as = "o1_utils::serialization::SerdeAs")] @@ -2140,12 +2148,12 @@ The prover then follows the following steps to create the proof: Note: unlike the original PLONK protocol, the prover also provides evaluations of the public polynomial to help the verifier circuit. This is why we need to absorb the commitment to the public polynomial at this point. -1. Commit to the witness columns by creating `COLUMNS` hidding commitments. +1. Commit to the witness columns by creating `KIMCHI_COLS` hidding commitments. Note: since the witness is in evaluation form, we can use the `commit_evaluation` optimization. 1. Absorb the witness commitments with the Fq-Sponge. -1. Compute the witness polynomials by interpolating each `COLUMNS` of the witness. +1. Compute the witness polynomials by interpolating each `KIMCHI_COLS` of the witness. As mentioned above, we commit using the evaluations form rather than the coefficients form so we can take advantage of the sparsity of the evaluations (i.e., there are many 0 entries and entries that have less-than-full-size field elemnts.) diff --git a/kimchi/src/alphas.rs b/kimchi/src/alphas.rs index 031c01e20a..f3fe7b6563 100644 --- a/kimchi/src/alphas.rs +++ b/kimchi/src/alphas.rs @@ -242,7 +242,7 @@ mod tests { use std::{fs, path::Path}; use super::*; - use crate::circuits::{gate::GateType, polynomial::COLUMNS}; + use crate::circuits::{gate::GateType, polynomial::KIMCHI_COLS}; use mina_curves::pasta::{Fp, Vesta}; // testing [Builder] @@ -322,9 +322,9 @@ mod tests { #[test] fn get_alphas_for_spec() { let gates = vec![CircuitGate::::zero(Wire::for_row(0)); 2]; - let index = new_index_for_test::(gates, 0); + let index = new_index_for_test::(gates, 0); let (_linearization, powers_of_alpha) = - expr_linearization::(Some(&index.cs.feature_flags), true); + expr_linearization::(Some(&index.cs.feature_flags), true); // make sure this is present in the specification let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let spec_path = Path::new(&manifest_dir) diff --git a/kimchi/src/bench.rs b/kimchi/src/bench.rs index 00fe661706..57cd64ff80 100644 --- a/kimchi/src/bench.rs +++ b/kimchi/src/bench.rs @@ -13,7 +13,7 @@ use crate::{ circuits::{ gate::CircuitGate, polynomials::generic::GenericGateSpec, - wires::{Wire, COLUMNS}, + wires::{Wire, KIMCHI_COLS}, }, proof::ProverProof, prover_index::{testing::new_index_for_test, ProverIndex}, @@ -77,9 +77,14 @@ impl BenchmarkCtx { } /// Produces a proof - pub fn create_proof(&self) -> (ProverProof, COLUMNS>, Vec) { + pub fn create_proof( + &self, + ) -> ( + ProverProof, KIMCHI_COLS>, + Vec, + ) { // create witness - let witness: [Vec; COLUMNS] = array::from_fn(|_| vec![1u32.into(); self.num_gates]); + let witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![1u32.into(); self.num_gates]); let public_input = witness[0][0..self.index.cs.public].to_vec(); @@ -99,7 +104,10 @@ impl BenchmarkCtx { #[allow(clippy::type_complexity)] pub fn batch_verification( &self, - batch: &[(ProverProof, COLUMNS>, Vec)], + batch: &[( + ProverProof, KIMCHI_COLS>, + Vec, + )], ) { // verify the proof let batch: Vec<_> = batch @@ -110,7 +118,7 @@ impl BenchmarkCtx { public_input: public, }) .collect(); - batch_verify::, COLUMNS>( + batch_verify::, KIMCHI_COLS>( &self.group_map, &batch, ) diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs index 454ba186b8..493395fbdc 100644 --- a/kimchi/src/circuits/berkeley_columns.rs +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -95,7 +95,9 @@ impl expr::Variable { } } -impl ColumnEvaluations for ProofEvaluations, W> { +impl ColumnEvaluations + for ProofEvaluations, COLUMNS> +{ type Column = Column; fn evaluate(&self, col: Self::Column) -> Result, ExprError> { use Column::*; diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 64ee13ef75..1c747c78ac 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -53,14 +53,14 @@ pub struct FeatureFlags { /// The polynomials representing evaluated columns, in coefficient form. #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] -pub struct EvaluatedColumnCoefficients { +pub struct EvaluatedColumnCoefficients { /// permutation coefficients #[serde_as(as = "[o1_utils::serialization::SerdeAs; PERMUTS]")] pub permutation_coefficients: [DP; PERMUTS], /// gate coefficients - #[serde_as(as = "[o1_utils::serialization::SerdeAs; W]")] - pub coefficients: [DP; W], + #[serde_as(as = "[o1_utils::serialization::SerdeAs; COLUMNS]")] + pub coefficients: [DP; COLUMNS], /// generic gate selector #[serde_as(as = "o1_utils::serialization::SerdeAs")] @@ -75,14 +75,14 @@ pub struct EvaluatedColumnCoefficients /// The evaluations are expanded to the domain size required for their constraints. #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] -pub struct ColumnEvaluations { +pub struct ColumnEvaluations { /// permutation coefficients over domain d8 #[serde_as(as = "[o1_utils::serialization::SerdeAs; PERMUTS]")] pub permutation_coefficients8: [E>; PERMUTS], /// coefficients over domain d8 - #[serde_as(as = "[o1_utils::serialization::SerdeAs; W]")] - pub coefficients8: [E>; W], + #[serde_as(as = "[o1_utils::serialization::SerdeAs; COLUMNS]")] + pub coefficients8: [E>; COLUMNS], /// generic selector over domain d4 #[serde_as(as = "o1_utils::serialization::SerdeAs")] @@ -273,17 +273,17 @@ impl< F: PrimeField + SquareRootField, G: KimchiCurve, OpeningProof: OpenProof, - const W: usize, - > ProverIndex + const COLUMNS: usize, + > ProverIndex { /// This function verifies the consistency of the wire /// assignments (witness) against the constraints /// witness: wire assignment witness /// RETURN: verification status - pub fn verify(&self, witness: &[Vec; W], public: &[F]) -> Result<(), GateError> { + pub fn verify(&self, witness: &[Vec; COLUMNS], public: &[F]) -> Result<(), GateError> { // pad the witness let pad = vec![F::zero(); self.cs.domain.d1.size() - witness[0].len()]; - let witness: [Vec; W] = array::from_fn(|i| { + let witness: [Vec; COLUMNS] = array::from_fn(|i| { let mut w = witness[i].to_vec(); w.extend_from_slice(&pad); w @@ -319,7 +319,7 @@ impl< } // check the gate's satisfiability - gate.verify::(row, &witness, self, public) + gate.verify::(row, &witness, self, public) .map_err(|err| GateError::Custom { row, err })?; } @@ -330,13 +330,17 @@ impl< impl ConstraintSystem { /// evaluate witness polynomials over domains - pub fn evaluate(&self, w: &[DP; W], z: &DP) -> WitnessOverDomains { + pub fn evaluate( + &self, + w: &[DP; COLUMNS], + z: &DP, + ) -> WitnessOverDomains { // compute shifted witness polynomials - let w8: [E>; W] = + let w8: [E>; COLUMNS] = array::from_fn(|i| w[i].evaluate_over_domain_by_ref(self.domain.d8)); let z8 = z.evaluate_over_domain_by_ref(self.domain.d8); - let w4: [E>; W] = array::from_fn(|i| { + let w4: [E>; COLUMNS] = array::from_fn(|i| { E::>::from_vec_and_domain( (0..self.domain.d4.size) .map(|j| w8[i].evals[2 * j as usize]) @@ -368,9 +372,9 @@ impl ConstraintSystem { } } - pub(crate) fn evaluated_column_coefficients( + pub(crate) fn evaluated_column_coefficients( &self, - ) -> EvaluatedColumnCoefficients { + ) -> EvaluatedColumnCoefficients { // compute permutation polynomials let shifts = Shifts::new(&self.domain.d1); @@ -432,7 +436,7 @@ impl ConstraintSystem { .interpolate(); // coefficient polynomial - let coefficients: [_; W] = array::from_fn(|i| { + let coefficients: [_; COLUMNS] = array::from_fn(|i| { let padded = self .gates .iter() @@ -450,10 +454,10 @@ impl ConstraintSystem { } } - pub(crate) fn column_evaluations( + pub(crate) fn column_evaluations( &self, - evaluated_column_coefficients: &EvaluatedColumnCoefficients, - ) -> ColumnEvaluations { + evaluated_column_coefficients: &EvaluatedColumnCoefficients, + ) -> ColumnEvaluations { let permutation_coefficients8 = array::from_fn(|i| { evaluated_column_coefficients.permutation_coefficients[i] .evaluate_over_domain_by_ref(self.domain.d8) @@ -676,7 +680,7 @@ impl Builder { } /// Build the [ConstraintSystem] from a [Builder]. - pub fn build(self) -> Result, SetupError> { + pub fn build(self) -> Result, SetupError> { let mut gates = self.gates; let lookup_tables = self.lookup_tables; let runtime_tables = self.runtime_tables; @@ -818,7 +822,7 @@ impl Builder { // // Lookup // ------ - let lookup_constraint_system = LookupConstraintSystem::create::( + let lookup_constraint_system = LookupConstraintSystem::create::( &gates, lookup_tables, runtime_tables, @@ -868,12 +872,12 @@ pub mod tests { use mina_curves::pasta::Fp; impl ConstraintSystem { - pub fn for_testing(gates: Vec>) -> Self { + pub fn for_testing(gates: Vec>) -> Self { let public = 0; // not sure if theres a smarter way instead of the double unwrap, but should be fine in the test ConstraintSystem::::create(gates) .public(public) - .build::() + .build::() .unwrap() } } @@ -881,7 +885,7 @@ pub mod tests { impl ConstraintSystem { pub fn fp_for_testing(gates: Vec>) -> Self { //let fp_sponge_params = mina_poseidon::pasta::fp_kimchi::params(); - Self::for_testing::(gates) + Self::for_testing::(gates) } } @@ -908,7 +912,10 @@ pub mod tests { } }) .collect(); - let res = builder.runtime(Some(rt_cfgs)).build::().unwrap(); + let res = builder + .runtime(Some(rt_cfgs)) + .build::() + .unwrap(); assert_eq!(res.domain.d1.size, expected_domain_size) } } diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 149c96efb1..393a69f728 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -97,11 +97,11 @@ pub struct LookupEnvironment<'a, F: FftField> { /// required to evaluate an expression as a polynomial. /// /// All are evaluations. -pub struct Environment<'a, F: FftField, const W: usize = COLUMNS> { +pub struct Environment<'a, F: FftField, const COLUMNS: usize = KIMCHI_COLS> { /// The witness column polynomials - pub witness: &'a [Evaluations>; W], + pub witness: &'a [Evaluations>; COLUMNS], /// The coefficient column polynomials - pub coefficient: &'a [Evaluations>; W], + pub coefficient: &'a [Evaluations>; COLUMNS], /// The polynomial that vanishes on the zero-knowledge rows and the row before. pub vanishes_on_zero_knowledge_and_previous_rows: &'a Evaluations>, /// The permutation aggregation polynomial. @@ -128,7 +128,9 @@ pub trait ColumnEnvironment<'a, F: FftField> { fn l0_1(&self) -> F; } -impl<'a, F: FftField, const W: usize> ColumnEnvironment<'a, F> for Environment<'a, F, W> { +impl<'a, F: FftField, const COLUMNS: usize> ColumnEnvironment<'a, F> + for Environment<'a, F, COLUMNS> +{ type Column = berkeley_columns::Column; fn get_column(&self, col: &Self::Column) -> Option<&'a Evaluations>> { @@ -1458,7 +1460,7 @@ impl Expr /// Evaluate an expression as a field element against an environment. pub fn evaluate< 'a, - const W: usize, + const COLUMNS: usize, Evaluations: ColumnEvaluations, Environment: ColumnEnvironment<'a, F, Column = Column>, >( @@ -2890,7 +2892,7 @@ macro_rules! auto_clone_array { pub use auto_clone; pub use auto_clone_array; -use super::wires::COLUMNS; +use super::wires::KIMCHI_COLS; /// You can import this module like `use kimchi::circuits::expr::prologue::*` to obtain a number of handy aliases and helpers pub mod prologue { @@ -2903,7 +2905,7 @@ pub mod test { use crate::{ circuits::{ constraints::ConstraintSystem, expr::constraints::ExprOps, gate::CircuitGate, - polynomial::COLUMNS, polynomials::generic::GenericGateSpec, wires::Wire, + polynomial::KIMCHI_COLS, polynomials::generic::GenericGateSpec, wires::Wire, }, curve::KimchiCurve, prover_index::ProverIndex, @@ -2966,7 +2968,7 @@ pub mod test { ProverIndex::>::create(constraint_system, endo_q, srs) }; - let witness_cols: [_; COLUMNS] = array::from_fn(|_| DensePolynomial::zero()); + let witness_cols: [_; KIMCHI_COLS] = array::from_fn(|_| DensePolynomial::zero()); let permutation = DensePolynomial::zero(); let domain_evals = index.cs.evaluate(&witness_cols, &permutation); diff --git a/kimchi/src/circuits/gate.rs b/kimchi/src/circuits/gate.rs index 1772b6309b..4738b966c0 100644 --- a/kimchi/src/circuits/gate.rs +++ b/kimchi/src/circuits/gate.rs @@ -171,7 +171,7 @@ impl ToBytes for CircuitGate { let typ: u8 = ToPrimitive::to_u8(&self.typ).unwrap(); typ.write(&mut w)?; // TODO: update to use real value of width here - for i in 0..COLUMNS { + for i in 0..KIMCHI_COLS { self.wires[i].write(&mut w)?; } @@ -195,50 +195,54 @@ impl CircuitGate { /// # Errors /// /// Will give error if verify process returns error. - pub fn verify, OpeningProof: OpenProof, const W: usize>( + pub fn verify< + G: KimchiCurve, + OpeningProof: OpenProof, + const COLUMNS: usize, + >( &self, row: usize, - witness: &[Vec; W], - index: &ProverIndex, + witness: &[Vec; COLUMNS], + index: &ProverIndex, public: &[F], ) -> Result<(), String> { use GateType::*; match self.typ { Zero => Ok(()), Generic => self.verify_generic(row, witness, public), - Poseidon => self.verify_poseidon::(row, witness), + Poseidon => self.verify_poseidon::(row, witness), CompleteAdd => self.verify_complete_add(row, witness), VarBaseMul => self.verify_vbmul(row, witness), - EndoMul => self.verify_endomul::(row, witness, &index.cs), - EndoMulScalar => self.verify_endomul_scalar::(row, witness, &index.cs), + EndoMul => self.verify_endomul::(row, witness, &index.cs), + EndoMulScalar => self.verify_endomul_scalar::(row, witness, &index.cs), // TODO: implement the verification for the lookup gate Lookup => Ok(()), CairoClaim | CairoInstruction | CairoFlags | CairoTransition => { - self.verify_cairo_gate::(row, witness, &index.cs) + self.verify_cairo_gate::(row, witness, &index.cs) } RangeCheck0 | RangeCheck1 => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), ForeignFieldAdd => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), ForeignFieldMul => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), Xor16 => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), Rot64 => self - .verify_witness::(row, witness, &index.cs, public) + .verify_witness::(row, witness, &index.cs, public) .map_err(|e| e.to_string()), } } /// Verify the witness against the constraints - pub fn verify_witness, const W: usize>( + pub fn verify_witness, const COLUMNS: usize>( &self, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], cs: &ConstraintSystem, _public: &[F], ) -> CircuitGateResult<()> { @@ -340,25 +344,25 @@ impl CircuitGate { } // Return the part of the witness relevant to this gate at the given row offset - fn argument_witness( + fn argument_witness( &self, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], ) -> CircuitGateResult> { // Get the part of the witness relevant to this gate - let witness_curr: [F; W] = (0..witness.len()) + let witness_curr: [F; COLUMNS] = (0..witness.len()) .map(|col| witness[col][row]) .collect::>() .try_into() .map_err(|_| CircuitGateError::FailedToGetWitnessForRow(self.typ, row))?; - let witness_next: [F; W] = if witness[0].len() > row + 1 { + let witness_next: [F; COLUMNS] = if witness[0].len() > row + 1 { (0..witness.len()) .map(|col| witness[col][row + 1]) .collect::>() .try_into() .map_err(|_| CircuitGateError::FailedToGetWitnessForRow(self.typ, row))? } else { - [F::zero(); W] + [F::zero(); COLUMNS] }; Ok(ArgumentWitness:: { diff --git a/kimchi/src/circuits/lookup/constraints.rs b/kimchi/src/circuits/lookup/constraints.rs index fbc464e068..317c9738c7 100644 --- a/kimchi/src/circuits/lookup/constraints.rs +++ b/kimchi/src/circuits/lookup/constraints.rs @@ -83,12 +83,12 @@ pub fn zk_patch( /// /// Will panic if `value(s)` are missing from the `table`. #[allow(clippy::too_many_arguments)] -pub fn sorted( +pub fn sorted( dummy_lookup_value: F, joint_lookup_table_d8: &Evaluations>, d1: D, gates: &[CircuitGate], - witness: &[Vec; W], + witness: &[Vec; COLUMNS], joint_combiner: F, table_id_combiner: F, lookup_info: &LookupInfo, @@ -225,12 +225,12 @@ pub fn sorted( /// /// Will panic if final evaluation is not 1. #[allow(clippy::too_many_arguments)] -pub fn aggregation( +pub fn aggregation( dummy_lookup_value: F, joint_lookup_table_d8: &Evaluations>, d1: D, gates: &[CircuitGate], - witness: &[Vec; W], + witness: &[Vec; COLUMNS], joint_combiner: &F, table_id_combiner: &F, beta: F, @@ -678,13 +678,13 @@ pub fn constraints( /// /// Will panic if `d1` and `s` domain sizes do not match. #[allow(clippy::too_many_arguments)] -pub fn verify, TABLE: Fn() -> I>( +pub fn verify, TABLE: Fn() -> I>( dummy_lookup_value: F, lookup_table: TABLE, lookup_table_entries: usize, d1: D, gates: &[CircuitGate], - witness: &[Vec; W], + witness: &[Vec; COLUMNS], joint_combiner: &F, table_id_combiner: &F, sorted: &[Evaluations>], diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index 6ba2c80ba4..3b0cbfd2a3 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -198,7 +198,7 @@ impl LookupConstraintSystem { /// # Errors /// /// Will give error if inputs validation do not match. - pub fn create( + pub fn create( gates: &[CircuitGate], lookup_tables: Vec>, runtime_tables: Option>>, @@ -219,7 +219,7 @@ impl LookupConstraintSystem { //~ 2. Get the lookup selectors and lookup tables (TODO: how?) let (lookup_selectors, gate_lookup_tables) = - lookup_info.selector_polynomials_and_tables::(domain, gates); + lookup_info.selector_polynomials_and_tables::(domain, gates); //~ 3. Concatenate runtime lookup tables with the ones used by gates let mut lookup_tables: Vec<_> = gate_lookup_tables diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 84c835363e..07222d550a 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -200,7 +200,7 @@ impl LookupInfo { /// Each entry in `kinds` has a corresponding selector polynomial that controls whether that /// lookup kind should be enforced at a given row. This computes those selector polynomials. - pub fn selector_polynomials_and_tables( + pub fn selector_polynomials_and_tables( &self, domain: &EvaluationDomains, gates: &[CircuitGate], diff --git a/kimchi/src/circuits/polynomial.rs b/kimchi/src/circuits/polynomial.rs index 23de59fe2a..12fd352f30 100644 --- a/kimchi/src/circuits/polynomial.rs +++ b/kimchi/src/circuits/polynomial.rs @@ -1,6 +1,6 @@ //! This module implements Plonk prover polynomials primitive. -pub use super::wires::COLUMNS; +pub use super::wires::KIMCHI_COLS; use ark_ff::FftField; use ark_poly::{univariate::DensePolynomial, Evaluations, Radix2EvaluationDomain as D}; @@ -8,27 +8,27 @@ use ark_poly::{univariate::DensePolynomial, Evaluations, Radix2EvaluationDomain /// Evaluations of the wires and permutation #[derive(Clone)] -pub struct WitnessEvals { +pub struct WitnessEvals { /// wire evaluations - pub w: [Evaluations>; W], + pub w: [Evaluations>; COLUMNS], /// permutation evaluations pub z: Evaluations>, } #[derive(Clone)] -pub struct WitnessShifts { +pub struct WitnessShifts { /// this wire evaluations - pub this: WitnessEvals, + pub this: WitnessEvals, /// next wire evaluations - pub next: WitnessEvals, + pub next: WitnessEvals, } #[derive(Clone)] -pub struct WitnessOverDomains { +pub struct WitnessOverDomains { /// evaluations over domain d4 - pub d4: WitnessShifts, + pub d4: WitnessShifts, /// evaluations over domain d8 - pub d8: WitnessShifts, + pub d8: WitnessShifts, } // PLOOKUP diff --git a/kimchi/src/circuits/polynomials/and.rs b/kimchi/src/circuits/polynomials/and.rs index fbaf6047fa..b9f5abdcfb 100644 --- a/kimchi/src/circuits/polynomials/and.rs +++ b/kimchi/src/circuits/polynomials/and.rs @@ -133,11 +133,11 @@ pub fn lookup_table() -> LookupTable { /// Create a And for inputs as field elements starting at row 0 /// Input: first input, second input, and desired byte length /// Panics if the input is too large for the chosen number of bytes -pub fn create_and_witness( +pub fn create_and_witness( input1: F, input2: F, bytes: usize, -) -> [Vec; W] { +) -> [Vec; COLUMNS] { let input1_big = input1.to_biguint(); let input2_big = input2.to_biguint(); if bytes * 8 < input1_big.bitlen() || bytes * 8 < input2_big.bitlen() { @@ -153,7 +153,7 @@ pub fn create_and_witness( let sum = input1 + input2; let and_row = num_xors(bytes * 8) + 1; - let mut and_witness: [Vec; W] = array::from_fn(|_| vec![F::zero(); and_row + 1]); + let mut and_witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); and_row + 1]); init_xor(&mut and_witness, 0, bytes * 8, (input1, input2, xor)); // Fill in double generic witness @@ -170,14 +170,14 @@ pub fn create_and_witness( /// Extends an AND witness to the whole witness /// Input: first input, second input, and desired byte length /// Panics if the input is too large for the chosen number of bytes -pub fn extend_and_witness( - witness: &mut [Vec; W], +pub fn extend_and_witness( + witness: &mut [Vec; COLUMNS], input1: F, input2: F, bytes: usize, ) { - let and_witness = create_and_witness::(input1, input2, bytes); - for col in 0..W { + let and_witness = create_and_witness::(input1, input2, bytes); + for col in 0..COLUMNS { witness[col].extend(and_witness[col].iter()); } } diff --git a/kimchi/src/circuits/polynomials/complete_add.rs b/kimchi/src/circuits/polynomials/complete_add.rs index 8f4f199d22..578af66046 100644 --- a/kimchi/src/circuits/polynomials/complete_add.rs +++ b/kimchi/src/circuits/polynomials/complete_add.rs @@ -227,10 +227,10 @@ impl CircuitGate { /// # Panics /// /// Will panic if `multiplicative inverse` operation between gate values fails. - pub fn verify_complete_add( + pub fn verify_complete_add( &self, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], ) -> Result<(), String> { let x1 = witness[0][row]; let y1 = witness[1][row]; diff --git a/kimchi/src/circuits/polynomials/endomul_scalar.rs b/kimchi/src/circuits/polynomials/endomul_scalar.rs index ad3a1324af..731d7841e1 100644 --- a/kimchi/src/circuits/polynomials/endomul_scalar.rs +++ b/kimchi/src/circuits/polynomials/endomul_scalar.rs @@ -7,7 +7,7 @@ use crate::{ constraints::ConstraintSystem, expr::{constraints::ExprOps, Cache}, gate::{CircuitGate, GateType}, - wires::COLUMNS, + wires::KIMCHI_COLS, }, curve::KimchiCurve, }; @@ -21,10 +21,10 @@ impl CircuitGate { /// # Errors /// /// Will give error if `self.typ` is not `GateType::EndoMulScalar`, or there are errors in gate values. - pub fn verify_endomul_scalar, const W: usize>( + pub fn verify_endomul_scalar, const COLUMNS: usize>( &self, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], _cs: &ConstraintSystem, ) -> Result<(), String> { ensure_eq!(self.typ, GateType::EndoMulScalar, "incorrect gate type"); @@ -219,7 +219,7 @@ where /// /// Will panic if `num_bits` length is not multiple of `bits_per_row` length. pub fn gen_witness( - witness_cols: &mut [Vec; COLUMNS], + witness_cols: &mut [Vec; KIMCHI_COLS], scalar: F, endo_scalar: F, num_bits: usize, diff --git a/kimchi/src/circuits/polynomials/endosclmul.rs b/kimchi/src/circuits/polynomials/endosclmul.rs index 3039b04c46..8bbcb2e0b4 100644 --- a/kimchi/src/circuits/polynomials/endosclmul.rs +++ b/kimchi/src/circuits/polynomials/endosclmul.rs @@ -12,7 +12,7 @@ use crate::{ Cache, }, gate::{CircuitGate, GateType}, - wires::{GateWires, COLUMNS}, + wires::{GateWires, KIMCHI_COLS}, }, curve::KimchiCurve, proof::{PointEvaluations, ProofEvaluations}, @@ -125,16 +125,16 @@ impl CircuitGate { /// # Errors /// /// Will give error if `self.typ` is not `GateType::EndoMul`, or `constraint evaluation` fails. - pub fn verify_endomul, const W: usize>( + pub fn verify_endomul, const COLUMNS: usize>( &self, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], cs: &ConstraintSystem, ) -> Result<(), String> { ensure_eq!(self.typ, GateType::EndoMul, "incorrect gate type"); - let this: [F; W] = std::array::from_fn(|i| witness[i][row]); - let next: [F; W] = std::array::from_fn(|i| witness[i][row + 1]); + let this: [F; COLUMNS] = std::array::from_fn(|i| witness[i][row]); + let next: [F; COLUMNS] = std::array::from_fn(|i| witness[i][row + 1]); let pt = F::from(123456u64); @@ -148,7 +148,7 @@ impl CircuitGate { zk_rows: cs.zk_rows, }; - let evals: ProofEvaluations, W> = + let evals: ProofEvaluations, COLUMNS> = ProofEvaluations::dummy_with_witness_evaluations(this, next); let constraints = EndosclMul::::constraints(&mut Cache::default()); @@ -271,7 +271,7 @@ pub struct EndoMulResult { /// /// Will panic if `bits` length does not match the requirement. pub fn gen_witness( - w: &mut [Vec; COLUMNS], + w: &mut [Vec; KIMCHI_COLS], row0: usize, endo: F, base: (F, F), diff --git a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs index 950f7a265d..55756468d4 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs @@ -4,7 +4,7 @@ use crate::circuits::expr::constraints::compact_limb; use crate::circuits::witness::Variables; use crate::{ circuits::{ - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, witness::{self, ConstantCell, VariableCell, WitnessCell}, }, variable_map, @@ -130,7 +130,7 @@ pub fn create_chain( inputs: &Vec, opcodes: &[FFOps], modulus: BigUint, -) -> [Vec; COLUMNS] { +) -> [Vec; KIMCHI_COLS] { if modulus > BigUint::max_foreign_field_modulus::() { panic!( "foreign_field_modulus exceeds maximum: {} > {}", @@ -178,7 +178,7 @@ pub fn create_chain( } fn init_ffadd_row( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], offset: usize, left: [F; 3], right: [F; 3], @@ -215,7 +215,7 @@ fn init_ffadd_row( } fn init_bound_rows( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], offset: usize, result: &[F; 3], bound: &[F; 3], @@ -270,7 +270,7 @@ fn init_bound_rows( /// Create witness for bound computation addition gate pub fn extend_witness_bound_addition( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], limbs: &[F; 3], foreign_field_modulus: &[F; 3], ) { @@ -297,7 +297,7 @@ pub fn extend_witness_bound_addition( // Extend the witness for the add gate let offset = witness[0].len(); - for col in witness.iter_mut().take(COLUMNS) { + for col in witness.iter_mut().take(KIMCHI_COLS) { col.extend(std::iter::repeat(F::zero()).take(2)) } diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs index 421c81e766..9bbf590d31 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/gadget.rs @@ -96,7 +96,7 @@ pub fn circuit_gates() -> [GateType; GATE_COUNT] { } /// Get combined constraints for a given foreign field multiplication circuit gate -pub fn circuit_gate_constraints( +pub fn circuit_gate_constraints( typ: GateType, alphas: &Alphas, cache: &mut Cache, diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs index 2c1e0e328d..8284916480 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs @@ -3,7 +3,7 @@ use crate::{ auto_clone_array, circuits::{ - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{foreign_field_add, range_check}, witness::{self, ConstantCell, VariableBitsCell, VariableCell, Variables, WitnessCell}, }, @@ -147,7 +147,7 @@ pub fn create( left_input: &BigUint, right_input: &BigUint, foreign_field_modulus: &BigUint, -) -> ([Vec; COLUMNS], ExternalChecks) { +) -> ([Vec; KIMCHI_COLS], ExternalChecks) { let mut witness = array::from_fn(|_| vec![F::zero(); 0]); let mut external_checks = ExternalChecks::::default(); @@ -269,7 +269,7 @@ impl ExternalChecks { } /// Extend the witness with external multi range_checks - pub fn extend_witness_multi_range_checks(&mut self, witness: &mut [Vec; COLUMNS]) { + pub fn extend_witness_multi_range_checks(&mut self, witness: &mut [Vec; KIMCHI_COLS]) { for [v0, v1, v2] in self.multi_ranges.clone() { range_check::witness::extend_multi(witness, v0, v1, v2) } @@ -277,7 +277,10 @@ impl ExternalChecks { } /// Extend the witness with external compact multi range_checks - pub fn extend_witness_compact_multi_range_checks(&mut self, witness: &mut [Vec; COLUMNS]) { + pub fn extend_witness_compact_multi_range_checks( + &mut self, + witness: &mut [Vec; KIMCHI_COLS], + ) { for [v01, v2] in self.compact_multi_ranges.clone() { range_check::witness::extend_multi_compact(witness, v01, v2) } @@ -285,7 +288,7 @@ impl ExternalChecks { } /// Extend the witness with external compact multi range_checks - pub fn extend_witness_limb_checks(&mut self, witness: &mut [Vec; COLUMNS]) { + pub fn extend_witness_limb_checks(&mut self, witness: &mut [Vec; KIMCHI_COLS]) { for chunk in self.limb_ranges.clone().chunks(3) { // Pad with zeros if necessary let limbs = match chunk.len() { @@ -302,7 +305,7 @@ impl ExternalChecks { /// Extend the witness with external bound addition as foreign field addition pub fn extend_witness_bound_addition( &mut self, - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], foreign_field_modulus: &[F; 3], ) { for bound in self.bounds.clone() { @@ -318,13 +321,13 @@ impl ExternalChecks { /// Extend the witness with external high bounds additions as double generic gates pub fn extend_witness_high_bounds_computation( &mut self, - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], foreign_field_modulus: &BigUint, ) { let hi_limb = F::two_to_limb() - foreign_field_modulus.to_field_limbs::()[2] - F::one(); for chunk in self.high_bounds.clone().chunks(2) { // Extend the witness for the generic gate - for col in witness.iter_mut().take(COLUMNS) { + for col in witness.iter_mut().take(KIMCHI_COLS) { col.extend(std::iter::repeat(F::zero()).take(1)) } let last_row = witness[0].len() - 1; diff --git a/kimchi/src/circuits/polynomials/generic.rs b/kimchi/src/circuits/polynomials/generic.rs index 63cbc0a096..77a985ad45 100644 --- a/kimchi/src/circuits/polynomials/generic.rs +++ b/kimchi/src/circuits/polynomials/generic.rs @@ -257,14 +257,14 @@ pub mod testing { /// # Errors /// /// Will give error if `self.typ` is not `GateType::Generic`. - pub fn verify_generic( + pub fn verify_generic( &self, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], public: &[F], ) -> Result<(), String> { // assignments - let this: [F; W] = array::from_fn(|i| witness[i][row]); + let this: [F; COLUMNS] = array::from_fn(|i| witness[i][row]); // constants let zero = F::zero(); @@ -311,16 +311,16 @@ pub mod testing { F: PrimeField, G: KimchiCurve, OpeningProof: OpenProof, - const W: usize, - > ProverIndex + const COLUMNS: usize, + > ProverIndex { /// Function to verify the generic polynomials with a witness. pub fn verify_generic( &self, - witness: &[DensePolynomial; W], + witness: &[DensePolynomial; COLUMNS], public: &DensePolynomial, ) -> bool { - let coefficientsm: [_; W] = array::from_fn(|i| { + let coefficientsm: [_; COLUMNS] = array::from_fn(|i| { self.column_evaluations.coefficients8[i] .clone() .interpolate() @@ -370,7 +370,7 @@ pub mod testing { /// # Panics /// /// Will panic if `gates_row` is None. - pub fn create_circuit( + pub fn create_circuit( start_row: usize, public: usize, ) -> Vec> { @@ -429,9 +429,9 @@ pub mod testing { /// # Panics /// /// Will panic if `witness_row` is None. - pub fn fill_in_witness( + pub fn fill_in_witness( start_row: usize, - witness: &mut [Vec; W], + witness: &mut [Vec; COLUMNS], public: &[F], ) { // fill witness diff --git a/kimchi/src/circuits/polynomials/keccak.rs b/kimchi/src/circuits/polynomials/keccak.rs index 637509344a..ba74f06dff 100644 --- a/kimchi/src/circuits/polynomials/keccak.rs +++ b/kimchi/src/circuits/polynomials/keccak.rs @@ -5,7 +5,7 @@ use ark_ff::{PrimeField, SquareRootField}; use crate::circuits::{ gate::{CircuitGate, Connect}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{ generic::GenericGateSpec, rot::{self, RotMode}, @@ -70,9 +70,9 @@ impl CircuitGate { /// Create a Keccak rotation (whole table) /// Input: state (5x5) array of words to be rotated -pub fn create_witness_keccak_rot(state: [[u64; 5]; 5]) -> [Vec; COLUMNS] { +pub fn create_witness_keccak_rot(state: [[u64; 5]; 5]) -> [Vec; KIMCHI_COLS] { // First generic gate with all zeros to constrain that the two most significant limbs of shifted output are zeros - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero()]); for (x, row) in ROT_TAB.iter().enumerate() { for (y, &rot) in row.iter().enumerate() { if rot == 0 { diff --git a/kimchi/src/circuits/polynomials/not.rs b/kimchi/src/circuits/polynomials/not.rs index 4db55e4d6d..8ac3435cd6 100644 --- a/kimchi/src/circuits/polynomials/not.rs +++ b/kimchi/src/circuits/polynomials/not.rs @@ -3,7 +3,7 @@ //! Note that this module does not include a `Not` gate type. use crate::circuits::{ gate::{CircuitGate, Connect, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, wires::Wire, }; use ark_ff::PrimeField; @@ -183,14 +183,14 @@ impl CircuitGate { /// Warning: /// - don't forget to set a row of the witness with public input `2^bits -1` and wire it to the second input of the first `Xor16` gate pub fn extend_not_witness_checked_length( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], input: F, bits: Option, ) { let input = input.to_biguint(); let output = BigUint::bitwise_not(&input, bits); let bits = max(input.bitlen(), bits.unwrap_or(0)); - let mut not_witness: [Vec; COLUMNS] = + let mut not_witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); num_xors(bits) + 1]); init_xor( &mut not_witness, @@ -203,7 +203,7 @@ pub fn extend_not_witness_checked_length( ), ); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(not_witness[col].iter()); } } @@ -215,7 +215,7 @@ pub fn extend_not_witness_checked_length( /// Warning: Set public input of bits in public generic gate /// Note: `witness[0][pub] = 2^bits - 1` pub fn extend_not_witness_unchecked_length( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], inputs: &[F], bits: usize, ) -> Result<(), String> { @@ -235,7 +235,7 @@ pub fn extend_not_witness_unchecked_length( } let all_ones = F::from(2u8).pow([bits as u64]) - F::one(); let rows = (inputs.len() as f64 / 2.0).ceil() as usize; - let mut not_witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); rows]); + let mut not_witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); rows]); for (i, input) in inputs.iter().enumerate().step_by(2) { let row = i / 2; // fill in first NOT @@ -253,7 +253,7 @@ pub fn extend_not_witness_unchecked_length( not_witness[5][row] = negated_input2; } } - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(not_witness[col].iter()); } Ok(()) diff --git a/kimchi/src/circuits/polynomials/permutation.rs b/kimchi/src/circuits/polynomials/permutation.rs index dffd84e65d..d2665a5dcb 100644 --- a/kimchi/src/circuits/polynomials/permutation.rs +++ b/kimchi/src/circuits/polynomials/permutation.rs @@ -198,8 +198,8 @@ impl< F: PrimeField, G: KimchiCurve, OpeningProof: OpenProof, - const W: usize, - > ProverIndex + const COLUMNS: usize, + > ProverIndex { /// permutation quotient poly contribution computation /// @@ -213,7 +213,7 @@ impl< #[allow(clippy::type_complexity)] pub fn perm_quot( &self, - lagrange: &WitnessOverDomains, + lagrange: &WitnessOverDomains, beta: F, gamma: F, z: &DensePolynomial, @@ -336,7 +336,7 @@ impl< /// permutation linearization poly contribution computation pub fn perm_lnrz( &self, - e: &ProofEvaluations, W>, + e: &ProofEvaluations, COLUMNS>, zeta: F, beta: F, gamma: F, @@ -365,8 +365,8 @@ impl< } impl ConstraintSystem { - pub fn perm_scalars( - e: &ProofEvaluations, W>, + pub fn perm_scalars( + e: &ProofEvaluations, COLUMNS>, beta: F, gamma: F, mut alphas: impl Iterator, @@ -410,8 +410,8 @@ impl< F: PrimeField, G: KimchiCurve, OpeningProof: OpenProof, - const W: usize, - > ProverIndex + const COLUMNS: usize, + > ProverIndex { /// permutation aggregation polynomial computation /// @@ -424,7 +424,7 @@ impl< /// Will panic if `first element` is not 1. pub fn perm_aggreg( &self, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], beta: &F, gamma: &F, rng: &mut (impl RngCore + CryptoRng), diff --git a/kimchi/src/circuits/polynomials/poseidon.rs b/kimchi/src/circuits/polynomials/poseidon.rs index 3187afa215..a636570d5b 100644 --- a/kimchi/src/circuits/polynomials/poseidon.rs +++ b/kimchi/src/circuits/polynomials/poseidon.rs @@ -30,7 +30,7 @@ use crate::{ argument::{Argument, ArgumentEnv, ArgumentType}, expr::{constraints::ExprOps, Cache}, gate::{CircuitGate, CurrOrNext, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, wires::{GateWires, Wire}, }, curve::KimchiCurve, @@ -51,7 +51,7 @@ use CurrOrNext::{Curr, Next}; pub const SPONGE_WIDTH: usize = PlonkSpongeConstantsKimchi::SPONGE_WIDTH; /// Number of rows -pub const ROUNDS_PER_ROW: usize = COLUMNS / SPONGE_WIDTH; +pub const ROUNDS_PER_ROW: usize = KIMCHI_COLS / SPONGE_WIDTH; /// Number of rounds pub const ROUNDS_PER_HASH: usize = PlonkSpongeConstantsKimchi::PERM_ROUNDS_FULL; @@ -137,11 +137,11 @@ impl CircuitGate { /// # Errors /// /// Will give error if `self.typ` is not `Poseidon` gate, or `state` does not match after `permutation`. - pub fn verify_poseidon, const W: usize>( + pub fn verify_poseidon, const COLUMNS: usize>( &self, row: usize, // TODO(mimoo): we should just pass two rows instead of the whole witness - witness: &[Vec; W], + witness: &[Vec; COLUMNS], ) -> Result<(), String> { ensure_eq!( self.typ, @@ -226,7 +226,7 @@ impl CircuitGate { pub fn generate_witness( row: usize, params: &'static ArithmeticSpongeParams, - witness_cols: &mut [Vec; COLUMNS], + witness_cols: &mut [Vec; KIMCHI_COLS], input: [F; SPONGE_WIDTH], ) { // add the input into the witness diff --git a/kimchi/src/circuits/polynomials/range_check/circuitgates.rs b/kimchi/src/circuits/polynomials/range_check/circuitgates.rs index fd56e6514f..f543aae001 100644 --- a/kimchi/src/circuits/polynomials/range_check/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/range_check/circuitgates.rs @@ -123,7 +123,7 @@ use crate::circuits::{ Cache, }, gate::GateType, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, }; use ark_ff::PrimeField; @@ -187,7 +187,7 @@ where // a single 64-bit range check // * Columns 3-6 are 12-bit plookup range constraints (these are specified in the lookup gate) // * Columns 7-14 are 2-bit crumb range constraints - let mut constraints = (7..COLUMNS) + let mut constraints = (7..KIMCHI_COLS) .map(|i| crumb(&env.witness_curr(i))) .collect::>(); @@ -205,7 +205,7 @@ where let mut sum_of_limbs = T::zero(); // Sum 2-bit limbs - for i in (7..COLUMNS).rev() { + for i in (7..KIMCHI_COLS).rev() { sum_of_limbs += power_of_2.clone() * env.witness_curr(i); power_of_2 *= T::from(4u64); // 2 bits } @@ -288,7 +288,7 @@ where // in the lookup gate) // * Columns 7-14 are 2-bit crumb range constraints constraints.append( - &mut (7..COLUMNS) + &mut (7..KIMCHI_COLS) .map(|i| crumb(&env.witness_curr(i))) .collect::>(), ); @@ -304,7 +304,7 @@ where // are specified in the lookup gate) // * Columns 7-14 are more 2-bit crumbs constraints.append( - &mut (7..COLUMNS) + &mut (7..KIMCHI_COLS) .map(|i| crumb(&env.witness_next(i))) .collect::>(), ); @@ -325,7 +325,7 @@ where let mut sum_of_limbs = T::zero(); // Next row: Sum 2-bit limbs - for i in (7..COLUMNS).rev() { + for i in (7..KIMCHI_COLS).rev() { sum_of_limbs += power_of_2.clone() * env.witness_next(i); power_of_2 *= 4u64.into(); // 2 bits } @@ -337,7 +337,7 @@ where } // Curr row: Sum 2-bit limbs - for i in (7..COLUMNS).rev() { + for i in (7..KIMCHI_COLS).rev() { sum_of_limbs += power_of_2.clone() * env.witness_curr(i); power_of_2 *= 4u64.into(); // 2 bits } diff --git a/kimchi/src/circuits/polynomials/range_check/gadget.rs b/kimchi/src/circuits/polynomials/range_check/gadget.rs index cd5a6b0b92..0a18b2b2b4 100644 --- a/kimchi/src/circuits/polynomials/range_check/gadget.rs +++ b/kimchi/src/circuits/polynomials/range_check/gadget.rs @@ -149,7 +149,7 @@ pub fn circuit_gate_constraints( } /// Get the combined constraints for all range check circuit gate types -pub fn combined_constraints( +pub fn combined_constraints( alphas: &Alphas, cache: &mut Cache, ) -> E { diff --git a/kimchi/src/circuits/polynomials/range_check/witness.rs b/kimchi/src/circuits/polynomials/range_check/witness.rs index 459c95435f..d970338818 100644 --- a/kimchi/src/circuits/polynomials/range_check/witness.rs +++ b/kimchi/src/circuits/polynomials/range_check/witness.rs @@ -11,7 +11,7 @@ use crate::circuits::witness::Variables; use crate::variable_map; use crate::{ circuits::{ - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, witness::{init_row, CopyBitsCell, CopyCell, VariableCell, WitnessCell}, }, variables, @@ -114,9 +114,9 @@ pub fn range_check_0_row( } /// Create a multi range check witness from three 88-bit values: v0, v1 and v2 -pub fn create_multi(v0: F, v1: F, v2: F) -> [Vec; COLUMNS] { +pub fn create_multi(v0: F, v1: F, v2: F) -> [Vec; KIMCHI_COLS] { let layout = layout(); - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); 4]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); 4]); init_row(&mut witness, 0, 0, &layout, &variables!(v0)); init_row(&mut witness, 0, 1, &layout, &variables!(v1)); @@ -134,9 +134,9 @@ pub fn create_multi(v0: F, v1: F, v2: F) -> [Vec; COLUMNS] { /// Create a multi range check witness from two limbs: v01 (176 bits), v2 (88 bits), /// where v2 is the most significant limb and v01 is the least significant limb -pub fn create_multi_compact(v01: F, v2: F) -> [Vec; COLUMNS] { +pub fn create_multi_compact(v01: F, v2: F) -> [Vec; KIMCHI_COLS] { let layout = layout(); - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); 4]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); 4]); let (v1, v0) = v01.to_biguint().div_rem(&BigUint::two_to_limb()); let v0: F = v0.to_field().expect("failed to convert to field element"); @@ -158,20 +158,20 @@ pub fn create_multi_compact(v01: F, v2: F) -> [Vec; COLUMNS] { } /// Create a multi range check witness from limbs -pub fn create_multi_limbs(limbs: &[F; 3]) -> [Vec; COLUMNS] { +pub fn create_multi_limbs(limbs: &[F; 3]) -> [Vec; KIMCHI_COLS] { create_multi(limbs[0], limbs[1], limbs[2]) } /// Create a multi range check witness from compact limbs -pub fn create_multi_compact_limbs(limbs: &[F; 2]) -> [Vec; COLUMNS] { +pub fn create_multi_compact_limbs(limbs: &[F; 2]) -> [Vec; KIMCHI_COLS] { create_multi_compact(limbs[0], limbs[1]) } /// Create a single range check witness /// Input: 88-bit value v0 -pub fn create(v0: F) -> [Vec; COLUMNS] { +pub fn create(v0: F) -> [Vec; KIMCHI_COLS] { let layout = vec![range_check_0_row("v0", 0)]; - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero()]); init_row(&mut witness, 0, 0, &layout, &variables!(v0)); @@ -179,58 +179,61 @@ pub fn create(v0: F) -> [Vec; COLUMNS] { } /// Extend an existing witness with a multi-range-check gadget for three 88-bit values: v0, v1 and v2 -pub fn extend_multi(witness: &mut [Vec; COLUMNS], v0: F, v1: F, v2: F) { +pub fn extend_multi(witness: &mut [Vec; KIMCHI_COLS], v0: F, v1: F, v2: F) { let limbs_witness = create_multi(v0, v1, v2); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(limbs_witness[col].iter()) } } /// Extend and existing witness with a multi range check witness for two limbs: v01 (176 bits), v2 (88 bits), /// where v2 is the most significant limb and v01 is the least significant limb -pub fn extend_multi_compact(witness: &mut [Vec; COLUMNS], v01: F, v2: F) { +pub fn extend_multi_compact(witness: &mut [Vec; KIMCHI_COLS], v01: F, v2: F) { let limbs_witness = create_multi_compact(v01, v2); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(limbs_witness[col].iter()) } } /// Extend an existing witness with a multi-range-check gadget for limbs -pub fn extend_multi_limbs(witness: &mut [Vec; COLUMNS], limbs: &[F; 3]) { +pub fn extend_multi_limbs(witness: &mut [Vec; KIMCHI_COLS], limbs: &[F; 3]) { let limbs_witness = create_multi_limbs(limbs); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(limbs_witness[col].iter()) } } /// Extend an existing witness with a multi-range-check gadget for compact limbs -pub fn extend_multi_compact_limbs(witness: &mut [Vec; COLUMNS], limbs: &[F; 2]) { +pub fn extend_multi_compact_limbs( + witness: &mut [Vec; KIMCHI_COLS], + limbs: &[F; 2], +) { let limbs_witness = create_multi_compact_limbs(limbs); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(limbs_witness[col].iter()) } } /// Extend an existing witness with a multi-range-check gadget for ForeignElement pub fn extend_multi_from_fe( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], fe: &ForeignElement, ) { extend_multi(witness, fe.limbs[0], fe.limbs[1], fe.limbs[2]); } /// Extend an existing witness with a single range check witness for foreign field element -pub fn extend(witness: &mut [Vec; COLUMNS], fe: F) { +pub fn extend(witness: &mut [Vec; KIMCHI_COLS], fe: F) { let limbs_witness = create(fe); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(limbs_witness[col].iter()) } } /// Extend an existing witness with a single-range-check gate for 88bits -pub fn extend_single(witness: &mut [Vec; COLUMNS], elem: F) { +pub fn extend_single(witness: &mut [Vec; KIMCHI_COLS], elem: F) { let single_wit = create(elem); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(single_wit[col].iter()) } } diff --git a/kimchi/src/circuits/polynomials/rot.rs b/kimchi/src/circuits/polynomials/rot.rs index bf0df63ab4..71bcdef994 100644 --- a/kimchi/src/circuits/polynomials/rot.rs +++ b/kimchi/src/circuits/polynomials/rot.rs @@ -13,7 +13,7 @@ use crate::{ self, tables::{GateLookupTable, LookupTable}, }, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, wires::Wire, witness::{self, VariableBitsCell, VariableCell, Variables, WitnessCell}, }, @@ -216,7 +216,7 @@ where fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { // Check that the last 8 columns are 2-bit crumbs // C1..C8: x * (x - 1) * (x - 2) * (x - 3) = 0 - let mut constraints = (7..COLUMNS) + let mut constraints = (7..KIMCHI_COLS) .map(|i| crumb(&env.witness_curr(i))) .collect::>(); @@ -244,7 +244,7 @@ where let mut bound = T::zero(); // Sum 2-bit limbs - for i in (7..COLUMNS).rev() { + for i in (7..KIMCHI_COLS).rev() { bound += power_of_2.clone() * env.witness_curr(i); power_of_2 *= T::two_pow(2); // 2 bits } @@ -297,7 +297,7 @@ fn rot_row() -> Vec>> { } fn init_rot64( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], curr_row: usize, word: F, rotated: F, @@ -323,7 +323,7 @@ fn init_rot64( /// Warning: /// - don't forget to include a public input row with zero value pub fn extend_rot( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], word: u64, rot: u32, side: RotMode, @@ -351,8 +351,8 @@ pub fn extend_rot( let bound = 2u128.pow(64) - 2u128.pow(rot); let rot_row = witness[0].len(); - let rot_witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); 3]); - for col in 0..COLUMNS { + let rot_witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); 3]); + for col in 0..KIMCHI_COLS { witness[col].extend(rot_witness[col].iter()); } init_rot64( diff --git a/kimchi/src/circuits/polynomials/turshi.rs b/kimchi/src/circuits/polynomials/turshi.rs index bb441bafbd..7a40b318ff 100644 --- a/kimchi/src/circuits/polynomials/turshi.rs +++ b/kimchi/src/circuits/polynomials/turshi.rs @@ -177,15 +177,15 @@ impl CircuitGate { /// # Panics /// /// Will panic if `constraint linearization` fails. - pub fn verify_cairo_gate, const W: usize>( + pub fn verify_cairo_gate, const COLUMNS: usize>( &self, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], cs: &ConstraintSystem, ) -> Result<(), String> { // assignments - let curr: [F; W] = array::from_fn(|i| witness[i][row]); - let mut next: [F; W] = array::from_fn(|_| F::zero()); + let curr: [F; COLUMNS] = array::from_fn(|i| witness[i][row]); + let mut next: [F; COLUMNS] = array::from_fn(|_| F::zero()); if self.typ != GateType::Zero { next = array::from_fn(|i| witness[i][row + 1]); } @@ -193,7 +193,7 @@ impl CircuitGate { // column polynomials let polys = { let mut h = std::collections::HashSet::new(); - for i in 0..W { + for i in 0..COLUMNS { h.insert(Column::Witness(i)); // column witness polynomials } // gate selector polynomials @@ -209,8 +209,11 @@ impl CircuitGate { alphas.register(ArgumentType::Gate(self.typ), Instruction::::CONSTRAINTS); // Get constraints for this circuit gate - let constraints = - circuit_gate_combined_constraints::(self.typ, &alphas, &mut Cache::default()); + let constraints = circuit_gate_combined_constraints::( + self.typ, + &alphas, + &mut Cache::default(), + ); // Linearize let linearized = constraints.linearize(polys).unwrap(); @@ -256,7 +259,9 @@ pub mod witness { use super::*; /// Returns the witness of an execution of a Cairo program in `CircuitGate` format - pub fn cairo_witness(prog: &CairoProgram) -> [Vec; W] { + pub fn cairo_witness( + prog: &CairoProgram, + ) -> [Vec; COLUMNS] { // 0: 1 row for final check CairoClaim gate // 4i+1: 1 row per instruction for CairoInstruction gate // 4i+2: 1 row per instruction for Flags argument @@ -268,34 +273,34 @@ pub mod witness { let n = prog.trace().len(); let rows = 4 * n - 1; let mut table: Vec> = vec![vec![]]; - table.resize(rows, vec![F::zero(); W]); + table.resize(rows, vec![F::zero(); COLUMNS]); for (i, inst) in prog.trace().iter().enumerate() { if i == 0 { let claim_wit = claim_witness(prog); table[i] = claim_wit; } - let ins_wit = instruction_witness::(inst); - let flg_wit = flag_witness::(inst); + let ins_wit = instruction_witness::(inst); + let flg_wit = flag_witness::(inst); table[4 * i + 1] = ins_wit; table[4 * i + 2] = flg_wit; if i != n - 1 { // all but last instruction - let tra_wit = transition_witness::(inst, &prog.trace()[i + 1]); - let aux_wit = auxiliary_witness::(&prog.trace()[i + 1]); + let tra_wit = transition_witness::(inst, &prog.trace()[i + 1]); + let aux_wit = auxiliary_witness::(&prog.trace()[i + 1]); table[4 * i + 3] = tra_wit; table[4 * i + 4] = aux_wit; } } - let mut witness: Vec> = vec![vec![]; W]; - for col in 0..W { + let mut witness: Vec> = vec![vec![]; COLUMNS]; + for col in 0..COLUMNS { // initialize column with zeroes witness[col].resize(table.len(), F::zero()); for (row, wit) in table.iter().enumerate() { witness[col][row] = wit[col]; } } - let witness: [Vec; W] = array::from_fn(|i| witness[i].clone()); + let witness: [Vec; COLUMNS] = array::from_fn(|i| witness[i].clone()); witness } @@ -320,7 +325,7 @@ pub mod witness { ] } - fn instruction_witness(inst: &CairoInstruction) -> Vec { + fn instruction_witness(inst: &CairoInstruction) -> Vec { vec![ inst.pc(), inst.ap(), @@ -340,7 +345,7 @@ pub mod witness { ] } - fn flag_witness(inst: &CairoInstruction) -> Vec { + fn flag_witness(inst: &CairoInstruction) -> Vec { vec![ inst.f_dst_fp(), inst.f_op0_fp(), @@ -360,7 +365,7 @@ pub mod witness { ] } - fn transition_witness( + fn transition_witness( curr: &CairoInstruction, next: &CairoInstruction, ) -> Vec { @@ -383,7 +388,7 @@ pub mod witness { ] } - fn auxiliary_witness(next: &CairoInstruction) -> Vec { + fn auxiliary_witness(next: &CairoInstruction) -> Vec { vec![ next.pc(), next.ap(), @@ -412,30 +417,30 @@ pub mod testing { /// # Errors /// /// Will give error if `gate` is not `Cairo`-related gate or `zero` gate. - pub fn ensure_cairo_gate( + pub fn ensure_cairo_gate( gate: &CircuitGate, row: usize, - witness: &[Vec; W], + witness: &[Vec; COLUMNS], //_cs: &ConstraintSystem, ) -> Result<(), String> { // assignments - let this: [F; W] = array::from_fn(|i| witness[i][row]); + let this: [F; COLUMNS] = array::from_fn(|i| witness[i][row]); match gate.typ { GateType::CairoClaim => { - let next: [F; W] = array::from_fn(|i| witness[i][row + 1]); + let next: [F; COLUMNS] = array::from_fn(|i| witness[i][row + 1]); ensure_claim(&this, &next) // CircuitGate::ensure_transition(&this), } GateType::CairoInstruction => { - let next: [F; W] = array::from_fn(|i| witness[i][row + 1]); + let next: [F; COLUMNS] = array::from_fn(|i| witness[i][row + 1]); ensure_instruction(&this, &next) } GateType::CairoFlags => { - let next: [F; W] = array::from_fn(|i| witness[i][row + 1]); + let next: [F; COLUMNS] = array::from_fn(|i| witness[i][row + 1]); ensure_flags(&this, &next) } GateType::CairoTransition => { - let next: [F; W] = array::from_fn(|i| witness[i][row + 1]); + let next: [F; COLUMNS] = array::from_fn(|i| witness[i][row + 1]); ensure_transition(&this, &next) } GateType::Zero => Ok(()), @@ -741,7 +746,7 @@ fn two>() -> T { /// # Panics /// /// Will panic if the `typ` is not `Cairo`-related gate type or `zero` gate type. -pub fn circuit_gate_combined_constraints( +pub fn circuit_gate_combined_constraints( typ: GateType, alphas: &Alphas, cache: &mut Cache, diff --git a/kimchi/src/circuits/polynomials/varbasemul.rs b/kimchi/src/circuits/polynomials/varbasemul.rs index 454cb8bf2f..a21f7305ab 100644 --- a/kimchi/src/circuits/polynomials/varbasemul.rs +++ b/kimchi/src/circuits/polynomials/varbasemul.rs @@ -145,10 +145,10 @@ impl CircuitGate { /// # Errors /// /// TODO - pub fn verify_vbmul( + pub fn verify_vbmul( &self, _row: usize, - _witness: &[Vec; W], + _witness: &[Vec; COLUMNS], ) -> Result<(), String> { // TODO: implement Ok(()) @@ -181,7 +181,7 @@ impl Point { } } -fn set(w: &mut [Vec; W], row0: usize, var: Variable, x: F) { +fn set(w: &mut [Vec; COLUMNS], row0: usize, var: Variable, x: F) { match var.col { Column::Witness(i) => w[i][row0 + var.row.shift()] = x, _ => panic!("Can only set witness columns"), @@ -189,8 +189,8 @@ fn set(w: &mut [Vec; W], row0: usize, var: Variable, x: F) } #[allow(clippy::too_many_arguments)] -fn single_bit_witness( - w: &mut [Vec; W], +fn single_bit_witness( + w: &mut [Vec; COLUMNS], row: usize, b: Variable, base: &Point, @@ -364,8 +364,8 @@ pub struct VarbaseMulResult { /// # Panics /// /// Will panic if `bits chunk` length validation fails. -pub fn witness( - w: &mut [Vec; W], +pub fn witness( + w: &mut [Vec; COLUMNS], row0: usize, base: (F, F), bits: &[bool], diff --git a/kimchi/src/circuits/polynomials/xor.rs b/kimchi/src/circuits/polynomials/xor.rs index 3ecc8390c5..431734926a 100644 --- a/kimchi/src/circuits/polynomials/xor.rs +++ b/kimchi/src/circuits/polynomials/xor.rs @@ -168,10 +168,10 @@ where } // Witness layout -fn layout( +fn layout( curr_row: usize, bits: usize, -) -> Vec>>> { +) -> Vec>>> { let num_xor = num_xors(bits); let mut layout = (0..num_xor) .map(|i| xor_row(i, curr_row + i)) @@ -180,10 +180,10 @@ fn layout( layout } -fn xor_row( +fn xor_row( nybble: usize, curr_row: usize, -) -> Vec>> { +) -> Vec>> { let start = nybble * 16; vec![ VariableBitsCell::create("in1", start, None), @@ -204,7 +204,7 @@ fn xor_row( ] } -fn zero_row() -> Vec>> { +fn zero_row() -> Vec>> { vec![ ConstantCell::create(F::zero()), ConstantCell::create(F::zero()), @@ -224,8 +224,8 @@ fn zero_row() -> Vec ] } -pub(crate) fn init_xor( - witness: &mut [Vec; W], +pub(crate) fn init_xor( + witness: &mut [Vec; COLUMNS], curr_row: usize, bits: usize, words: (F, F, F), @@ -242,14 +242,14 @@ pub(crate) fn init_xor( /// Extends the Xor rows to the full witness /// Panics if the words are larger than the desired bits -pub fn extend_xor_witness( - witness: &mut [Vec; W], +pub fn extend_xor_witness( + witness: &mut [Vec; COLUMNS], input1: F, input2: F, bits: usize, ) { - let xor_witness = create_xor_witness::(input1, input2, bits); - for col in 0..W { + let xor_witness = create_xor_witness::(input1, input2, bits); + for col in 0..COLUMNS { witness[col].extend(xor_witness[col].iter()); } } @@ -257,11 +257,11 @@ pub fn extend_xor_witness( /// Create a Xor for up to the native length starting at row 0 /// Input: first input and second input, bits length, current row /// Panics if the desired bits is smaller than the inputs length -pub fn create_xor_witness( +pub fn create_xor_witness( input1: F, input2: F, bits: usize, -) -> [Vec; W] { +) -> [Vec; COLUMNS] { let input1_big = input1.to_biguint(); let input2_big = input2.to_biguint(); if bits < input1_big.bitlen() || bits < input2_big.bitlen() { @@ -269,7 +269,8 @@ pub fn create_xor_witness( } let output = BigUint::bitwise_xor(&input1_big, &input2_big); - let mut xor_witness: [Vec; W] = array::from_fn(|_| vec![F::zero(); 1 + num_xors(bits)]); + let mut xor_witness: [Vec; COLUMNS] = + array::from_fn(|_| vec![F::zero(); 1 + num_xors(bits)]); init_xor( &mut xor_witness, diff --git a/kimchi/src/circuits/wires.rs b/kimchi/src/circuits/wires.rs index 1ab40d4b83..ff8c258078 100644 --- a/kimchi/src/circuits/wires.rs +++ b/kimchi/src/circuits/wires.rs @@ -6,13 +6,13 @@ use std::array; use std::io::{Read, Result as IoResult, Write}; /// Number of registers -pub const COLUMNS: usize = 15; +pub const KIMCHI_COLS: usize = 15; /// Number of registers that can be wired (participating in the permutation) pub const PERMUTS: usize = 7; /// index of all registers -pub const WIRES: [usize; COLUMNS] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; +pub const WIRES: [usize; KIMCHI_COLS] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; /// Wire documents the other cell that is wired to this one. /// If the cell represents an internal wire, an input to the circuit, diff --git a/kimchi/src/circuits/witness/constant_cell.rs b/kimchi/src/circuits/witness/constant_cell.rs index cbc7aaa7c8..03f333ced1 100644 --- a/kimchi/src/circuits/witness/constant_cell.rs +++ b/kimchi/src/circuits/witness/constant_cell.rs @@ -13,8 +13,13 @@ impl ConstantCell { } } -impl WitnessCell for ConstantCell { - fn value(&self, _witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { +impl WitnessCell for ConstantCell { + fn value( + &self, + _witness: &mut [Vec; COLUMNS], + _variables: &Variables, + _index: usize, + ) -> F { self.value } } diff --git a/kimchi/src/circuits/witness/copy_bits_cell.rs b/kimchi/src/circuits/witness/copy_bits_cell.rs index a61ca183a8..66a8a4f099 100644 --- a/kimchi/src/circuits/witness/copy_bits_cell.rs +++ b/kimchi/src/circuits/witness/copy_bits_cell.rs @@ -23,8 +23,13 @@ impl CopyBitsCell { } } -impl WitnessCell for CopyBitsCell { - fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { +impl WitnessCell for CopyBitsCell { + fn value( + &self, + witness: &mut [Vec; COLUMNS], + _variables: &Variables, + _index: usize, + ) -> F { F::from_bits(&witness[self.col][self.row].to_bits()[self.start..self.end]) .expect("failed to deserialize field bits for copy bits cell") } diff --git a/kimchi/src/circuits/witness/copy_cell.rs b/kimchi/src/circuits/witness/copy_cell.rs index d3fad71654..87784943f1 100644 --- a/kimchi/src/circuits/witness/copy_cell.rs +++ b/kimchi/src/circuits/witness/copy_cell.rs @@ -15,8 +15,13 @@ impl CopyCell { } } -impl WitnessCell for CopyCell { - fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { +impl WitnessCell for CopyCell { + fn value( + &self, + witness: &mut [Vec; COLUMNS], + _variables: &Variables, + _index: usize, + ) -> F { witness[self.col][self.row] } } diff --git a/kimchi/src/circuits/witness/copy_shift_cell.rs b/kimchi/src/circuits/witness/copy_shift_cell.rs index b0c87587d1..f194e2f797 100644 --- a/kimchi/src/circuits/witness/copy_shift_cell.rs +++ b/kimchi/src/circuits/witness/copy_shift_cell.rs @@ -15,8 +15,13 @@ impl CopyShiftCell { } } -impl WitnessCell for CopyShiftCell { - fn value(&self, witness: &mut [Vec; W], _variables: &Variables, _index: usize) -> F { +impl WitnessCell for CopyShiftCell { + fn value( + &self, + witness: &mut [Vec; COLUMNS], + _variables: &Variables, + _index: usize, + ) -> F { F::from(2u32).pow([self.shift]) * witness[self.col][self.row] } } diff --git a/kimchi/src/circuits/witness/index_cell.rs b/kimchi/src/circuits/witness/index_cell.rs index fd2628a316..f8fe8cd65a 100644 --- a/kimchi/src/circuits/witness/index_cell.rs +++ b/kimchi/src/circuits/witness/index_cell.rs @@ -18,8 +18,13 @@ impl<'a> IndexCell<'a> { } } -impl<'a, F: Field, const W: usize> WitnessCell, W> for IndexCell<'a> { - fn value(&self, _witness: &mut [Vec; W], variables: &Variables>, index: usize) -> F { +impl<'a, F: Field, const COLUMNS: usize> WitnessCell, COLUMNS> for IndexCell<'a> { + fn value( + &self, + _witness: &mut [Vec; COLUMNS], + variables: &Variables>, + index: usize, + ) -> F { assert!(index < self.length, "index out of bounds of `IndexCell`"); variables[self.name][index] } diff --git a/kimchi/src/circuits/witness/mod.rs b/kimchi/src/circuits/witness/mod.rs index 830e2af5e7..ddee4bb9ea 100644 --- a/kimchi/src/circuits/witness/mod.rs +++ b/kimchi/src/circuits/witness/mod.rs @@ -20,11 +20,11 @@ pub use self::{ variables::{variable_map, variables, Variables}, }; -use super::polynomial::COLUMNS; +use super::polynomial::KIMCHI_COLS; /// Witness cell interface. By default, the witness cell is a single element of type F. -pub trait WitnessCell { - fn value(&self, witness: &mut [Vec; W], variables: &Variables, index: usize) -> F; +pub trait WitnessCell { + fn value(&self, witness: &mut [Vec; COLUMNS], variables: &Variables, index: usize) -> F; // Length is 1 by default (T is single F element) unless overridden fn length(&self) -> usize { @@ -43,25 +43,25 @@ pub trait WitnessCell { /// - layout: the partial layout to initialize from /// - variables: the hashmap of variables to get the values from #[allow(clippy::too_many_arguments)] -pub fn init_cell( - witness: &mut [Vec; W], +pub fn init_cell( + witness: &mut [Vec; COLUMNS], offset: usize, row: usize, col: usize, cell: usize, index: usize, - layout: &[Vec>>], + layout: &[Vec>>], variables: &Variables, ) { witness[col][row + offset] = layout[row][cell].value(witness, variables, index); } /// Initialize a witness row based on layout and computed variables -pub fn init_row( - witness: &mut [Vec; W], +pub fn init_row( + witness: &mut [Vec; COLUMNS], offset: usize, row: usize, - layout: &[Vec>>], + layout: &[Vec>>], variables: &Variables, ) { let mut col = 0; @@ -75,10 +75,10 @@ pub fn init_row( } /// Initialize a witness based on layout and computed variables -pub fn init( - witness: &mut [Vec; W], +pub fn init( + witness: &mut [Vec; COLUMNS], offset: usize, - layout: &[Vec>>], + layout: &[Vec>>], variables: &Variables, ) { for row in 0..layout.len() { @@ -92,7 +92,7 @@ mod tests { use super::*; - use crate::circuits::polynomial::COLUMNS; + use crate::circuits::polynomial::KIMCHI_COLS; use ark_ec::AffineCurve; use ark_ff::{Field, One, Zero}; use mina_curves::pasta::Pallas; @@ -118,7 +118,7 @@ mod tests { ConstantCell::create(PallasField::zero()), ]]; - let mut witness: [Vec; COLUMNS] = + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![PallasField::one(); 1]); for col in witness.clone() { @@ -180,7 +180,7 @@ mod tests { ], ]; - let mut witness: [Vec; COLUMNS] = + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![PallasField::zero(); 2]); // Local variable (witness computation) with same names as VariableCell above @@ -216,7 +216,7 @@ mod tests { assert_eq!(witness[7][1], something_else); assert_eq!(witness[14][1], final_value); - let mut witness2: [Vec; COLUMNS] = + let mut witness2: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![PallasField::zero(); 2]); init( &mut witness2, diff --git a/kimchi/src/circuits/witness/variable_bits_cell.rs b/kimchi/src/circuits/witness/variable_bits_cell.rs index 584920592d..b380e25e19 100644 --- a/kimchi/src/circuits/witness/variable_bits_cell.rs +++ b/kimchi/src/circuits/witness/variable_bits_cell.rs @@ -18,8 +18,13 @@ impl<'a> VariableBitsCell<'a> { } } -impl<'a, F: Field, const W: usize> WitnessCell for VariableBitsCell<'a> { - fn value(&self, _witness: &mut [Vec; W], variables: &Variables, _index: usize) -> F { +impl<'a, F: Field, const COLUMNS: usize> WitnessCell for VariableBitsCell<'a> { + fn value( + &self, + _witness: &mut [Vec; COLUMNS], + variables: &Variables, + _index: usize, + ) -> F { let bits = if let Some(end) = self.end { F::from_bits(&variables[self.name].to_bits()[self.start..end]) } else { diff --git a/kimchi/src/circuits/witness/variable_cell.rs b/kimchi/src/circuits/witness/variable_cell.rs index fcb6ee9f21..5f7bb76253 100644 --- a/kimchi/src/circuits/witness/variable_cell.rs +++ b/kimchi/src/circuits/witness/variable_cell.rs @@ -14,8 +14,13 @@ impl<'a> VariableCell<'a> { } } -impl<'a, F: Field, const W: usize> WitnessCell for VariableCell<'a> { - fn value(&self, _witness: &mut [Vec; W], variables: &Variables, _index: usize) -> F { +impl<'a, F: Field, const COLUMNS: usize> WitnessCell for VariableCell<'a> { + fn value( + &self, + _witness: &mut [Vec; COLUMNS], + variables: &Variables, + _index: usize, + ) -> F { variables[self.name] } } diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 0b5ae39ae7..675ff5055f 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -35,7 +35,7 @@ use ark_ff::{FftField, PrimeField, SquareRootField, Zero}; /// # Panics /// /// Will panic if `generic_gate` is not associate with `alpha^0`. -pub fn constraints_expr( +pub fn constraints_expr( feature_flags: Option<&FeatureFlags>, generic: bool, ) -> (Expr, Column>, Alphas) { @@ -220,7 +220,7 @@ pub fn constraints_expr( // flags. if cfg!(feature = "check_feature_flags") { if let Some(feature_flags) = feature_flags { - let (feature_flagged_expr, _) = constraints_expr::(None, generic); + let (feature_flagged_expr, _) = constraints_expr::(None, generic); let feature_flagged_expr = feature_flagged_expr.apply_feature_flags(feature_flags); assert_eq!(expr, feature_flagged_expr); } @@ -232,7 +232,7 @@ pub fn constraints_expr( /// Adds the polynomials that are evaluated as part of the proof /// for the linearization to work. -pub fn linearization_columns( +pub fn linearization_columns( feature_flags: Option<&FeatureFlags>, ) -> std::collections::HashSet { let mut h = std::collections::HashSet::new(); @@ -265,12 +265,12 @@ pub fn linearization_columns( }; // the witness polynomials - for i in 0..W { + for i in 0..COLUMNS { h.insert(Witness(i)); } // the coefficient polynomials - for i in 0..W { + for i in 0..COLUMNS { h.insert(Coefficient(i)); } @@ -335,16 +335,16 @@ pub fn linearization_columns( /// /// Will panic if the `linearization` process fails. #[allow(clippy::type_complexity)] -pub fn expr_linearization( +pub fn expr_linearization( feature_flags: Option<&FeatureFlags>, generic: bool, ) -> ( Linearization>, Column>, Alphas, ) { - let evaluated_cols = linearization_columns::(feature_flags); + let evaluated_cols = linearization_columns::(feature_flags); - let (expr, powers_of_alpha) = constraints_expr::(feature_flags, generic); + let (expr, powers_of_alpha) = constraints_expr::(feature_flags, generic); let linearization = expr .linearize(evaluated_cols) diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index b60a423a91..9cdb5863fa 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -37,7 +37,7 @@ where #[cfg(feature = "ocaml_types")] pub mod caml { - use crate::circuits::wires::COLUMNS; + use crate::circuits::wires::KIMCHI_COLS; use ark_ff::PrimeField; use poly_commitment::{commitment::shift_scalar, evaluation_proof::OpeningProof}; @@ -58,15 +58,15 @@ pub mod caml { pub fn create_caml_oracles( lgr_comm: Vec>, - index: VerifierIndex>, - proof: ProverProof>, + index: VerifierIndex>, + proof: ProverProof>, public_input: &[G::ScalarField], ) -> Result, VerifyError> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, CamlF: From, { let lgr_comm: Vec> = lgr_comm.into_iter().take(public_input.len()).collect(); diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index 67ae88dd29..0a8cb05776 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -5,10 +5,10 @@ use mina_poseidon::{ poseidon::{ArithmeticSponge, ArithmeticSpongeParams, Sponge}, }; -use crate::circuits::wires::COLUMNS; +use crate::circuits::wires::KIMCHI_COLS; use crate::proof::{PointEvaluations, ProofEvaluations}; -pub trait FrSponge { +pub trait FrSponge { /// Creates a new Fr-Sponge. fn new(p: &'static ArithmeticSpongeParams) -> Self; @@ -26,10 +26,10 @@ pub trait FrSponge { /// Absorbs the given evaluations into the sponge. // TODO: IMO this function should be inlined in prover/verifier - fn absorb_evaluations(&mut self, e: &ProofEvaluations>, W>); + fn absorb_evaluations(&mut self, e: &ProofEvaluations>, COLUMNS>); } -impl FrSponge for DefaultFrSponge { +impl FrSponge for DefaultFrSponge { fn new(params: &'static ArithmeticSpongeParams) -> DefaultFrSponge { DefaultFrSponge { sponge: ArithmeticSponge::new(params), @@ -57,7 +57,7 @@ impl FrSponge for DefaultFrSponge } // We absorb all evaluations of the same polynomial at the same time - fn absorb_evaluations(&mut self, e: &ProofEvaluations>, W>) { + fn absorb_evaluations(&mut self, e: &ProofEvaluations>, COLUMNS>) { self.last_squeezed = vec![]; let ProofEvaluations { diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 3a9bfc8aeb..cdd8d6f223 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -4,7 +4,7 @@ use crate::circuits::{ berkeley_columns::Column, gate::GateType, lookup::lookups::LookupPattern, - wires::{COLUMNS, PERMUTS}, + wires::{KIMCHI_COLS, PERMUTS}, }; use ark_ec::AffineCurve; use ark_ff::{FftField, One, Zero}; @@ -42,7 +42,7 @@ pub struct PointEvaluations { /// - **Non chunked evaluations** `Field` is instantiated with a field, so they are single-sized#[serde_as] #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ProofEvaluations { +pub struct ProofEvaluations { /// public input polynomials pub public: Option, /// witness polynomials @@ -121,7 +121,7 @@ pub struct LookupCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverCommitments { +pub struct ProverCommitments { /// The commitments to the witness (execution trace) pub w_comm: Vec>, /// The commitment to the permutation polynomial @@ -136,9 +136,9 @@ pub struct ProverCommitments { #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")] -pub struct ProverProof { +pub struct ProverProof { /// All the polynomial commitments required in the proof - pub commitments: ProverCommitments, + pub commitments: ProverCommitments, /// batched commitment opening proof #[serde(bound( @@ -148,7 +148,7 @@ pub struct ProverProof { pub proof: OpeningProof, /// Two evaluations over a number of committed polynomials - pub evals: ProofEvaluations>, W>, + pub evals: ProofEvaluations>, COLUMNS>, /// Required evaluation for [Maller's optimization](https://o1-labs.github.io/mina-book/crypto/plonk/maller_15.html#the-evaluation-of-l) #[serde_as(as = "o1_utils::serialization::SerdeAs")] @@ -193,8 +193,8 @@ impl PointEvaluations { } } -impl ProofEvaluations { - pub fn map Eval2>(self, f: &FN) -> ProofEvaluations { +impl ProofEvaluations { + pub fn map Eval2>(self, f: &FN) -> ProofEvaluations { let ProofEvaluations { public, w, @@ -253,7 +253,10 @@ impl ProofEvaluations { } } - pub fn map_ref Eval2>(&self, f: &FN) -> ProofEvaluations { + pub fn map_ref Eval2>( + &self, + f: &FN, + ) -> ProofEvaluations { let ProofEvaluations { public, w, @@ -360,11 +363,11 @@ impl RecursionChallenge { } } -impl ProofEvaluations, W> { +impl ProofEvaluations, COLUMNS> { pub fn dummy_with_witness_evaluations( - curr: [F; W], - next: [F; W], - ) -> ProofEvaluations, W> { + curr: [F; COLUMNS], + next: [F; COLUMNS], + ) -> ProofEvaluations, COLUMNS> { let pt = |curr, next| PointEvaluations { zeta: curr, zeta_omega: next, @@ -374,7 +377,7 @@ impl ProofEvaluations, W> { w: curr.iter().zip(next).map(|(c, n)| pt(*c, n)).collect(), z: pt(F::zero(), F::zero()), s: array::from_fn(|_| pt(F::zero(), F::zero())), - coefficients: vec![pt(F::zero(), F::zero()); W], + coefficients: vec![pt(F::zero(), F::zero()); COLUMNS], generic_selector: pt(F::zero(), F::zero()), poseidon_selector: pt(F::zero(), F::zero()), complete_add_selector: pt(F::zero(), F::zero()), @@ -400,8 +403,11 @@ impl ProofEvaluations, W> { } } -impl ProofEvaluations>, W> { - pub fn combine(&self, pt: &PointEvaluations) -> ProofEvaluations, W> { +impl ProofEvaluations>, COLUMNS> { + pub fn combine( + &self, + pt: &PointEvaluations, + ) -> ProofEvaluations, COLUMNS> { self.map_ref(&|evals| PointEvaluations { zeta: DensePolynomial::eval_polynomial(&evals.zeta, pt.zeta), zeta_omega: DensePolynomial::eval_polynomial(&evals.zeta_omega, pt.zeta_omega), @@ -409,7 +415,7 @@ impl ProofEvaluations>, W> } } -impl ProofEvaluations { +impl ProofEvaluations { pub fn get_column(&self, col: Column) -> Option<&F> { match col { Column::Witness(i) => Some(&self.w[i]), @@ -455,7 +461,7 @@ impl ProofEvaluations { #[cfg(feature = "ocaml_types")] pub mod caml { use super::*; - use crate::circuits::wires::COLUMNS; + use crate::circuits::wires::KIMCHI_COLS; use poly_commitment::commitment::caml::CamlPolyComm; // @@ -579,7 +585,7 @@ pub mod caml { // ProofEvaluations> <-> CamlProofEvaluations // - impl From>>> + impl From>>> for ( Option>>, CamlProofEvaluations, @@ -588,7 +594,7 @@ pub mod caml { F: Clone, CamlF: From, { - fn from(pe: ProofEvaluations>>) -> Self { + fn from(pe: ProofEvaluations>>) -> Self { let w = ( pe.w[0] .clone() @@ -790,7 +796,7 @@ pub mod caml { From<( Option>>, CamlProofEvaluations, - )> for ProofEvaluations>> + )> for ProofEvaluations>> where F: Clone, CamlF: Clone, diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 8062081963..aee0c8857a 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -122,7 +122,8 @@ where runtime_second_col_d8: Option>>, } -impl, const W: usize> ProverProof +impl, const COLUMNS: usize> + ProverProof where G::BaseField: PrimeField, { @@ -133,15 +134,15 @@ where /// Will give error if `create_recursive` process fails. pub fn create< EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, >( groupmap: &G::Map, - witness: [Vec; W], + witness: [Vec; COLUMNS], runtime_tables: &[RuntimeTable], - index: &ProverIndex, + index: &ProverIndex, ) -> Result where - VerifierIndex: Clone, + VerifierIndex: Clone, { Self::create_recursive::( groupmap, @@ -164,17 +165,17 @@ where /// Will panic if `lookup_context.joint_lookup_table_d8` is None. pub fn create_recursive< EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, >( group_map: &G::Map, - mut witness: [Vec; W], + mut witness: [Vec; COLUMNS], runtime_tables: &[RuntimeTable], - index: &ProverIndex, + index: &ProverIndex, prev_challenges: Vec>, - blinders: Option<[Option>; W]>, + blinders: Option<[Option>; COLUMNS]>, ) -> Result where - VerifierIndex: Clone, + VerifierIndex: Clone, { internal_tracing::checkpoint!(internal_traces; create_recursive); let d1_size = index.cs.domain.d1.size(); @@ -279,13 +280,13 @@ where //~ This is why we need to absorb the commitment to the public polynomial at this point. absorb_commitment(&mut fq_sponge, &public_comm); - //~ 1. Commit to the witness columns by creating `COLUMNS` hidding commitments. + //~ 1. Commit to the witness columns by creating `KIMCHI_COLS` hidding commitments. //~ //~ Note: since the witness is in evaluation form, //~ we can use the `commit_evaluation` optimization. internal_tracing::checkpoint!(internal_traces; commit_to_witness_columns); let mut w_comm = vec![]; - for col in 0..W { + for col in 0..COLUMNS { // witness coeff -> witness eval let witness_eval = Evaluations::>::from_vec_and_domain( @@ -314,7 +315,7 @@ where w_comm.push(com); } - let w_comm: [BlindedCommitment; W] = w_comm + let w_comm: [BlindedCommitment; COLUMNS] = w_comm .try_into() .expect("previous loop is of the correct length"); @@ -323,11 +324,11 @@ where .iter() .for_each(|c| absorb_commitment(&mut fq_sponge, &c.commitment)); - //~ 1. Compute the witness polynomials by interpolating each `COLUMNS` of the witness. + //~ 1. Compute the witness polynomials by interpolating each `KIMCHI_COLS` of the witness. //~ As mentioned above, we commit using the evaluations form rather than the coefficients //~ form so we can take advantage of the sparsity of the evaluations (i.e., there are many //~ 0 entries and entries that have less-than-full-size field elemnts.) - let witness_poly: [DensePolynomial; W] = array::from_fn(|i| { + let witness_poly: [DensePolynomial; COLUMNS] = array::from_fn(|i| { Evaluations::>::from_vec_and_domain( witness[i].clone(), index.cs.domain.d1, @@ -567,7 +568,7 @@ where //~~ * Compute the lookup aggregation polynomial. let joint_lookup_table_d8 = lookup_context.joint_lookup_table_d8.as_ref().unwrap(); - let aggreg = lookup::constraints::aggregation::<_, G::ScalarField, W>( + let aggreg = lookup::constraints::aggregation::<_, G::ScalarField, COLUMNS>( lookup_context.dummy_lookup_value.unwrap(), joint_lookup_table_d8, index.cs.domain.d1, @@ -971,7 +972,7 @@ where }; internal_tracing::checkpoint!(internal_traces; chunk_eval_zeta_omega_poly); - let chunked_evals = ProofEvaluations::>, W> { + let chunked_evals = ProofEvaluations::>, COLUMNS> { public: { let chunked = public_poly.to_chunked_polynomial(num_chunks, index.max_poly_size); Some(PointEvaluations { @@ -1519,7 +1520,7 @@ internal_tracing::decl_traces!(internal_traces; #[cfg(feature = "ocaml_types")] pub mod caml { use super::*; - use crate::circuits::wires::COLUMNS; + use crate::circuits::wires::KIMCHI_COLS; use crate::proof::caml::{CamlProofEvaluations, CamlRecursionChallenge}; use ark_ec::AffineCurve; use poly_commitment::{ @@ -1651,12 +1652,12 @@ pub mod caml { // CamlProverCommitments <-> ProverCommitments // - impl From> for CamlProverCommitments + impl From> for CamlProverCommitments where G: AffineCurve, CamlPolyComm: From>, { - fn from(prover_comm: ProverCommitments) -> Self { + fn from(prover_comm: ProverCommitments) -> Self { Self { w_comm: ( prover_comm.w_comm[0].clone().into(), @@ -1682,12 +1683,14 @@ pub mod caml { } } - impl From> for ProverCommitments + impl From> for ProverCommitments where G: AffineCurve, PolyComm: From>, { - fn from(caml_prover_comm: CamlProverCommitments) -> ProverCommitments { + fn from( + caml_prover_comm: CamlProverCommitments, + ) -> ProverCommitments { let ( w_comm0, w_comm1, @@ -1736,7 +1739,7 @@ pub mod caml { impl From<( - ProverProof>, + ProverProof>, Vec, )> for CamlProofWithPublic where @@ -1746,7 +1749,7 @@ pub mod caml { { fn from( pp: ( - ProverProof>, + ProverProof>, Vec, ), ) -> Self { @@ -1767,7 +1770,7 @@ pub mod caml { impl From> for ( - ProverProof>, + ProverProof>, Vec, ) where @@ -1778,7 +1781,7 @@ pub mod caml { fn from( caml_pp: CamlProofWithPublic, ) -> ( - ProverProof>, + ProverProof>, Vec, ) { let CamlProofWithPublic { diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index b4e624b116..edd7087951 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -6,7 +6,7 @@ use crate::{ berkeley_columns::Column, constraints::{ColumnEvaluations, ConstraintSystem}, expr::{Linearization, PolishToken}, - wires::COLUMNS, + wires::KIMCHI_COLS, }, curve::KimchiCurve, linearization::expr_linearization, @@ -23,7 +23,11 @@ use std::sync::Arc; #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] //~spec:startcode -pub struct ProverIndex, const W: usize = COLUMNS> { +pub struct ProverIndex< + G: KimchiCurve, + OpeningProof: OpenProof, + const COLUMNS: usize = KIMCHI_COLS, +> { /// constraints system polynomials #[serde(bound = "ConstraintSystem: Serialize + DeserializeOwned")] pub cs: ConstraintSystem, @@ -44,12 +48,12 @@ pub struct ProverIndex, const W: usiz /// maximal size of polynomial section pub max_poly_size: usize, - #[serde(bound = "ColumnEvaluations: Serialize + DeserializeOwned")] - pub column_evaluations: ColumnEvaluations, + #[serde(bound = "ColumnEvaluations: Serialize + DeserializeOwned")] + pub column_evaluations: ColumnEvaluations, /// The verifier index corresponding to this prover index #[serde(skip)] - pub verifier_index: Option>, + pub verifier_index: Option>, /// The verifier index digest corresponding to this prover index #[serde_as(as = "Option")] @@ -57,7 +61,8 @@ pub struct ProverIndex, const W: usiz } //~spec:endcode -impl, const W: usize> ProverIndex +impl, const COLUMNS: usize> + ProverIndex where G::BaseField: PrimeField, { @@ -72,7 +77,7 @@ where // pre-compute the linearization let (linearization, powers_of_alpha) = - expr_linearization::(Some(&cs.feature_flags), true); + expr_linearization::(Some(&cs.feature_flags), true); let evaluated_column_coefficients = cs.evaluated_column_coefficients(); @@ -98,7 +103,7 @@ where &mut self, ) -> G::BaseField where - VerifierIndex: Clone, + VerifierIndex: Clone, { if let Some(verifier_index_digest) = self.verifier_index_digest { return verifier_index_digest; @@ -118,7 +123,7 @@ where &self, ) -> G::BaseField where - VerifierIndex: Clone, + VerifierIndex: Clone, { if let Some(verifier_index_digest) = self.verifier_index_digest { return verifier_index_digest; @@ -151,7 +156,7 @@ pub mod testing { pub fn new_index_for_test_with_lookups_and_custom_srs< G: KimchiCurve, OpeningProof: OpenProof, - const W: usize, + const COLUMNS: usize, F: FnMut(D, usize) -> OpeningProof::SRS, >( gates: Vec>, @@ -162,7 +167,7 @@ pub mod testing { disable_gates_checks: bool, override_srs_size: Option, mut get_srs: F, - ) -> ProverIndex + ) -> ProverIndex where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, @@ -175,7 +180,7 @@ pub mod testing { .prev_challenges(prev_challenges) .disable_gates_checks(disable_gates_checks) .max_poly_size(override_srs_size) - .build::() + .build::() .unwrap(); let srs_size = override_srs_size.unwrap_or_else(|| cs.domain.d1.size()); @@ -191,7 +196,7 @@ pub mod testing { /// # Panics /// /// Will panic if `constraint system` is not built with `gates` input. - pub fn new_index_for_test_with_lookups( + pub fn new_index_for_test_with_lookups( gates: Vec>, public: usize, prev_challenges: usize, @@ -199,7 +204,7 @@ pub mod testing { runtime_tables: Option>>, disable_gates_checks: bool, override_srs_size: Option, - ) -> ProverIndex, W> + ) -> ProverIndex, COLUMNS> where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, @@ -228,14 +233,14 @@ pub mod testing { ) } - pub fn new_index_for_test( + pub fn new_index_for_test( gates: Vec>, public: usize, - ) -> ProverIndex, W> + ) -> ProverIndex, COLUMNS> where G::BaseField: PrimeField, G::ScalarField: PrimeField + SquareRootField, { - new_index_for_test_with_lookups::(gates, public, 0, vec![], None, false, None) + new_index_for_test_with_lookups::(gates, public, 0, vec![], None, false, None) } } diff --git a/kimchi/src/snarky/constraint_system.rs b/kimchi/src/snarky/constraint_system.rs index 1b9e42e558..f95bb07137 100644 --- a/kimchi/src/snarky/constraint_system.rs +++ b/kimchi/src/snarky/constraint_system.rs @@ -2,7 +2,7 @@ use crate::circuits::gate::{CircuitGate, GateType}; use crate::circuits::polynomials::poseidon::{ROUNDS_PER_HASH, SPONGE_WIDTH}; -use crate::circuits::wires::{Wire, COLUMNS, PERMUTS}; +use crate::circuits::wires::{Wire, KIMCHI_COLS, PERMUTS}; use ark_ff::PrimeField; use itertools::Itertools; use std::collections::{HashMap, HashSet}; @@ -289,7 +289,7 @@ impl SnarkyConstraintSystem { let mut internal_values = HashMap::new(); let public_input_size = self.public_input_size.unwrap(); let num_rows = public_input_size + self.next_row; - let mut res = vec![vec![Field::zero(); num_rows]; COLUMNS]; + let mut res = vec![vec![Field::zero(); num_rows]; KIMCHI_COLS]; for i in 0..public_input_size { res[0][i] = external_values(i + 1); } diff --git a/kimchi/src/tests/and.rs b/kimchi/src/tests/and.rs index 94ed8a7295..a1ef13afd7 100644 --- a/kimchi/src/tests/and.rs +++ b/kimchi/src/tests/and.rs @@ -2,7 +2,7 @@ use crate::{ circuits::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateError, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{and, xor}, wires::Wire, }, @@ -49,7 +49,7 @@ where // Manually checks the AND of the witness fn check_and( - witness: &[Vec; COLUMNS], + witness: &[Vec; KIMCHI_COLS], bytes: usize, input1: G::ScalarField, input2: G::ScalarField, @@ -74,7 +74,7 @@ fn setup_and( bytes: usize, ) -> ( ConstraintSystem, - [Vec; COLUMNS], + [Vec; KIMCHI_COLS], ) where G::BaseField: PrimeField, @@ -82,7 +82,9 @@ where let rng = &mut StdRng::from_seed(RNG_SEED); let gates = create_test_gates_and::(bytes); - let cs = ConstraintSystem::create(gates).build::().unwrap(); + let cs = ConstraintSystem::create(gates) + .build::() + .unwrap(); // Initalize inputs let input1 = rng.gen(input1, Some(bytes * 8)); @@ -99,7 +101,7 @@ fn test_and( input1: Option, input2: Option, bytes: usize, -) -> [Vec; COLUMNS] +) -> [Vec; KIMCHI_COLS] where G::BaseField: PrimeField, { @@ -107,7 +109,7 @@ where for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -125,7 +127,7 @@ fn prove_and_verify(bytes: usize) where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let rng = &mut StdRng::from_seed(RNG_SEED); @@ -235,13 +237,13 @@ fn test_and_overflow_one() { } fn verify_bad_and_decomposition( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], cs: ConstraintSystem, ) where G::BaseField: PrimeField, { // modify by one each of the witness cells individually - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { // first three columns make fail the ith+1 constraint // for the rest, the first 4 make the 1st fail, the following 4 make the 2nd fail, the last 4 make the 3rd fail let bad = if col < 3 { col + 1 } else { (col - 3) / 4 + 1 }; @@ -251,7 +253,7 @@ fn verify_bad_and_decomposition( // Update copy constraints of generic gate if col < 2 { assert_eq!( - cs.gates[0].verify_witness::( + cs.gates[0].verify_witness::( 0, witness, &cs, @@ -267,7 +269,7 @@ fn verify_bad_and_decomposition( } if col == 2 { assert_eq!( - cs.gates[0].verify_witness::( + cs.gates[0].verify_witness::( 0, witness, &cs, @@ -285,7 +287,12 @@ fn verify_bad_and_decomposition( witness[4][and_row] += G::ScalarField::one(); } assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::( + 0, + witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::Xor16, bad)) ); witness[col][xor_row] -= G::ScalarField::one(); @@ -298,7 +305,7 @@ fn verify_bad_and_decomposition( } // undo changes assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), Ok(()) ); } @@ -328,7 +335,7 @@ fn test_bad_and() { // Corrupt the witness: modify the output to be all zero witness[2][0] = PallasField::zero(); for i in 1..=4 { - witness[COLUMNS - i][0] = PallasField::zero(); + witness[KIMCHI_COLS - i][0] = PallasField::zero(); } witness[4][2] = PallasField::zero(); diff --git a/kimchi/src/tests/chunked.rs b/kimchi/src/tests/chunked.rs index 7e00d715aa..e37abf69d1 100644 --- a/kimchi/src/tests/chunked.rs +++ b/kimchi/src/tests/chunked.rs @@ -2,7 +2,7 @@ use super::framework::TestFramework; use crate::circuits::polynomials::generic::GenericGateSpec; use crate::circuits::{ gate::CircuitGate, - wires::{Wire, COLUMNS}, + wires::{Wire, KIMCHI_COLS}, }; use ark_ff::{UniformRand, Zero}; use itertools::iterate; @@ -26,7 +26,7 @@ fn test_generic_gate_with_srs_override( let mut gates_row = iterate(0, |&i| i + 1); let mut gates = Vec::with_capacity(circuit_size); - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); circuit_size]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); circuit_size]); let rng = &mut rand::rngs::OsRng; diff --git a/kimchi/src/tests/ec.rs b/kimchi/src/tests/ec.rs index 9deec7a32a..2a980eb603 100644 --- a/kimchi/src/tests/ec.rs +++ b/kimchi/src/tests/ec.rs @@ -35,7 +35,7 @@ fn ec_test() { )); } - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![]); let rng = &mut StdRng::from_seed([0; 32]); diff --git a/kimchi/src/tests/endomul.rs b/kimchi/src/tests/endomul.rs index 5a4fa08246..1610c03e97 100644 --- a/kimchi/src/tests/endomul.rs +++ b/kimchi/src/tests/endomul.rs @@ -49,7 +49,7 @@ fn endomul_test() { let (endo_q, endo_r) = endos::(); - let mut witness: [Vec; COLUMNS] = + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); rows_per_scalar * num_scalars]); let rng = &mut StdRng::from_seed([0; 32]); diff --git a/kimchi/src/tests/endomul_scalar.rs b/kimchi/src/tests/endomul_scalar.rs index f39c0bf236..97068a91ab 100644 --- a/kimchi/src/tests/endomul_scalar.rs +++ b/kimchi/src/tests/endomul_scalar.rs @@ -45,7 +45,7 @@ fn endomul_scalar_test() { let (_, endo_scalar_coeff) = endos::(); - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![]); let rng = &mut StdRng::from_seed([0; 32]); diff --git a/kimchi/src/tests/foreign_field_add.rs b/kimchi/src/tests/foreign_field_add.rs index f0911ba0a6..568e0c19b9 100644 --- a/kimchi/src/tests/foreign_field_add.rs +++ b/kimchi/src/tests/foreign_field_add.rs @@ -4,7 +4,7 @@ use crate::circuits::polynomials::generic::GenericGateSpec; use crate::circuits::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateError, Connect, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{ foreign_field_add::witness::{self, FFOps}, range_check::{self, witness::extend_multi}, @@ -266,11 +266,11 @@ fn short_witness( inputs: &Vec, opcodes: &[FFOps], modulus: BigUint, -) -> [Vec; COLUMNS] { - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); 1]); +) -> [Vec; KIMCHI_COLS] { + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); 1]); witness[0][0] = F::one(); let add_witness = witness::create_chain::(inputs, opcodes, modulus); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(add_witness[col].iter()); } witness @@ -284,8 +284,8 @@ fn long_witness( inputs: &Vec, opcodes: &[FFOps], modulus: BigUint, -) -> [Vec; COLUMNS] { - let mut witness: [Vec; COLUMNS] = short_witness(inputs, opcodes, modulus); +) -> [Vec; KIMCHI_COLS] { + let mut witness: [Vec; KIMCHI_COLS] = short_witness(inputs, opcodes, modulus); let num = inputs.len() - 1; // number of chained additions @@ -325,7 +325,7 @@ fn create_test_constraint_system_ffadd( let cs = ConstraintSystem::create(gates) .public(1) - .build::() + .build::() .unwrap(); let mut srs = SRS::::create(cs.domain.d1.size()); srs.add_lagrange_basis(cs.domain.d1); @@ -342,7 +342,7 @@ fn test_ffadd( opcodes: &[FFOps], full: bool, ) -> ( - [Vec; COLUMNS], + [Vec; KIMCHI_COLS], ProverIndex>, ) { let index = create_test_constraint_system_ffadd(opcodes, foreign_field_modulus.clone(), full); @@ -357,7 +357,7 @@ fn test_ffadd( for row in 0..all_rows { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -371,7 +371,10 @@ fn test_ffadd( } // checks that the result cells of the witness are computed as expected -fn check_result(witness: [Vec; COLUMNS], result: Vec>) { +fn check_result( + witness: [Vec; KIMCHI_COLS], + result: Vec>, +) { for (i, res) in result.iter().enumerate() { assert_eq!(witness[0][i + 2], res[LO]); assert_eq!(witness[1][i + 2], res[MI]); @@ -380,12 +383,12 @@ fn check_result(witness: [Vec; COLUMNS], result: Vec; COLUMNS], ovf: PallasField) { +fn check_ovf(witness: [Vec; KIMCHI_COLS], ovf: PallasField) { assert_eq!(witness[6][1], ovf); } // checks the result of the carry bits for one addition -fn check_carry(witness: [Vec; COLUMNS], carry: PallasField) { +fn check_carry(witness: [Vec; KIMCHI_COLS], carry: PallasField) { assert_eq!(witness[7][1], carry); } @@ -761,7 +764,7 @@ fn test_wrong_sum() { witness[0][12] = all_ones_limb; assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -785,7 +788,7 @@ fn test_wrong_dif() { witness[0][12] = PallasField::zero(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1072,7 +1075,7 @@ fn test_bad_bound() { // Modify overflow to check first the copy constraint and then the ovf constraint witness[6][2] = -PallasField::one(); assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1086,7 +1089,7 @@ fn test_bad_bound() { ); witness[0][0] = -PallasField::one(); assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1097,7 +1100,7 @@ fn test_bad_bound() { witness[6][2] = PallasField::one(); witness[0][0] = PallasField::one(); assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1126,7 +1129,7 @@ fn test_random_bad_input() { // First modify left input only to cause an invalid copy constraint witness[0][1] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1141,7 +1144,7 @@ fn test_random_bad_input() { // then modify the value in the range check to cause an invalid FFAdd constraint witness[0][4] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1170,7 +1173,7 @@ fn test_random_bad_parameters() { // Modify bot carry witness[7][1] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1182,7 +1185,7 @@ fn test_random_bad_parameters() { // Modify overflow witness[6][1] += PallasField::one(); assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1194,7 +1197,7 @@ fn test_random_bad_parameters() { // Modify sign index.cs.gates[1].coeffs[3] = PallasField::zero() - index.cs.gates[1].coeffs[3]; assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1205,7 +1208,7 @@ fn test_random_bad_parameters() { index.cs.gates[1].coeffs[3] = PallasField::zero() - index.cs.gates[1].coeffs[3]; // Check back to normal assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1303,7 +1306,7 @@ fn extend_gate_bound_rc(gates: &mut Vec>) -> usize { } // Extends a witness with the final bound range check -fn extend_witness_bound_rc(witness: &mut [Vec; COLUMNS]) { +fn extend_witness_bound_rc(witness: &mut [Vec; KIMCHI_COLS]) { let bound_row = witness[0].len() - 1; let bound_lo = witness[0][bound_row]; let bound_mi = witness[1][bound_row]; @@ -1332,7 +1335,7 @@ fn test_ffadd_no_rc() { let cs = ConstraintSystem::create(gates) .public(1) - .build::() + .build::() .unwrap(); // Create inputs @@ -1347,7 +1350,7 @@ fn test_ffadd_no_rc() { for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -1391,7 +1394,7 @@ fn test_pallas_on_pallas() { // Boilerplate for tests fn run_test( foreign_field_modulus: &BigUint, -) -> (CircuitGateResult<()>, [Vec; COLUMNS]) +) -> (CircuitGateResult<()>, [Vec; KIMCHI_COLS]) where G::BaseField: PrimeField, G: KimchiCurve, @@ -1415,13 +1418,13 @@ where let cs = ConstraintSystem::create(gates.clone()) .public(1) - .build::() + .build::() .unwrap(); // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return (result, witness); } @@ -1478,14 +1481,14 @@ fn test_ffadd_finalization() { // witness let witness = { // create row for the public value 1 - let mut witness: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); 1]); + let mut witness: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); 1]); witness[0][0] = Fp::one(); // create inputs to the addition let left = modulus.clone() - BigUint::one(); let right = modulus.clone() - BigUint::one(); // create a chain of 1 addition let add_witness = witness::create_chain::(&vec![left, right], operation, modulus); - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { witness[col].extend(add_witness[col].iter()); } // extend range checks for all of left, right, output, and bound @@ -1504,7 +1507,7 @@ fn test_ffadd_finalization() { let cs = ConstraintSystem::create(gates.clone()) .lookup(vec![range_check::gadget::lookup_table()]) .public(num_public_inputs) - .build::() + .build::() .unwrap(); let mut srs = SRS::::create(cs.domain.d1.size()); srs.add_lagrange_basis(cs.domain.d1); @@ -1516,7 +1519,7 @@ fn test_ffadd_finalization() { for row in 0..witness[0].len() { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, diff --git a/kimchi/src/tests/foreign_field_mul.rs b/kimchi/src/tests/foreign_field_mul.rs index 631c94fed5..21d68baa6e 100644 --- a/kimchi/src/tests/foreign_field_mul.rs +++ b/kimchi/src/tests/foreign_field_mul.rs @@ -2,7 +2,7 @@ use crate::{ circuits::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateError, CircuitGateResult, Connect, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::foreign_field_mul, }, curve::KimchiCurve, @@ -75,11 +75,11 @@ fn run_test( right_input: &BigUint, foreign_field_modulus: &BigUint, invalidations: Vec<((usize, usize), G::ScalarField)>, -) -> (CircuitGateResult<()>, [Vec; COLUMNS]) +) -> (CircuitGateResult<()>, [Vec; KIMCHI_COLS]) where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { // Create foreign field multiplication gates let (mut next_row, mut gates) = @@ -205,14 +205,14 @@ where } else { // If not full mode, just create constraint system (this is much faster) ConstraintSystem::create(gates.clone()) - .build::() + .build::() .unwrap() }; // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return (result, witness); } @@ -246,7 +246,7 @@ where // When targeting the plookup constraints the invalidated values would cause custom constraint // failures, so we want to suppress these witness verification checks when doing plookup tests. for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { - let result = gate.verify_witness::( + let result = gate.verify_witness::( row, &witness, &cs, @@ -295,7 +295,7 @@ fn test_custom_constraints(foreign_field_m where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let rng = &mut StdRng::from_seed(RNG_SEED); diff --git a/kimchi/src/tests/framework.rs b/kimchi/src/tests/framework.rs index e1e4fd52f0..e224d9e895 100644 --- a/kimchi/src/tests/framework.rs +++ b/kimchi/src/tests/framework.rs @@ -7,7 +7,7 @@ use crate::{ runtime_tables::{RuntimeTable, RuntimeTableCfg}, tables::LookupTable, }, - wires::COLUMNS, + wires::KIMCHI_COLS, }, curve::KimchiCurve, plonk_sponge::FrSponge, @@ -36,15 +36,15 @@ use std::{fmt::Write, time::Instant}; #[derive(Default, Clone)] pub(crate) struct TestFramework< G: KimchiCurve, - const W: usize = COLUMNS, + const COLUMNS: usize = KIMCHI_COLS, OpeningProof: OpenProof = DlogOpeningProof, > where G::BaseField: PrimeField, OpeningProof::SRS: Clone, - VerifierIndex: Clone, + VerifierIndex: Clone, { gates: Option>>, - witness: Option<[Vec; W]>, + witness: Option<[Vec; COLUMNS]>, public_inputs: Vec, lookup_tables: Vec>, runtime_tables_setup: Option>>, @@ -54,26 +54,27 @@ pub(crate) struct TestFramework< disable_gates_checks: bool, override_srs_size: Option, - prover_index: Option>, - verifier_index: Option>, + prover_index: Option>, + verifier_index: Option>, } #[derive(Clone)] pub(crate) struct TestRunner< G: KimchiCurve, - const W: usize = COLUMNS, + const COLUMNS: usize = KIMCHI_COLS, OpeningProof: OpenProof = DlogOpeningProof, ->(TestFramework) +>(TestFramework) where G::BaseField: PrimeField, OpeningProof::SRS: Clone, - VerifierIndex: Clone; + VerifierIndex: Clone; -impl> TestFramework +impl> + TestFramework where G::BaseField: PrimeField, OpeningProof::SRS: Clone, - VerifierIndex: Clone, + VerifierIndex: Clone, { #[must_use] pub(crate) fn gates(mut self, gates: Vec>) -> Self { @@ -82,7 +83,7 @@ where } #[must_use] - pub(crate) fn witness(mut self, witness: [Vec; W]) -> Self { + pub(crate) fn witness(mut self, witness: [Vec; COLUMNS]) -> Self { self.witness = Some(witness); self } @@ -131,7 +132,7 @@ where pub(crate) fn setup_with_custom_srs, usize) -> OpeningProof::SRS>( mut self, get_srs: F, - ) -> TestRunner { + ) -> TestRunner { let start = Instant::now(); let lookup_tables = std::mem::take(&mut self.lookup_tables); @@ -159,19 +160,19 @@ where } } -impl TestFramework +impl TestFramework where G::BaseField: PrimeField, { /// creates the indexes #[must_use] - pub(crate) fn setup(mut self) -> TestRunner { + pub(crate) fn setup(mut self) -> TestRunner { let start = Instant::now(); let lookup_tables = std::mem::take(&mut self.lookup_tables); let runtime_tables_setup = self.runtime_tables_setup.take(); - let index = new_index_for_test_with_lookups::( + let index = new_index_for_test_with_lookups::( self.gates.take().unwrap(), self.public_inputs.len(), self.num_prev_challenges, @@ -192,12 +193,13 @@ where } } -impl> TestRunner +impl> + TestRunner where G::ScalarField: PrimeField + Clone, G::BaseField: PrimeField + Clone, OpeningProof::SRS: Clone, - VerifierIndex: Clone, + VerifierIndex: Clone, { #[must_use] pub(crate) fn runtime_tables( @@ -215,12 +217,12 @@ where } #[must_use] - pub(crate) fn witness(mut self, witness: [Vec; W]) -> Self { + pub(crate) fn witness(mut self, witness: [Vec; COLUMNS]) -> Self { self.0.witness = Some(witness); self } - pub(crate) fn prover_index(&self) -> &ProverIndex { + pub(crate) fn prover_index(&self) -> &ProverIndex { self.0.prover_index.as_ref().unwrap() } @@ -229,7 +231,7 @@ where pub(crate) fn prove(self) -> Result<(), String> where EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let prover = self.0.prover_index.unwrap(); let witness = self.0.witness.unwrap(); @@ -260,7 +262,7 @@ where pub(crate) fn prove_and_verify(self) -> Result<(), String> where EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let prover = self.0.prover_index.unwrap(); let witness = self.0.witness.unwrap(); @@ -291,7 +293,7 @@ where // verify the proof (propagate any errors) let start = Instant::now(); - verify::( + verify::( &group_map, &self.0.verifier_index.unwrap(), &proof, @@ -304,7 +306,7 @@ where } } -pub fn print_witness(cols: &[Vec; COLUMNS], start_row: usize, end_row: usize) +pub fn print_witness(cols: &[Vec; KIMCHI_COLS], start_row: usize, end_row: usize) where F: PrimeField, { diff --git a/kimchi/src/tests/generic.rs b/kimchi/src/tests/generic.rs index ac1b785a29..57f0ca78c6 100644 --- a/kimchi/src/tests/generic.rs +++ b/kimchi/src/tests/generic.rs @@ -1,6 +1,6 @@ use super::framework::TestFramework; use crate::circuits::polynomials::generic::testing::{create_circuit, fill_in_witness}; -use crate::circuits::wires::COLUMNS; +use crate::circuits::wires::KIMCHI_COLS; use ark_ff::Zero; use mina_curves::pasta::{Fp, Vesta, VestaParameters}; use mina_poseidon::{ @@ -15,10 +15,10 @@ type ScalarSponge = DefaultFrSponge; #[test] fn test_generic_gate() { - let gates = create_circuit::(0, 0); + let gates = create_circuit::(0, 0); // create witness - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &[]); // create and verify proof based on the witness @@ -33,10 +33,10 @@ fn test_generic_gate() { #[test] fn test_generic_gate_pub() { let public = vec![Fp::from(3u8); 5]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); // create and verify proof based on the witness @@ -52,14 +52,14 @@ fn test_generic_gate_pub() { #[test] fn test_generic_gate_pub_all_zeros() { let public = vec![Fp::from(0u8); 5]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); // create and verify proof based on the witness - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(public) @@ -71,14 +71,14 @@ fn test_generic_gate_pub_all_zeros() { #[test] fn test_generic_gate_pub_empty() { let public = vec![]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); // create and verify proof based on the witness - TestFramework::::default() + TestFramework::::default() .gates(gates) .witness(witness) .public_inputs(public) @@ -98,19 +98,19 @@ fn test_generic_gate_pairing() { use ark_ff::UniformRand; let public = vec![Fp::from(3u8); 5]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); let rng = &mut rand::rngs::OsRng; let x = Fp::rand(rng); // create witness - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); // create and verify proof based on the witness >, > as Default>::default() .gates(gates) diff --git a/kimchi/src/tests/lookup.rs b/kimchi/src/tests/lookup.rs index a674eba78f..16168d229a 100644 --- a/kimchi/src/tests/lookup.rs +++ b/kimchi/src/tests/lookup.rs @@ -5,7 +5,7 @@ use crate::circuits::{ runtime_tables::{RuntimeTable, RuntimeTableCfg}, tables::LookupTable, }, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, wires::Wire, }; use ark_ff::{UniformRand, Zero}; @@ -146,7 +146,7 @@ fn setup_successfull_runtime_table_test( // witness let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); // only the first 7 registers are used in the lookup gate let (lookup_cols, _rest) = cols.split_at_mut(7); @@ -229,7 +229,7 @@ fn test_runtime_table() { // witness let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); // only the first 7 registers are used in the lookup gate let (lookup_cols, _rest) = cols.split_at_mut(7); @@ -290,7 +290,7 @@ fn test_negative_test_runtime_table_value_not_in_table() { // witness. The whole witness is going to be wrong. let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); nb_gates]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); nb_gates]); // only the first 7 registers are used in the lookup gate let (lookup_cols, _rest) = cols.split_at_mut(7); @@ -352,7 +352,7 @@ fn test_negative_test_runtime_table_prover_with_undefined_id_in_index_and_witnes // witness let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); nb_gates]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); nb_gates]); // only the first 7 registers are used in the lookup gate let (lookup_cols, _rest) = cols.split_at_mut(7); @@ -412,7 +412,7 @@ fn test_negative_test_runtime_table_prover_uses_undefined_id_in_index_and_witnes // witness let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); nb_gates]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); nb_gates]); // only the first 7 registers are used in the lookup gate let (lookup_cols, _rest) = cols.split_at_mut(7); @@ -492,7 +492,7 @@ fn test_runtime_table_with_more_than_one_runtime_table_data_given_by_prover() { // witness let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); gates.len()]); // only the first 7 registers are used in the lookup gate let (lookup_cols, _rest) = cols.split_at_mut(7); diff --git a/kimchi/src/tests/not.rs b/kimchi/src/tests/not.rs index 072f185643..0bd2835ad3 100644 --- a/kimchi/src/tests/not.rs +++ b/kimchi/src/tests/not.rs @@ -4,7 +4,7 @@ use crate::{ circuits::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateError, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{generic::GenericGateSpec, not, xor}, wires::Wire, }, @@ -46,8 +46,8 @@ const RNG_SEED: [u8; 32] = [ fn create_not_witness_unchecked_length( inputs: &[F], bits: usize, -) -> [Vec; COLUMNS] { - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); 1]); +) -> [Vec; KIMCHI_COLS] { + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); 1]); witness[0][0] = F::from(2u8).pow([bits as u64]) - F::one(); let result = not::extend_not_witness_unchecked_length(&mut witness, inputs, bits); if let Err(e) = result { @@ -63,8 +63,8 @@ fn create_not_witness_unchecked_length( fn create_not_witness_checked_length( input: F, bits: Option, -) -> [Vec; COLUMNS] { - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![F::zero(); 1]); +) -> [Vec; KIMCHI_COLS] { + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); 1]); let input_big = input.to_biguint(); let real_bits = max(input_big.bitlen(), bits.unwrap_or(0)); witness[0][0] = F::from(2u8).pow([real_bits as u64]) - F::one(); @@ -92,7 +92,7 @@ where ConstraintSystem::create(gates) .public(1) - .build::() + .build::() .unwrap() } @@ -113,7 +113,7 @@ where ConstraintSystem::create(gates) .public(1) - .build::() + .build::() .unwrap() } @@ -122,7 +122,7 @@ fn setup_not_xor( input: Option, bits: Option, ) -> ( - [Vec; COLUMNS], + [Vec; KIMCHI_COLS], ConstraintSystem, ) where @@ -149,7 +149,7 @@ where fn test_not_xor( input: Option, bits: Option, -) -> [Vec; COLUMNS] +) -> [Vec; KIMCHI_COLS] where G::BaseField: PrimeField, { @@ -157,7 +157,7 @@ where for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -176,7 +176,7 @@ fn setup_not_gnrc( bits: usize, len: Option, ) -> ( - [Vec; COLUMNS], + [Vec; KIMCHI_COLS], ConstraintSystem, ) where @@ -209,7 +209,7 @@ fn test_not_gnrc( inputs: Option>, bits: usize, len: Option, -) -> [Vec; COLUMNS] +) -> [Vec; KIMCHI_COLS] where G::BaseField: PrimeField, { @@ -218,7 +218,7 @@ where // test public input and not generic gate for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -233,7 +233,7 @@ where // Manually checks the NOT of each crumb in the witness fn check_not_xor( - witness: &[Vec; COLUMNS], + witness: &[Vec; KIMCHI_COLS], input: G::ScalarField, bits: Option, ) { @@ -248,7 +248,7 @@ fn check_not_xor( // Manually checks the NOTs of a vector of inputs in generic gates fn check_not_gnrc( - witness: &[Vec; COLUMNS], + witness: &[Vec; KIMCHI_COLS], inputs: &[G::ScalarField], bits: usize, ) { @@ -408,7 +408,12 @@ fn test_bad_not_gnrc() { // modify public input row to make sure the copy constraint fails and the generic gate also fails witness[0][0] += PallasField::one(); assert_eq!( - cs.gates[0].verify_witness::(0, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::( + 0, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::CopyConstraint { typ: GateType::Generic, src: Wire { row: 0, col: 0 }, @@ -426,7 +431,12 @@ fn test_bad_not_gnrc() { None, ); assert_eq!( - index.cs.gates[1].verify::, COLUMNS>(1, &witness, &index, &[]), + index.cs.gates[1].verify::, KIMCHI_COLS>( + 1, + &witness, + &index, + &[] + ), Err(("generic: incorrect gate").to_string()) ); } @@ -438,7 +448,12 @@ fn test_bad_not_xor() { // modify public input row to make sure the copy constraint fails and the XOR gate also fails witness[0][0] += PallasField::one(); assert_eq!( - cs.gates[0].verify_witness::(0, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::( + 0, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::CopyConstraint { typ: GateType::Generic, src: Wire { row: 0, col: 0 }, @@ -448,7 +463,12 @@ fn test_bad_not_xor() { witness[1][1] += PallasField::one(); // decomposition of xor fails assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::( + 1, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::Xor16, 2)) ); // Make the second input zero with correct decomposition to make sure XOR table fails diff --git a/kimchi/src/tests/poseidon.rs b/kimchi/src/tests/poseidon.rs index f5f31e0f49..5f8ceb56f8 100644 --- a/kimchi/src/tests/poseidon.rs +++ b/kimchi/src/tests/poseidon.rs @@ -3,7 +3,7 @@ use crate::{ gate::CircuitGate, polynomials, polynomials::poseidon::ROUNDS_PER_ROW, - wires::{Wire, COLUMNS}, + wires::{Wire, KIMCHI_COLS}, }, curve::KimchiCurve, tests::framework::TestFramework, @@ -62,7 +62,7 @@ fn test_poseidon() { } // witness for Poseidon permutation custom constraints - let mut witness: [Vec; COLUMNS] = + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); POS_ROWS_PER_HASH * NUM_POS + 1 /* last output row */]); // creates a random input diff --git a/kimchi/src/tests/range_check.rs b/kimchi/src/tests/range_check.rs index c4c21af35b..da1edd759a 100644 --- a/kimchi/src/tests/range_check.rs +++ b/kimchi/src/tests/range_check.rs @@ -2,7 +2,7 @@ use crate::{ circuits::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateError, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{ generic::GenericGateSpec, range_check::{self}, @@ -78,11 +78,12 @@ fn create_test_prover_index( #[test] fn verify_range_check0_zero_valid_witness() { let index = create_test_prover_index(0, false); - let witness: [Vec; COLUMNS] = array::from_fn(|_| vec![PallasField::from(0); 4]); + let witness: [Vec; KIMCHI_COLS] = + array::from_fn(|_| vec![PallasField::from(0); 4]); // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -93,7 +94,7 @@ fn verify_range_check0_zero_valid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -106,11 +107,12 @@ fn verify_range_check0_zero_valid_witness() { #[test] fn verify_range_check0_one_invalid_witness() { let index = create_test_prover_index(0, false); - let witness: [Vec; COLUMNS] = array::from_fn(|_| vec![PallasField::from(1); 4]); + let witness: [Vec; KIMCHI_COLS] = + array::from_fn(|_| vec![PallasField::from(1); 4]); // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -121,7 +123,7 @@ fn verify_range_check0_one_invalid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -146,7 +148,7 @@ fn verify_range_check0_valid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -157,7 +159,7 @@ fn verify_range_check0_valid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -177,7 +179,7 @@ fn verify_range_check0_valid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -188,7 +190,7 @@ fn verify_range_check0_valid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -216,7 +218,7 @@ fn verify_range_check0_invalid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -234,7 +236,7 @@ fn verify_range_check0_invalid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -261,7 +263,7 @@ fn verify_range_check0_invalid_witness() { // gates[0] is RangeCheck0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -275,7 +277,7 @@ fn verify_range_check0_invalid_witness() { // gates[1] is RangeCheck0 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -297,7 +299,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -314,7 +316,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -331,7 +333,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -348,7 +350,7 @@ fn verify_range_check0_valid_v0_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -370,7 +372,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -387,7 +389,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -404,7 +406,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -421,7 +423,7 @@ fn verify_range_check0_valid_v1_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -443,7 +445,7 @@ fn verify_range_check0_invalid_v0_not_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -460,7 +462,7 @@ fn verify_range_check0_invalid_v0_not_in_range() { // gates[0] is RangeCheck0 and contains v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -482,7 +484,7 @@ fn verify_range_check0_invalid_v1_not_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -499,7 +501,7 @@ fn verify_range_check0_invalid_v1_not_in_range() { // gates[1] is RangeCheck0 and contains v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -524,7 +526,7 @@ fn verify_range_check0_test_copy_constraints() { // Positive test case (gates[row] is a RangeCheck0 circuit gate) assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -537,7 +539,7 @@ fn verify_range_check0_test_copy_constraints() { assert_ne!(witness[col][row], PallasField::zero()); witness[col][row] = PallasField::zero(); assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, @@ -569,7 +571,7 @@ fn verify_range_check0_v0_test_lookups() { // Positive test // gates[0] is RangeCheck0 and constrains some of v0 assert_eq!( - index.cs.gates[0].verify_witness::( + index.cs.gates[0].verify_witness::( 0, &witness, &index.cs, @@ -622,7 +624,7 @@ fn verify_range_check0_v1_test_lookups() { // Positive test // gates[1] is RangeCheck0 and constrains some of v1 assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -665,11 +667,12 @@ fn verify_range_check0_v1_test_lookups() { #[test] fn verify_range_check1_zero_valid_witness() { let index = create_test_prover_index(0, false); - let witness: [Vec; COLUMNS] = array::from_fn(|_| vec![PallasField::from(0); 4]); + let witness: [Vec; KIMCHI_COLS] = + array::from_fn(|_| vec![PallasField::from(0); 4]); // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -682,11 +685,12 @@ fn verify_range_check1_zero_valid_witness() { #[test] fn verify_range_check1_one_invalid_witness() { let index = create_test_prover_index(0, false); - let witness: [Vec; COLUMNS] = array::from_fn(|_| vec![PallasField::from(1); 4]); + let witness: [Vec; KIMCHI_COLS] = + array::from_fn(|_| vec![PallasField::from(1); 4]); // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -711,7 +715,7 @@ fn verify_range_check1_valid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -731,7 +735,7 @@ fn verify_range_check1_valid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -759,7 +763,7 @@ fn verify_range_check1_invalid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -782,7 +786,7 @@ fn verify_range_check1_invalid_witness() { // gates[2] is RangeCheck1 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -804,7 +808,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -821,7 +825,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -838,7 +842,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -855,7 +859,7 @@ fn verify_range_check1_valid_v2_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -877,7 +881,7 @@ fn verify_range_check1_invalid_v2_not_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -894,7 +898,7 @@ fn verify_range_check1_invalid_v2_not_in_range() { // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -919,7 +923,7 @@ fn verify_range_check1_test_copy_constraints() { // Positive test case (gates[2] is a RangeCheck1 circuit gate) assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -934,7 +938,7 @@ fn verify_range_check1_test_copy_constraints() { // RangeCheck1's current row doesn't have any copy constraints assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -945,7 +949,7 @@ fn verify_range_check1_test_copy_constraints() { // RangeCheck1's next row has copy constraints, but it's a Zero gate assert_eq!( - index.cs.gates[3].verify_witness::( + index.cs.gates[3].verify_witness::( 3, &witness, &index.cs, @@ -976,7 +980,7 @@ fn verify_range_check1_test_curr_row_lookups() { // Positive test // gates[2] is RangeCheck1 and constrains v2 assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1025,7 +1029,7 @@ fn verify_range_check1_test_next_row_lookups() { // Positive test case (gates[2] is RangeCheck1 and constrains // both v0's and v1's lookups that are deferred to 4th row) assert_eq!( - index.cs.gates[2].verify_witness::( + index.cs.gates[2].verify_witness::( 2, &witness, &index.cs, @@ -1087,7 +1091,7 @@ fn verify_64_bit_range_check() { // Create constraint system let cs = ConstraintSystem::::create(gates /*, mina_poseidon::pasta::fp_kimchi::params()*/) - .build::() + .build::() .unwrap(); let index = { @@ -1103,7 +1107,8 @@ fn verify_64_bit_range_check() { // Row 0 1 2 3 ... 14 Gate // 0 0 0 0 0 ... 0 GenericPub // 1 0 0 X X ... X RangeCheck0 - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![PallasField::zero()]); + let mut witness: [Vec; KIMCHI_COLS] = + array::from_fn(|_| vec![PallasField::zero()]); range_check::witness::create::( PallasField::from(2u64).pow([64]) - PallasField::one(), // in range ) @@ -1113,7 +1118,7 @@ fn verify_64_bit_range_check() { // Positive test case assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1126,7 +1131,8 @@ fn verify_64_bit_range_check() { // Row 0 1 2 3 ... 14 Gate // 0 0 0 0 0 ... 0 GenericPub // 1 0 X X X ... X RangeCheck0 - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![PallasField::zero()]); + let mut witness: [Vec; KIMCHI_COLS] = + array::from_fn(|_| vec![PallasField::zero()]); range_check::witness::create::( PallasField::from(2u64).pow([64]), // out of range ) @@ -1136,7 +1142,7 @@ fn verify_64_bit_range_check() { // Negative test case assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1168,7 +1174,7 @@ fn compact_multi_range_check() { // Positive test assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1182,7 +1188,7 @@ fn compact_multi_range_check() { // Negative test assert_eq!( - index.cs.gates[1].verify_witness::( + index.cs.gates[1].verify_witness::( 1, &witness, &index.cs, @@ -1222,7 +1228,7 @@ fn verify_range_check_valid_proof1() { let verifier_index = prover_index.verifier_index(); // Verify proof - let res = verify::, COLUMNS>( + let res = verify::, KIMCHI_COLS>( &group_map, &verifier_index, &proof, diff --git a/kimchi/src/tests/recursion.rs b/kimchi/src/tests/recursion.rs index 60ef234e7c..1aff106d8c 100644 --- a/kimchi/src/tests/recursion.rs +++ b/kimchi/src/tests/recursion.rs @@ -1,6 +1,6 @@ use super::framework::TestFramework; use crate::circuits::polynomials::generic::testing::{create_circuit, fill_in_witness}; -use crate::circuits::wires::COLUMNS; +use crate::circuits::wires::KIMCHI_COLS; use crate::proof::RecursionChallenge; use ark_ff::{UniformRand, Zero}; use ark_poly::univariate::DensePolynomial; @@ -21,10 +21,10 @@ type ScalarSponge = DefaultFrSponge; #[test] fn test_recursion() { - let gates = create_circuit::(0, 0); + let gates = create_circuit::(0, 0); // create witness - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &[]); // setup diff --git a/kimchi/src/tests/rot.rs b/kimchi/src/tests/rot.rs index a92ca36b57..0d0cf183d9 100644 --- a/kimchi/src/tests/rot.rs +++ b/kimchi/src/tests/rot.rs @@ -5,7 +5,7 @@ use crate::{ circuits::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateError, Connect, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{ generic::GenericGateSpec, rot::{self, RotMode}, @@ -65,12 +65,12 @@ fn create_rot_witness( word: u64, rot: u32, side: RotMode, -) -> [Vec; COLUMNS] +) -> [Vec; KIMCHI_COLS] where G::BaseField: PrimeField, { // Include the zero row - let mut witness: [Vec; COLUMNS] = + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![G::ScalarField::zero()]); rot::extend_rot(&mut witness, word, rot, side); witness @@ -86,7 +86,9 @@ where // gate for the zero value let gates = create_rot_gadget::(rot, side); - ConstraintSystem::create(gates).build::().unwrap() + ConstraintSystem::create(gates) + .build::() + .unwrap() } // Function to create a prover and verifier to test the ROT circuit @@ -94,7 +96,7 @@ fn prove_and_verify() where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let rng = &mut StdRng::from_seed(RNG_SEED); let rot = rng.gen_range(1..64); @@ -129,7 +131,7 @@ where let (witness, cs) = setup_rot::(word, rot, side); for row in 0..=2 { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -146,7 +148,7 @@ fn setup_rot( rot: u32, side: RotMode, ) -> ( - [Vec; COLUMNS], + [Vec; KIMCHI_COLS], ConstraintSystem, ) where @@ -207,7 +209,7 @@ fn test_bad_constraints() { witness[i + 7][1] += PallasField::from(4u32); // Decomposition constraint fails assert_eq!( - cs.gates[1].verify_witness::( + cs.gates[1].verify_witness::( 1, &witness, &cs, @@ -224,7 +226,12 @@ fn test_bad_constraints() { witness[0][1] += PallasField::one(); // Decomposition constraint fails assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::( + 1, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::Rot64, 9)) ); // undo @@ -235,7 +242,12 @@ fn test_bad_constraints() { witness[1][1] += PallasField::one(); // Rotated word is wrong assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::( + 1, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::Rot64, 10)) ); // undo @@ -248,7 +260,7 @@ fn test_bad_constraints() { witness[i + 3][1] += PallasField::one(); // Bound constraint fails assert_eq!( - cs.gates[1].verify_witness::( + cs.gates[1].verify_witness::( 1, &witness, &cs, @@ -264,11 +276,21 @@ fn test_bad_constraints() { witness[2][1] += PallasField::one(); witness[0][3] += PallasField::one(); assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::( + 1, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::Rot64, 9)) ); assert_eq!( - cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[3].verify_witness::( + 3, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); witness[2][1] -= PallasField::one(); @@ -277,11 +299,21 @@ fn test_bad_constraints() { // modify shifted witness[0][2] += PallasField::one(); assert_eq!( - cs.gates[1].verify_witness::(1, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[1].verify_witness::( + 1, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::Rot64, 9)) ); assert_eq!( - cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[2].verify_witness::( + 2, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); witness[0][2] -= PallasField::one(); @@ -289,14 +321,24 @@ fn test_bad_constraints() { // modify value of shifted to be more than 64 bits witness[0][2] += PallasField::two_pow(64); assert_eq!( - cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[2].verify_witness::( + 2, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); // Update decomposition witness[2][2] += PallasField::one(); // Make sure the 64-bit check fails assert_eq!( - cs.gates[2].verify_witness::(2, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[2].verify_witness::( + 2, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::CopyConstraint { typ: GateType::RangeCheck0, src: Wire { row: 2, col: 2 }, @@ -310,14 +352,24 @@ fn test_bad_constraints() { witness[0][3] += PallasField::two_pow(64); witness[2][1] += PallasField::two_pow(64); assert_eq!( - cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[3].verify_witness::( + 3, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::RangeCheck0, 9)) ); // Update decomposition witness[2][3] += PallasField::one(); // Make sure the 64-bit check fails assert_eq!( - cs.gates[3].verify_witness::(3, &witness, &cs, &witness[0][0..cs.public]), + cs.gates[3].verify_witness::( + 3, + &witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::CopyConstraint { typ: GateType::RangeCheck0, src: Wire { row: 3, col: 2 }, @@ -356,7 +408,7 @@ fn test_rot_finalization() { // witness let witness = { // create one row for the public word - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); 2]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); 2]); // initialize the public input containing the word to be rotated let input = 0xDC811727DAF22EC1u64; @@ -370,7 +422,7 @@ fn test_rot_finalization() { let cs = ConstraintSystem::create(gates.clone()) .public(num_public_inputs) .lookup(vec![rot::lookup_table()]) - .build::() + .build::() .unwrap(); let mut srs = SRS::::create(cs.domain.d1.size()); srs.add_lagrange_basis(cs.domain.d1); @@ -382,7 +434,7 @@ fn test_rot_finalization() { for row in 0..witness[0].len() { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, diff --git a/kimchi/src/tests/serde.rs b/kimchi/src/tests/serde.rs index 1a1735a406..50ecebb72a 100644 --- a/kimchi/src/tests/serde.rs +++ b/kimchi/src/tests/serde.rs @@ -2,7 +2,7 @@ use crate::{ bench::BenchmarkCtx, circuits::{ polynomials::generic::testing::{create_circuit, fill_in_witness}, - wires::COLUMNS, + wires::KIMCHI_COLS, }, proof::ProverProof, prover_index::testing::new_index_for_test, @@ -51,10 +51,10 @@ mod tests { #[test] pub fn test_serialization() { let public = vec![Fp::from(3u8); 5]; - let gates = create_circuit::(0, public.len()); + let gates = create_circuit::(0, public.len()); // create witness - let mut witness: [Vec; COLUMNS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![Fp::zero(); gates.len()]); fill_in_witness(0, &mut witness, &public); let index = new_index_for_test(gates, public.len()); @@ -85,7 +85,7 @@ mod tests { // verify the proof let start = Instant::now(); - verify::, COLUMNS>( + verify::, KIMCHI_COLS>( &group_map, &verifier_index_deserialize, &proof, diff --git a/kimchi/src/tests/turshi.rs b/kimchi/src/tests/turshi.rs index 25b1d311b1..aed7e850c1 100644 --- a/kimchi/src/tests/turshi.rs +++ b/kimchi/src/tests/turshi.rs @@ -1,6 +1,6 @@ use crate::circuits::{ gate::CircuitGate, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::turshi::{testing::*, witness::*}, }; use mina_curves::pasta::Fp as F; @@ -22,7 +22,7 @@ fn test_cairo_should_fail() { let inirow = 0; let (circuit, _) = CircuitGate::::create_cairo_gadget(inirow, ninstr); - let mut witness = cairo_witness::(&prog); + let mut witness = cairo_witness::(&prog); // break a witness witness[0][0] += F::from(1u32); let res_ensure = ensure_cairo_gate(&circuit[0], 0, &witness); @@ -68,7 +68,7 @@ fn test_cairo_gate() { mem.write(F::from(23u32), F::from(44u32)); //end of program let prog = CairoProgram::new(&mut mem, 5); - let witness = cairo_witness::(&prog); + let witness = cairo_witness::(&prog); // Create the Cairo circuit let ninstr = prog.trace().len(); diff --git a/kimchi/src/tests/varbasemul.rs b/kimchi/src/tests/varbasemul.rs index 91eed12b78..160f374766 100644 --- a/kimchi/src/tests/varbasemul.rs +++ b/kimchi/src/tests/varbasemul.rs @@ -46,7 +46,7 @@ fn varbase_mul_test() { )); } - let mut witness: [Vec; COLUMNS] = + let mut witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![F::zero(); rows_per_scalar * num_scalars]); let rng = &mut StdRng::from_seed([0; 32]); diff --git a/kimchi/src/tests/xor.rs b/kimchi/src/tests/xor.rs index f520a56cab..994f92e22c 100644 --- a/kimchi/src/tests/xor.rs +++ b/kimchi/src/tests/xor.rs @@ -4,7 +4,7 @@ use crate::{ circuits::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateError, Connect, GateType}, - polynomial::COLUMNS, + polynomial::KIMCHI_COLS, polynomials::{generic::GenericGateSpec, xor}, wires::Wire, }, @@ -53,7 +53,9 @@ where let mut gates = vec![]; let _next_row = CircuitGate::::extend_xor_gadget(&mut gates, bits); - ConstraintSystem::create(gates).build::().unwrap() + ConstraintSystem::create(gates) + .build::() + .unwrap() } // Returns the all ones BigUint of bits length @@ -68,7 +70,7 @@ pub(crate) fn xor_nybble(word: BigUint, nybble: usize) -> BigUint { // Manually checks the XOR of each nybble in the witness pub(crate) fn check_xor( - witness: &[Vec; COLUMNS], + witness: &[Vec; KIMCHI_COLS], bits: usize, input1: G::ScalarField, input2: G::ScalarField, @@ -105,7 +107,7 @@ fn setup_xor( bits: Option, ) -> ( ConstraintSystem, - [Vec; COLUMNS], + [Vec; KIMCHI_COLS], ) where G::BaseField: PrimeField, @@ -136,14 +138,14 @@ fn test_xor( in1: Option, in2: Option, bits: Option, -) -> [Vec; COLUMNS] +) -> [Vec; KIMCHI_COLS] where G::BaseField: PrimeField, { let (cs, witness) = setup_xor::(in1, in2, bits); for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -246,26 +248,31 @@ fn test_xor128_random() { } fn verify_bad_xor_decomposition( - witness: &mut [Vec; COLUMNS], + witness: &mut [Vec; KIMCHI_COLS], cs: ConstraintSystem, ) where G::BaseField: PrimeField, { // modify by one each of the witness cells individually - for col in 0..COLUMNS { + for col in 0..KIMCHI_COLS { // first three columns make fail the ith+1 constraint // for the rest, the first 4 make the 1st fail, the following 4 make the 2nd fail, the last 4 make the 3rd fail let bad = if col < 3 { col + 1 } else { (col - 3) / 4 + 1 }; witness[col][0] += G::ScalarField::one(); assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::( + 0, + witness, + &cs, + &witness[0][0..cs.public] + ), Err(CircuitGateError::Constraint(GateType::Xor16, bad)) ); witness[col][0] -= G::ScalarField::one(); } // undo changes assert_eq!( - cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), + cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), Ok(()) ); } @@ -307,17 +314,17 @@ fn test_extend_xor() { let cs = ConstraintSystem::create(gates) .public(2) - .build::() + .build::() .unwrap(); - let mut witness: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); 2]); + let mut witness: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); 2]); witness[0][0] = input1; witness[0][1] = input2; - xor::extend_xor_witness::(&mut witness, input1, input2, bits); + xor::extend_xor_witness::(&mut witness, input1, input2, bits); for row in 0..witness[0].len() { assert_eq!( - cs.gates[row].verify_witness::( + cs.gates[row].verify_witness::( row, &witness, &cs, @@ -350,7 +357,7 @@ fn test_bad_xor() { // modify the output to be all zero witness[2][0] = PallasField::zero(); for i in 1..=4 { - witness[COLUMNS - i][0] = PallasField::zero(); + witness[KIMCHI_COLS - i][0] = PallasField::zero(); } assert_eq!( @@ -391,7 +398,7 @@ fn test_xor_finalization() { // witness let witness = { - let mut cols: [_; COLUMNS] = array::from_fn(|_col| vec![Fp::zero(); num_inputs]); + let mut cols: [_; KIMCHI_COLS] = array::from_fn(|_col| vec![Fp::zero(); num_inputs]); // initialize the 2 inputs let input1 = 0xDC811727DAF22EC15927D6AA275F406Bu128.into(); @@ -407,7 +414,7 @@ fn test_xor_finalization() { let cs = ConstraintSystem::create(gates.clone()) .lookup(vec![xor::lookup_table()]) .public(num_inputs) - .build::() + .build::() .unwrap(); let mut srs = SRS::::create(cs.domain.d1.size()); srs.add_lagrange_basis(cs.domain.d1); @@ -419,7 +426,7 @@ fn test_xor_finalization() { for row in 0..witness[0].len() { assert_eq!( - index.cs.gates[row].verify_witness::( + index.cs.gates[row].verify_witness::( row, &witness, &index.cs, diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 8e5837f0b2..d2c5d8d2e1 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -10,7 +10,7 @@ use crate::{ lookup::{lookups::LookupPattern, tables::combine_table}, polynomials::permutation, scalars::RandomOracles, - wires::{COLUMNS, PERMUTS}, + wires::{KIMCHI_COLS, PERMUTS}, }, curve::KimchiCurve, error::VerifyError, @@ -35,19 +35,24 @@ use rand::thread_rng; /// The result of a proof verification. pub type Result = std::result::Result; -pub struct Context<'a, G: KimchiCurve, OpeningProof: OpenProof, const W: usize = COLUMNS> { +pub struct Context< + 'a, + G: KimchiCurve, + OpeningProof: OpenProof, + const COLUMNS: usize = KIMCHI_COLS, +> { /// The [VerifierIndex] associated to the proof - pub verifier_index: &'a VerifierIndex, + pub verifier_index: &'a VerifierIndex, /// The proof to verify - pub proof: &'a ProverProof, + pub proof: &'a ProverProof, /// The public input used in the creation of the proof pub public_input: &'a [G::ScalarField], } -impl<'a, G: KimchiCurve, OpeningProof: OpenProof, const W: usize> - Context<'a, G, OpeningProof, W> +impl<'a, G: KimchiCurve, OpeningProof: OpenProof, const COLUMNS: usize> + Context<'a, G, OpeningProof, COLUMNS> { pub fn get_column(&self, col: Column) -> Option<&'a PolyComm> { use Column::*; @@ -94,7 +99,8 @@ impl<'a, G: KimchiCurve, OpeningProof: OpenProof, const W: usize> } } -impl, const W: usize> ProverProof +impl, const COLUMNS: usize> + ProverProof where G::BaseField: PrimeField, { @@ -109,10 +115,10 @@ where /// Will panic if `PolishToken` evaluation is invalid. pub fn oracles< EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, >( &self, - index: &VerifierIndex, + index: &VerifierIndex, public_comm: &PolyComm, public_input: Option<&[G::ScalarField]>, ) -> Result> { @@ -470,8 +476,8 @@ where Column::Index(GateType::EndoMulScalar), ] .into_iter() - .chain((0..W).map(Column::Witness)) - .chain((0..W).map(Column::Coefficient)) + .chain((0..COLUMNS).map(Column::Witness)) + .chain((0..COLUMNS).map(Column::Coefficient)) .chain((0..PERMUTS - 1).map(Column::Permutation)) .chain( index @@ -601,8 +607,8 @@ where /// Enforce the length of evaluations inside [`Proof`]. /// Atm, the length of evaluations(both `zeta` and `zeta_omega`) SHOULD be 1. /// The length value is prone to future change. -fn check_proof_evals_len( - proof: &ProverProof, +fn check_proof_evals_len( + proof: &ProverProof, expected_size: usize, ) -> Result<()> where @@ -741,16 +747,16 @@ where Ok(()) } -fn to_batch<'a, G, EFqSponge, EFrSponge, OpeningProof: OpenProof, const W: usize>( - verifier_index: &VerifierIndex, - proof: &'a ProverProof, +fn to_batch<'a, G, EFqSponge, EFrSponge, OpeningProof: OpenProof, const COLUMNS: usize>( + verifier_index: &VerifierIndex, + proof: &'a ProverProof, public_input: &'a [::ScalarField], ) -> Result> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { //~ //~ #### Partial verification @@ -950,9 +956,9 @@ where ] .into_iter() //~~ * witness commitments - .chain((0..W).map(Column::Witness)) + .chain((0..COLUMNS).map(Column::Witness)) //~~ * coefficient commitments - .chain((0..W).map(Column::Coefficient)) + .chain((0..COLUMNS).map(Column::Coefficient)) //~~ * sigma commitments .chain((0..PERMUTS - 1).map(Column::Permutation)) //~~ * optional gate commitments @@ -1150,24 +1156,24 @@ where /// # Errors /// /// Will give error if `proof(s)` are not verified as valid. -pub fn verify, const W: usize>( +pub fn verify, const COLUMNS: usize>( group_map: &G::Map, - verifier_index: &VerifierIndex, - proof: &ProverProof, + verifier_index: &VerifierIndex, + proof: &ProverProof, public_input: &[G::ScalarField], ) -> Result<()> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let proofs = vec![Context { verifier_index, proof, public_input, }]; - batch_verify::(group_map, &proofs) + batch_verify::(group_map, &proofs) } /// This function verifies the batch of zk-proofs @@ -1177,15 +1183,15 @@ where /// # Errors /// /// Will give error if `srs` of `proof` is invalid or `verify` process fails. -pub fn batch_verify, const W: usize>( +pub fn batch_verify, const COLUMNS: usize>( group_map: &G::Map, - proofs: &[Context], + proofs: &[Context], ) -> Result<()> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { //~ #### Batch verification of proofs //~ @@ -1216,7 +1222,7 @@ where public_input, } in proofs { - batch.push(to_batch::( + batch.push(to_batch::( verifier_index, proof, public_input, diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 9ddd318c2a..2cf0c2fb7a 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -8,7 +8,7 @@ use crate::{ expr::{Linearization, PolishToken}, lookup::{index::LookupSelectors, lookups::LookupInfo}, polynomials::permutation::{vanishes_on_last_n_rows, zk_w}, - wires::{COLUMNS, PERMUTS}, + wires::{KIMCHI_COLS, PERMUTS}, }, curve::KimchiCurve, prover_index::ProverIndex, @@ -56,7 +56,11 @@ pub struct LookupVerifierIndex { #[serde_as] #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VerifierIndex, const W: usize = COLUMNS> { +pub struct VerifierIndex< + G: KimchiCurve, + OpeningProof: OpenProof, + const COLUMNS: usize = KIMCHI_COLS, +> { /// evaluation domain #[serde_as(as = "o1_utils::serialization::SerdeAs")] pub domain: D, @@ -78,8 +82,8 @@ pub struct VerifierIndex, const W: us #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub sigma_comm: [PolyComm; PERMUTS], /// coefficient commitment array - #[serde_as(as = "[_; W]")] - pub coefficients_comm: [PolyComm; W], + #[serde_as(as = "[_; COLUMNS]")] + pub coefficients_comm: [PolyComm; COLUMNS], /// coefficient commitment array #[serde(bound = "PolyComm: Serialize + DeserializeOwned")] pub generic_comm: PolyComm, @@ -152,7 +156,8 @@ pub struct VerifierIndex, const W: us } //~spec:endcode -impl, const W: usize> ProverIndex +impl, const COLUMNS: usize> + ProverIndex where G::BaseField: PrimeField, { @@ -161,9 +166,9 @@ where /// # Panics /// /// Will panic if `srs` cannot be in `cell`. - pub fn verifier_index(&self) -> VerifierIndex + pub fn verifier_index(&self) -> VerifierIndex where - VerifierIndex: Clone, + VerifierIndex: Clone, { if let Some(verifier_index) = &self.verifier_index { return verifier_index.clone(); @@ -315,7 +320,9 @@ where } } -impl, const W: usize> VerifierIndex { +impl, const COLUMNS: usize> + VerifierIndex +{ /// Gets srs from [`VerifierIndex`] lazily pub fn srs(&self) -> &Arc where diff --git a/tools/kimchi-visu/src/lib.rs b/tools/kimchi-visu/src/lib.rs index ece3ffad0d..541a51a106 100644 --- a/tools/kimchi-visu/src/lib.rs +++ b/tools/kimchi-visu/src/lib.rs @@ -75,8 +75,8 @@ where /// # Panics /// /// Will panic if `TinyTemplate::render()` returns `Error` or `std::fs::File::create()` returns `Error`. -pub fn visu( - index: &ProverIndex, W>, +pub fn visu( + index: &ProverIndex, COLUMNS>, witness: Option>, ) where G::BaseField: PrimeField, diff --git a/tools/kimchi-visu/src/main.rs b/tools/kimchi-visu/src/main.rs index b8c1636f09..ce81d5add7 100644 --- a/tools/kimchi-visu/src/main.rs +++ b/tools/kimchi-visu/src/main.rs @@ -2,7 +2,7 @@ use kimchi::{ circuits::{ gate::CircuitGate, polynomials::{generic::GenericGateSpec, poseidon::generate_witness}, - wires::{Wire, COLUMNS}, + wires::{Wire, KIMCHI_COLS}, }, curve::KimchiCurve, prover_index::testing::new_index_for_test, @@ -59,7 +59,7 @@ fn main() { }; // create the index - let index = new_index_for_test::(gates, public); + let index = new_index_for_test::(gates, public); // create the witness let mut witness = Witness::new(row + 1).inner(); diff --git a/tools/kimchi-visu/src/witness.rs b/tools/kimchi-visu/src/witness.rs index 404af0375c..5ef0c02b6d 100644 --- a/tools/kimchi-visu/src/witness.rs +++ b/tools/kimchi-visu/src/witness.rs @@ -1,11 +1,11 @@ use ark_ff::Field; -use kimchi::circuits::polynomial::COLUMNS; +use kimchi::circuits::polynomial::KIMCHI_COLS; use serde::Serialize; use serde_with::serde_as; use std::array; /// The type that represents the execution trace. -/// It represents a table of [COLUMNS] columns, with `n` rows. +/// It represents a table of [KIMCHI_COLS] columns, with `n` rows. /// `n` being the maximum size of the circuit, and the size of the domain. #[serde_as] #[derive(Debug, Serialize)] @@ -13,8 +13,8 @@ pub struct Witness where F: Field, { - #[serde_as(as = "[Vec; COLUMNS]")] - inner: [Vec; COLUMNS], + #[serde_as(as = "[Vec; KIMCHI_COLS]")] + inner: [Vec; KIMCHI_COLS], } impl Witness @@ -31,16 +31,16 @@ where /// Returns the inner witness. // TODO: deprecate this - pub fn inner(self) -> [Vec; COLUMNS] { + pub fn inner(self) -> [Vec; KIMCHI_COLS] { self.inner } } -impl From<[Vec; COLUMNS]> for Witness +impl From<[Vec; KIMCHI_COLS]> for Witness where F: Field, { - fn from(inner: [Vec; COLUMNS]) -> Self { + fn from(inner: [Vec; KIMCHI_COLS]) -> Self { Witness { inner } } } From a7793dab99d84b29fc9a96ea6441cc548d2e9d08 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 30 Oct 2023 19:29:24 +0100 Subject: [PATCH 209/242] make w and coefficients back into arrays --- book/src/specs/kimchi.md | 6 ++++-- kimchi/src/proof.rs | 18 ++++++++++-------- kimchi/src/prover.rs | 27 +++++++++++---------------- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index d80a376832..8bd7d3cbba 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1975,14 +1975,16 @@ pub struct ProofEvaluations { /// public input polynomials pub public: Option, /// witness polynomials - pub w: Vec, + #[serde_as(as = "[_; COLUMNS]")] + pub w: [Evals; COLUMNS], /// permutation polynomial pub z: Evals, /// permutation polynomials /// (PERMUTS-1 evaluations because the last permutation is only used in commitment form) pub s: [Evals; PERMUTS - 1], /// coefficient polynomials - pub coefficients: Vec, + #[serde_as(as = "[_; COLUMNS]")] + pub coefficients: [Evals; COLUMNS], /// evaluation of the generic selector polynomial pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index cdd8d6f223..daa9e28b15 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -46,14 +46,16 @@ pub struct ProofEvaluations { /// public input polynomials pub public: Option, /// witness polynomials - pub w: Vec, + #[serde_as(as = "[_; COLUMNS]")] + pub w: [Evals; COLUMNS], /// permutation polynomial pub z: Evals, /// permutation polynomials /// (PERMUTS-1 evaluations because the last permutation is only used in commitment form) pub s: [Evals; PERMUTS - 1], /// coefficient polynomials - pub coefficients: Vec, + #[serde_as(as = "[_; COLUMNS]")] + pub coefficients: [Evals; COLUMNS], /// evaluation of the generic selector polynomial pub generic_selector: Evals, /// evaluation of the poseidon selector polynomial @@ -225,10 +227,10 @@ impl ProofEvaluations { } = self; ProofEvaluations { public: public.map(f), - w: w.into_iter().map(f).collect(), + w: w.map(f), z: f(z), s: s.map(f), - coefficients: coefficients.into_iter().map(f).collect(), + coefficients: coefficients.map(f), generic_selector: f(generic_selector), poseidon_selector: f(poseidon_selector), complete_add_selector: f(complete_add_selector), @@ -287,10 +289,10 @@ impl ProofEvaluations { } = self; ProofEvaluations { public: public.as_ref().map(f), - w: w.iter().map(f).collect(), + w: array::from_fn(|i: usize| f(&w[i])), z: f(z), s: [f(s0), f(s1), f(s2), f(s3), f(s4), f(s5)], - coefficients: coefficients.iter().map(f).collect(), + coefficients: array::from_fn(|i: usize| f(&coefficients[i])), generic_selector: f(generic_selector), poseidon_selector: f(poseidon_selector), complete_add_selector: f(complete_add_selector), @@ -374,10 +376,10 @@ impl ProofEvaluations, }; ProofEvaluations { public: Some(pt(F::zero(), F::zero())), - w: curr.iter().zip(next).map(|(c, n)| pt(*c, n)).collect(), + w: array::from_fn(|i| pt(curr[i], next[i])), z: pt(F::zero(), F::zero()), s: array::from_fn(|_| pt(F::zero(), F::zero())), - coefficients: vec![pt(F::zero(), F::zero()); COLUMNS], + coefficients: [pt(F::zero(), F::zero()); COLUMNS], generic_selector: pt(F::zero(), F::zero()), poseidon_selector: pt(F::zero(), F::zero()), complete_add_selector: pt(F::zero(), F::zero()), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index aee0c8857a..cea6b10a4d 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -985,22 +985,17 @@ where &index.column_evaluations.permutation_coefficients8[i], ) }), - coefficients: index - .column_evaluations - .coefficients8 - .iter() - .map(|c| chunked_evals_for_evaluations(c)) - .collect(), - w: witness_poly - .iter() - .map(|w| { - let chunked = w.to_chunked_polynomial(num_chunks, index.max_poly_size); - PointEvaluations { - zeta: chunked.evaluate_chunks(zeta), - zeta_omega: chunked.evaluate_chunks(zeta_omega), - } - }) - .collect(), + coefficients: array::from_fn(|i| { + chunked_evals_for_evaluations(&index.column_evaluations.coefficients8[i]) + }), + w: array::from_fn(|i| { + let chunked = + witness_poly[i].to_chunked_polynomial(num_chunks, index.max_poly_size); + PointEvaluations { + zeta: chunked.evaluate_chunks(zeta), + zeta_omega: chunked.evaluate_chunks(zeta_omega), + } + }), z: { let chunked = z_poly.to_chunked_polynomial(num_chunks, index.max_poly_size); From e9929565fec8655d899b4521e91a2b4ac5a95ce2 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 30 Oct 2023 19:34:31 +0100 Subject: [PATCH 210/242] fix ocaml_types --- kimchi/src/oracles.rs | 6 +++--- kimchi/src/proof.rs | 10 +++++----- kimchi/src/prover.rs | 16 ++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/kimchi/src/oracles.rs b/kimchi/src/oracles.rs index 9cdb5863fa..52a2f5e081 100644 --- a/kimchi/src/oracles.rs +++ b/kimchi/src/oracles.rs @@ -58,15 +58,15 @@ pub mod caml { pub fn create_caml_oracles( lgr_comm: Vec>, - index: VerifierIndex>, - proof: ProverProof>, + index: VerifierIndex, KIMCHI_COLS>, + proof: ProverProof, KIMCHI_COLS>, public_input: &[G::ScalarField], ) -> Result, VerifyError> where G: KimchiCurve, G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, CamlF: From, { let lgr_comm: Vec> = lgr_comm.into_iter().take(public_input.len()).collect(); diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index daa9e28b15..c5616fe83b 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -587,7 +587,7 @@ pub mod caml { // ProofEvaluations> <-> CamlProofEvaluations // - impl From>>> + impl From>, KIMCHI_COLS>> for ( Option>>, CamlProofEvaluations, @@ -596,7 +596,7 @@ pub mod caml { F: Clone, CamlF: From, { - fn from(pe: ProofEvaluations>>) -> Self { + fn from(pe: ProofEvaluations>, KIMCHI_COLS>) -> Self { let w = ( pe.w[0] .clone() @@ -798,7 +798,7 @@ pub mod caml { From<( Option>>, CamlProofEvaluations, - )> for ProofEvaluations>> + )> for ProofEvaluations>, KIMCHI_COLS> where F: Clone, CamlF: Clone, @@ -810,7 +810,7 @@ pub mod caml { CamlProofEvaluations, ), ) -> Self { - let w = vec![ + let w = [ cpe.w.0.map(&|x| x.into_iter().map(Into::into).collect()), cpe.w.1.map(&|x| x.into_iter().map(Into::into).collect()), cpe.w.2.map(&|x| x.into_iter().map(Into::into).collect()), @@ -827,7 +827,7 @@ pub mod caml { cpe.w.13.map(&|x| x.into_iter().map(Into::into).collect()), cpe.w.14.map(&|x| x.into_iter().map(Into::into).collect()), ]; - let coefficients = vec![ + let coefficients = [ cpe.coefficients .0 .map(&|x| x.into_iter().map(Into::into).collect()), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index cea6b10a4d..2bbe9e4173 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1647,12 +1647,12 @@ pub mod caml { // CamlProverCommitments <-> ProverCommitments // - impl From> for CamlProverCommitments + impl From> for CamlProverCommitments where G: AffineCurve, CamlPolyComm: From>, { - fn from(prover_comm: ProverCommitments) -> Self { + fn from(prover_comm: ProverCommitments) -> Self { Self { w_comm: ( prover_comm.w_comm[0].clone().into(), @@ -1678,14 +1678,14 @@ pub mod caml { } } - impl From> for ProverCommitments + impl From> for ProverCommitments where G: AffineCurve, PolyComm: From>, { fn from( caml_prover_comm: CamlProverCommitments, - ) -> ProverCommitments { + ) -> ProverCommitments { let ( w_comm0, w_comm1, @@ -1734,7 +1734,7 @@ pub mod caml { impl From<( - ProverProof>, + ProverProof, KIMCHI_COLS>, Vec, )> for CamlProofWithPublic where @@ -1744,7 +1744,7 @@ pub mod caml { { fn from( pp: ( - ProverProof>, + ProverProof, KIMCHI_COLS>, Vec, ), ) -> Self { @@ -1765,7 +1765,7 @@ pub mod caml { impl From> for ( - ProverProof>, + ProverProof, KIMCHI_COLS>, Vec, ) where @@ -1776,7 +1776,7 @@ pub mod caml { fn from( caml_pp: CamlProofWithPublic, ) -> ( - ProverProof>, + ProverProof, KIMCHI_COLS>, Vec, ) { let CamlProofWithPublic { From 0276c756bb3f58cfc667daa9d31efe66ab96af0e Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 30 Oct 2023 20:37:10 +0100 Subject: [PATCH 211/242] adapt order of generics in witness layout --- kimchi/src/circuits/polynomials/keccak/witness.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kimchi/src/circuits/polynomials/keccak/witness.rs b/kimchi/src/circuits/polynomials/keccak/witness.rs index d6aa7971e2..bd0df8463c 100644 --- a/kimchi/src/circuits/polynomials/keccak/witness.rs +++ b/kimchi/src/circuits/polynomials/keccak/witness.rs @@ -5,9 +5,9 @@ use ark_ff::PrimeField; use super::KECCAK_COLS; -type _Layout = Vec>>>; +type _Layout = Vec, COLUMNS>>>; -fn _layout_round() -> _Layout { +fn _layout_round() -> _Layout { vec![ IndexCell::create("state_a", 0, 100), IndexCell::create("state_c", 100, 120), @@ -34,7 +34,7 @@ fn _layout_round() -> _Layout { ] } -fn _layout_sponge() -> _Layout { +fn _layout_sponge() -> _Layout { vec![ IndexCell::create("old_state", 0, 100), IndexCell::create("new_state", 100, 200), From 8f89ae2f532d077a93aca8f66609064314b6dab4 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 31 Oct 2023 16:46:46 +0100 Subject: [PATCH 212/242] remove COLUMNS parameter to set default value --- kimchi/src/bench.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/kimchi/src/bench.rs b/kimchi/src/bench.rs index 57cd64ff80..97cb026a2e 100644 --- a/kimchi/src/bench.rs +++ b/kimchi/src/bench.rs @@ -77,12 +77,7 @@ impl BenchmarkCtx { } /// Produces a proof - pub fn create_proof( - &self, - ) -> ( - ProverProof, KIMCHI_COLS>, - Vec, - ) { + pub fn create_proof(&self) -> (ProverProof>, Vec) { // create witness let witness: [Vec; KIMCHI_COLS] = array::from_fn(|_| vec![1u32.into(); self.num_gates]); @@ -102,13 +97,7 @@ impl BenchmarkCtx { } #[allow(clippy::type_complexity)] - pub fn batch_verification( - &self, - batch: &[( - ProverProof, KIMCHI_COLS>, - Vec, - )], - ) { + pub fn batch_verification(&self, batch: &[(ProverProof>, Vec)]) { // verify the proof let batch: Vec<_> = batch .iter() From bb0a7f0becbba32cce617658933f11ad1b97149e Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 10:50:13 +0100 Subject: [PATCH 213/242] changes to make ArgumentWitness generic over COLUMNS so curr and next can be arrays again instead of vectors --- kimchi/src/circuits/argument.rs | 30 ++++++++------ kimchi/src/circuits/expr.rs | 39 ++++++++++++++----- kimchi/src/circuits/gate.rs | 15 ++++--- .../src/circuits/polynomials/complete_add.rs | 5 ++- .../circuits/polynomials/endomul_scalar.rs | 5 ++- kimchi/src/circuits/polynomials/endosclmul.rs | 5 ++- .../foreign_field_add/circuitgates.rs | 5 ++- .../foreign_field_mul/circuitgates.rs | 5 ++- kimchi/src/circuits/polynomials/generic.rs | 5 ++- kimchi/src/circuits/polynomials/poseidon.rs | 5 ++- .../polynomials/range_check/circuitgates.rs | 10 ++++- kimchi/src/circuits/polynomials/rot.rs | 5 ++- kimchi/src/circuits/polynomials/turshi.rs | 20 ++++++++-- kimchi/src/circuits/polynomials/varbasemul.rs | 21 +++++++--- kimchi/src/circuits/polynomials/xor.rs | 5 ++- 15 files changed, 133 insertions(+), 47 deletions(-) diff --git a/kimchi/src/circuits/argument.rs b/kimchi/src/circuits/argument.rs index 7667d9eab8..16f04e41f6 100644 --- a/kimchi/src/circuits/argument.rs +++ b/kimchi/src/circuits/argument.rs @@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize}; use super::{ expr::{constraints::ExprOps, Cache, ConstantExpr, Constants}, gate::{CurrOrNext, GateType}, + wires::KIMCHI_COLS, }; use CurrOrNext::{Curr, Next}; @@ -36,8 +37,8 @@ pub enum ArgumentType { /// created with ArgumentData and F = Field or F = PrimeField, then the constraints /// are built as expressions of real field elements and can be evaluated directly on /// the witness without using the prover. -pub struct ArgumentEnv { - data: Option>, +pub struct ArgumentEnv { + data: Option>, phantom_data: PhantomData, } @@ -51,10 +52,14 @@ impl Default for ArgumentEnv { } } -impl> ArgumentEnv { +impl, const COLUMNS: usize> ArgumentEnv { /// Initialize the environment for creating constraints of real field elements that can be /// evaluated directly over the witness without the prover/verifier - pub fn create(witness: ArgumentWitness, coeffs: Vec, constants: Constants) -> Self { + pub fn create( + witness: ArgumentWitness, + coeffs: Vec, + constants: Constants, + ) -> Self { ArgumentEnv { data: Some(ArgumentData { witness, @@ -102,9 +107,9 @@ impl> ArgumentEnv { } /// Argument environment data for constraints of field elements -pub struct ArgumentData { +pub struct ArgumentData { /// Witness rows - pub witness: ArgumentWitness, + pub witness: ArgumentWitness, /// Gate coefficients pub coeffs: Vec, /// Constants @@ -112,14 +117,14 @@ pub struct ArgumentData { } /// Witness data for a argument -pub struct ArgumentWitness { +pub struct ArgumentWitness { /// Witness for current row - pub curr: Vec, + pub curr: [T; COLUMNS], /// Witness for next row - pub next: Vec, + pub next: [T; COLUMNS], } -impl std::ops::Index<(CurrOrNext, usize)> for ArgumentWitness { +impl std::ops::Index<(CurrOrNext, usize)> for ArgumentWitness { type Output = T; fn index(&self, idx: (CurrOrNext, usize)) -> &T { @@ -141,7 +146,10 @@ pub trait Argument { const CONSTRAINTS: u32; /// Constraints for this argument - fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec; + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + cache: &mut Cache, + ) -> Vec; /// Returns the set of constraints required to prove this argument. fn constraints(cache: &mut Cache) -> Vec> { diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 393a69f728..3f153895ea 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -2660,13 +2660,20 @@ pub mod constraints { fn literal(x: F) -> Self; // Witness variable - fn witness(row: CurrOrNext, col: usize, env: Option<&ArgumentData>) -> Self; + fn witness( + row: CurrOrNext, + col: usize, + env: Option<&ArgumentData>, + ) -> Self; /// Coefficient - fn coeff(col: usize, env: Option<&ArgumentData>) -> Self; + fn coeff(col: usize, env: Option<&ArgumentData>) -> Self; /// Create a constant - fn constant(expr: ConstantExpr, env: Option<&ArgumentData>) -> Self; + fn constant( + expr: ConstantExpr, + env: Option<&ArgumentData>, + ) -> Self; /// Cache item fn cache(&self, cache: &mut Cache) -> Self; @@ -2726,15 +2733,22 @@ pub mod constraints { Expr::Constant(ConstantExpr::Literal(x)) } - fn witness(row: CurrOrNext, col: usize, _: Option<&ArgumentData>) -> Self { + fn witness( + row: CurrOrNext, + col: usize, + _: Option<&ArgumentData>, + ) -> Self { witness(col, row) } - fn coeff(col: usize, _: Option<&ArgumentData>) -> Self { + fn coeff(col: usize, _: Option<&ArgumentData>) -> Self { coeff(col) } - fn constant(expr: ConstantExpr, _: Option<&ArgumentData>) -> Self { + fn constant( + expr: ConstantExpr, + _: Option<&ArgumentData>, + ) -> Self { Expr::Constant(expr) } @@ -2784,21 +2798,28 @@ pub mod constraints { x } - fn witness(row: CurrOrNext, col: usize, env: Option<&ArgumentData>) -> Self { + fn witness( + row: CurrOrNext, + col: usize, + env: Option<&ArgumentData>, + ) -> Self { match env { Some(data) => data.witness[(row, col)], None => panic!("Missing witness"), } } - fn coeff(col: usize, env: Option<&ArgumentData>) -> Self { + fn coeff(col: usize, env: Option<&ArgumentData>) -> Self { match env { Some(data) => data.coeffs[col], None => panic!("Missing coefficients"), } } - fn constant(expr: ConstantExpr, env: Option<&ArgumentData>) -> Self { + fn constant( + expr: ConstantExpr, + env: Option<&ArgumentData>, + ) -> Self { match env { Some(data) => expr.value(&data.constants), None => panic!("Missing constants"), diff --git a/kimchi/src/circuits/gate.rs b/kimchi/src/circuits/gate.rs index 4738b966c0..c92342a0a5 100644 --- a/kimchi/src/circuits/gate.rs +++ b/kimchi/src/circuits/gate.rs @@ -260,7 +260,8 @@ impl CircuitGate { zk_rows: cs.zk_rows, }; // Create the argument environment for the constraints over field elements - let env = ArgumentEnv::::create(argument_witness, self.coeffs.clone(), constants); + let env = + ArgumentEnv::::create(argument_witness, self.coeffs.clone(), constants); // Check the wiring (i.e. copy constraints) for this gate // Note: Gates can operated on row Curr or Curr and Next. @@ -295,7 +296,9 @@ impl CircuitGate { // TODO: implement the verification for the generic gate vec![] } - GateType::Poseidon => poseidon::Poseidon::constraint_checks(&env, &mut cache), + GateType::Poseidon => { + poseidon::Poseidon::constraint_checks::(&env, &mut cache) + } GateType::CompleteAdd => complete_add::CompleteAdd::constraint_checks(&env, &mut cache), GateType::VarBaseMul => varbasemul::VarbaseMul::constraint_checks(&env, &mut cache), GateType::EndoMul => endosclmul::EndosclMul::constraint_checks(&env, &mut cache), @@ -348,7 +351,7 @@ impl CircuitGate { &self, row: usize, witness: &[Vec; COLUMNS], - ) -> CircuitGateResult> { + ) -> CircuitGateResult> { // Get the part of the witness relevant to this gate let witness_curr: [F; COLUMNS] = (0..witness.len()) .map(|col| witness[col][row]) @@ -365,9 +368,9 @@ impl CircuitGate { [F::zero(); COLUMNS] }; - Ok(ArgumentWitness:: { - curr: witness_curr.to_vec(), - next: witness_next.to_vec(), + Ok(ArgumentWitness:: { + curr: witness_curr, + next: witness_next, }) } } diff --git a/kimchi/src/circuits/polynomials/complete_add.rs b/kimchi/src/circuits/polynomials/complete_add.rs index 578af66046..3b39b9d711 100644 --- a/kimchi/src/circuits/polynomials/complete_add.rs +++ b/kimchi/src/circuits/polynomials/complete_add.rs @@ -97,7 +97,10 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::CompleteAdd); const CONSTRAINTS: u32 = 7; - fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + cache: &mut Cache, + ) -> Vec { // This function makes 2 + 1 + 1 + 1 + 2 = 7 constraints let x1 = env.witness_curr(0); let y1 = env.witness_curr(1); diff --git a/kimchi/src/circuits/polynomials/endomul_scalar.rs b/kimchi/src/circuits/polynomials/endomul_scalar.rs index 731d7841e1..5e46d74432 100644 --- a/kimchi/src/circuits/polynomials/endomul_scalar.rs +++ b/kimchi/src/circuits/polynomials/endomul_scalar.rs @@ -167,7 +167,10 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::EndoMulScalar); const CONSTRAINTS: u32 = 11; - fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + cache: &mut Cache, + ) -> Vec { let n0 = env.witness_curr(0); let n8 = env.witness_curr(1); let a0 = env.witness_curr(2); diff --git a/kimchi/src/circuits/polynomials/endosclmul.rs b/kimchi/src/circuits/polynomials/endosclmul.rs index 8bbcb2e0b4..63156559c8 100644 --- a/kimchi/src/circuits/polynomials/endosclmul.rs +++ b/kimchi/src/circuits/polynomials/endosclmul.rs @@ -186,7 +186,10 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::EndoMul); const CONSTRAINTS: u32 = 11; - fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + cache: &mut Cache, + ) -> Vec { let b1 = env.witness_curr(11); let b2 = env.witness_curr(12); let b3 = env.witness_curr(13); diff --git a/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs b/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs index cc25e60565..289d31a6bf 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_add/circuitgates.rs @@ -142,7 +142,10 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::ForeignFieldAdd); const CONSTRAINTS: u32 = 4; - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { let foreign_modulus: [T; LIMB_COUNT] = array::from_fn(|i| env.coeff(i)); // stored as coefficient for better correspondance with the relation being proved diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs index 4baa6a9eb9..b4e390ccd8 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/circuitgates.rs @@ -193,7 +193,10 @@ where const CONSTRAINTS: u32 = 11; // DEGREE is 4 - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { let mut constraints = vec![]; // diff --git a/kimchi/src/circuits/polynomials/generic.rs b/kimchi/src/circuits/polynomials/generic.rs index 77a985ad45..29bd71b825 100644 --- a/kimchi/src/circuits/polynomials/generic.rs +++ b/kimchi/src/circuits/polynomials/generic.rs @@ -74,7 +74,10 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::Generic); const CONSTRAINTS: u32 = 2; - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { // First generic gate let left_coeff1 = env.coeff(0); let right_coeff1 = env.coeff(1); diff --git a/kimchi/src/circuits/polynomials/poseidon.rs b/kimchi/src/circuits/polynomials/poseidon.rs index a636570d5b..b690ce45fd 100644 --- a/kimchi/src/circuits/polynomials/poseidon.rs +++ b/kimchi/src/circuits/polynomials/poseidon.rs @@ -337,7 +337,10 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::Poseidon); const CONSTRAINTS: u32 = 15; - fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + cache: &mut Cache, + ) -> Vec { let mut res = vec![]; let mut idx = 0; diff --git a/kimchi/src/circuits/polynomials/range_check/circuitgates.rs b/kimchi/src/circuits/polynomials/range_check/circuitgates.rs index f543aae001..6e4b3def8e 100644 --- a/kimchi/src/circuits/polynomials/range_check/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/range_check/circuitgates.rs @@ -178,7 +178,10 @@ where // * Operates on Curr row // * Range constrain all limbs except vp0 and vp1 (barring plookup constraints, which are done elsewhere) // * Constrain that combining all limbs equals the limb stored in column 0 - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { // 1) Apply range constraints on the limbs // * Columns 1-2 are 12-bit copy constraints // * They are copied 3 rows ahead (to the final row) and are constrained by lookups @@ -279,7 +282,10 @@ where // * Operates on Curr and Next row // * Range constrain all limbs (barring plookup constraints, which are done elsewhere) // * Constrain that combining all limbs equals the value v2 stored in row Curr, column 0 - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { // 1) Apply range constraints on limbs for Curr row // * Column 2 is a 2-bit crumb let mut constraints = vec![crumb(&env.witness_curr(2))]; diff --git a/kimchi/src/circuits/polynomials/rot.rs b/kimchi/src/circuits/polynomials/rot.rs index 71bcdef994..e1ef1e4acb 100644 --- a/kimchi/src/circuits/polynomials/rot.rs +++ b/kimchi/src/circuits/polynomials/rot.rs @@ -213,7 +213,10 @@ where // (stored in coefficient as a power-of-two form) // * Operates on Curr row // * Shifts the words by `rot` bits and then adds the excess to obtain the rotated word. - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { // Check that the last 8 columns are 2-bit crumbs // C1..C8: x * (x - 1) * (x - 2) * (x - 3) = 0 let mut constraints = (7..KIMCHI_COLS) diff --git a/kimchi/src/circuits/polynomials/turshi.rs b/kimchi/src/circuits/polynomials/turshi.rs index 7a40b318ff..6a8a76fd85 100644 --- a/kimchi/src/circuits/polynomials/turshi.rs +++ b/kimchi/src/circuits/polynomials/turshi.rs @@ -772,7 +772,10 @@ where /// Generates the constraints for the Cairo initial claim and first memory checks /// Accesses Curr and Next rows - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { let pc_ini = env.witness_curr(0); // copy from public input let ap_ini = env.witness_curr(1); // copy from public input let pc_fin = env.witness_curr(2); // copy from public input @@ -809,7 +812,10 @@ where /// Generates the constraints for the Cairo instruction /// Accesses Curr and Next rows - fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + cache: &mut Cache, + ) -> Vec { // load all variables of the witness corresponding to Cairoinstruction gates let pc = env.witness_curr(0); let ap = env.witness_curr(1); @@ -955,7 +961,10 @@ where /// Generates the constraints for the Cairo flags /// Accesses Curr and Next rows - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { // Load current row let f_pc_abs = env.witness_curr(7); let f_pc_rel = env.witness_curr(8); @@ -1022,7 +1031,10 @@ where /// Generates the constraints for the Cairo transition /// Accesses Curr and Next rows (Next only first 3 entries) - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { // load computed updated registers let pcup = env.witness_curr(7); let apup = env.witness_curr(8); diff --git a/kimchi/src/circuits/polynomials/varbasemul.rs b/kimchi/src/circuits/polynomials/varbasemul.rs index a21f7305ab..9f9e524c0b 100644 --- a/kimchi/src/circuits/polynomials/varbasemul.rs +++ b/kimchi/src/circuits/polynomials/varbasemul.rs @@ -176,7 +176,10 @@ impl Point { } impl Point { - pub fn new_from_env>(&self, env: &ArgumentEnv) -> Point { + pub fn new_from_env, const COLUMNS: usize>( + &self, + env: &ArgumentEnv, + ) -> Point { Point::create(self.x.new_from_env(env), self.y.new_from_env(env)) } } @@ -287,7 +290,7 @@ trait FromWitness where F: PrimeField, { - fn new_from_env(&self, env: &ArgumentEnv) -> T; + fn new_from_env(&self, env: &ArgumentEnv) -> T; } impl FromWitness for Variable @@ -295,7 +298,7 @@ where F: PrimeField, T: ExprOps, { - fn new_from_env(&self, env: &ArgumentEnv) -> T { + fn new_from_env(&self, env: &ArgumentEnv) -> T { let column_to_index = |_| match self.col { Column::Witness(i) => i, _ => panic!("Can't get index from witness columns"), @@ -331,7 +334,10 @@ impl Layout { } } - fn new_from_env>(&self, env: &ArgumentEnv) -> Layout { + fn new_from_env, const COLUMNS: usize>( + &self, + env: &ArgumentEnv, + ) -> Layout { Layout { accs: self.accs.map(|point| point.new_from_env(env)), bits: self.bits.map(|var| var.new_from_env(env)), @@ -414,7 +420,10 @@ where const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::VarBaseMul); const CONSTRAINTS: u32 = 21; - fn constraint_checks>(env: &ArgumentEnv, cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + cache: &mut Cache, + ) -> Vec { let Layout { base, accs, @@ -422,7 +431,7 @@ where ss, n_prev, n_next, - } = Layout::create().new_from_env::(env); + } = Layout::create().new_from_env::(env); // n' // = 2^5 * n + 2^4 b0 + 2^3 b1 + 2^2 b2 + 2^1 b3 + b4 diff --git a/kimchi/src/circuits/polynomials/xor.rs b/kimchi/src/circuits/polynomials/xor.rs index 431734926a..630df1d2c9 100644 --- a/kimchi/src/circuits/polynomials/xor.rs +++ b/kimchi/src/circuits/polynomials/xor.rs @@ -149,7 +149,10 @@ where // * Operates on Curr and Next rows // * Constrain the decomposition of `in1`, `in2` and `out` of multiples of 16 bits // * The actual XOR is performed thanks to the plookups of 4-bit XORs. - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { let two = T::from(2u64); // in1 = in1_0 + in1_1 * 2^4 + in1_2 * 2^8 + in1_3 * 2^12 + next_in1 * 2^16 // in2 = in2_0 + in2_1 * 2^4 + in2_2 * 2^8 + in2_3 * 2^12 + next_in2 * 2^16 From 1a64113b9d389df99a0e08314afe09af4c5f0688 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 19 Oct 2023 13:41:09 +0200 Subject: [PATCH 214/242] add functionality to convert from hexadecimal string BigUints --- utils/src/biguint_helpers.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/src/biguint_helpers.rs b/utils/src/biguint_helpers.rs index 73c5955e2a..be97df1625 100644 --- a/utils/src/biguint_helpers.rs +++ b/utils/src/biguint_helpers.rs @@ -7,6 +7,9 @@ pub trait BigUintHelpers { /// Returns the minimum number of bits required to represent a BigUint /// As opposed to BigUint::bits, this function returns 1 for the input zero fn bitlen(&self) -> usize; + + /// Creates a BigUint from an hexadecimal string in big endian + fn from_hex(s: &str) -> Self; } impl BigUintHelpers for BigUint { @@ -17,4 +20,7 @@ impl BigUintHelpers for BigUint { self.bits() as usize } } + fn from_hex(s: &str) -> Self { + BigUint::parse_bytes(s.as_bytes(), 16).unwrap() + } } From 5ecf0ad80851fa0791db41645b3ae96c1a359b54 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 19 Oct 2023 13:42:35 +0200 Subject: [PATCH 215/242] add a few tests for the keccak witness generation code, and printing tools --- kimchi/src/tests/keccak.rs | 243 +++++++++++++++++++++++++++++++++++-- 1 file changed, 233 insertions(+), 10 deletions(-) diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index f5fa597068..06eb16b618 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -1,14 +1,237 @@ use std::array; -use crate::circuits::{ - constraints::ConstraintSystem, - gate::CircuitGate, - polynomials::keccak::{self, OFF}, - wires::Wire, +use crate::{ + circuits::{ + constraints::ConstraintSystem, + gate::{CircuitGate, GateType}, + polynomials::keccak::{ + collapse, compose, decompose, expand, pad, reset, shift, + witness::extend_keccak_witness, KECCAK_COLS, QUARTERS, + }, + wires::Wire, + }, + curve::KimchiCurve, }; -use ark_ec::AffineCurve; -use mina_curves::pasta::{Fp, Pallas, Vesta}; -use rand::Rng; +use ark_ff::{Field, PrimeField, Zero}; +use mina_curves::pasta::Pallas; +use num_bigint::BigUint; +use o1_utils::{BigUintHelpers, FieldHelpers}; -//use super::framework::TestFramework; -type PallasField = ::BaseField; +fn create_test_constraint_system( + bytelength: usize, +) -> ConstraintSystem +where + G::BaseField: PrimeField, +{ + let mut gates = vec![]; + let next_row = CircuitGate::extend_keccak(&mut gates, bytelength); + // Adding dummy row to avoid out of bounds in squeeze constraints accessing Next row + gates.push(CircuitGate { + typ: GateType::Zero, + wires: Wire::for_row(next_row), + coeffs: vec![], + }); + + ConstraintSystem::create(gates).build().unwrap() +} + +fn create_keccak_witness(message: BigUint) -> [Vec; KECCAK_COLS] +where + G::BaseField: PrimeField, +{ + let mut witness: [Vec; KECCAK_COLS] = + array::from_fn(|_| vec![G::ScalarField::zero(); 0]); + extend_keccak_witness(&mut witness, message); + // Adding dummy row to avoid out of bounds in squeeze constraints accessing Next row + let dummy_row: [Vec; KECCAK_COLS] = + array::from_fn(|_| vec![G::ScalarField::zero()]); + for col in 0..KECCAK_COLS { + witness[col].extend(dummy_row[col].iter()); + } + witness +} + +fn print_witness(witness: &[Vec; KECCAK_COLS], round: usize) { + fn to_u64(elem: F) -> u64 { + let mut bytes = FieldHelpers::::to_bytes(&elem); + bytes.reverse(); + bytes.iter().fold(0, |acc: u64, x| (acc << 8) + *x as u64) + } + fn print_line(state: &[u64]) { + print!(" "); + for x in 0..5 { + let quarters = &state[4 * x..4 * (x + 1)]; + let word = compose(&collapse(&reset(&shift(quarters)))); + print!("{:016x} ", word); + } + println!(); + } + fn print_matrix(state: &[u64]) { + for x in 0..5 { + print!(" "); + for y in 0..5 { + let quarters = &state[4 * (5 * y + x)..4 * (5 * y + x) + 4]; + let word = compose(&collapse(&reset(&shift(quarters)))); + print!("{:016x} ", word); + } + println!(); + } + } + + let row = witness + .iter() + .map(|x| to_u64::(x[round])) + .collect::>(); + let next = witness + .iter() + .map(|x| to_u64::(x[round + 1])) + .collect::>(); + + println!("----------------------------------------"); + println!("ROUND {}", round); + println!("State A:"); + print_matrix(&row[0..100]); + println!("State C:"); + print_line(&row[100..120]); + println!("State D:"); + print_line(&row[320..340]); + println!("State E:"); + print_matrix(&row[340..440]); + println!("State B:"); + print_matrix(&row[1440..1540]); + + let mut state_f = row[2340..2344].to_vec(); + let mut tail = next[4..100].to_vec(); + state_f.append(&mut tail); + + println!("State F:"); + print_matrix(&state_f); + println!("State G:"); + print_matrix(&next[0..100]); +} + +// Sets up test for a given message and desired input bytelength +fn test_keccak(message: BigUint) -> BigUint +where + G::BaseField: PrimeField, +{ + let bytelength = message.to_bytes_be().len(); + let padded_len = { + let mut sized = message.to_bytes_be(); + sized.resize(bytelength - sized.len(), 0); + pad(&sized).len() + }; + let _index = create_test_constraint_system::(padded_len); + let witness = create_keccak_witness::(message); + + for r in 1..=24 { + print_witness::(&witness, r); + } + + let mut hash = vec![]; + let hash_row = witness[0].len() - 2; // Hash row is dummy row + println!(); + println!("----------------------------------------"); + print!("Hash: "); + for b in 0..32 { + hash.push(FieldHelpers::to_bytes(&witness[200 + b][hash_row])[0]); + print!("{:02x}", hash[b]); + } + println!(); + println!(); + + BigUint::from_bytes_be(&hash) +} + +#[test] +fn test_bitwise_sparse_representation() { + assert_eq!(expand(0xFFFF), 0x1111111111111111); + + let word_a: u64 = 0x70d324ac9215fd8e; + let dense_a = decompose(word_a); + let real_dense_a = [0xfd8e, 0x9215, 0x24ac, 0x70d3]; + for i in 0..QUARTERS { + assert_eq!(dense_a[i], real_dense_a[i]); + } + assert_eq!(word_a, compose(&dense_a)); + + let sparse_a = dense_a.iter().map(|x| expand(*x)).collect::>(); + let real_sparse_a: Vec = vec![ + 0x1111110110001110, + 0x1001001000010101, + 0x10010010101100, + 0x111000011010011, + ]; + for i in 0..QUARTERS { + assert_eq!(sparse_a[i], real_sparse_a[i]); + } + + let word_b: u64 = 0x11c76438a7f9e94d; + let dense_b = decompose(word_b); + let sparse_b = dense_b.iter().map(|x| expand(*x)).collect::>(); + + let xor_ab: u64 = word_a ^ word_b; + assert_eq!(xor_ab, 0x6114409435ec14c3); + + let sparse_xor = decompose(xor_ab) + .iter() + .map(|x| expand(*x)) + .collect::>(); + let real_sparse_xor = [ + 0x1010011000011, + 0x11010111101100, + 0x100000010010100, + 0x110000100010100, + ]; + for i in 0..QUARTERS { + assert_eq!(sparse_xor[i], real_sparse_xor[i]); + } + + let sparse_sum_ab = sparse_a + .iter() + .zip(sparse_b.iter()) + .map(|(a, b)| a + b) + .collect::>(); + let shifts_sum_ab = shift(&sparse_sum_ab); + let reset_sum_ab = reset(&shifts_sum_ab); + assert_eq!(sparse_xor, reset_sum_ab); + + for i in 0..QUARTERS { + assert_eq!( + sparse_sum_ab[i], + shifts_sum_ab[i] + + shifts_sum_ab[4 + i] * 2 + + shifts_sum_ab[8 + i] * 4 + + shifts_sum_ab[12 + i] * 8 + ) + } +} + +#[test] +// Tests a random block of 1080 bits +fn test_random_block() { + let claim_random = test_keccak::( + BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126"), + ); + let hash_random = + BigUint::from_hex("845e9dd4e22b4917a80c5419a0ddb3eebf5f4f7cc6035d827314a18b718f751f"); + assert_eq!(claim_random, hash_random); +} + +#[test] +// Test hash of message zero with 1 byte +fn test_dummy() { + let claim1 = test_keccak::(BigUint::from_bytes_be(&[0x00])); + let hash1 = + BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); + assert_eq!(claim1, hash1); +} + +#[test] +// Test hash of message zero with 1 byte +fn test_blocks() { + let claim_3blocks = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f")); + let hash_3blocks = + BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); + assert_eq!(claim_3blocks, hash_3blocks); +} From 576028b1b0cb70cc5f417af4b894381d40a20633 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 11 Sep 2023 17:42:58 +0200 Subject: [PATCH 216/242] created sparse table with 16 bits + 64 bits expansion --- book/src/specs/kimchi.md | 3 ++ kimchi/src/circuits/lookup/tables/mod.rs | 7 +++++ kimchi/src/circuits/lookup/tables/sparse.rs | 32 +++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 kimchi/src/circuits/lookup/tables/sparse.rs diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 842ecbb171..a86006fb3c 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -343,6 +343,9 @@ pub const XOR_TABLE_ID: i32 = 0; /// The range check table ID. pub const RANGE_CHECK_TABLE_ID: i32 = 1; + +/// The table ID associated with the sparse lookup table. +pub const SPARSE_TABLE_ID: i32 = 2; ``` diff --git a/kimchi/src/circuits/lookup/tables/mod.rs b/kimchi/src/circuits/lookup/tables/mod.rs index d6be11f9bd..4e1cd0b125 100644 --- a/kimchi/src/circuits/lookup/tables/mod.rs +++ b/kimchi/src/circuits/lookup/tables/mod.rs @@ -3,6 +3,7 @@ use poly_commitment::PolyComm; use serde::{Deserialize, Serialize}; pub mod range_check; +pub mod sparse; pub mod xor; //~ spec:startcode @@ -11,6 +12,9 @@ pub const XOR_TABLE_ID: i32 = 0; /// The range check table ID. pub const RANGE_CHECK_TABLE_ID: i32 = 1; + +/// The table ID associated with the sparse lookup table. +pub const SPARSE_TABLE_ID: i32 = 2; //~ spec:endcode /// Enumerates the different 'fixed' lookup tables used by individual gates @@ -18,6 +22,7 @@ pub const RANGE_CHECK_TABLE_ID: i32 = 1; pub enum GateLookupTable { Xor, RangeCheck, + Sparse, } /// A table of values that can be used for a lookup, along with the ID for the table. @@ -70,6 +75,7 @@ pub fn get_table(table_name: GateLookupTable) -> LookupTable { match table_name { GateLookupTable::Xor => xor::xor_table(), GateLookupTable::RangeCheck => range_check::range_check_table(), + GateLookupTable::Sparse => sparse::sparse_table(), } } @@ -79,6 +85,7 @@ impl GateLookupTable { match self { GateLookupTable::Xor => xor::TABLE_SIZE, GateLookupTable::RangeCheck => range_check::TABLE_SIZE, + GateLookupTable::Sparse => sparse::TABLE_SIZE, } } } diff --git a/kimchi/src/circuits/lookup/tables/sparse.rs b/kimchi/src/circuits/lookup/tables/sparse.rs new file mode 100644 index 0000000000..196a8dc429 --- /dev/null +++ b/kimchi/src/circuits/lookup/tables/sparse.rs @@ -0,0 +1,32 @@ +use crate::circuits::lookup::tables::{LookupTable, SPARSE_TABLE_ID}; +use ark_ff::Field; + +//~ The lookup table for 16-bit expansion for Keccak words encoding. +//~ This is a 2-column table containing the sparse representation of the 16-bit values. +//~ The first column contains the 16-bit values, and the second column contains their expansion to 64-bit values. + +/// Returns the sparse lookup table +/// +/// # Panics +/// +/// Will panic if `data` is invalid. +pub fn sparse_table() -> LookupTable { + let mut data = vec![vec![]; 2]; + + // Sparse expansion table for all of the 16-bit values + for i in 0u64..=0xFFFF { + data[0].push(F::from(i)); + // Uses the fact that the expansion coincides with the hexadecimal interpretation of the index expressed in binary + // (i.e. expanding 1b gives 0x0001, expanding 0b gives 0x0000) + data[1].push(F::from( + u64::from_str_radix(&format!("{:b}", i), 16).unwrap(), + )); + } + + LookupTable { + id: SPARSE_TABLE_ID, + data, + } +} + +pub const TABLE_SIZE: usize = 65536; From 7acaaa97479fe03cfadb13643c72594acc741708 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 3 Oct 2023 18:16:27 +0200 Subject: [PATCH 217/242] additional tables containing individual columns --- book/src/specs/kimchi.md | 11 +++++-- kimchi/src/circuits/lookup/tables/bits16.rs | 27 ++++++++++++++++ kimchi/src/circuits/lookup/tables/mod.rs | 23 +++++++++++--- kimchi/src/circuits/lookup/tables/reset.rs | 34 +++++++++++++++++++++ kimchi/src/circuits/lookup/tables/sparse.rs | 10 ++---- 5 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 kimchi/src/circuits/lookup/tables/bits16.rs create mode 100644 kimchi/src/circuits/lookup/tables/reset.rs diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index a86006fb3c..b079c012d1 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -344,8 +344,15 @@ pub const XOR_TABLE_ID: i32 = 0; /// The range check table ID. pub const RANGE_CHECK_TABLE_ID: i32 = 1; -/// The table ID associated with the sparse lookup table. -pub const SPARSE_TABLE_ID: i32 = 2; +/// The table ID associated with the 16-bit lookup table. +pub const BITS16_TABLE_ID: i32 = 2; + +/// The table ID associated with the 1-column sparse lookup table. +pub const SPARSE_TABLE_ID: i32 = 3; + +/// The table ID associated with the 2-column sparse lookup table. +pub const RESET_TABLE_ID: i32 = 4; + ``` diff --git a/kimchi/src/circuits/lookup/tables/bits16.rs b/kimchi/src/circuits/lookup/tables/bits16.rs new file mode 100644 index 0000000000..50ae56b613 --- /dev/null +++ b/kimchi/src/circuits/lookup/tables/bits16.rs @@ -0,0 +1,27 @@ +use crate::circuits::lookup::tables::LookupTable; +use ark_ff::Field; + +use super::BITS16_TABLE_ID; + +//~ The lookup table for 16-bits + +/// Returns the lookup table for all 16-bit values +/// +/// # Panics +/// +/// Will panic if `data` is invalid. +pub fn bits16_table() -> LookupTable { + let mut data = vec![vec![]; 1]; + + // All of the 16-bit values + for i in 0u64..=0xFFFF { + data[0].push(F::from(i)); + } + + LookupTable { + id: BITS16_TABLE_ID, + data, + } +} + +pub const TABLE_SIZE: usize = 65536; diff --git a/kimchi/src/circuits/lookup/tables/mod.rs b/kimchi/src/circuits/lookup/tables/mod.rs index 4e1cd0b125..ac259385e7 100644 --- a/kimchi/src/circuits/lookup/tables/mod.rs +++ b/kimchi/src/circuits/lookup/tables/mod.rs @@ -2,7 +2,9 @@ use ark_ff::{FftField, One, Zero}; use poly_commitment::PolyComm; use serde::{Deserialize, Serialize}; +pub mod bits16; pub mod range_check; +pub mod reset; pub mod sparse; pub mod xor; @@ -13,8 +15,15 @@ pub const XOR_TABLE_ID: i32 = 0; /// The range check table ID. pub const RANGE_CHECK_TABLE_ID: i32 = 1; -/// The table ID associated with the sparse lookup table. -pub const SPARSE_TABLE_ID: i32 = 2; +/// The table ID associated with the 16-bit lookup table. +pub const BITS16_TABLE_ID: i32 = 2; + +/// The table ID associated with the 1-column sparse lookup table. +pub const SPARSE_TABLE_ID: i32 = 3; + +/// The table ID associated with the 2-column sparse lookup table. +pub const RESET_TABLE_ID: i32 = 4; + //~ spec:endcode /// Enumerates the different 'fixed' lookup tables used by individual gates @@ -22,7 +31,9 @@ pub const SPARSE_TABLE_ID: i32 = 2; pub enum GateLookupTable { Xor, RangeCheck, + Bits16, Sparse, + Reset, } /// A table of values that can be used for a lookup, along with the ID for the table. @@ -75,17 +86,21 @@ pub fn get_table(table_name: GateLookupTable) -> LookupTable { match table_name { GateLookupTable::Xor => xor::xor_table(), GateLookupTable::RangeCheck => range_check::range_check_table(), + GateLookupTable::Bits16 => bits16::bits16_table(), GateLookupTable::Sparse => sparse::sparse_table(), + GateLookupTable::Reset => reset::reset_table(), } } impl GateLookupTable { - /// Returns the lookup table associated to a [`GateLookupTable`]. + /// Returns the size of a lookup table associated to a [`GateLookupTable`]. pub fn table_size(&self) -> usize { match self { GateLookupTable::Xor => xor::TABLE_SIZE, GateLookupTable::RangeCheck => range_check::TABLE_SIZE, - GateLookupTable::Sparse => sparse::TABLE_SIZE, + GateLookupTable::Bits16 | GateLookupTable::Reset | GateLookupTable::Sparse => { + sparse::TABLE_SIZE + } } } } diff --git a/kimchi/src/circuits/lookup/tables/reset.rs b/kimchi/src/circuits/lookup/tables/reset.rs new file mode 100644 index 0000000000..2be1e04bd3 --- /dev/null +++ b/kimchi/src/circuits/lookup/tables/reset.rs @@ -0,0 +1,34 @@ +use crate::circuits::lookup::tables::LookupTable; +use ark_ff::Field; + +use super::RESET_TABLE_ID; + +//~ The lookup table for 16-bit expansion for Keccak words encoding. +//~ This is a 2-column table containing the reset sparse representation of the 16-bit values. +//~ The first column contains the 16-bit values, and the second column contains their expansion to 64-bit values. + +/// Returns the sparse lookup table +/// +/// # Panics +/// +/// Will panic if `data` is invalid. +pub fn reset_table() -> LookupTable { + let mut data = vec![vec![]; 2]; + + // Sparse expansion table for all of the 16-bit values + for i in 0u64..=0xFFFF { + data[0].push(F::from(i)); + // Uses the fact that the expansion coincides with the hexadecimal interpretation of the index expressed in binary + // (i.e. expanding 1b gives 0x0001, expanding 0b gives 0x0000) + data[1].push(F::from( + u64::from_str_radix(&format!("{:b}", i), 16).unwrap(), + )); + } + + LookupTable { + id: RESET_TABLE_ID, + data, + } +} + +pub const TABLE_SIZE: usize = 65536; diff --git a/kimchi/src/circuits/lookup/tables/sparse.rs b/kimchi/src/circuits/lookup/tables/sparse.rs index 196a8dc429..3c8de10cd0 100644 --- a/kimchi/src/circuits/lookup/tables/sparse.rs +++ b/kimchi/src/circuits/lookup/tables/sparse.rs @@ -2,8 +2,7 @@ use crate::circuits::lookup::tables::{LookupTable, SPARSE_TABLE_ID}; use ark_ff::Field; //~ The lookup table for 16-bit expansion for Keccak words encoding. -//~ This is a 2-column table containing the sparse representation of the 16-bit values. -//~ The first column contains the 16-bit values, and the second column contains their expansion to 64-bit values. +//~ This is a 1-column table containing the sparse representation of all 16-bit preimages. /// Returns the sparse lookup table /// @@ -13,12 +12,9 @@ use ark_ff::Field; pub fn sparse_table() -> LookupTable { let mut data = vec![vec![]; 2]; - // Sparse expansion table for all of the 16-bit values + // Sparse expansion table for i in 0u64..=0xFFFF { - data[0].push(F::from(i)); - // Uses the fact that the expansion coincides with the hexadecimal interpretation of the index expressed in binary - // (i.e. expanding 1b gives 0x0001, expanding 0b gives 0x0000) - data[1].push(F::from( + data[0].push(F::from( u64::from_str_radix(&format!("{:b}", i), 16).unwrap(), )); } From edf301bfd7303b3cf707e8d796c298c7beea3b3d Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 10 Oct 2023 17:21:50 +0200 Subject: [PATCH 218/242] fix sparse table width --- kimchi/src/circuits/lookup/tables/sparse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/circuits/lookup/tables/sparse.rs b/kimchi/src/circuits/lookup/tables/sparse.rs index 3c8de10cd0..e1a3fcc79d 100644 --- a/kimchi/src/circuits/lookup/tables/sparse.rs +++ b/kimchi/src/circuits/lookup/tables/sparse.rs @@ -10,7 +10,7 @@ use ark_ff::Field; /// /// Will panic if `data` is invalid. pub fn sparse_table() -> LookupTable { - let mut data = vec![vec![]; 2]; + let mut data = vec![vec![]; 1]; // Sparse expansion table for i in 0u64..=0xFFFF { From 40e784700ce535310d92ddf35faf31e54fa571af Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 31 Oct 2023 16:42:03 +0100 Subject: [PATCH 219/242] delete comment about panicking inside lookups --- kimchi/src/circuits/lookup/tables/bits16.rs | 4 ---- kimchi/src/circuits/lookup/tables/reset.rs | 4 ---- kimchi/src/circuits/lookup/tables/sparse.rs | 4 ---- kimchi/src/circuits/lookup/tables/xor.rs | 4 ---- 4 files changed, 16 deletions(-) diff --git a/kimchi/src/circuits/lookup/tables/bits16.rs b/kimchi/src/circuits/lookup/tables/bits16.rs index 50ae56b613..91db8ae786 100644 --- a/kimchi/src/circuits/lookup/tables/bits16.rs +++ b/kimchi/src/circuits/lookup/tables/bits16.rs @@ -6,10 +6,6 @@ use super::BITS16_TABLE_ID; //~ The lookup table for 16-bits /// Returns the lookup table for all 16-bit values -/// -/// # Panics -/// -/// Will panic if `data` is invalid. pub fn bits16_table() -> LookupTable { let mut data = vec![vec![]; 1]; diff --git a/kimchi/src/circuits/lookup/tables/reset.rs b/kimchi/src/circuits/lookup/tables/reset.rs index 2be1e04bd3..9e359f3ad9 100644 --- a/kimchi/src/circuits/lookup/tables/reset.rs +++ b/kimchi/src/circuits/lookup/tables/reset.rs @@ -8,10 +8,6 @@ use super::RESET_TABLE_ID; //~ The first column contains the 16-bit values, and the second column contains their expansion to 64-bit values. /// Returns the sparse lookup table -/// -/// # Panics -/// -/// Will panic if `data` is invalid. pub fn reset_table() -> LookupTable { let mut data = vec![vec![]; 2]; diff --git a/kimchi/src/circuits/lookup/tables/sparse.rs b/kimchi/src/circuits/lookup/tables/sparse.rs index e1a3fcc79d..e33130197f 100644 --- a/kimchi/src/circuits/lookup/tables/sparse.rs +++ b/kimchi/src/circuits/lookup/tables/sparse.rs @@ -5,10 +5,6 @@ use ark_ff::Field; //~ This is a 1-column table containing the sparse representation of all 16-bit preimages. /// Returns the sparse lookup table -/// -/// # Panics -/// -/// Will panic if `data` is invalid. pub fn sparse_table() -> LookupTable { let mut data = vec![vec![]; 1]; diff --git a/kimchi/src/circuits/lookup/tables/xor.rs b/kimchi/src/circuits/lookup/tables/xor.rs index d846942a31..3ecc9d3b4f 100644 --- a/kimchi/src/circuits/lookup/tables/xor.rs +++ b/kimchi/src/circuits/lookup/tables/xor.rs @@ -14,10 +14,6 @@ use ark_ff::Field; //~ will translate into a scalar multiplication by 0, which is free. /// Returns the XOR lookup table -/// -/// # Panics -/// -/// Will panic if `data` is invalid. pub fn xor_table() -> LookupTable { let mut data = vec![vec![]; 3]; From 12499343b963c9941ad8365402c6be87e9b25668 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 19 Oct 2023 14:40:18 +0200 Subject: [PATCH 220/242] first version of keccak patterns and support for several tables in the same row --- kimchi/src/circuits/constraints.rs | 4 +- kimchi/src/circuits/lookup/lookups.rs | 238 ++++++++++++++++++++++++-- kimchi/src/linearization.rs | 4 + kimchi/src/verifier_index.rs | 2 + 4 files changed, 237 insertions(+), 11 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 238e725bc1..70429d0100 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -674,7 +674,9 @@ impl Builder { let LookupFeatures { patterns, .. } = &lookup_features; for pattern in patterns.into_iter() { if let Some(gate_table) = pattern.table() { - num_lookups += gate_table.table_size(); + for table in gate_table { + num_lookups += table.table_size(); + } } } num_lookups diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 8d9bec6169..85863b4558 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -4,7 +4,7 @@ use crate::circuits::{ lookup::index::LookupSelectors, lookup::tables::{ combine_table_entry, get_table, GateLookupTable, LookupTable, RANGE_CHECK_TABLE_ID, - XOR_TABLE_ID, + SPARSE_TABLE_ID, XOR_TABLE_ID, }, }; use ark_ff::{Field, One, PrimeField, Zero}; @@ -15,6 +15,8 @@ use std::collections::HashSet; use std::ops::{Mul, Neg}; use strum_macros::EnumIter; +use super::tables::{BITS16_TABLE_ID, RESET_TABLE_ID}; + type Evaluations = E>; //~ Lookups patterns are extremely flexible and can be configured in a number of ways. @@ -47,6 +49,8 @@ pub struct LookupPatterns { pub lookup: bool, pub range_check: bool, pub foreign_field_mul: bool, + pub keccak_round: bool, + pub keccak_sponge: bool, } impl IntoIterator for LookupPatterns { @@ -60,6 +64,8 @@ impl IntoIterator for LookupPatterns { lookup, range_check, foreign_field_mul, + keccak_round, + keccak_sponge, } = self; let mut patterns = Vec::with_capacity(5); @@ -76,6 +82,12 @@ impl IntoIterator for LookupPatterns { if foreign_field_mul { patterns.push(LookupPattern::ForeignFieldMul) } + if keccak_round { + patterns.push(LookupPattern::KeccakRound); + } + if keccak_sponge { + patterns.push(LookupPattern::KeccakSponge) + } patterns.into_iter() } } @@ -89,6 +101,8 @@ impl std::ops::Index for LookupPatterns { LookupPattern::Lookup => &self.lookup, LookupPattern::RangeCheck => &self.range_check, LookupPattern::ForeignFieldMul => &self.foreign_field_mul, + LookupPattern::KeccakRound => &self.keccak_round, + LookupPattern::KeccakSponge => &self.keccak_sponge, } } } @@ -100,6 +114,8 @@ impl std::ops::IndexMut for LookupPatterns { LookupPattern::Lookup => &mut self.lookup, LookupPattern::RangeCheck => &mut self.range_check, LookupPattern::ForeignFieldMul => &mut self.foreign_field_mul, + LookupPattern::KeccakRound => &mut self.keccak_round, + LookupPattern::KeccakSponge => &mut self.keccak_sponge, } } } @@ -157,7 +173,7 @@ impl LookupFeatures { } /// Describes the desired lookup configuration. -#[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Copy, Clone, Serialize, Deserialize, Debug)] pub struct LookupInfo { /// The maximum length of an element of `kinds`. This can be computed from `kinds`. pub max_per_row: usize, @@ -225,13 +241,17 @@ impl LookupInfo { if let Some(lookup_pattern) = LookupPattern::from_gate(typ, CurrOrNext::Curr) { update_selector(lookup_pattern, i); if let Some(table_kind) = lookup_pattern.table() { - gate_tables.insert(table_kind); + for (_i, table) in table_kind.iter().enumerate() { + gate_tables.insert(*table); + } } } if let Some(lookup_pattern) = LookupPattern::from_gate(typ, CurrOrNext::Next) { update_selector(lookup_pattern, i + 1); if let Some(table_kind) = lookup_pattern.table() { - gate_tables.insert(table_kind); + for (_i, table) in table_kind.iter().enumerate() { + gate_tables.insert(*table); + } } } } @@ -386,12 +406,16 @@ pub enum LookupPattern { Lookup, RangeCheck, ForeignFieldMul, + KeccakRound, + KeccakSponge, } impl LookupPattern { /// Returns the maximum number of lookups per row that are used by the pattern. pub fn max_lookups_per_row(&self) -> usize { match self { + LookupPattern::KeccakRound => 1760, + LookupPattern::KeccakSponge => 800, LookupPattern::Xor | LookupPattern::RangeCheck | LookupPattern::ForeignFieldMul => 4, LookupPattern::Lookup => 3, } @@ -401,7 +425,7 @@ impl LookupPattern { pub fn max_joint_size(&self) -> u32 { match self { LookupPattern::Xor => 3, - LookupPattern::Lookup => 2, + LookupPattern::Lookup | LookupPattern::KeccakRound | LookupPattern::KeccakSponge => 2, LookupPattern::ForeignFieldMul | LookupPattern::RangeCheck => 1, } } @@ -490,16 +514,208 @@ impl LookupPattern { }) .collect() } + LookupPattern::KeccakRound => { + let mut lookups = + Vec::with_capacity(LookupPattern::KeccakRound.max_lookups_per_row()); + let l = |loc: LocalPosition| SingleLookup { + value: vec![(F::one(), loc)], + }; + // Theta + for i in 0..20 { + // 2-column lookups + let shift0_c = curr_row(120 + i); + let dense_c = curr_row(200 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![l(dense_c), l(shift0_c)], + }); + let dense_rot_c = curr_row(280 + i); + let expand_rot_c = curr_row(300 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![l(dense_rot_c), l(expand_rot_c)], + }); + + // Second column lookups + let shift1_c = curr_row(140 + i); + let shift2_c = curr_row(160 + i); + let shift3_c = curr_row(180 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift1_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift2_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift3_c)], + }); + + // First column lookups + let quotient_c = curr_row(220 + i); + let remainder_c = curr_row(240 + i); + let bound_c = curr_row(260 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(quotient_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(remainder_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(bound_c)], + }); + } + // PiRho + for i in 0..100 { + // 2-column lookups + let shift0_e = curr_row(440 + i); + let dense_e = curr_row(840 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![l(dense_e), l(shift0_e)], + }); + let dense_rot_e = curr_row(1240 + i); + let expand_rot_e = curr_row(1340 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(dense_rot_e), l(expand_rot_e)], + }); + + // Second column lookups + let shift1_e = curr_row(540 + i); + let shift2_e = curr_row(640 + i); + let shift3_e = curr_row(740 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift1_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift2_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift3_e)], + }); + + // First column lookups + let quotient_e = curr_row(940 + i); + let remainder_e = curr_row(1040 + i); + let bound_e = curr_row(1140 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(quotient_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(remainder_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(bound_e)], + }); + } + // Chi + for i in 0..400 { + // Second column lookups + let shift_b: LocalPosition = curr_row(1540 + i); + let shift_sum = curr_row(1940 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift_b)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift_sum)], + }); + } + lookups + } + LookupPattern::KeccakSponge => { + let mut lookups = + Vec::with_capacity(LookupPattern::KeccakSponge.max_lookups_per_row()); + let l = |loc: LocalPosition| SingleLookup { + value: vec![(F::one(), loc)], + }; + for i in 0..100 { + let shift1 = curr_row(500 + i); + let shift2 = curr_row(600 + i); + let shift3 = curr_row(700 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift1)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift2)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift3)], + }); + for b in 0..2 { + let byte = curr_row(200 + 2 * i + b); + // byte < 12 bits + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RANGE_CHECK_TABLE_ID), + entry: vec![SingleLookup { + value: vec![(F::one(), byte)], + }], + }); + // byte * 2^4 < 12 bits + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RANGE_CHECK_TABLE_ID), + entry: vec![SingleLookup { + value: vec![(F::from(2u64).pow([4u64]), byte)], + }], + }); + } + let byte1 = curr_row(200 + 2 * i); + let byte2 = curr_row(201 + 2 * i); + let shift0 = curr_row(400 + i); + // dense := byte1 + byte2 * 2^8 and dense used for first column of RESET table + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![ + SingleLookup { + value: vec![(F::from(256u32), byte2), (F::one(), byte1)], + }, + l(shift0), + ], + }); + } + lookups + } } } - /// Returns the lookup table used by the pattern, or `None` if no specific table is rqeuired. - pub fn table(&self) -> Option { + /// Returns the lookup table(s) used by the pattern, or `None` if no specific table is required. + pub fn table(&self) -> Option> { match self { - LookupPattern::Xor => Some(GateLookupTable::Xor), + LookupPattern::Xor => Some(vec![GateLookupTable::Xor]), LookupPattern::Lookup => None, - LookupPattern::RangeCheck => Some(GateLookupTable::RangeCheck), - LookupPattern::ForeignFieldMul => Some(GateLookupTable::RangeCheck), + LookupPattern::RangeCheck => Some(vec![GateLookupTable::RangeCheck]), + LookupPattern::ForeignFieldMul => Some(vec![GateLookupTable::RangeCheck]), + LookupPattern::KeccakRound => Some(vec![ + GateLookupTable::Sparse, + GateLookupTable::Reset, + GateLookupTable::Bits16, + ]), + LookupPattern::KeccakSponge => Some(vec![ + GateLookupTable::Sparse, + GateLookupTable::Reset, + GateLookupTable::RangeCheck, + ]), } } @@ -527,6 +743,8 @@ impl GateType { LookupPattern::Lookup, LookupPattern::RangeCheck, LookupPattern::ForeignFieldMul, + LookupPattern::KeccakRound, + LookupPattern::KeccakSponge, ] } } diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index ec42689059..9d9543c87b 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -186,6 +186,8 @@ pub fn constraints_expr( lookup: true, range_check: true, foreign_field_mul: true, + keccak_round: false, + keccak_sponge: false, }, uses_runtime_tables: true, joint_lookup_used: true, @@ -258,6 +260,8 @@ pub fn linearization_columns( lookup: true, range_check: true, foreign_field_mul: true, + keccak_round: false, + keccak_sponge: false, }, joint_lookup_used: true, uses_runtime_tables: true, diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 1163885f0d..d10733295d 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -484,6 +484,8 @@ impl VerifierIndex { lookup, range_check, ffmul, + keccak_round: _, + keccak_sponge: _, }, }) = lookup_index { From 14484abff1e8929d6a445c00a87eb64cb3868931 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 19 Oct 2023 18:22:31 +0200 Subject: [PATCH 221/242] remove unneeded clone --- kimchi/src/verifier_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index d10733295d..2e929c470a 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -176,7 +176,7 @@ impl ProverIndex { .as_ref() .map(|cs| LookupVerifierIndex { joint_lookup_used: cs.configuration.lookup_info.features.joint_lookup_used, - lookup_info: cs.configuration.lookup_info.clone(), + lookup_info: cs.configuration.lookup_info, lookup_selectors: cs .lookup_selectors .as_ref() From a16a599669c47796668eda5aa91fd411b18c81c4 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 31 Oct 2023 16:44:37 +0100 Subject: [PATCH 222/242] add missing pattern inside wasm bindings --- kimchi/src/circuits/lookup/lookups.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 40a1ee46f4..9db4eb037a 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -781,12 +781,16 @@ pub mod wasm { lookup: bool, range_check: bool, foreign_field_mul: bool, + keccak_round: bool, + keccak_sponge: bool, ) -> LookupPatterns { LookupPatterns { xor, lookup, range_check, foreign_field_mul, + keccak_round, + keccak_sponge, } } } From a298cb45a878d6c6bbf4c03ce9d37f98a00c5fa8 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 14:39:38 +0100 Subject: [PATCH 223/242] include patterns for keccak inside matches with todo --- kimchi/src/circuits/berkeley_columns.rs | 2 ++ kimchi/src/proof.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs index 6558f4c367..b56389161b 100644 --- a/kimchi/src/circuits/berkeley_columns.rs +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -150,6 +150,8 @@ impl ColumnEvaluations for ProofEvaluations> { LookupKindIndex(LookupPattern::ForeignFieldMul) => self .foreign_field_mul_lookup_selector .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::KeccakRound) => todo!(), + LookupKindIndex(LookupPattern::KeccakSponge) => todo!(), LookupRuntimeSelector => self .runtime_lookup_table_selector .ok_or(ExprError::MissingIndexEvaluation(col)), diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index f7ace0c5fd..6feaf26c28 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -459,6 +459,8 @@ impl ProofEvaluations { Column::LookupKindIndex(LookupPattern::ForeignFieldMul) => { self.foreign_field_mul_lookup_selector.as_ref() } + Column::LookupKindIndex(LookupPattern::KeccakRound) => todo!(), + Column::LookupKindIndex(LookupPattern::KeccakSponge) => todo!(), Column::LookupRuntimeSelector => self.runtime_lookup_table_selector.as_ref(), Column::LookupRuntimeTable => self.runtime_lookup_table.as_ref(), Column::Index(GateType::Generic) => Some(&self.generic_selector), From 6b215b48ee2f0e74c6b9778f1381b81b7f11aaf6 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 10 Oct 2023 17:20:41 +0200 Subject: [PATCH 224/242] include keccak in from_gate --- kimchi/src/circuits/lookup/lookups.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 1c1d3e29fa..770aa347cf 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -733,6 +733,8 @@ impl LookupPattern { } (ForeignFieldMul, Curr | Next) => Some(LookupPattern::ForeignFieldMul), (Xor16, Curr) => Some(LookupPattern::Xor), + (KeccakRound, Curr) => Some(LookupPattern::KeccakRound), + (KeccakSponge, Curr) => Some(LookupPattern::KeccakSponge), _ => None, } } From e9747d9a4a14d08a42e6a7570d0cc0d6482d8688 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 11 Oct 2023 16:47:46 +0200 Subject: [PATCH 225/242] fix selector of keccak gates and activate feature flags --- kimchi/src/circuits/constraints.rs | 46 ++++++++++++++++++++++++++++++ kimchi/src/linearization.rs | 6 ++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index e672d8fffe..5c0500e13d 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -46,6 +46,10 @@ pub struct FeatureFlags { pub xor: bool, /// ROT gate pub rot: bool, + /// Keccak round gate + pub keccak_round: bool, + /// Keccak sponge gate + pub keccak_sponge: bool, /// Lookup features pub lookup_features: LookupFeatures, } @@ -131,6 +135,14 @@ pub struct ColumnEvaluations /// Rot gate selector over domain d8 #[serde_as(as = "Option")] pub rot_selector8: Option>>, + + /// Keccak round gate selector over domain d4 + #[serde_as(as = "Option")] + pub keccak_round_selector4: Option>>, + + /// Keccak sponge gate selector over domain d4 + #[serde_as(as = "Option")] + pub keccak_sponge_selector4: Option>>, } #[serde_as] @@ -592,6 +604,34 @@ impl ConstraintSystem { } }; + let keccak_round_selector4 = { + if !self.feature_flags.keccak_round { + None + } else { + Some(selector_polynomial( + GateType::KeccakRound, + &self.gates, + &self.domain, + &self.domain.d4, + self.disable_gates_checks, + )) + } + }; + + let keccak_sponge_selector4 = { + if !self.feature_flags.keccak_sponge { + None + } else { + Some(selector_polynomial( + GateType::KeccakSponge, + &self.gates, + &self.domain, + &self.domain.d4, + self.disable_gates_checks, + )) + } + }; + // TODO: This doesn't need to be degree 8 but that would require some changes in expr let coefficients8 = array::from_fn(|i| { evaluated_column_coefficients.coefficients[i] @@ -613,6 +653,8 @@ impl ConstraintSystem { foreign_field_mul_selector8, xor_selector8, rot_selector8, + keccak_round_selector4, + keccak_sponge_selector4, } } } @@ -804,6 +846,8 @@ impl Builder { foreign_field_mul: false, xor: false, rot: false, + keccak_round: false, + keccak_sponge: false, }; for gate in &gates { @@ -814,6 +858,8 @@ impl Builder { GateType::ForeignFieldMul => feature_flags.foreign_field_mul = true, GateType::Xor16 => feature_flags.xor = true, GateType::Rot64 => feature_flags.rot = true, + GateType::KeccakRound => feature_flags.keccak_round = true, + GateType::KeccakSponge => feature_flags.keccak_sponge = true, _ => (), } } diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 363bbd6c6e..ed4830a9a5 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -252,14 +252,16 @@ pub fn linearization_columns Date: Mon, 23 Oct 2023 16:52:37 +0200 Subject: [PATCH 226/242] add missing commitments for keccak --- book/src/specs/kimchi.md | 8 ++++++++ kimchi/src/circuits/constraints.rs | 16 ++++++++-------- kimchi/src/verifier.rs | 4 ++-- kimchi/src/verifier_index.rs | 30 ++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 4e05f421d3..78a23e09d0 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1856,6 +1856,14 @@ pub struct VerifierIndex< #[serde(bound = "Option>: Serialize + DeserializeOwned")] pub rot_comm: Option>, + /// Keccak round commitments + #[serde(bound = "Option>: Serialize + DeserializeOwned")] + pub keccak_round_comm: Option>, + + /// Keccak sponge commitments + #[serde(bound = "Option>: Serialize + DeserializeOwned")] + pub keccak_sponge_comm: Option>, + /// wire coordinate shifts #[serde_as(as = "[o1_utils::serialization::SerdeAs; PERMUTS]")] pub shift: [G::ScalarField; PERMUTS], diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 5c0500e13d..17caf44e8c 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -138,11 +138,11 @@ pub struct ColumnEvaluations /// Keccak round gate selector over domain d4 #[serde_as(as = "Option")] - pub keccak_round_selector4: Option>>, + pub keccak_round_selector8: Option>>, /// Keccak sponge gate selector over domain d4 #[serde_as(as = "Option")] - pub keccak_sponge_selector4: Option>>, + pub keccak_sponge_selector8: Option>>, } #[serde_as] @@ -604,7 +604,7 @@ impl ConstraintSystem { } }; - let keccak_round_selector4 = { + let keccak_round_selector8 = { if !self.feature_flags.keccak_round { None } else { @@ -612,13 +612,13 @@ impl ConstraintSystem { GateType::KeccakRound, &self.gates, &self.domain, - &self.domain.d4, + &self.domain.d8, self.disable_gates_checks, )) } }; - let keccak_sponge_selector4 = { + let keccak_sponge_selector8 = { if !self.feature_flags.keccak_sponge { None } else { @@ -626,7 +626,7 @@ impl ConstraintSystem { GateType::KeccakSponge, &self.gates, &self.domain, - &self.domain.d4, + &self.domain.d8, self.disable_gates_checks, )) } @@ -653,8 +653,8 @@ impl ConstraintSystem { foreign_field_mul_selector8, xor_selector8, rot_selector8, - keccak_round_selector4, - keccak_sponge_selector4, + keccak_round_selector8, + keccak_sponge_selector8, } } } diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 64246200fc..de803cc2c2 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -93,8 +93,8 @@ impl<'a, G: KimchiCurve, OpeningProof: OpenProof, const COLUMNS: usize> ForeignFieldMul => Some(self.verifier_index.foreign_field_mul_comm.as_ref()?), Xor16 => Some(self.verifier_index.xor_comm.as_ref()?), Rot64 => Some(self.verifier_index.rot_comm.as_ref()?), - KeccakRound => todo!(), - KeccakSponge => todo!(), + KeccakRound => Some(self.verifier_index.keccak_round_comm.as_ref()?), + KeccakSponge => Some(self.verifier_index.keccak_sponge_comm.as_ref()?), } } } diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 3b0325250a..26ef4e0252 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -131,6 +131,14 @@ pub struct VerifierIndex< #[serde(bound = "Option>: Serialize + DeserializeOwned")] pub rot_comm: Option>, + /// Keccak round commitments + #[serde(bound = "Option>: Serialize + DeserializeOwned")] + pub keccak_round_comm: Option>, + + /// Keccak sponge commitments + #[serde(bound = "Option>: Serialize + DeserializeOwned")] + pub keccak_sponge_comm: Option>, + /// wire coordinate shifts #[serde_as(as = "[o1_utils::serialization::SerdeAs; PERMUTS]")] pub shift: [G::ScalarField; PERMUTS], @@ -296,6 +304,18 @@ where .as_ref() .map(|eval8| self.srs.commit_evaluations_non_hiding(domain, eval8)), + keccak_round_comm: self + .column_evaluations + .keccak_round_selector8 + .as_ref() + .map(|eval4| self.srs.commit_evaluations_non_hiding(domain, eval4)), + + keccak_sponge_comm: self + .column_evaluations + .keccak_sponge_selector8 + .as_ref() + .map(|eval4| self.srs.commit_evaluations_non_hiding(domain, eval4)), + shift: self.cs.shift, permutation_vanishing_polynomial_m: { let cell = OnceCell::new(); @@ -431,6 +451,8 @@ impl, const COLUMNS: usize> foreign_field_mul_comm, xor_comm, rot_comm, + keccak_round_comm, + keccak_sponge_comm, // Lookup index; optional lookup_index, @@ -485,6 +507,14 @@ impl, const COLUMNS: usize> fq_sponge.absorb_g(&rot_comm.unshifted); } + if let Some(keccak_round_comm) = keccak_round_comm { + fq_sponge.absorb_g(&keccak_round_comm.unshifted); + } + + if let Some(keccak_sponge_comm) = keccak_sponge_comm { + fq_sponge.absorb_g(&keccak_sponge_comm.unshifted); + } + // Lookup index; optional if let Some(LookupVerifierIndex { From ac90abe08146e78170e6c93e480f2cc7c0c04273 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 13:15:59 +0200 Subject: [PATCH 227/242] fix domain sizes of keccak gates and include them inside index evals --- kimchi/src/circuits/constraints.rs | 16 ++++++++-------- kimchi/src/prover.rs | 20 +++++++++++++++++++- kimchi/src/verifier_index.rs | 4 ++-- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 17caf44e8c..5c0500e13d 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -138,11 +138,11 @@ pub struct ColumnEvaluations /// Keccak round gate selector over domain d4 #[serde_as(as = "Option")] - pub keccak_round_selector8: Option>>, + pub keccak_round_selector4: Option>>, /// Keccak sponge gate selector over domain d4 #[serde_as(as = "Option")] - pub keccak_sponge_selector8: Option>>, + pub keccak_sponge_selector4: Option>>, } #[serde_as] @@ -604,7 +604,7 @@ impl ConstraintSystem { } }; - let keccak_round_selector8 = { + let keccak_round_selector4 = { if !self.feature_flags.keccak_round { None } else { @@ -612,13 +612,13 @@ impl ConstraintSystem { GateType::KeccakRound, &self.gates, &self.domain, - &self.domain.d8, + &self.domain.d4, self.disable_gates_checks, )) } }; - let keccak_sponge_selector8 = { + let keccak_sponge_selector4 = { if !self.feature_flags.keccak_sponge { None } else { @@ -626,7 +626,7 @@ impl ConstraintSystem { GateType::KeccakSponge, &self.gates, &self.domain, - &self.domain.d8, + &self.domain.d4, self.disable_gates_checks, )) } @@ -653,8 +653,8 @@ impl ConstraintSystem { foreign_field_mul_selector8, xor_selector8, rot_selector8, - keccak_round_selector8, - keccak_sponge_selector8, + keccak_round_selector4, + keccak_sponge_selector4, } } } diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 2bbe9e4173..46c8bf42c3 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -13,7 +13,9 @@ use crate::{ endosclmul::EndosclMul, foreign_field_add::circuitgates::ForeignFieldAdd, foreign_field_mul::{self, circuitgates::ForeignFieldMul}, - generic, permutation, + generic, + keccak::circuitgates::{KeccakRound, KeccakSponge}, + permutation, poseidon::Poseidon, range_check::circuitgates::{RangeCheck0, RangeCheck1}, rot::Rot64, @@ -702,6 +704,14 @@ where index_evals.insert(GateType::Rot64, selector); } + if let Some(selector) = index.column_evaluations.keccak_round_selector4.as_ref() { + index_evals.insert(GateType::KeccakRound, selector); + } + + if let Some(selector) = index.column_evaluations.keccak_sponge_selector4.as_ref() { + index_evals.insert(GateType::KeccakSponge, selector); + } + let mds = &G::sponge_params().mds; Environment { constants: Constants { @@ -775,6 +785,10 @@ where .is_some(); let xor_enabled = index.column_evaluations.xor_selector8.is_some(); let rot_enabled = index.column_evaluations.rot_selector8.is_some(); + let keccak_round_enabled = + index.column_evaluations.keccak_round_selector4.is_some(); + let keccak_sponge_enabled = + index.column_evaluations.keccak_sponge_selector4.is_some(); for gate in [ ( @@ -799,6 +813,10 @@ where (&Xor16::default(), xor_enabled), // Rot gate (&Rot64::default(), rot_enabled), + // Keccak round gate + (&KeccakRound::default(), keccak_round_enabled), + // Keccak sponge gate + (&KeccakSponge::default(), keccak_sponge_enabled), ] .into_iter() .filter_map(|(gate, is_enabled)| if is_enabled { Some(gate) } else { None }) diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 26ef4e0252..8712135470 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -306,13 +306,13 @@ where keccak_round_comm: self .column_evaluations - .keccak_round_selector8 + .keccak_round_selector4 .as_ref() .map(|eval4| self.srs.commit_evaluations_non_hiding(domain, eval4)), keccak_sponge_comm: self .column_evaluations - .keccak_sponge_selector8 + .keccak_sponge_selector4 .as_ref() .map(|eval4| self.srs.commit_evaluations_non_hiding(domain, eval4)), From 07e18f3bf9e9b730c2e4717eef86678ec245498a Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 13:28:54 +0200 Subject: [PATCH 228/242] include keccak in linearization and feature flags --- kimchi/src/circuits/expr.rs | 4 ++++ kimchi/src/linearization.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 3f153895ea..1ec95d0edc 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -402,6 +402,8 @@ pub enum FeatureFlag { ForeignFieldMul, Xor, Rot, + KeccakRound, + KeccakSponge, LookupTables, RuntimeLookupTables, LookupPattern(LookupPattern), @@ -560,6 +562,8 @@ impl + PartialEq + Clone, Column: Clone + Partia ForeignFieldMul => features.foreign_field_mul, Xor => features.xor, Rot => features.rot, + KeccakRound => features.keccak_round, + KeccakSponge => features.keccak_sponge, LookupTables => { features.lookup_features.patterns != LookupPatterns::default() } diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index ed4830a9a5..2b3f16e7e0 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -8,6 +8,7 @@ use crate::circuits::lookup::{ constraints::LookupConfiguration, lookups::{LookupFeatures, LookupInfo, LookupPattern, LookupPatterns}, }; +use crate::circuits::polynomials::keccak; use crate::circuits::polynomials::{ complete_add::CompleteAdd, endomul_scalar::EndomulScalar, @@ -151,6 +152,40 @@ pub fn constraints_expr( } } + { + let mut keccak_round_expr = || { + keccak::circuitgates::KeccakRound::combined_constraints(&powers_of_alpha, &mut cache) + }; + if let Some(feature_flags) = feature_flags { + if feature_flags.keccak_round { + expr += keccak_round_expr(); + } + } else { + expr += Expr::IfFeature( + FeatureFlag::KeccakRound, + Box::new(keccak_round_expr()), + Box::new(Expr::zero()), + ); + } + } + + { + let mut keccak_sponge_expr = || { + keccak::circuitgates::KeccakSponge::combined_constraints(&powers_of_alpha, &mut cache) + }; + if let Some(feature_flags) = feature_flags { + if feature_flags.keccak_sponge { + expr += keccak_sponge_expr(); + } + } else { + expr += Expr::IfFeature( + FeatureFlag::KeccakSponge, + Box::new(keccak_sponge_expr()), + Box::new(Expr::zero()), + ); + } + } + if generic { expr += generic::Generic::combined_constraints(&powers_of_alpha, &mut cache); } From 249430f9a3c84cc3e6371801146c00728de4f251 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 14:51:17 +0200 Subject: [PATCH 229/242] use larger exponent if keccak in use --- kimchi/src/linearization.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 2b3f16e7e0..83e73fb768 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -9,6 +9,7 @@ use crate::circuits::lookup::{ lookups::{LookupFeatures, LookupInfo, LookupPattern, LookupPatterns}, }; use crate::circuits::polynomials::keccak; +use crate::circuits::polynomials::keccak::circuitgates::KeccakRound; use crate::circuits::polynomials::{ complete_add::CompleteAdd, endomul_scalar::EndomulScalar, @@ -45,7 +46,12 @@ pub fn constraints_expr( // Set up powers of alpha. Only the max number of constraints matters. // The gate type argument can just be the zero gate. - let max_exponents = VarbaseMul::::CONSTRAINTS; + let mut max_exponents = VarbaseMul::::CONSTRAINTS; + if let Some(feature_flags) = feature_flags { + if feature_flags.keccak_round { + max_exponents = KeccakRound::::CONSTRAINTS; + } + } powers_of_alpha.register(ArgumentType::Gate(GateType::Zero), max_exponents); let mut cache = expr::Cache::default(); From 2d8811bda3913c2ca87371ee66b113fd2b603ab7 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 15:18:17 +0200 Subject: [PATCH 230/242] make keccak rows evaluations over d8 and simplify feature flags --- kimchi/src/circuits/constraints.rs | 36 +++++++++++++----------------- kimchi/src/circuits/expr.rs | 6 ++--- kimchi/src/linearization.rs | 22 ++++++++++-------- kimchi/src/prover.rs | 8 +++---- kimchi/src/verifier_index.rs | 8 +++---- 5 files changed, 39 insertions(+), 41 deletions(-) diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index 5c0500e13d..efa75aaf5d 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -46,10 +46,8 @@ pub struct FeatureFlags { pub xor: bool, /// ROT gate pub rot: bool, - /// Keccak round gate - pub keccak_round: bool, - /// Keccak sponge gate - pub keccak_sponge: bool, + /// Keccak gates + pub keccak: bool, /// Lookup features pub lookup_features: LookupFeatures, } @@ -136,13 +134,13 @@ pub struct ColumnEvaluations #[serde_as(as = "Option")] pub rot_selector8: Option>>, - /// Keccak round gate selector over domain d4 + /// Keccak round gate selector over domain d8 #[serde_as(as = "Option")] - pub keccak_round_selector4: Option>>, + pub keccak_round_selector8: Option>>, - /// Keccak sponge gate selector over domain d4 + /// Keccak sponge gate selector over domain d8 #[serde_as(as = "Option")] - pub keccak_sponge_selector4: Option>>, + pub keccak_sponge_selector8: Option>>, } #[serde_as] @@ -604,29 +602,29 @@ impl ConstraintSystem { } }; - let keccak_round_selector4 = { - if !self.feature_flags.keccak_round { + let keccak_round_selector8 = { + if !self.feature_flags.keccak { None } else { Some(selector_polynomial( GateType::KeccakRound, &self.gates, &self.domain, - &self.domain.d4, + &self.domain.d8, self.disable_gates_checks, )) } }; - let keccak_sponge_selector4 = { - if !self.feature_flags.keccak_sponge { + let keccak_sponge_selector8 = { + if !self.feature_flags.keccak { None } else { Some(selector_polynomial( GateType::KeccakSponge, &self.gates, &self.domain, - &self.domain.d4, + &self.domain.d8, self.disable_gates_checks, )) } @@ -653,8 +651,8 @@ impl ConstraintSystem { foreign_field_mul_selector8, xor_selector8, rot_selector8, - keccak_round_selector4, - keccak_sponge_selector4, + keccak_round_selector8, + keccak_sponge_selector8, } } } @@ -846,8 +844,7 @@ impl Builder { foreign_field_mul: false, xor: false, rot: false, - keccak_round: false, - keccak_sponge: false, + keccak: false, }; for gate in &gates { @@ -858,8 +855,7 @@ impl Builder { GateType::ForeignFieldMul => feature_flags.foreign_field_mul = true, GateType::Xor16 => feature_flags.xor = true, GateType::Rot64 => feature_flags.rot = true, - GateType::KeccakRound => feature_flags.keccak_round = true, - GateType::KeccakSponge => feature_flags.keccak_sponge = true, + GateType::KeccakRound | GateType::KeccakSponge => feature_flags.keccak = true, _ => (), } } diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index 1ec95d0edc..90150e237f 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -402,8 +402,7 @@ pub enum FeatureFlag { ForeignFieldMul, Xor, Rot, - KeccakRound, - KeccakSponge, + Keccak, LookupTables, RuntimeLookupTables, LookupPattern(LookupPattern), @@ -562,8 +561,7 @@ impl + PartialEq + Clone, Column: Clone + Partia ForeignFieldMul => features.foreign_field_mul, Xor => features.xor, Rot => features.rot, - KeccakRound => features.keccak_round, - KeccakSponge => features.keccak_sponge, + Keccak => features.keccak, LookupTables => { features.lookup_features.patterns != LookupPatterns::default() } diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 83e73fb768..98d21bfbc1 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -1,5 +1,7 @@ //! This module implements the linearization. +use std::cmp::max; + use crate::alphas::Alphas; use crate::circuits::argument::{Argument, ArgumentType}; use crate::circuits::expr; @@ -9,7 +11,7 @@ use crate::circuits::lookup::{ lookups::{LookupFeatures, LookupInfo, LookupPattern, LookupPatterns}, }; use crate::circuits::polynomials::keccak; -use crate::circuits::polynomials::keccak::circuitgates::KeccakRound; +use crate::circuits::polynomials::keccak::circuitgates::{KeccakRound, KeccakSponge}; use crate::circuits::polynomials::{ complete_add::CompleteAdd, endomul_scalar::EndomulScalar, @@ -48,8 +50,11 @@ pub fn constraints_expr( // The gate type argument can just be the zero gate. let mut max_exponents = VarbaseMul::::CONSTRAINTS; if let Some(feature_flags) = feature_flags { - if feature_flags.keccak_round { - max_exponents = KeccakRound::::CONSTRAINTS; + if feature_flags.keccak { + max_exponents = max( + KeccakRound::::CONSTRAINTS, + KeccakSponge::::CONSTRAINTS, + ); } } powers_of_alpha.register(ArgumentType::Gate(GateType::Zero), max_exponents); @@ -163,12 +168,12 @@ pub fn constraints_expr( keccak::circuitgates::KeccakRound::combined_constraints(&powers_of_alpha, &mut cache) }; if let Some(feature_flags) = feature_flags { - if feature_flags.keccak_round { + if feature_flags.keccak { expr += keccak_round_expr(); } } else { expr += Expr::IfFeature( - FeatureFlag::KeccakRound, + FeatureFlag::Keccak, Box::new(keccak_round_expr()), Box::new(Expr::zero()), ); @@ -180,12 +185,12 @@ pub fn constraints_expr( keccak::circuitgates::KeccakSponge::combined_constraints(&powers_of_alpha, &mut cache) }; if let Some(feature_flags) = feature_flags { - if feature_flags.keccak_sponge { + if feature_flags.keccak { expr += keccak_sponge_expr(); } } else { expr += Expr::IfFeature( - FeatureFlag::KeccakSponge, + FeatureFlag::Keccak, Box::new(keccak_sponge_expr()), Box::new(Expr::zero()), ); @@ -293,8 +298,7 @@ pub fn linearization_columns Date: Mon, 30 Oct 2023 20:29:31 +0100 Subject: [PATCH 231/242] update proof system changes after some parts went missing after merge with master --- book/src/specs/kimchi.md | 8 ++++++++ kimchi/src/plonk_sponge.rs | 16 ++++++++++++++++ kimchi/src/proof.rs | 38 ++++++++++++++++++++++++++++++++++++-- kimchi/src/prover.rs | 26 ++++++++++++++++++++++++++ kimchi/src/verifier.rs | 19 +++++++++++++++++++ 5 files changed, 105 insertions(+), 2 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 78a23e09d0..7180405f1d 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2029,6 +2029,10 @@ pub struct ProofEvaluations { pub xor_selector: Option, /// evaluation of the Rot selector polynomial pub rot_selector: Option, + /// evaluation of the KeccakRound selector polynomial + pub keccak_round_selector: Option, + /// evaluation of the KeccakRound selector polynomial + pub keccak_sponge_selector: Option, // lookup-related evaluations /// evaluation of lookup aggregation polynomial @@ -2051,6 +2055,10 @@ pub struct ProofEvaluations { pub range_check_lookup_selector: Option, /// evaluation of the ForeignFieldMul range check pattern selector polynomial pub foreign_field_mul_lookup_selector: Option, + /// evaluation of the KeccakRound pattern selector polynomial + pub keccak_round_lookup_selector: Option, + /// evaluation of the KeccakSponge pattern selector polynomial + pub keccak_sponge_lookup_selector: Option, } /// Commitments linked to the lookup feature diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index 0a8cb05776..59f9ccf15f 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -78,6 +78,8 @@ impl FrSponge for DefaultFrSp foreign_field_mul_selector, xor_selector, rot_selector, + keccak_round_selector, + keccak_sponge_selector, lookup_aggregation, lookup_table, lookup_sorted, @@ -87,6 +89,8 @@ impl FrSponge for DefaultFrSp lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, + keccak_round_lookup_selector, + keccak_sponge_lookup_selector, } = e; let mut points = vec![ @@ -122,6 +126,12 @@ impl FrSponge for DefaultFrSp if let Some(rot_selector) = rot_selector.as_ref() { points.push(rot_selector) } + if let Some(keccak_round_selector) = keccak_round_selector.as_ref() { + points.push(keccak_round_selector) + } + if let Some(keccak_sponge_selector) = keccak_sponge_selector.as_ref() { + points.push(keccak_sponge_selector) + } if let Some(lookup_aggregation) = lookup_aggregation.as_ref() { points.push(lookup_aggregation) } @@ -152,6 +162,12 @@ impl FrSponge for DefaultFrSp { points.push(foreign_field_mul_lookup_selector) } + if let Some(keccak_round_lookup_selector) = keccak_round_lookup_selector.as_ref() { + points.push(keccak_round_lookup_selector) + } + if let Some(keccak_sponge_lookup_selector) = keccak_sponge_lookup_selector.as_ref() { + points.push(keccak_sponge_lookup_selector) + } points.into_iter().for_each(|p| { self.sponge.absorb(&p.zeta); diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 70ab48adf7..edc12b26bb 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -82,6 +82,10 @@ pub struct ProofEvaluations { pub xor_selector: Option, /// evaluation of the Rot selector polynomial pub rot_selector: Option, + /// evaluation of the KeccakRound selector polynomial + pub keccak_round_selector: Option, + /// evaluation of the KeccakRound selector polynomial + pub keccak_sponge_selector: Option, // lookup-related evaluations /// evaluation of lookup aggregation polynomial @@ -104,6 +108,10 @@ pub struct ProofEvaluations { pub range_check_lookup_selector: Option, /// evaluation of the ForeignFieldMul range check pattern selector polynomial pub foreign_field_mul_lookup_selector: Option, + /// evaluation of the KeccakRound pattern selector polynomial + pub keccak_round_lookup_selector: Option, + /// evaluation of the KeccakSponge pattern selector polynomial + pub keccak_sponge_lookup_selector: Option, } /// Commitments linked to the lookup feature @@ -215,6 +223,8 @@ impl ProofEvaluations { foreign_field_mul_selector, xor_selector, rot_selector, + keccak_round_selector, + keccak_sponge_selector, lookup_aggregation, lookup_table, lookup_sorted, @@ -224,6 +234,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, + keccak_round_lookup_selector, + keccak_sponge_lookup_selector, } = self; ProofEvaluations { public: public.map(f), @@ -243,6 +255,8 @@ impl ProofEvaluations { foreign_field_mul_selector: foreign_field_mul_selector.map(f), xor_selector: xor_selector.map(f), rot_selector: rot_selector.map(f), + keccak_round_selector: keccak_round_selector.map(f), + keccak_sponge_selector: keccak_sponge_selector.map(f), lookup_aggregation: lookup_aggregation.map(f), lookup_table: lookup_table.map(f), lookup_sorted: lookup_sorted.map(|x| x.map(f)), @@ -252,6 +266,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector: lookup_gate_lookup_selector.map(f), range_check_lookup_selector: range_check_lookup_selector.map(f), foreign_field_mul_lookup_selector: foreign_field_mul_lookup_selector.map(f), + keccak_round_lookup_selector: keccak_round_lookup_selector.map(f), + keccak_sponge_lookup_selector: keccak_sponge_lookup_selector.map(f), } } @@ -277,6 +293,8 @@ impl ProofEvaluations { foreign_field_mul_selector, xor_selector, rot_selector, + keccak_round_selector, + keccak_sponge_selector, lookup_aggregation, lookup_table, lookup_sorted, @@ -286,6 +304,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, + keccak_round_lookup_selector, + keccak_sponge_lookup_selector, } = self; ProofEvaluations { public: public.as_ref().map(f), @@ -305,6 +325,8 @@ impl ProofEvaluations { foreign_field_mul_selector: foreign_field_mul_selector.as_ref().map(f), xor_selector: xor_selector.as_ref().map(f), rot_selector: rot_selector.as_ref().map(f), + keccak_round_selector: keccak_round_selector.as_ref().map(f), + keccak_sponge_selector: keccak_sponge_selector.as_ref().map(f), lookup_aggregation: lookup_aggregation.as_ref().map(f), lookup_table: lookup_table.as_ref().map(f), lookup_sorted: array::from_fn(|i| lookup_sorted[i].as_ref().map(f)), @@ -314,6 +336,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector: lookup_gate_lookup_selector.as_ref().map(f), range_check_lookup_selector: range_check_lookup_selector.as_ref().map(f), foreign_field_mul_lookup_selector: foreign_field_mul_lookup_selector.as_ref().map(f), + keccak_round_lookup_selector: keccak_round_lookup_selector.as_ref().map(f), + keccak_sponge_lookup_selector: keccak_sponge_lookup_selector.as_ref().map(f), } } } @@ -392,6 +416,8 @@ impl ProofEvaluations, foreign_field_mul_selector: None, xor_selector: None, rot_selector: None, + keccak_round_selector: None, + keccak_sponge_selector: None, lookup_aggregation: None, lookup_table: None, lookup_sorted: array::from_fn(|_| None), @@ -401,6 +427,8 @@ impl ProofEvaluations, lookup_gate_lookup_selector: None, range_check_lookup_selector: None, foreign_field_mul_lookup_selector: None, + keccak_round_lookup_selector: None, + keccak_sponge_lookup_selector: None, } } } @@ -435,8 +463,12 @@ impl ProofEvaluations { Column::LookupKindIndex(LookupPattern::ForeignFieldMul) => { self.foreign_field_mul_lookup_selector.as_ref() } - Column::LookupKindIndex(LookupPattern::KeccakRound) => todo!(), - Column::LookupKindIndex(LookupPattern::KeccakSponge) => todo!(), + Column::LookupKindIndex(LookupPattern::KeccakRound) => { + self.keccak_round_lookup_selector.as_ref() + } + Column::LookupKindIndex(LookupPattern::KeccakSponge) => { + self.keccak_sponge_lookup_selector.as_ref() + } Column::LookupRuntimeSelector => self.runtime_lookup_table_selector.as_ref(), Column::LookupRuntimeTable => self.runtime_lookup_table.as_ref(), Column::Index(GateType::Generic) => Some(&self.generic_selector), @@ -451,6 +483,8 @@ impl ProofEvaluations { Column::Index(GateType::ForeignFieldMul) => self.foreign_field_mul_selector.as_ref(), Column::Index(GateType::Xor16) => self.xor_selector.as_ref(), Column::Index(GateType::Rot64) => self.rot_selector.as_ref(), + Column::Index(GateType::KeccakRound) => self.keccak_round_selector.as_ref(), + Column::Index(GateType::KeccakSponge) => self.keccak_sponge_selector.as_ref(), Column::Index(_) => None, Column::Coefficient(i) => Some(&self.coefficients[i]), Column::Permutation(i) => Some(&self.s[i]), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index ad652fc047..38f03c81c5 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1072,6 +1072,16 @@ where .rot_selector8 .as_ref() .map(chunked_evals_for_selector), + keccak_round_selector: index + .column_evaluations + .keccak_round_selector8 + .as_ref() + .map(chunked_evals_for_selector), + keccak_sponge_selector: index + .column_evaluations + .keccak_sponge_selector8 + .as_ref() + .map(chunked_evals_for_selector), runtime_lookup_table_selector: index.cs.lookup_constraint_system.as_ref().and_then( |lcs| { @@ -1110,6 +1120,22 @@ where .map(chunked_evals_for_selector) }, ), + keccak_round_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then( + |lcs| { + lcs.lookup_selectors + .keccak_round + .as_ref() + .map(chunked_evals_for_selector) + }, + ), + keccak_sponge_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then( + |lcs| { + lcs.lookup_selectors + .keccak_sponge + .as_ref() + .map(chunked_evals_for_selector) + }, + ), }; let zeta_to_srs_len = zeta.pow([index.max_poly_size as u64]); diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index de803cc2c2..ffae4af8eb 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -635,6 +635,8 @@ where foreign_field_mul_selector, xor_selector, rot_selector, + keccak_round_selector, + keccak_sponge_selector, lookup_aggregation, lookup_table, lookup_sorted, @@ -644,6 +646,8 @@ where lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, + keccak_round_lookup_selector, + keccak_sponge_lookup_selector, } = &proof.evals; let check_eval_len = |eval: &PointEvaluations>, str: &'static str| -> Result<()> { @@ -721,6 +725,12 @@ where if let Some(rot_selector) = rot_selector { check_eval_len(rot_selector, "rot selector")? } + if let Some(keccak_round_selector) = keccak_round_selector { + check_eval_len(keccak_round_selector, "keccak round selector")? + } + if let Some(keccak_sponge_selector) = keccak_sponge_selector { + check_eval_len(keccak_sponge_selector, "keccak sponge selector")? + } // Lookup selectors @@ -745,6 +755,15 @@ where "foreign field mul lookup selector", )? } + if let Some(keccak_round_lookup_selector) = keccak_round_lookup_selector { + check_eval_len(keccak_round_lookup_selector, "keccak round lookup selector")? + } + if let Some(keccak_sponge_lookup_selector) = keccak_sponge_lookup_selector { + check_eval_len( + keccak_sponge_lookup_selector, + "keccak sponge lookup selector", + )? + } Ok(()) } From cd71cdf8daeaa073cf648fc22c564044364e0428 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 15:22:21 +0100 Subject: [PATCH 232/242] include keccak inside chain of combined inner product --- kimchi/src/circuits/berkeley_columns.rs | 8 ++++-- kimchi/src/linearization.rs | 4 +++ kimchi/src/proof.rs | 2 +- kimchi/src/verifier.rs | 34 +++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs index 84e5b8ebf5..9509eb69fa 100644 --- a/kimchi/src/circuits/berkeley_columns.rs +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -152,8 +152,12 @@ impl ColumnEvaluations LookupKindIndex(LookupPattern::ForeignFieldMul) => self .foreign_field_mul_lookup_selector .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupKindIndex(LookupPattern::KeccakRound) => todo!(), - LookupKindIndex(LookupPattern::KeccakSponge) => todo!(), + LookupKindIndex(LookupPattern::KeccakRound) => self + .keccak_round_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(LookupPattern::KeccakSponge) => self + .keccak_sponge_lookup_selector + .ok_or(ExprError::MissingIndexEvaluation(col)), LookupRuntimeSelector => self .runtime_lookup_table_selector .ok_or(ExprError::MissingIndexEvaluation(col)), diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 98d21bfbc1..ca75cb7f3d 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -366,6 +366,8 @@ pub fn linearization_columns ProofEvaluations { Column::LookupSorted(i) => self.lookup_sorted[i].as_ref(), Column::LookupAggreg => self.lookup_aggregation.as_ref(), Column::LookupTable => self.lookup_table.as_ref(), - Column::LookupKindIndex(LookupPattern::Xor) => self.xor_lookup_selector.as_ref(), Column::LookupKindIndex(LookupPattern::Lookup) => { self.lookup_gate_lookup_selector.as_ref() } + Column::LookupKindIndex(LookupPattern::Xor) => self.xor_lookup_selector.as_ref(), Column::LookupKindIndex(LookupPattern::RangeCheck) => { self.range_check_lookup_selector.as_ref() } diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index ffae4af8eb..64f9097e60 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -517,6 +517,18 @@ where .as_ref() .map(|_| Column::Index(GateType::Rot64)), ) + .chain( + index + .keccak_round_comm + .as_ref() + .map(|_| Column::Index(GateType::KeccakRound)), + ) + .chain( + index + .keccak_sponge_comm + .as_ref() + .map(|_| Column::Index(GateType::KeccakSponge)), + ) .chain( index .lookup_index @@ -558,6 +570,16 @@ where .chain(self.evals.foreign_field_mul_lookup_selector.as_ref().map( |_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul), )) + .chain( + self.evals.keccak_round_lookup_selector.as_ref().map(|_| { + Column::LookupKindIndex(LookupPattern::KeccakRound) + }), + ) + .chain( + self.evals.keccak_sponge_lookup_selector.as_ref().map(|_| { + Column::LookupKindIndex(LookupPattern::KeccakSponge) + }), + ) }) .into_iter() .flatten(), @@ -1141,6 +1163,18 @@ where .as_ref() .map(|_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul)), ) + .chain( + li.lookup_selectors + .keccak_round + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::KeccakRound)), + ) + .chain( + li.lookup_selectors + .keccak_sponge + .as_ref() + .map(|_| Column::LookupKindIndex(LookupPattern::KeccakSponge)), + ) }) .into_iter() .flatten() From 6287dd8675abf61b3077080735418c076ab1aea8 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 15:23:59 +0100 Subject: [PATCH 233/242] remove keccak tables from berkeley columns --- kimchi/src/circuits/berkeley_columns.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs index 9509eb69fa..f756fe4c66 100644 --- a/kimchi/src/circuits/berkeley_columns.rs +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -152,16 +152,11 @@ impl ColumnEvaluations LookupKindIndex(LookupPattern::ForeignFieldMul) => self .foreign_field_mul_lookup_selector .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupKindIndex(LookupPattern::KeccakRound) => self - .keccak_round_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), - LookupKindIndex(LookupPattern::KeccakSponge) => self - .keccak_sponge_lookup_selector - .ok_or(ExprError::MissingIndexEvaluation(col)), LookupRuntimeSelector => self .runtime_lookup_table_selector .ok_or(ExprError::MissingIndexEvaluation(col)), Index(_) => Err(ExprError::MissingIndexEvaluation(col)), + LookupKindIndex(_) => Err(ExprError::MissingIndexEvaluation(col)), } } } From 2ba05a3bfca9668087ca0adb78206c11b736ab97 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 15:29:10 +0100 Subject: [PATCH 234/242] disabling keccak selectors for ocamltypes inside proof --- kimchi/src/proof.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index d28e61b75f..9a67281b82 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -961,6 +961,8 @@ pub mod caml { rot_selector: cpe .rot_selector .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), + keccak_round_selector: None, + keccak_sponge_selector: None, lookup_aggregation: cpe .lookup_aggregation .map(|x| x.map(&|x| x.into_iter().map(Into::into).collect())), @@ -993,6 +995,8 @@ pub mod caml { foreign_field_mul_lookup_selector: cpe .foreign_field_mul_lookup_selector .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), + keccak_round_lookup_selector: None, + keccak_sponge_lookup_selector: None, } } } From c3bef8e6be1eda2948ffb80234e56527ed9cde8b Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 19 Oct 2023 19:00:25 +0200 Subject: [PATCH 235/242] include tests using framework for existing keccak witness tests --- kimchi/src/tests/keccak.rs | 94 ++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index a33938a660..95dcb7828e 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -3,28 +3,38 @@ use std::array; use crate::{ circuits::{ constraints::ConstraintSystem, - gate::{CircuitGate, GateType}, + gate::{CircuitGate, CircuitGateResult, GateType}, polynomials::keccak::{ - collapse, compose, decompose, expand, pad, reset, shift, + collapse, compose, decompose, expand, padded_length, reset, shift, witness::extend_keccak_witness, KECCAK_COLS, QUARTERS, }, wires::Wire, }, curve::KimchiCurve, + plonk_sponge::FrSponge, + tests::framework::TestFramework, }; +use ark_ec::{AffineCurve, ProjectiveCurve}; use ark_ff::{Field, PrimeField, Zero}; -use mina_curves::pasta::Pallas; +use mina_curves::pasta::{Fq, Pallas, PallasParameters}; +use mina_poseidon::{ + constants::PlonkSpongeConstantsKimchi, + sponge::{DefaultFqSponge, DefaultFrSponge}, + FqSponge, +}; use num_bigint::BigUint; use o1_utils::{BigUintHelpers, FieldHelpers}; -fn create_test_constraint_system( - bytelength: usize, -) -> ConstraintSystem +type SpongeParams = PlonkSpongeConstantsKimchi; +type PallasBaseSponge = DefaultFqSponge; +type PallasScalarSponge = DefaultFrSponge; + +fn create_test_gates(bytelength: usize) -> Vec> where G::BaseField: PrimeField, { let mut gates = vec![]; - let next_row = CircuitGate::extend_keccak(&mut gates, bytelength); + let next_row = CircuitGate::::extend_keccak(&mut gates, bytelength); // Adding dummy row to avoid out of bounds in squeeze constraints accessing Next row gates.push(CircuitGate { typ: GateType::Zero, @@ -113,18 +123,21 @@ fn print_witness(witness: &[Vec; KECCAK_COLS], round: usize) { } // Sets up test for a given message and desired input bytelength -fn test_keccak(message: BigUint) -> BigUint +fn test_keccak( + message: BigUint, + full: bool, +) -> (CircuitGateResult<()>, BigUint) where G::BaseField: PrimeField, + EFqSponge: Clone + FqSponge, + EFrSponge: FrSponge, { let bytelength = message.to_bytes_be().len(); - let padded_len = { - let mut sized = message.to_bytes_be(); - sized.resize(bytelength - sized.len(), 0); - pad(&sized).len() - }; - let _index = create_test_constraint_system::(padded_len); - let witness = create_keccak_witness::(message); + let padded_len = padded_length(bytelength); + + let gates = create_test_gates::(padded_len); + let witness: [Vec<<::Projective as ProjectiveCurve>::ScalarField>; + KECCAK_COLS] = create_keccak_witness::(message); for r in 1..=24 { print_witness::(&witness, r); @@ -141,8 +154,46 @@ where } println!(); println!(); + let hash = BigUint::from_bytes_be(&hash); + + let runner = if full { + // Create prover index with test framework + Some( + TestFramework::::default() + .gates(gates.clone()) + .setup(), + ) + } else { + None + }; + let cs = if let Some(runner) = runner.as_ref() { + runner.clone().prover_index().cs.clone() + } else { + ConstraintSystem::create(gates.clone()) + .build::() + .unwrap() + }; - BigUint::from_bytes_be(&hash) + // Perform witness verification that everything is ok before invalidation (quick checks) + for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { + let result = + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + if result.is_err() { + return (result, hash); + } + } + + if let Some(runner) = runner.as_ref() { + // Perform full test that everything is ok before invalidation + assert_eq!( + runner + .clone() + .witness(witness.clone()) + .prove_and_verify::(), + Ok(()) + ); + } + (Ok(()), hash) } #[test] @@ -212,9 +263,9 @@ fn test_bitwise_sparse_representation() { #[test] // Tests a random block of 1080 bits fn test_random_block() { - let claim_random = test_keccak::( + let (_,claim_random) = test_keccak::( BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126"), - ); + false); let hash_random = BigUint::from_hex("845e9dd4e22b4917a80c5419a0ddb3eebf5f4f7cc6035d827314a18b718f751f"); assert_eq!(claim_random, hash_random); @@ -223,7 +274,10 @@ fn test_random_block() { #[test] // Test hash of message zero with 1 byte fn test_dummy() { - let claim1 = test_keccak::(BigUint::from_bytes_be(&[0x00])); + let (_, claim1) = test_keccak::( + BigUint::from_bytes_be(&[0x00]), + false, + ); let hash1 = BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); assert_eq!(claim1, hash1); @@ -232,7 +286,7 @@ fn test_dummy() { #[test] // Test hash of message zero with 1 byte fn test_blocks() { - let claim_3blocks = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f")); + let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), false); let hash_3blocks = BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); assert_eq!(claim_3blocks, hash_3blocks); From b267e80bff766744caa093b31dd578f2f5b80f92 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 23 Oct 2023 15:29:14 +0200 Subject: [PATCH 236/242] fix constraint system being built twice --- kimchi/src/tests/keccak.rs | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index 95dcb7828e..2ed4165b3c 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -42,9 +42,7 @@ where coeffs: vec![], }); - ConstraintSystem::create(gates) - .build::() - .unwrap() + gates } fn create_keccak_witness(message: BigUint) -> [Vec; KECCAK_COLS] @@ -155,7 +153,7 @@ where println!(); println!(); let hash = BigUint::from_bytes_be(&hash); - + println!("entering runner"); let runner = if full { // Create prover index with test framework Some( @@ -166,6 +164,7 @@ where } else { None }; + println!("entering constraint system"); let cs = if let Some(runner) = runner.as_ref() { runner.clone().prover_index().cs.clone() } else { @@ -173,7 +172,7 @@ where .build::() .unwrap() }; - + println!("enter constraint system"); // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = @@ -182,7 +181,7 @@ where return (result, hash); } } - + println!("entering prover"); if let Some(runner) = runner.as_ref() { // Perform full test that everything is ok before invalidation assert_eq!( @@ -193,6 +192,7 @@ where Ok(()) ); } + (Ok(()), hash) } @@ -260,29 +260,30 @@ fn test_bitwise_sparse_representation() { } } -#[test] -// Tests a random block of 1080 bits -fn test_random_block() { - let (_,claim_random) = test_keccak::( - BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126"), - false); - let hash_random = - BigUint::from_hex("845e9dd4e22b4917a80c5419a0ddb3eebf5f4f7cc6035d827314a18b718f751f"); - assert_eq!(claim_random, hash_random); -} - #[test] // Test hash of message zero with 1 byte fn test_dummy() { let (_, claim1) = test_keccak::( BigUint::from_bytes_be(&[0x00]), - false, + true, ); let hash1 = BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); assert_eq!(claim1, hash1); } +/* +#[test] +// Tests a random block of 1080 bits +fn test_random_block() { + let (_,claim_random) = test_keccak::( + BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126"), + false); + let hash_random = + BigUint::from_hex("845e9dd4e22b4917a80c5419a0ddb3eebf5f4f7cc6035d827314a18b718f751f"); + assert_eq!(claim_random, hash_random); +} + #[test] // Test hash of message zero with 1 byte fn test_blocks() { @@ -291,3 +292,4 @@ fn test_blocks() { BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); assert_eq!(claim_3blocks, hash_3blocks); } +*/ From 3d4744faefe243b02b532d77d37ee3e7c15dc5a1 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 23 Oct 2023 20:23:05 +0200 Subject: [PATCH 237/242] disable lookup tables --- kimchi/src/circuits/lookup/index.rs | 36 +- kimchi/src/circuits/lookup/lookups.rs | 407 +++++++++++------------ kimchi/src/circuits/lookup/tables/mod.rs | 24 +- kimchi/src/linearization.rs | 8 +- kimchi/src/tests/keccak.rs | 5 +- kimchi/src/verifier_index.rs | 4 +- 6 files changed, 243 insertions(+), 241 deletions(-) diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index e55425ad6b..964c4aeff5 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -45,10 +45,12 @@ pub struct LookupSelectors { pub range_check: Option, /// Foreign field multiplication pattern lookup selector pub ffmul: Option, + /* /// Keccak round pattern lookup selector pub keccak_round: Option, /// Keccak sponge pattern lookup selector pub keccak_sponge: Option, + */ } #[serde_as] @@ -62,10 +64,12 @@ struct LookupSelectorsSerdeAs { pub range_check: Option>>, #[serde_as(as = "Option")] pub ffmul: Option>>, + /* #[serde_as(as = "Option")] pub keccak_round: Option>>, #[serde_as(as = "Option")] pub keccak_sponge: Option>>, + */ } impl serde_with::SerializeAs>>> @@ -80,8 +84,8 @@ impl serde_with::SerializeAs>>> lookup: val.lookup.clone(), range_check: val.range_check.clone(), ffmul: val.ffmul.clone(), - keccak_round: val.keccak_round.clone(), - keccak_sponge: val.keccak_sponge.clone(), + //keccak_round: val.keccak_round.clone(), + //keccak_sponge: val.keccak_sponge.clone(), }; repr.serialize(serializer) } @@ -99,16 +103,16 @@ impl<'de, F: FftField> serde_with::DeserializeAs<'de, LookupSelectors> lookup, range_check, ffmul, - keccak_round, - keccak_sponge, + //keccak_round, + //keccak_sponge, } = LookupSelectorsSerdeAs::deserialize(deserializer)?; Ok(LookupSelectors { xor, lookup, range_check, ffmul, - keccak_round, - keccak_sponge, + //keccak_round, + //keccak_sponge, }) } } @@ -122,8 +126,8 @@ impl std::ops::Index for LookupSelectors { LookupPattern::Lookup => &self.lookup, LookupPattern::RangeCheck => &self.range_check, LookupPattern::ForeignFieldMul => &self.ffmul, - LookupPattern::KeccakRound => &self.keccak_round, - LookupPattern::KeccakSponge => &self.keccak_sponge, + //LookupPattern::KeccakRound => &self.keccak_round, + //LookupPattern::KeccakSponge => &self.keccak_sponge, } } } @@ -135,8 +139,8 @@ impl std::ops::IndexMut for LookupSelectors { LookupPattern::Lookup => &mut self.lookup, LookupPattern::RangeCheck => &mut self.range_check, LookupPattern::ForeignFieldMul => &mut self.ffmul, - LookupPattern::KeccakRound => &mut self.keccak_round, - LookupPattern::KeccakSponge => &mut self.keccak_sponge, + //LookupPattern::KeccakRound => &mut self.keccak_round, + //LookupPattern::KeccakSponge => &mut self.keccak_sponge, } } } @@ -148,8 +152,8 @@ impl LookupSelectors { lookup, range_check, ffmul, - keccak_round, - keccak_sponge, + //keccak_round, + //keccak_sponge, } = self; // This closure isn't really redundant -- it shields the parameter from a copy -- but // clippy isn't smart enough to figure that out.. @@ -160,8 +164,8 @@ impl LookupSelectors { lookup: lookup.map(f), range_check: range_check.map(f), ffmul: ffmul.map(f), - keccak_round: keccak_round.map(f), - keccak_sponge: keccak_sponge.map(f), + //keccak_round: keccak_round.map(f), + //keccak_sponge: keccak_sponge.map(f), } } @@ -171,8 +175,8 @@ impl LookupSelectors { lookup: self.lookup.as_ref(), range_check: self.range_check.as_ref(), ffmul: self.ffmul.as_ref(), - keccak_round: self.keccak_round.as_ref(), - keccak_sponge: self.keccak_sponge.as_ref(), + //keccak_round: self.keccak_round.as_ref(), + //keccak_sponge: self.keccak_sponge.as_ref(), } } } diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 770aa347cf..a9445cfb18 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -50,8 +50,8 @@ pub struct LookupPatterns { pub lookup: bool, pub range_check: bool, pub foreign_field_mul: bool, - pub keccak_round: bool, - pub keccak_sponge: bool, + //pub keccak_round: bool, + //pub keccak_sponge: bool, } impl IntoIterator for LookupPatterns { @@ -65,8 +65,8 @@ impl IntoIterator for LookupPatterns { lookup, range_check, foreign_field_mul, - keccak_round, - keccak_sponge, + //keccak_round, + //keccak_sponge, } = self; let mut patterns = Vec::with_capacity(5); @@ -83,12 +83,12 @@ impl IntoIterator for LookupPatterns { if foreign_field_mul { patterns.push(LookupPattern::ForeignFieldMul) } - if keccak_round { + /*if keccak_round { patterns.push(LookupPattern::KeccakRound); } if keccak_sponge { patterns.push(LookupPattern::KeccakSponge) - } + }*/ patterns.into_iter() } } @@ -102,8 +102,8 @@ impl std::ops::Index for LookupPatterns { LookupPattern::Lookup => &self.lookup, LookupPattern::RangeCheck => &self.range_check, LookupPattern::ForeignFieldMul => &self.foreign_field_mul, - LookupPattern::KeccakRound => &self.keccak_round, - LookupPattern::KeccakSponge => &self.keccak_sponge, + //LookupPattern::KeccakRound => &self.keccak_round, + //LookupPattern::KeccakSponge => &self.keccak_sponge, } } } @@ -115,8 +115,8 @@ impl std::ops::IndexMut for LookupPatterns { LookupPattern::Lookup => &mut self.lookup, LookupPattern::RangeCheck => &mut self.range_check, LookupPattern::ForeignFieldMul => &mut self.foreign_field_mul, - LookupPattern::KeccakRound => &mut self.keccak_round, - LookupPattern::KeccakSponge => &mut self.keccak_sponge, + //LookupPattern::KeccakRound => &mut self.keccak_round, + //LookupPattern::KeccakSponge => &mut self.keccak_sponge, } } } @@ -409,16 +409,16 @@ pub enum LookupPattern { Lookup, RangeCheck, ForeignFieldMul, - KeccakRound, - KeccakSponge, + //KeccakRound, + //KeccakSponge, } impl LookupPattern { /// Returns the maximum number of lookups per row that are used by the pattern. pub fn max_lookups_per_row(&self) -> usize { match self { - LookupPattern::KeccakRound => 1760, - LookupPattern::KeccakSponge => 800, + //LookupPattern::KeccakRound => 1760, + //LookupPattern::KeccakSponge => 800, LookupPattern::Xor | LookupPattern::RangeCheck | LookupPattern::ForeignFieldMul => 4, LookupPattern::Lookup => 3, } @@ -428,7 +428,7 @@ impl LookupPattern { pub fn max_joint_size(&self) -> u32 { match self { LookupPattern::Xor => 3, - LookupPattern::Lookup | LookupPattern::KeccakRound | LookupPattern::KeccakSponge => 2, + LookupPattern::Lookup /*| LookupPattern::KeccakRound | LookupPattern::KeccakSponge*/ => 2, LookupPattern::ForeignFieldMul | LookupPattern::RangeCheck => 1, } } @@ -516,189 +516,188 @@ impl LookupPattern { } }) .collect() - } - LookupPattern::KeccakRound => { - let mut lookups = - Vec::with_capacity(LookupPattern::KeccakRound.max_lookups_per_row()); - let l = |loc: LocalPosition| SingleLookup { - value: vec![(F::one(), loc)], - }; - // Theta - for i in 0..20 { - // 2-column lookups - let shift0_c = curr_row(120 + i); - let dense_c = curr_row(200 + i); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(RESET_TABLE_ID), - entry: vec![l(dense_c), l(shift0_c)], - }); - let dense_rot_c = curr_row(280 + i); - let expand_rot_c = curr_row(300 + i); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(RESET_TABLE_ID), - entry: vec![l(dense_rot_c), l(expand_rot_c)], - }); - - // Second column lookups - let shift1_c = curr_row(140 + i); - let shift2_c = curr_row(160 + i); - let shift3_c = curr_row(180 + i); - - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift1_c)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift2_c)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift3_c)], - }); - - // First column lookups - let quotient_c = curr_row(220 + i); - let remainder_c = curr_row(240 + i); - let bound_c = curr_row(260 + i); - - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(quotient_c)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(remainder_c)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(bound_c)], - }); - } - // PiRho - for i in 0..100 { - // 2-column lookups - let shift0_e = curr_row(440 + i); - let dense_e = curr_row(840 + i); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(RESET_TABLE_ID), - entry: vec![l(dense_e), l(shift0_e)], - }); - let dense_rot_e = curr_row(1240 + i); - let expand_rot_e = curr_row(1340 + i); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(dense_rot_e), l(expand_rot_e)], - }); - - // Second column lookups - let shift1_e = curr_row(540 + i); - let shift2_e = curr_row(640 + i); - let shift3_e = curr_row(740 + i); - - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift1_e)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift2_e)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift3_e)], - }); - - // First column lookups - let quotient_e = curr_row(940 + i); - let remainder_e = curr_row(1040 + i); - let bound_e = curr_row(1140 + i); - - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(quotient_e)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(remainder_e)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(bound_e)], - }); - } - // Chi - for i in 0..400 { - // Second column lookups - let shift_b: LocalPosition = curr_row(1540 + i); - let shift_sum = curr_row(1940 + i); - - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift_b)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift_sum)], - }); - } - lookups - } - LookupPattern::KeccakSponge => { - let mut lookups = - Vec::with_capacity(LookupPattern::KeccakSponge.max_lookups_per_row()); - let l = |loc: LocalPosition| SingleLookup { - value: vec![(F::one(), loc)], - }; - for i in 0..100 { - let shift1 = curr_row(500 + i); - let shift2 = curr_row(600 + i); - let shift3 = curr_row(700 + i); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift1)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift2)], - }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(SPARSE_TABLE_ID), - entry: vec![l(shift3)], - }); - for b in 0..2 { - let byte = curr_row(200 + 2 * i + b); - // byte < 12 bits - lookups.push(JointLookup { - table_id: LookupTableID::Constant(RANGE_CHECK_TABLE_ID), - entry: vec![SingleLookup { - value: vec![(F::one(), byte)], - }], - }); - // byte * 2^4 < 12 bits - lookups.push(JointLookup { - table_id: LookupTableID::Constant(RANGE_CHECK_TABLE_ID), - entry: vec![SingleLookup { - value: vec![(F::from(2u64).pow([4u64]), byte)], - }], - }); - } - let byte1 = curr_row(200 + 2 * i); - let byte2 = curr_row(201 + 2 * i); - let shift0 = curr_row(400 + i); - // dense := byte1 + byte2 * 2^8 and dense used for first column of RESET table - lookups.push(JointLookup { - table_id: LookupTableID::Constant(RESET_TABLE_ID), - entry: vec![ - SingleLookup { - value: vec![(F::from(256u32), byte2), (F::one(), byte1)], - }, - l(shift0), - ], - }); - } - lookups - } + } /*LookupPattern::KeccakRound => { + let mut lookups = + Vec::with_capacity(LookupPattern::KeccakRound.max_lookups_per_row()); + let l = |loc: LocalPosition| SingleLookup { + value: vec![(F::one(), loc)], + }; + // Theta + for i in 0..20 { + // 2-column lookups + let shift0_c = curr_row(120 + i); + let dense_c = curr_row(200 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![l(dense_c), l(shift0_c)], + }); + let dense_rot_c = curr_row(280 + i); + let expand_rot_c = curr_row(300 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![l(dense_rot_c), l(expand_rot_c)], + }); + + // Second column lookups + let shift1_c = curr_row(140 + i); + let shift2_c = curr_row(160 + i); + let shift3_c = curr_row(180 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift1_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift2_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift3_c)], + }); + + // First column lookups + let quotient_c = curr_row(220 + i); + let remainder_c = curr_row(240 + i); + let bound_c = curr_row(260 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(quotient_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(remainder_c)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(bound_c)], + }); + } + // PiRho + for i in 0..100 { + // 2-column lookups + let shift0_e = curr_row(440 + i); + let dense_e = curr_row(840 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![l(dense_e), l(shift0_e)], + }); + let dense_rot_e = curr_row(1240 + i); + let expand_rot_e = curr_row(1340 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(dense_rot_e), l(expand_rot_e)], + }); + + // Second column lookups + let shift1_e = curr_row(540 + i); + let shift2_e = curr_row(640 + i); + let shift3_e = curr_row(740 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift1_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift2_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift3_e)], + }); + + // First column lookups + let quotient_e = curr_row(940 + i); + let remainder_e = curr_row(1040 + i); + let bound_e = curr_row(1140 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(quotient_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(remainder_e)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(BITS16_TABLE_ID), + entry: vec![l(bound_e)], + }); + } + // Chi + for i in 0..400 { + // Second column lookups + let shift_b: LocalPosition = curr_row(1540 + i); + let shift_sum = curr_row(1940 + i); + + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift_b)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift_sum)], + }); + } + lookups + } + LookupPattern::KeccakSponge => { + let mut lookups = + Vec::with_capacity(LookupPattern::KeccakSponge.max_lookups_per_row()); + let l = |loc: LocalPosition| SingleLookup { + value: vec![(F::one(), loc)], + }; + for i in 0..100 { + let shift1 = curr_row(500 + i); + let shift2 = curr_row(600 + i); + let shift3 = curr_row(700 + i); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift1)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift2)], + }); + lookups.push(JointLookup { + table_id: LookupTableID::Constant(SPARSE_TABLE_ID), + entry: vec![l(shift3)], + }); + for b in 0..2 { + let byte = curr_row(200 + 2 * i + b); + // byte < 12 bits + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RANGE_CHECK_TABLE_ID), + entry: vec![SingleLookup { + value: vec![(F::one(), byte)], + }], + }); + // byte * 2^4 < 12 bits + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RANGE_CHECK_TABLE_ID), + entry: vec![SingleLookup { + value: vec![(F::from(2u64).pow([4u64]), byte)], + }], + }); + } + let byte1 = curr_row(200 + 2 * i); + let byte2 = curr_row(201 + 2 * i); + let shift0 = curr_row(400 + i); + // dense := byte1 + byte2 * 2^8 and dense used for first column of RESET table + lookups.push(JointLookup { + table_id: LookupTableID::Constant(RESET_TABLE_ID), + entry: vec![ + SingleLookup { + value: vec![(F::from(256u32), byte2), (F::one(), byte1)], + }, + l(shift0), + ], + }); + } + lookups + }*/ } } @@ -709,7 +708,7 @@ impl LookupPattern { LookupPattern::Lookup => None, LookupPattern::RangeCheck => Some(vec![GateLookupTable::RangeCheck]), LookupPattern::ForeignFieldMul => Some(vec![GateLookupTable::RangeCheck]), - LookupPattern::KeccakRound => Some(vec![ + /*LookupPattern::KeccakRound => Some(vec![ GateLookupTable::Sparse, GateLookupTable::Reset, GateLookupTable::Bits16, @@ -718,7 +717,7 @@ impl LookupPattern { GateLookupTable::Sparse, GateLookupTable::Reset, GateLookupTable::RangeCheck, - ]), + ]),*/ } } @@ -733,8 +732,8 @@ impl LookupPattern { } (ForeignFieldMul, Curr | Next) => Some(LookupPattern::ForeignFieldMul), (Xor16, Curr) => Some(LookupPattern::Xor), - (KeccakRound, Curr) => Some(LookupPattern::KeccakRound), - (KeccakSponge, Curr) => Some(LookupPattern::KeccakSponge), + //(KeccakRound, Curr) => Some(LookupPattern::KeccakRound), + //(KeccakSponge, Curr) => Some(LookupPattern::KeccakSponge), _ => None, } } @@ -748,8 +747,8 @@ impl GateType { LookupPattern::Lookup, LookupPattern::RangeCheck, LookupPattern::ForeignFieldMul, - LookupPattern::KeccakRound, - LookupPattern::KeccakSponge, + //LookupPattern::KeccakRound, + //LookupPattern::KeccakSponge, ] } } diff --git a/kimchi/src/circuits/lookup/tables/mod.rs b/kimchi/src/circuits/lookup/tables/mod.rs index ac259385e7..8e01a3d4fe 100644 --- a/kimchi/src/circuits/lookup/tables/mod.rs +++ b/kimchi/src/circuits/lookup/tables/mod.rs @@ -2,10 +2,10 @@ use ark_ff::{FftField, One, Zero}; use poly_commitment::PolyComm; use serde::{Deserialize, Serialize}; -pub mod bits16; +//pub mod bits16; pub mod range_check; -pub mod reset; -pub mod sparse; +//pub mod reset; +//pub mod sparse; pub mod xor; //~ spec:startcode @@ -31,9 +31,11 @@ pub const RESET_TABLE_ID: i32 = 4; pub enum GateLookupTable { Xor, RangeCheck, - Bits16, - Sparse, - Reset, + /* + Bits16, + Sparse, + Reset, + */ } /// A table of values that can be used for a lookup, along with the ID for the table. @@ -86,9 +88,9 @@ pub fn get_table(table_name: GateLookupTable) -> LookupTable { match table_name { GateLookupTable::Xor => xor::xor_table(), GateLookupTable::RangeCheck => range_check::range_check_table(), - GateLookupTable::Bits16 => bits16::bits16_table(), - GateLookupTable::Sparse => sparse::sparse_table(), - GateLookupTable::Reset => reset::reset_table(), + //GateLookupTable::Bits16 => bits16::bits16_table(), + //GateLookupTable::Sparse => sparse::sparse_table(), + //GateLookupTable::Reset => reset::reset_table(), } } @@ -98,9 +100,9 @@ impl GateLookupTable { match self { GateLookupTable::Xor => xor::TABLE_SIZE, GateLookupTable::RangeCheck => range_check::TABLE_SIZE, - GateLookupTable::Bits16 | GateLookupTable::Reset | GateLookupTable::Sparse => { + /*GateLookupTable::Bits16 | GateLookupTable::Reset | GateLookupTable::Sparse => { sparse::TABLE_SIZE - } + }*/ } } } diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index ca75cb7f3d..51e37a5313 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -230,8 +230,8 @@ pub fn constraints_expr( lookup: true, range_check: true, foreign_field_mul: true, - keccak_round: false, - keccak_sponge: false, + //keccak_round: false, + //keccak_sponge: false, }, uses_runtime_tables: true, joint_lookup_used: true, @@ -305,8 +305,8 @@ pub fn linearization_columns() .unwrap() }; - println!("enter constraint system"); // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = @@ -181,7 +178,7 @@ where return (result, hash); } } - println!("entering prover"); + if let Some(runner) = runner.as_ref() { // Perform full test that everything is ok before invalidation assert_eq!( diff --git a/kimchi/src/verifier_index.rs b/kimchi/src/verifier_index.rs index 0b9982ce5a..501b70be42 100644 --- a/kimchi/src/verifier_index.rs +++ b/kimchi/src/verifier_index.rs @@ -530,8 +530,8 @@ impl, const COLUMNS: usize> lookup, range_check, ffmul, - keccak_round: _, - keccak_sponge: _, + //keccak_round: _, + //keccak_sponge: _, }, }) = lookup_index { From a17a59f39606221c52526cd130387fecd8c1a567 Mon Sep 17 00:00:00 2001 From: querolita Date: Tue, 24 Oct 2023 13:10:44 +0200 Subject: [PATCH 238/242] included test for 1000 hashes in the same circuit --- kimchi/src/tests/keccak.rs | 85 +++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index fe7ed157fa..1ecf546d33 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -5,8 +5,8 @@ use crate::{ constraints::ConstraintSystem, gate::{CircuitGate, CircuitGateResult, GateType}, polynomials::keccak::{ - collapse, compose, decompose, expand, padded_length, reset, shift, - witness::extend_keccak_witness, KECCAK_COLS, QUARTERS, + collapse, compose, decompose, expand, reset, shift, witness::extend_keccak_witness, + KECCAK_COLS, QUARTERS, }, wires::Wire, }, @@ -22,8 +22,12 @@ use mina_poseidon::{ sponge::{DefaultFqSponge, DefaultFrSponge}, FqSponge, }; -use num_bigint::BigUint; +use num_bigint::{BigUint, RandBigInt}; use o1_utils::{BigUintHelpers, FieldHelpers}; +use rand::rngs::StdRng; +use rand_core::SeedableRng; + +use super::framework::TestRunner; type SpongeParams = PlonkSpongeConstantsKimchi; type PallasBaseSponge = DefaultFqSponge; @@ -120,6 +124,65 @@ fn print_witness(witness: &[Vec; KECCAK_COLS], round: usize) { print_matrix(&next[0..100]); } +const RNG_SEED: [u8; 32] = [ + 0, 131, 43, 175, 229, 252, 206, 26, 67, 193, 86, 160, 1, 90, 131, 86, 168, 4, 95, 50, 48, 9, + 192, 13, 250, 215, 172, 130, 24, 164, 162, 221, +]; + +// Sets up test for a given message and desired input bytelength +fn test_keccak_n( + n: usize, + rng: &mut StdRng, +) -> CircuitGateResult<()> +where + G::BaseField: PrimeField, + EFqSponge: Clone + FqSponge, + EFrSponge: FrSponge, +{ + let messages = vec![rng.gen_biguint_below(&BigUint::from(2u32).pow(1080)); n]; + + let mut gates = vec![]; + let mut witness = array::from_fn(|_| vec![G::ScalarField::zero(); 0]); + + for msg in messages { + let next_row = + CircuitGate::::extend_keccak(&mut gates, msg.to_bytes_be().len()); + // Adding dummy row to avoid out of bounds in squeeze constraints accessing Next row + gates.push(CircuitGate { + typ: GateType::Zero, + wires: Wire::for_row(next_row), + coeffs: vec![], + }); + let hash_wit: [Vec<<::Projective as ProjectiveCurve>::ScalarField>; + KECCAK_COLS] = create_keccak_witness::(msg); + for col in 0..KECCAK_COLS { + witness[col].extend(hash_wit[col].iter()); + } + } + + let runner: TestRunner<2344, G> = TestFramework::::default() + .gates(gates.clone()) + .setup(); + let cs = runner.clone().prover_index().cs.clone(); + // Perform witness verification that everything is ok before invalidation (quick checks) + for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { + let result = + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + if result.is_err() { + return result; + } + } + assert_eq!( + runner + .clone() + .witness(witness.clone()) + .prove_and_verify::(), + Ok(()) + ); + + Ok(()) +} + // Sets up test for a given message and desired input bytelength fn test_keccak( message: BigUint, @@ -269,7 +332,6 @@ fn test_dummy() { assert_eq!(claim1, hash1); } -/* #[test] // Tests a random block of 1080 bits fn test_random_block() { @@ -284,9 +346,20 @@ fn test_random_block() { #[test] // Test hash of message zero with 1 byte fn test_blocks() { - let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), false); + let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), true); let hash_3blocks = BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); assert_eq!(claim_3blocks, hash_3blocks); } -*/ + +#[test] +// Test hash of message zero with 1 byte +fn test_1000_hashes() { + assert_eq!( + Ok(()), + test_keccak_n::( + 1000, + &mut StdRng::from_seed(RNG_SEED), + ) + ); +} From 305c9d6c30cfc03c21290dfe23206f657fdcae8f Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 25 Oct 2023 11:01:01 +0200 Subject: [PATCH 239/242] use of stacker for automated stack size augment for keccak full tests --- Cargo.lock | 23 ++++++++++++++++++++ kimchi/Cargo.toml | 1 + kimchi/src/tests/keccak.rs | 44 ++++++++++++++++++++++---------------- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77da43c308..6c7365613e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1264,6 +1264,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "stacker", "strum", "strum_macros", "thiserror", @@ -2050,6 +2051,15 @@ dependencies = [ "syn 0.15.44", ] +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -2449,6 +2459,19 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "libc", + "psm", + "winapi 0.3.9", +] + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/kimchi/Cargo.toml b/kimchi/Cargo.toml index d9415dce18..667b9c232c 100644 --- a/kimchi/Cargo.toml +++ b/kimchi/Cargo.toml @@ -36,6 +36,7 @@ once_cell = "1.10.0" hex = "0.4" strum = "0.24.0" strum_macros = "0.24.0" +stacker = "0.1" # TODO: audit this disjoint-set = "0.0.2" diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index 1ecf546d33..0a992ec7c0 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -323,13 +323,17 @@ fn test_bitwise_sparse_representation() { #[test] // Test hash of message zero with 1 byte fn test_dummy() { - let (_, claim1) = test_keccak::( - BigUint::from_bytes_be(&[0x00]), - true, - ); - let hash1 = - BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); - assert_eq!(claim1, hash1); + stacker::grow(30 * 1024 * 1024, || { + // guaranteed to have at least 30MB of stack + + let (_, claim1) = test_keccak::( + BigUint::from_bytes_be(&[0x00]), + true, + ); + let hash1 = + BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); + assert_eq!(claim1, hash1); + }); } #[test] @@ -346,20 +350,24 @@ fn test_random_block() { #[test] // Test hash of message zero with 1 byte fn test_blocks() { - let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), true); - let hash_3blocks = - BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); - assert_eq!(claim_3blocks, hash_3blocks); + stacker::grow(30 * 1024 * 1024, || { + let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), true); + let hash_3blocks = + BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); + assert_eq!(claim_3blocks, hash_3blocks); + }); } #[test] // Test hash of message zero with 1 byte fn test_1000_hashes() { - assert_eq!( - Ok(()), - test_keccak_n::( - 1000, - &mut StdRng::from_seed(RNG_SEED), - ) - ); + stacker::grow(30 * 1024 * 1024, || { + assert_eq!( + Ok(()), + test_keccak_n::( + 1000, + &mut StdRng::from_seed(RNG_SEED), + ) + ); + }); } From 844ac0f685ac92c5ccc9a2020f28b7f2f1cc1994 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 25 Oct 2023 14:48:03 +0200 Subject: [PATCH 240/242] remove unused tables imports --- kimchi/src/circuits/lookup/lookups.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index a9445cfb18..d8694c19d4 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -4,7 +4,7 @@ use crate::circuits::{ lookup::index::LookupSelectors, lookup::tables::{ combine_table_entry, get_table, GateLookupTable, LookupTable, RANGE_CHECK_TABLE_ID, - SPARSE_TABLE_ID, XOR_TABLE_ID, + XOR_TABLE_ID, }, }; use ark_ff::{Field, One, PrimeField, Zero}; @@ -15,8 +15,6 @@ use std::collections::HashSet; use std::ops::{Mul, Neg}; use strum_macros::EnumIter; -use super::tables::{BITS16_TABLE_ID, RESET_TABLE_ID}; - type Evaluations = E>; //~ Lookups patterns are extremely flexible and can be configured in a number of ways. From 96f40d0a01f2561ca43c933a6154ddb18f5521d6 Mon Sep 17 00:00:00 2001 From: querolita Date: Thu, 26 Oct 2023 16:34:53 +0200 Subject: [PATCH 241/242] replace block of error to ? according to clippy --- kimchi/src/tests/keccak.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index 0a992ec7c0..e99b2ec0d1 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -168,9 +168,7 @@ where for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); - if result.is_err() { - return result; - } + result?; } assert_eq!( runner From 37c12305426cfff38e1e22cac7cc6af80d245ec4 Mon Sep 17 00:00:00 2001 From: querolita Date: Mon, 30 Oct 2023 20:36:04 +0100 Subject: [PATCH 242/242] disable lookups for now after getting them back when merging with master --- book/src/specs/kimchi.md | 2 ++ kimchi/src/plonk_sponge.rs | 6 ++++-- kimchi/src/proof.rs | 25 ++++++++++++++----------- kimchi/src/prover.rs | 4 ++-- kimchi/src/tests/keccak.rs | 12 ++++++------ kimchi/src/verifier.rs | 7 ++++--- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 7180405f1d..cffb7b02aa 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -2055,10 +2055,12 @@ pub struct ProofEvaluations { pub range_check_lookup_selector: Option, /// evaluation of the ForeignFieldMul range check pattern selector polynomial pub foreign_field_mul_lookup_selector: Option, + /* /// evaluation of the KeccakRound pattern selector polynomial pub keccak_round_lookup_selector: Option, /// evaluation of the KeccakSponge pattern selector polynomial pub keccak_sponge_lookup_selector: Option, + */ } /// Commitments linked to the lookup feature diff --git a/kimchi/src/plonk_sponge.rs b/kimchi/src/plonk_sponge.rs index 59f9ccf15f..0df42f38cb 100644 --- a/kimchi/src/plonk_sponge.rs +++ b/kimchi/src/plonk_sponge.rs @@ -89,8 +89,8 @@ impl FrSponge for DefaultFrSp lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, - keccak_round_lookup_selector, - keccak_sponge_lookup_selector, + //keccak_round_lookup_selector, + //keccak_sponge_lookup_selector, } = e; let mut points = vec![ @@ -162,12 +162,14 @@ impl FrSponge for DefaultFrSp { points.push(foreign_field_mul_lookup_selector) } + /* if let Some(keccak_round_lookup_selector) = keccak_round_lookup_selector.as_ref() { points.push(keccak_round_lookup_selector) } if let Some(keccak_sponge_lookup_selector) = keccak_sponge_lookup_selector.as_ref() { points.push(keccak_sponge_lookup_selector) } + */ points.into_iter().for_each(|p| { self.sponge.absorb(&p.zeta); diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index 9a67281b82..be4c6f019a 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -108,10 +108,12 @@ pub struct ProofEvaluations { pub range_check_lookup_selector: Option, /// evaluation of the ForeignFieldMul range check pattern selector polynomial pub foreign_field_mul_lookup_selector: Option, + /* /// evaluation of the KeccakRound pattern selector polynomial pub keccak_round_lookup_selector: Option, /// evaluation of the KeccakSponge pattern selector polynomial pub keccak_sponge_lookup_selector: Option, + */ } /// Commitments linked to the lookup feature @@ -234,8 +236,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, - keccak_round_lookup_selector, - keccak_sponge_lookup_selector, + //keccak_round_lookup_selector, + //keccak_sponge_lookup_selector, } = self; ProofEvaluations { public: public.map(f), @@ -266,8 +268,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector: lookup_gate_lookup_selector.map(f), range_check_lookup_selector: range_check_lookup_selector.map(f), foreign_field_mul_lookup_selector: foreign_field_mul_lookup_selector.map(f), - keccak_round_lookup_selector: keccak_round_lookup_selector.map(f), - keccak_sponge_lookup_selector: keccak_sponge_lookup_selector.map(f), + //keccak_round_lookup_selector: keccak_round_lookup_selector.map(f), + //keccak_sponge_lookup_selector: keccak_sponge_lookup_selector.map(f), } } @@ -304,8 +306,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, - keccak_round_lookup_selector, - keccak_sponge_lookup_selector, + //keccak_round_lookup_selector, + //keccak_sponge_lookup_selector, } = self; ProofEvaluations { public: public.as_ref().map(f), @@ -336,8 +338,8 @@ impl ProofEvaluations { lookup_gate_lookup_selector: lookup_gate_lookup_selector.as_ref().map(f), range_check_lookup_selector: range_check_lookup_selector.as_ref().map(f), foreign_field_mul_lookup_selector: foreign_field_mul_lookup_selector.as_ref().map(f), - keccak_round_lookup_selector: keccak_round_lookup_selector.as_ref().map(f), - keccak_sponge_lookup_selector: keccak_sponge_lookup_selector.as_ref().map(f), + //keccak_round_lookup_selector: keccak_round_lookup_selector.as_ref().map(f), + //keccak_sponge_lookup_selector: keccak_sponge_lookup_selector.as_ref().map(f), } } } @@ -427,8 +429,8 @@ impl ProofEvaluations, lookup_gate_lookup_selector: None, range_check_lookup_selector: None, foreign_field_mul_lookup_selector: None, - keccak_round_lookup_selector: None, - keccak_sponge_lookup_selector: None, + //keccak_round_lookup_selector: None, + //keccak_sponge_lookup_selector: None, } } } @@ -463,12 +465,13 @@ impl ProofEvaluations { Column::LookupKindIndex(LookupPattern::ForeignFieldMul) => { self.foreign_field_mul_lookup_selector.as_ref() } + /* Column::LookupKindIndex(LookupPattern::KeccakRound) => { self.keccak_round_lookup_selector.as_ref() } Column::LookupKindIndex(LookupPattern::KeccakSponge) => { self.keccak_sponge_lookup_selector.as_ref() - } + }*/ Column::LookupRuntimeSelector => self.runtime_lookup_table_selector.as_ref(), Column::LookupRuntimeTable => self.runtime_lookup_table.as_ref(), Column::Index(GateType::Generic) => Some(&self.generic_selector), diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 38f03c81c5..63d783dff6 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1120,7 +1120,7 @@ where .map(chunked_evals_for_selector) }, ), - keccak_round_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then( + /*keccak_round_lookup_selector: index.cs.lookup_constraint_system.as_ref().and_then( |lcs| { lcs.lookup_selectors .keccak_round @@ -1135,7 +1135,7 @@ where .as_ref() .map(chunked_evals_for_selector) }, - ), + ),*/ }; let zeta_to_srs_len = zeta.pow([index.max_poly_size as u64]); diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index e99b2ec0d1..9f921c583f 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -137,7 +137,7 @@ fn test_keccak_n( where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let messages = vec![rng.gen_biguint_below(&BigUint::from(2u32).pow(1080)); n]; @@ -160,14 +160,14 @@ where } } - let runner: TestRunner<2344, G> = TestFramework::::default() + let runner: TestRunner = TestFramework::::default() .gates(gates.clone()) .setup(); let cs = runner.clone().prover_index().cs.clone(); // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); result?; } assert_eq!( @@ -189,7 +189,7 @@ fn test_keccak( where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let bytelength = message.to_bytes_be().len(); let padded_len = padded_length(bytelength); @@ -217,7 +217,7 @@ where let runner = if full { // Create prover index with test framework Some( - TestFramework::::default() + TestFramework::::default() .gates(gates.clone()) .setup(), ) @@ -234,7 +234,7 @@ where // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return (result, hash); } diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 64f9097e60..97522df4a8 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -668,8 +668,8 @@ where lookup_gate_lookup_selector, range_check_lookup_selector, foreign_field_mul_lookup_selector, - keccak_round_lookup_selector, - keccak_sponge_lookup_selector, + //keccak_round_lookup_selector, + //keccak_sponge_lookup_selector, } = &proof.evals; let check_eval_len = |eval: &PointEvaluations>, str: &'static str| -> Result<()> { @@ -777,6 +777,7 @@ where "foreign field mul lookup selector", )? } + /* if let Some(keccak_round_lookup_selector) = keccak_round_lookup_selector { check_eval_len(keccak_round_lookup_selector, "keccak round lookup selector")? } @@ -785,7 +786,7 @@ where keccak_sponge_lookup_selector, "keccak sponge lookup selector", )? - } + }*/ Ok(()) }