From 3e0ed05b1d6dd105b95dea296d615d5de4c0c64c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1igo=20Querejeta=20Azurmendi?= <31273774+iquerejeta@users.noreply.github.com> Date: Wed, 22 Jan 2025 13:29:52 +0100 Subject: [PATCH] PK size fix (#29) * PK size fix * Nits --- src/plonk/keygen.rs | 42 ++++++++++++++++--------- src/plonk/mod.rs | 26 +++++++--------- src/plonk/permutation.rs | 18 ++++++----- src/plonk/permutation/keygen.rs | 55 ++++++++++++++++++++------------- 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index dcda180d7..ea74ad22d 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -15,8 +15,8 @@ use super::{ permutation, Challenge, Error, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey, }; use crate::circuit::Value; -use crate::poly::batch_invert_rational; use crate::poly::commitment::{Params, PolynomialCommitmentScheme}; +use crate::poly::{batch_invert_rational, ExtendedLagrangeCoeff}; use crate::utils::rational::Rational; use crate::{poly::EvaluationDomain, utils::arithmetic::parallelize}; @@ -395,6 +395,30 @@ where .permutation .build_pk::(&vk.domain, &cs.permutation); + let [l0, l_last, l_active_row] = compute_lagrange_polys(&vk, &cs); + // Compute the optimized evaluation data structure + let ev = Evaluator::new(&vk.cs); + Ok(ProvingKey { + vk, + l0, + l_last, + l_active_row, + fixed_values: fixed, + fixed_polys, + fixed_cosets, + permutation: permutation_pk, + ev, + }) +} + +pub(crate) fn compute_lagrange_polys( + vk: &VerifyingKey, + cs: &ConstraintSystem, +) -> [Polynomial; 3] +where + F: WithSmallOrderMulGroup<3>, + CS: PolynomialCommitmentScheme, +{ // Compute l_0(X) // TODO: this can be done more efficiently let mut l0 = vk.domain.empty_lagrange(); @@ -414,6 +438,7 @@ where // Compute l_last(X) which evaluates to 1 on the first inactive row (just // before the blinding factors) and 0 otherwise over the domain let mut l_last = vk.domain.empty_lagrange(); + let n = vk.domain.n as usize; l_last[n - cs.blinding_factors() - 1] = F::ONE; let l_last = vk.domain.lagrange_to_coeff(l_last); let l_last = vk.domain.coeff_to_extended(l_last); @@ -428,18 +453,5 @@ where } }); - // Compute the optimized evaluation data structure - let ev = Evaluator::new(&vk.cs); - - Ok(ProvingKey { - vk, - l0, - l_last, - l_active_row, - fixed_values: fixed, - fixed_polys, - fixed_cosets, - permutation: permutation_pk, - ev, - }) + [l0, l_last, l_active_row] } diff --git a/src/plonk/mod.rs b/src/plonk/mod.rs index 46ace58a9..d2a78ae42 100644 --- a/src/plonk/mod.rs +++ b/src/plonk/mod.rs @@ -316,13 +316,9 @@ where /// Gets the total number of bytes in the serialization of `self` fn bytes_length(&self, format: SerdeFormat) -> usize { - let scalar_len = F::default().to_repr().as_ref().len(); self.vk.bytes_length(format) + 12 // bytes used for encoding the length(u32) of "l0", "l_last" & "l_active_row" polys - + scalar_len * (self.l0.len() + self.l_last.len() + self.l_active_row.len()) + polynomial_slice_byte_length(&self.fixed_values) - + polynomial_slice_byte_length(&self.fixed_polys) - + polynomial_slice_byte_length(&self.fixed_cosets) + self.permutation.bytes_length() } } @@ -343,12 +339,7 @@ where /// Does so by first writing the verifying key and then serializing the rest of the data (in the form of field polynomials) pub fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { self.vk.write(writer, format)?; - self.l0.write(writer)?; - self.l_last.write(writer)?; - self.l_active_row.write(writer)?; write_polynomial_slice(&self.fixed_values, writer)?; - write_polynomial_slice(&self.fixed_polys, writer)?; - write_polynomial_slice(&self.fixed_cosets, writer)?; self.permutation.write(writer)?; Ok(()) } @@ -375,13 +366,18 @@ where #[cfg(feature = "circuit-params")] params, )?; - let l0 = Polynomial::read(reader, format)?; - let l_last = Polynomial::read(reader, format)?; - let l_active_row = Polynomial::read(reader, format)?; + let [l0, l_last, l_active_row] = compute_lagrange_polys(&vk, &vk.cs); let fixed_values = read_polynomial_vec(reader, format)?; - let fixed_polys = read_polynomial_vec(reader, format)?; - let fixed_cosets = read_polynomial_vec(reader, format)?; - let permutation = permutation::ProvingKey::read(reader, format)?; + let fixed_polys: Vec<_> = fixed_values + .iter() + .map(|poly| vk.domain.lagrange_to_coeff(poly.clone())) + .collect(); + let fixed_cosets = fixed_polys + .iter() + .map(|poly| vk.domain.coeff_to_extended(poly.clone())) + .collect(); + let permutation = + permutation::ProvingKey::read(reader, format, &vk.domain, &vk.cs.permutation)?; let ev = Evaluator::new(vk.cs()); Ok(Self { vk, diff --git a/src/plonk/permutation.rs b/src/plonk/permutation.rs index 3dc79ac98..fb3f0bd3c 100644 --- a/src/plonk/permutation.rs +++ b/src/plonk/permutation.rs @@ -13,9 +13,11 @@ pub(crate) mod verifier; pub use keygen::Assembly; +use crate::plonk::permutation::keygen::compute_polys_and_cosets; use crate::poly::commitment::PolynomialCommitmentScheme; +use crate::poly::EvaluationDomain; use crate::utils::helpers::{byte_length, ProcessedSerdeObject}; -use ff::PrimeField; +use ff::{PrimeField, WithSmallOrderMulGroup}; use halo2curves::serde::SerdeObject; use std::io; @@ -133,12 +135,16 @@ pub(crate) struct ProvingKey { pub(super) cosets: Vec>, } -impl ProvingKey { +impl + SerdeObject> ProvingKey { /// Reads proving key for a single permutation argument from buffer using `Polynomial::read`. - pub(super) fn read(reader: &mut R, format: SerdeFormat) -> io::Result { + pub(super) fn read( + reader: &mut R, + format: SerdeFormat, + domain: &EvaluationDomain, + p: &Argument, + ) -> io::Result { let permutations = read_polynomial_vec(reader, format)?; - let polys = read_polynomial_vec(reader, format)?; - let cosets = read_polynomial_vec(reader, format)?; + let (polys, cosets) = compute_polys_and_cosets::(domain, p, &permutations); Ok(ProvingKey { permutations, polys, @@ -149,8 +155,6 @@ impl ProvingKey { /// Writes proving key for a single permutation argument to buffer using `Polynomial::write`. pub(super) fn write(&self, writer: &mut W) -> io::Result<()> { write_polynomial_slice(&self.permutations, writer)?; - write_polynomial_slice(&self.polys, writer)?; - write_polynomial_slice(&self.cosets, writer)?; Ok(()) } } diff --git a/src/plonk/permutation/keygen.rs b/src/plonk/permutation/keygen.rs index c378eb074..8420b47fd 100644 --- a/src/plonk/permutation/keygen.rs +++ b/src/plonk/permutation/keygen.rs @@ -17,6 +17,7 @@ use { use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use crate::poly::commitment::PolynomialCommitmentScheme; +use crate::poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial}; use rayon::iter::IntoParallelRefMutIterator; #[cfg(feature = "thread-safe-region")] use std::collections::{BTreeSet, HashMap}; @@ -372,27 +373,7 @@ pub(crate) fn build_pk>( }); } - let mut polys = vec![domain.empty_coeff(); p.columns.len()]; - { - parallelize(&mut polys, |o, start| { - o.par_iter_mut().enumerate().for_each(|(x, poly)| { - let i = start + x; - let permutation_poly = permutations[i].clone(); - *poly = domain.lagrange_to_coeff(permutation_poly); - }) - }); - } - - let mut cosets = vec![domain.empty_extended(); p.columns.len()]; - { - parallelize(&mut cosets, |o, start| { - o.par_iter_mut().enumerate().for_each(|(x, coset)| { - let i = start + x; - let poly = polys[i].clone(); - *coset = domain.coeff_to_extended(poly); - }) - }); - } + let (polys, cosets) = compute_polys_and_cosets::(domain, p, &permutations); ProvingKey { permutations, @@ -458,3 +439,35 @@ pub(crate) fn build_vk, CS: PolynomialCommitmentSch VerifyingKey { commitments } } + +#[allow(clippy::type_complexity)] +pub(crate) fn compute_polys_and_cosets>( + domain: &EvaluationDomain, + p: &Argument, + permutations: &[Polynomial], +) -> ( + Vec>, + Vec>, +) { + let mut polys = vec![domain.empty_coeff(); p.columns.len()]; + { + parallelize(&mut polys, |o, start| { + for (x, poly) in o.iter_mut().enumerate() { + let i = start + x; + let permutation_poly = permutations[i].clone(); + *poly = domain.lagrange_to_coeff(permutation_poly); + } + }); + } + let mut cosets = vec![domain.empty_extended(); p.columns.len()]; + { + parallelize(&mut cosets, |o, start| { + for (x, coset) in o.iter_mut().enumerate() { + let i = start + x; + let poly = polys[i].clone(); + *coset = domain.coeff_to_extended(poly); + } + }); + } + (polys, cosets) +}