From 805ebb1b0dd9857f02e5ec34e8547462a650a3f2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 8 Jul 2021 15:13:29 +0200 Subject: [PATCH 1/3] Working verifier --- src/circuit_builder.rs | 14 ++++++++------ src/circuit_data.rs | 6 +++--- src/gadgets/arithmetic_extension.rs | 3 +++ src/gadgets/insert.rs | 3 +++ src/gadgets/interpolation.rs | 5 +++++ src/gadgets/rotate.rs | 3 +++ src/gadgets/split_base.rs | 3 +++ src/plonk_common.rs | 4 ++-- src/polynomial/commitment.rs | 2 +- src/prover.rs | 18 ++++++++---------- src/verifier.rs | 13 +++++++++---- 11 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index f1db3ae3..84973cd6 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -392,6 +392,7 @@ impl, const D: usize> CircuitBuilder { /// Builds a "full circuit", with both prover and verifier data. pub fn build(mut self) -> CircuitData { + let quotient_degree = 7; // TODO: add this as a parameter. let start = Instant::now(); info!( "Degree before blinding & padding: {}", @@ -403,7 +404,10 @@ impl, const D: usize> CircuitBuilder { let gates = self.gates.iter().cloned().collect(); let (gate_tree, max_filtered_constraint_degree, num_constants) = Tree::from_gates(gates); - let max_filtered_constraint_degree = max_filtered_constraint_degree.max(3); + assert!( + max_filtered_constraint_degree <= quotient_degree + 1, + "Constraints are too high degree." + ); let prefixed_gates = PrefixedGate::from_tree(gate_tree); let degree_bits = log2_strict(degree); @@ -446,10 +450,8 @@ impl, const D: usize> CircuitBuilder { .max() .expect("No gates?"); - let num_partial_products = num_partial_products( - self.config.num_routed_wires, - max_filtered_constraint_degree - 1, - ); + let num_partial_products = + num_partial_products(self.config.num_routed_wires, quotient_degree); // TODO: This should also include an encoding of gate constraints. let circuit_digest_parts = [ @@ -462,7 +464,7 @@ impl, const D: usize> CircuitBuilder { config: self.config, degree_bits, gates: prefixed_gates, - max_filtered_constraint_degree, + quotient_degree_factor: quotient_degree, num_gate_constraints, num_constants, k_is, diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 4cc60c5d..10c5ffe0 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -145,8 +145,8 @@ pub struct CommonCircuitData, const D: usize> { /// The types of gates used in this circuit, along with their prefixes. pub(crate) gates: Vec>, - /// The maximum degree of a filter times a constraint by any gate. - pub(crate) max_filtered_constraint_degree: usize, + /// The degree of the PLONK quotient polynomial. + pub(crate) quotient_degree_factor: usize, /// The largest number of constraints imposed by any gate. pub(crate) num_gate_constraints: usize, @@ -188,7 +188,7 @@ impl, const D: usize> CommonCircuitData { } pub fn quotient_degree(&self) -> usize { - (self.max_filtered_constraint_degree - 1) * self.degree() + self.quotient_degree_factor * self.degree() } pub fn total_constraints(&self) -> usize { diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 4f7b1e14..3bf9c8a9 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -438,6 +438,7 @@ mod tests { use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; use crate::fri::FriConfig; + use crate::verifier::verify; use crate::witness::PartialWitness; #[test] @@ -461,5 +462,7 @@ mod tests { let data = builder.build(); let proof = data.prove(PartialWitness::new()); + + verify(proof, &data.verifier_only, &data.common).unwrap(); } } diff --git a/src/gadgets/insert.rs b/src/gadgets/insert.rs index 1f69cb24..29e360fc 100644 --- a/src/gadgets/insert.rs +++ b/src/gadgets/insert.rs @@ -78,6 +78,7 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; + use crate::verifier::verify; use crate::witness::PartialWitness; fn real_insert( @@ -113,6 +114,8 @@ mod tests { let data = builder.build(); let proof = data.prove(PartialWitness::new()); + + verify(proof, &data.verifier_only, &data.common).unwrap(); } #[test] diff --git a/src/gadgets/interpolation.rs b/src/gadgets/interpolation.rs index 37746685..8ece6063 100644 --- a/src/gadgets/interpolation.rs +++ b/src/gadgets/interpolation.rs @@ -66,6 +66,7 @@ mod tests { use crate::field::extension_field::FieldExtension; use crate::field::field::Field; use crate::field::interpolation::{interpolant, interpolate}; + use crate::verifier::verify; use crate::witness::PartialWitness; #[test] @@ -103,6 +104,8 @@ mod tests { let data = builder.build(); let proof = data.prove(PartialWitness::new()); + + verify(proof, &data.verifier_only, &data.common).unwrap(); } #[test] @@ -135,5 +138,7 @@ mod tests { let data = builder.build(); let proof = data.prove(PartialWitness::new()); + + verify(proof, &data.verifier_only, &data.common).unwrap(); } } diff --git a/src/gadgets/rotate.rs b/src/gadgets/rotate.rs index bd39a36b..61c1d2cc 100644 --- a/src/gadgets/rotate.rs +++ b/src/gadgets/rotate.rs @@ -118,6 +118,7 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; + use crate::verifier::verify; use crate::witness::PartialWitness; fn real_rotate( @@ -150,6 +151,8 @@ mod tests { let data = builder.build(); let proof = data.prove(PartialWitness::new()); + + verify(proof, &data.verifier_only, &data.common).unwrap(); } #[test] diff --git a/src/gadgets/split_base.rs b/src/gadgets/split_base.rs index 37f88409..a3177a1f 100644 --- a/src/gadgets/split_base.rs +++ b/src/gadgets/split_base.rs @@ -41,6 +41,7 @@ mod tests { use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::field::Field; + use crate::verifier::verify; use crate::witness::PartialWitness; #[test] @@ -67,5 +68,7 @@ mod tests { let data = builder.build(); let proof = data.prove(PartialWitness::new()); + + verify(proof, &data.verifier_only, &data.common).unwrap(); } } diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 2ae5ec01..5179b474 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -73,7 +73,7 @@ pub(crate) fn eval_vanishing_poly, const D: usize>( gammas: &[F], alphas: &[F], ) -> Vec { - let max_degree = common_data.max_filtered_constraint_degree - 1; + let max_degree = common_data.quotient_degree_factor; let (num_prods, final_num_prod) = common_data.num_partial_products; let constraint_terms = @@ -160,7 +160,7 @@ pub(crate) fn eval_vanishing_poly_base, const D: usize>( alphas: &[F], z_h_on_coset: &ZeroPolyOnCoset, ) -> Vec { - let max_degree = common_data.max_filtered_constraint_degree - 1; + let max_degree = common_data.quotient_degree_factor; let (num_prods, final_num_prod) = common_data.num_partial_products; let constraint_terms = diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index b68e8cc2..7298331c 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -331,7 +331,7 @@ mod tests { }, degree_bits: 0, gates: vec![], - max_filtered_constraint_degree: 0, + quotient_degree_factor: 0, num_gate_constraints: 0, num_constants: 4, k_is: vec![F::ONE; 6], diff --git a/src/prover.rs b/src/prover.rs index a6f2ce4d..63c32995 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -80,7 +80,7 @@ pub(crate) fn prove, const D: usize>( let gammas = challenger.get_n_challenges(num_challenges); assert!( - common_data.max_filtered_constraint_degree<=common_data.config.num_routed_wires, + common_data.quotient_degree_factor + 1 <=common_data.config.num_routed_wires, "When the number of routed wires is smaller that the degree, we should change the logic to avoid computing partial products." ); let mut partial_products = timed!( @@ -213,7 +213,7 @@ fn wires_permutation_partial_products, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, ) -> Vec> { - let degree = common_data.max_filtered_constraint_degree - 1; + let degree = common_data.quotient_degree_factor; let subgroup = &prover_data.subgroup; let k_is = &common_data.k_is; let values = subgroup @@ -286,22 +286,21 @@ fn compute_quotient_polys<'a, F: Extendable, const D: usize>( alphas: &[F], ) -> Vec> { let num_challenges = common_data.config.num_challenges; - let max_filtered_constraint_degree_bits = log2_ceil(common_data.max_filtered_constraint_degree); + let max_degree_bits = log2_ceil(common_data.quotient_degree_factor + 1); assert!( - max_filtered_constraint_degree_bits <= common_data.config.rate_bits, + max_degree_bits <= common_data.config.rate_bits, "Having constraints of degree higher than the rate is not supported yet. \ If we need this in the future, we can precompute the larger LDE before computing the `ListPolynomialCommitment`s." ); // We reuse the LDE computed in `ListPolynomialCommitment` and extract every `step` points to get // an LDE matching `max_filtered_constraint_degree`. - let step = 1 << (common_data.config.rate_bits - max_filtered_constraint_degree_bits); + let step = 1 << (common_data.config.rate_bits - max_degree_bits); // When opening the `Z`s polys at the "next" point in Plonk, need to look at the point `next_step` // steps away since we work on an LDE of degree `max_filtered_constraint_degree`. - let next_step = 1 << max_filtered_constraint_degree_bits; + let next_step = 1 << max_degree_bits; - let points = - F::two_adic_subgroup(common_data.degree_bits + max_filtered_constraint_degree_bits); + let points = F::two_adic_subgroup(common_data.degree_bits + max_degree_bits); let lde_size = points.len(); // Retrieve the LDE values at index `i`. @@ -309,8 +308,7 @@ fn compute_quotient_polys<'a, F: Extendable, const D: usize>( comm.get_lde_values(i * step) }; - let z_h_on_coset = - ZeroPolyOnCoset::new(common_data.degree_bits, max_filtered_constraint_degree_bits); + let z_h_on_coset = ZeroPolyOnCoset::new(common_data.degree_bits, max_degree_bits); let quotient_values: Vec> = points .into_par_iter() diff --git a/src/verifier.rs b/src/verifier.rs index 3bfe2dc6..64d4b371 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -2,8 +2,9 @@ use anyhow::{ensure, Result}; use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; use crate::field::extension_field::Extendable; +use crate::field::field::Field; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{eval_vanishing_poly, eval_zero_poly}; +use crate::plonk_common::{eval_vanishing_poly, eval_zero_poly, reduce_with_powers}; use crate::proof::Proof; use crate::vars::EvaluationVars; @@ -57,9 +58,13 @@ pub(crate) fn verify, const D: usize>( // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta. let quotient_polys_zeta = &proof.openings.quotient_polys; - let z_h_zeta = eval_zero_poly(common_data.degree(), zeta); - for i in 0..num_challenges { - ensure!(vanishing_polys_zeta[i] == z_h_zeta * quotient_polys_zeta[i]); + let zeta_pow_deg = zeta.exp_power_of_2(common_data.degree_bits); + let z_h_zeta = zeta_pow_deg - F::Extension::ONE; + for (i, chunk) in quotient_polys_zeta + .chunks(common_data.quotient_degree_factor) + .enumerate() + { + ensure!(vanishing_polys_zeta[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg)); } let evaluations = proof.openings.clone(); From 0512817d6825d60ea4d7e423b9f311041a12f4a9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 8 Jul 2021 15:16:05 +0200 Subject: [PATCH 2/3] quotient_degree -> quotient_degree_factor --- src/circuit_builder.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 84973cd6..c9f35212 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -392,7 +392,7 @@ impl, const D: usize> CircuitBuilder { /// Builds a "full circuit", with both prover and verifier data. pub fn build(mut self) -> CircuitData { - let quotient_degree = 7; // TODO: add this as a parameter. + let quotient_degree_factor = 7; // TODO: add this as a parameter. let start = Instant::now(); info!( "Degree before blinding & padding: {}", @@ -405,7 +405,7 @@ impl, const D: usize> CircuitBuilder { let gates = self.gates.iter().cloned().collect(); let (gate_tree, max_filtered_constraint_degree, num_constants) = Tree::from_gates(gates); assert!( - max_filtered_constraint_degree <= quotient_degree + 1, + max_filtered_constraint_degree <= quotient_degree_factor + 1, "Constraints are too high degree." ); let prefixed_gates = PrefixedGate::from_tree(gate_tree); @@ -451,7 +451,7 @@ impl, const D: usize> CircuitBuilder { .expect("No gates?"); let num_partial_products = - num_partial_products(self.config.num_routed_wires, quotient_degree); + num_partial_products(self.config.num_routed_wires, quotient_degree_factor); // TODO: This should also include an encoding of gate constraints. let circuit_digest_parts = [ @@ -464,7 +464,7 @@ impl, const D: usize> CircuitBuilder { config: self.config, degree_bits, gates: prefixed_gates, - quotient_degree_factor: quotient_degree, + quotient_degree_factor, num_gate_constraints, num_constants, k_is, From 9cd5f82090efe755d77f92e096a4269a5b8d5aed Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 8 Jul 2021 15:21:47 +0200 Subject: [PATCH 3/3] Add verification to scaling gadget --- src/util/scaling.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 3449e0b9..6effc5db 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -174,6 +174,7 @@ mod tests { use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::verifier::verify; use crate::witness::PartialWitness; fn test_reduce_gadget(n: usize) { @@ -205,6 +206,8 @@ mod tests { let data = builder.build(); let proof = data.prove(PartialWitness::new()); + + verify(proof, &data.verifier_only, &data.common).unwrap(); } #[test]