From 50cafca70543c645dcaf0fa7475c3bb622953430 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 6 Jul 2021 10:51:32 +0200 Subject: [PATCH] Partial products of quotient --- src/circuit_builder.rs | 6 ++- src/plonk_common.rs | 90 +++++++++++++++--------------------- src/prover.rs | 52 +++++++-------------- src/util/partial_products.rs | 21 ++++++--- 4 files changed, 74 insertions(+), 95 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index eca0f205..a28d5121 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -439,8 +439,10 @@ 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); + let num_partial_products = num_partial_products( + self.config.num_routed_wires, + max_filtered_constraint_degree - 1, + ); // TODO: This should also include an encoding of gate constraints. let circuit_digest_parts = [ diff --git a/src/plonk_common.rs b/src/plonk_common.rs index baaf8fc5..2da30fcd 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; + let max_degree = common_data.max_filtered_constraint_degree - 1; let (num_prods, final_num_prod) = common_data.num_partial_products; let constraint_terms = @@ -106,38 +106,29 @@ pub(crate) fn eval_vanishing_poly, const D: usize>( wire_value + s_sigma * betas[i].into() + gammas[i].into() }) .collect::>(); + let quotient_values = (0..common_data.config.num_routed_wires) + .map(|j| numerator_values[j] / denominator_values[j]) + .collect::>(); // The partial products considered for this iteration of `i`. - let current_partial_products = - &partial_products[2 * i * num_prods..(2 * i + 2) * num_prods]; - // The partial products for the numerator are in the first `num_prods` elements. - let numerator_partial_products = ¤t_partial_products[..num_prods]; - // The partial products for the denominator are in the last `num_prods` elements. - let denominator_partial_products = ¤t_partial_products[num_prods..]; + let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; // Check the numerator partial products. - vanishing_partial_products_terms.extend(check_partial_products( - &numerator_values, - numerator_partial_products, - max_degree, - )); - // Check the denominator partial products. - vanishing_partial_products_terms.extend(check_partial_products( - &denominator_values, - denominator_partial_products, - max_degree, - )); + let mut partial_product_check = + check_partial_products("ient_values, current_partial_products, max_degree); + denominator_values + .chunks(max_degree - 1) + .zip(partial_product_check.iter_mut()) + .for_each(|(d, q)| { + *q *= d.iter().copied().product(); + }); + vanishing_partial_products_terms.extend(partial_product_check); // The numerator final product is the product of the last `final_num_prod` elements. - let f_prime: F::Extension = numerator_partial_products[num_prods - final_num_prod..] + let quotient: F::Extension = current_partial_products[num_prods - final_num_prod..] .iter() .copied() .product(); - // The denominator final product is the product of the last `final_num_prod` elements. - let g_prime: F::Extension = denominator_partial_products[num_prods - final_num_prod..] - .iter() - .copied() - .product(); - vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz); + vanishing_v_shift_terms.push(quotient * z_x - z_gz); } let vanishing_terms = [ @@ -167,7 +158,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; + let max_degree = common_data.max_filtered_constraint_degree - 1; let (num_prods, final_num_prod) = common_data.num_partial_products; let constraint_terms = @@ -200,44 +191,39 @@ pub(crate) fn eval_vanishing_poly_base, const D: usize>( wire_value + betas[i] * s_sigma + gammas[i] }) .collect::>(); + let quotient_values = (0..common_data.config.num_routed_wires) + .map(|j| numerator_values[j] / denominator_values[j]) + .collect::>(); // The partial products considered for this iteration of `i`. - let current_partial_products = - &partial_products[2 * i * num_prods..(2 * i + 2) * num_prods]; - // The partial products for the numerator are in the first `num_prods` elements. - let numerator_partial_products = ¤t_partial_products[..num_prods]; - // The partial products for the denominator are in the last `num_prods` elements. - let denominator_partial_products = ¤t_partial_products[num_prods..]; + let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods]; // Check the numerator partial products. - vanishing_partial_products_terms.extend(check_partial_products( - &numerator_values, - numerator_partial_products, - max_degree, - )); - // Check the denominator partial products. - vanishing_partial_products_terms.extend(check_partial_products( - &denominator_values, - denominator_partial_products, - max_degree, - )); + let mut partial_product_check = + check_partial_products("ient_values, current_partial_products, max_degree); + denominator_values + .chunks(max_degree) + .zip(partial_product_check.iter_mut()) + .for_each(|(d, q)| { + *q *= d.iter().copied().product(); + }); + dbg!( + quotient_values[27], + current_partial_products.last().unwrap() + ); + partial_product_check.pop(); + vanishing_partial_products_terms.extend(partial_product_check); // The numerator final product is the product of the last `final_num_prod` elements. - let f_prime: F = numerator_partial_products[num_prods - final_num_prod..] + let quotient: F = current_partial_products[num_prods - final_num_prod..] .iter() .copied() .product(); - // The denominator final product is the product of the last `final_num_prod` elements. - let g_prime: F = denominator_partial_products[num_prods - final_num_prod..] - .iter() - .copied() - .product(); - vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz); + vanishing_v_shift_terms.push(quotient * z_x - z_gz); } - let vanishing_terms = [ vanishing_z_1_terms, vanishing_partial_products_terms, - vanishing_v_shift_terms, + // vanishing_v_shift_terms, constraint_terms, ] .concat(); diff --git a/src/prover.rs b/src/prover.rs index b19f0360..88cd2b4b 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -93,7 +93,7 @@ pub(crate) fn prove, const D: usize>( // The first two polynomials in `partial_products` represent the final products used in the // computation of `Z`. They aren't needed anymore so we discard them. partial_products.iter_mut().for_each(|part| { - part.drain(0..2); + part.remove(0); }); let zs_partial_products = [plonk_z_vecs, partial_products.concat()].concat(); @@ -204,8 +204,8 @@ fn all_wires_permutation_partial_products, const D: usize>( } /// Compute the partial products used in the `Z` polynomial. -/// Returns the polynomials interpolating `partial_products(f) + partial_products(g)` -/// where `f, g` are the products in the definition of `Z`: `Z(g^i) = n / d`. +/// Returns the polynomials interpolating `partial_products(f / g)` +/// where `f, g` are the products in the definition of `Z`: `Z(g^i) = f / g`. fn wires_permutation_partial_products, const D: usize>( witness: &Witness, beta: F, @@ -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; + let degree = common_data.max_filtered_constraint_degree - 1; let subgroup = &prover_data.subgroup; let k_is = &common_data.k_is; let values = subgroup @@ -221,47 +221,29 @@ fn wires_permutation_partial_products, const D: usize>( .enumerate() .map(|(i, &x)| { let s_sigmas = &prover_data.sigmas[i]; - let numerator_values = (0..common_data.config.num_routed_wires) + let quotient_values = (0..common_data.config.num_routed_wires) .map(|j| { let wire_value = witness.get_wire(i, j); let k_i = k_is[j]; let s_id = k_i * x; - wire_value + beta * s_id + gamma - }) - .collect::>(); - let denominator_values = (0..common_data.config.num_routed_wires) - .map(|j| { - let wire_value = witness.get_wire(i, j); let s_sigma = s_sigmas[j]; - wire_value + beta * s_sigma + gamma + let numerator = wire_value + beta * s_id + gamma; + let denominator = wire_value + beta * s_sigma + gamma; + numerator / denominator }) .collect::>(); - let numerator_partials = partial_products(&numerator_values, degree); - let denominator_partials = partial_products(&denominator_values, degree); + let quotient_partials = partial_products("ient_values, degree); - // This is the final product for the numerator. - let numerator = numerator_partials - [common_data.num_partial_products.0 - common_data.num_partial_products.1..] - .iter() - .copied() - .product(); - // This is the final product for the denominator. - let denominator = denominator_partials + // This is the final product for the quotient. + let quotient = quotient_partials [common_data.num_partial_products.0 - common_data.num_partial_products.1..] .iter() .copied() .product(); - // We add the numerator and denominator at the beginning of the vector to reuse them - // later in the computation of `Z`. - [ - vec![numerator], - vec![denominator], - numerator_partials, - denominator_partials, - ] - .concat() + // We add the quotient at the beginning of the vector to reuse them later in the computation of `Z`. + [vec![quotient], quotient_partials].concat() }) .collect::>(); @@ -287,10 +269,9 @@ fn compute_z, const D: usize>( ) -> PolynomialValues { let mut plonk_z_points = vec![F::ONE]; for i in 1..common_data.degree() { - let numerator = partial_products[0].values[i - 1]; - let denominator = partial_products[1].values[i - 1]; + let quotient = partial_products[0].values[i - 1]; let last = *plonk_z_points.last().unwrap(); - plonk_z_points.push(last * numerator / denominator); + plonk_z_points.push(last * quotient); } plonk_z_points.into() } @@ -332,7 +313,8 @@ fn compute_quotient_polys<'a, F: Extendable, const D: usize>( ZeroPolyOnCoset::new(common_data.degree_bits, max_filtered_constraint_degree_bits); let quotient_values: Vec> = points - .into_par_iter() + // .into_par_iter() + .into_iter() .enumerate() .map(|(i, x)| { let shifted_x = F::coset_shift() * x; diff --git a/src/util/partial_products.rs b/src/util/partial_products.rs index 5c215fde..e9edde2b 100644 --- a/src/util/partial_products.rs +++ b/src/util/partial_products.rs @@ -10,7 +10,7 @@ use crate::util::ceil_div_usize; pub fn partial_products(v: &[T], max_degree: usize) -> Vec { let mut res = Vec::new(); let mut remainder = v.to_vec(); - while remainder.len() >= max_degree { + while remainder.len() > max_degree { let new_partials = remainder .chunks(max_degree) // No need to compute the product if the chunk has size 1. @@ -25,7 +25,10 @@ pub fn partial_products(v: &[T], max_degree: usize) -> Vec }; remainder = new_partials; // If there were a chunk of size 1, add it back to the remainder. - remainder.extend(addendum); + remainder.extend_from_slice(&addendum); + if remainder.len() <= max_degree { + res.extend(addendum); + } } res @@ -36,11 +39,14 @@ pub fn partial_products(v: &[T], max_degree: usize) -> Vec pub fn num_partial_products(n: usize, max_degree: usize) -> (usize, usize) { let mut res = 0; let mut remainder = n; - while remainder >= max_degree { + while remainder > max_degree { let new_partials_len = ceil_div_usize(remainder, max_degree); let addendum = if remainder % max_degree == 1 { 1 } else { 0 }; res += new_partials_len - addendum; remainder = new_partials_len; + if remainder <= max_degree { + res += addendum; + } } (res, remainder) @@ -56,7 +62,7 @@ pub fn check_partial_products>( let mut res = Vec::new(); let mut remainder = v.to_vec(); let mut partials = partials.to_vec(); - while remainder.len() >= max_degree { + while remainder.len() > max_degree { let products = remainder .chunks(max_degree) .filter(|chunk| chunk.len() != 1) @@ -69,7 +75,10 @@ pub fn check_partial_products>( vec![] }; remainder = partials.drain(..products.len()).collect(); - remainder.extend(addendum) + remainder.extend_from_slice(&addendum); + if remainder.len() <= max_degree { + res.extend(addendum.into_iter().map(|a| a - *partials.last().unwrap())); + } } res @@ -85,7 +94,7 @@ mod tests { fn test_partial_products() { let v = vec![1, 2, 3, 4, 5, 6]; let p = partial_products(&v, 2); - assert_eq!(p, vec![2, 12, 30, 24, 720]); + assert_eq!(p, vec![2, 12, 30, 24, 30]); let nums = num_partial_products(v.len(), 2); assert_eq!(p.len(), nums.0); assert!(check_partial_products(&v, &p, 2)