Skip to content

Commit

Permalink
Reduce size of proving keys and verifying keys (#6)
Browse files Browse the repository at this point in the history
* plonk/keygen: add function to compute l polys

* plonk/permutation/keygen: add function to compute polys and cosets

* plonk: improve size of serialized prover keys

Co-authored-by: Iñigo Querejeta Azurmendi <31273774+iquerejeta@users.noreply.github.com>

* plonk/keygen: disable complex selectors

---------

Co-authored-by: Iñigo Querejeta Azurmendi <31273774+iquerejeta@users.noreply.github.com>
  • Loading branch information
miguel-ambrona and iquerejeta committed May 8, 2024
1 parent 8714940 commit 0087735
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 63 deletions.
27 changes: 12 additions & 15 deletions halo2_proofs/src/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,13 +346,9 @@ where
where
C: SerdeCurveAffine,
{
let scalar_len = C::Scalar::default().to_repr().as_ref().len();
self.vk.bytes_length(format)
+ 12
+ 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()
}
}
Expand All @@ -373,12 +369,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<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
self.vk.write(writer, format)?;
self.l0.write(writer, format)?;
self.l_last.write(writer, format)?;
self.l_active_row.write(writer, format)?;
write_polynomial_slice(&self.fixed_values, writer, format)?;
write_polynomial_slice(&self.fixed_polys, writer, format)?;
write_polynomial_slice(&self.fixed_cosets, writer, format)?;
self.permutation.write(writer, format)?;
Ok(())
}
Expand All @@ -405,13 +396,19 @@ 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,
Expand Down
57 changes: 39 additions & 18 deletions halo2_proofs/src/plonk/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
poly::{
batch_invert_assigned,
commitment::{Blind, Params, MSM},
EvaluationDomain,
EvaluationDomain, ExtendedLagrangeCoeff,
},
};

Expand Down Expand Up @@ -207,7 +207,16 @@ where
ConcreteCircuit: Circuit<C::Scalar>,
C::Scalar: FromUniformBytes<64>,
{
keygen_vk_custom(params, circuit, true)
// We disable "complex selectors" for now, because they are not properly
// serialized. At the moment, they are stored as boolean vectors containing
// their value on every single row. This makes the verification key size
// linear when they are enabled.
// Furthermore, having complex selectors makes the cs structure variable
// depending on the selector instantiation. This is undesirable.
// In the future, if we want to enjoy the benefits of complex selectors
// (about a 10-20% improvement in proof size and verifying key payload size)
// we need to improve their serialization.
keygen_vk_custom(params, circuit, false)
}

/// Generate a `VerifyingKey` from an instance of `Circuit`.
Expand Down Expand Up @@ -350,6 +359,31 @@ where
.permutation
.build_pk(params, &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<C>(
vk: &VerifyingKey<C>,
cs: &ConstraintSystem<C::Scalar>,
) -> [Polynomial<C::Scalar, ExtendedLagrangeCoeff>; 3]
where
C: CurveAffine,
{
// Compute l_0(X)
// TODO: this can be done more efficiently
let mut l0 = vk.domain.empty_lagrange();
Expand All @@ -369,7 +403,8 @@ 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();
l_last[params.n() as usize - cs.blinding_factors() - 1] = C::Scalar::ONE;
let n = l_last.len();
l_last[n - cs.blinding_factors() - 1] = C::Scalar::ONE;
let l_last = vk.domain.lagrange_to_coeff(l_last);
let l_last = vk.domain.coeff_to_extended(l_last);

Expand All @@ -382,19 +417,5 @@ where
*value = one - (l_last[idx] + l_blind[idx]);
}
});

// 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]
}
18 changes: 10 additions & 8 deletions halo2_proofs/src/plonk/permutation.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! Implementation of permutation argument.

use self::keygen::compute_polys_and_cosets;

use super::circuit::{Any, Column};
use crate::{
arithmetic::CurveAffine,
helpers::{
polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice,
SerdeCurveAffine, SerdePrimeField,
},
poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial},
poly::{Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial},
SerdeFormat,
};
use ff::PrimeField;
Expand Down Expand Up @@ -139,10 +141,14 @@ where
C::Scalar: SerdePrimeField,
{
/// Reads proving key for a single permutation argument from buffer using `Polynomial::read`.
pub(super) fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self> {
pub(super) fn read<R: io::Read>(
reader: &mut R,
format: SerdeFormat,
domain: &EvaluationDomain<C::Scalar>,
p: &Argument,
) -> io::Result<Self> {
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::<C>(domain, p, &permutations);
Ok(ProvingKey {
permutations,
polys,
Expand All @@ -157,8 +163,6 @@ where
format: SerdeFormat,
) -> io::Result<()> {
write_polynomial_slice(&self.permutations, writer, format)?;
write_polynomial_slice(&self.polys, writer, format)?;
write_polynomial_slice(&self.cosets, writer, format)?;
Ok(())
}
}
Expand All @@ -167,7 +171,5 @@ impl<C: CurveAffine> ProvingKey<C> {
/// Gets the total number of bytes in the serialization of `self`
pub(super) fn bytes_length(&self) -> usize {
polynomial_slice_byte_length(&self.permutations)
+ polynomial_slice_byte_length(&self.polys)
+ polynomial_slice_byte_length(&self.cosets)
}
}
57 changes: 35 additions & 22 deletions halo2_proofs/src/plonk/permutation/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
plonk::{Any, Column, Error},
poly::{
commitment::{Blind, CommitmentScheme, Params},
EvaluationDomain,
Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial,
},
};

Expand Down Expand Up @@ -211,27 +211,7 @@ impl Assembly {
});
}

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);
}
});
}
let (polys, cosets) = compute_polys_and_cosets::<C>(domain, p, &permutations);

ProvingKey {
permutations,
Expand All @@ -250,3 +230,36 @@ impl Assembly {
&self.mapping
}
}

#[allow(clippy::type_complexity)]
pub(crate) fn compute_polys_and_cosets<C: CurveAffine>(
domain: &EvaluationDomain<C::Scalar>,
p: &Argument,
permutations: &[Polynomial<C::Scalar, LagrangeCoeff>],
) -> (
Vec<Polynomial<C::Scalar, Coeff>>,
Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
) {
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)
}

0 comments on commit 0087735

Please sign in to comment.