Skip to content

Commit

Permalink
Reimplement keygen_pk for fe-be split as keygen_pk_v2
Browse files Browse the repository at this point in the history
  • Loading branch information
ed255 committed Dec 13, 2023
1 parent eb5d1aa commit d318a9d
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 39 deletions.
16 changes: 16 additions & 0 deletions halo2_proofs/src/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,22 @@ pub struct PinnedVerificationKey<'a, C: CurveAffine> {
fixed_commitments: &'a Vec<C>,
permutation: &'a permutation::VerifyingKey<C>,
}

/// This is a proving key which allows for the creation of proofs for a
/// particular circuit.
#[derive(Clone, Debug)]
pub struct ProvingKeyV2<C: CurveAffine> {
vk: VerifyingKeyV2<C>,

Check warning on line 381 in halo2_proofs/src/plonk.rs

View workflow job for this annotation

GitHub Actions / Clippy (beta)

multiple fields are never read

warning: multiple fields are never read --> halo2_proofs/src/plonk.rs:381:5 | 380 | pub struct ProvingKeyV2<C: CurveAffine> { | ------------ fields in this struct 381 | vk: VerifyingKeyV2<C>, | ^^ 382 | l0: Polynomial<C::Scalar, ExtendedLagrangeCoeff>, | ^^ 383 | l_last: Polynomial<C::Scalar, ExtendedLagrangeCoeff>, | ^^^^^^ 384 | l_active_row: Polynomial<C::Scalar, ExtendedLagrangeCoeff>, | ^^^^^^^^^^^^ 385 | fixed_values: Vec<Polynomial<C::Scalar, LagrangeCoeff>>, | ^^^^^^^^^^^^ 386 | fixed_polys: Vec<Polynomial<C::Scalar, Coeff>>, | ^^^^^^^^^^^ 387 | fixed_cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>, | ^^^^^^^^^^^^ 388 | permutation: permutation::ProvingKey<C>, | ^^^^^^^^^^^ 389 | ev: Evaluator<C>, | ^^ | = note: `ProvingKeyV2` has derived impls for the traits `Debug` and `Clone`, but these are intentionally ignored during dead code analysis

Check warning on line 381 in halo2_proofs/src/plonk.rs

View workflow job for this annotation

GitHub Actions / Clippy (beta)

multiple fields are never read

warning: multiple fields are never read --> halo2_proofs/src/plonk.rs:381:5 | 380 | pub struct ProvingKeyV2<C: CurveAffine> { | ------------ fields in this struct 381 | vk: VerifyingKeyV2<C>, | ^^ 382 | l0: Polynomial<C::Scalar, ExtendedLagrangeCoeff>, | ^^ 383 | l_last: Polynomial<C::Scalar, ExtendedLagrangeCoeff>, | ^^^^^^ 384 | l_active_row: Polynomial<C::Scalar, ExtendedLagrangeCoeff>, | ^^^^^^^^^^^^ 385 | fixed_values: Vec<Polynomial<C::Scalar, LagrangeCoeff>>, | ^^^^^^^^^^^^ 386 | fixed_polys: Vec<Polynomial<C::Scalar, Coeff>>, | ^^^^^^^^^^^ 387 | fixed_cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>, | ^^^^^^^^^^^^ 388 | permutation: permutation::ProvingKey<C>, | ^^^^^^^^^^^ 389 | ev: Evaluator<C>, | ^^ | = note: `ProvingKeyV2` has derived impls for the traits `Debug` and `Clone`, but these are intentionally ignored during dead code analysis
l0: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
l_last: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
l_active_row: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
fixed_values: Vec<Polynomial<C::Scalar, LagrangeCoeff>>,
fixed_polys: Vec<Polynomial<C::Scalar, Coeff>>,
fixed_cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
permutation: permutation::ProvingKey<C>,
ev: Evaluator<C>,
}

/// This is a proving key which allows for the creation of proofs for a
/// particular circuit.
#[derive(Clone, Debug)]
Expand Down
91 changes: 90 additions & 1 deletion halo2_proofs/src/plonk/evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};
use group::ff::{Field, PrimeField, WithSmallOrderMulGroup};

use super::{shuffle, ConstraintSystem, Expression};
use super::{shuffle, ConstraintSystem, ConstraintSystemV2Backend, Expression};

/// Return the index in the polynomial of size `isize` after rotation `rot`.
fn get_rotation_idx(idx: usize, rot: i32, rot_scale: i32, isize: i32) -> usize {
Expand Down Expand Up @@ -205,6 +205,95 @@ pub struct CalculationInfo {
}

impl<C: CurveAffine> Evaluator<C> {
/// Creates a new evaluation structure
pub fn new_v2(cs: &ConstraintSystemV2Backend<C::ScalarExt>) -> Self {
let mut ev = Evaluator::default();

// Custom gates
let mut parts = Vec::new();
for gate in cs.gates.iter() {
parts.extend(
gate.polynomials()
.iter()
.map(|poly| ev.custom_gates.add_expression(poly)),
);
}
ev.custom_gates.add_calculation(Calculation::Horner(
ValueSource::PreviousValue(),
parts,
ValueSource::Y(),
));

// Lookups
for lookup in cs.lookups.iter() {
let mut graph = GraphEvaluator::default();

let mut evaluate_lc = |expressions: &Vec<Expression<_>>| {
let parts = expressions
.iter()
.map(|expr| graph.add_expression(expr))
.collect();
graph.add_calculation(Calculation::Horner(
ValueSource::Constant(0),
parts,
ValueSource::Theta(),
))
};

// Input coset
let compressed_input_coset = evaluate_lc(&lookup.input_expressions);
// table coset
let compressed_table_coset = evaluate_lc(&lookup.table_expressions);
// z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
let right_gamma = graph.add_calculation(Calculation::Add(
compressed_table_coset,
ValueSource::Gamma(),
));
let lc = graph.add_calculation(Calculation::Add(
compressed_input_coset,
ValueSource::Beta(),
));
graph.add_calculation(Calculation::Mul(lc, right_gamma));

ev.lookups.push(graph);
}

// Shuffles
for shuffle in cs.shuffles.iter() {
let evaluate_lc = |expressions: &Vec<Expression<_>>, graph: &mut GraphEvaluator<C>| {
let parts = expressions
.iter()
.map(|expr| graph.add_expression(expr))
.collect();
graph.add_calculation(Calculation::Horner(
ValueSource::Constant(0),
parts,
ValueSource::Theta(),
))
};

let mut graph_input = GraphEvaluator::default();
let compressed_input_coset = evaluate_lc(&shuffle.input_expressions, &mut graph_input);
let _ = graph_input.add_calculation(Calculation::Add(
compressed_input_coset,
ValueSource::Gamma(),
));

let mut graph_shuffle = GraphEvaluator::default();
let compressed_shuffle_coset =
evaluate_lc(&shuffle.shuffle_expressions, &mut graph_shuffle);
let _ = graph_shuffle.add_calculation(Calculation::Add(
compressed_shuffle_coset,
ValueSource::Gamma(),
));

ev.shuffles.push(graph_input);
ev.shuffles.push(graph_shuffle);
}

ev
}

/// Creates a new evaluation structure
pub fn new(cs: &ConstraintSystem<C::ScalarExt>) -> Self {
let mut ev = Evaluator::default();
Expand Down
124 changes: 86 additions & 38 deletions halo2_proofs/src/plonk/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use super::{
FloorPlanner, Instance, Selector,
},
evaluation::Evaluator,
permutation, Assigned, Challenge, Error, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey,
VerifyingKeyV2,
permutation, Assigned, Challenge, Error, LagrangeCoeff, Polynomial, ProvingKey, ProvingKeyV2,
VerifyingKey, VerifyingKeyV2,
};
use crate::{
arithmetic::{parallelize, CurveAffine},
Expand Down Expand Up @@ -215,47 +215,11 @@ where
{
let cs = &circuit.cs;
let domain = EvaluationDomain::new(cs.degree() as u32, params.k());
// let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(
// params.k(),
// #[cfg(feature = "circuit-params")]
// circuit.params(),
// );

if (params.n() as usize) < cs.minimum_rows() {
return Err(Error::not_enough_rows_available(params.k()));
}

// let mut assembly: Assembly<C::Scalar> = Assembly {
// k: params.k(),
// fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns],
// permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation),
// // selectors: vec![vec![false; params.n() as usize]; cs.num_selectors],
// usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1),
// _marker: std::marker::PhantomData,
// };

// Synthesize the circuit to obtain URS
// ConcreteCircuit::FloorPlanner::synthesize(
// &mut assembly,
// circuit,
// config,
// cs.constants.clone(),
// )?;

// let mut fixed = batch_invert_assigned(assembly.fixed);
// let (cs, selector_polys) = if compress_selectors {
// cs.compress_selectors(assembly.selectors.clone())
// } else {
// // After this, the ConstraintSystem should not have any selectors: `verify` does not need them, and `keygen_pk` regenerates `cs` from scratch anyways.
// let selectors = std::mem::take(&mut assembly.selectors);
// cs.directly_convert_selectors_to_fixed(selectors)
// };
// fixed.extend(
// selector_polys
// .into_iter()
// .map(|poly| domain.lagrange_from_vec(poly)),
// );

let permutation_vk =
circuit
.preprocessing
Expand Down Expand Up @@ -367,6 +331,90 @@ where
))
}

/// Generate a `ProvingKey` from a `VerifyingKey` and an instance of `CompiledCircuit`.
pub fn keygen_pk_v2<'params, C, P>(
params: &P,
vk: VerifyingKeyV2<C>,
circuit: &CompiledCircuitV2<C::Scalar>,
) -> Result<ProvingKeyV2<C>, Error>
where
C: CurveAffine,
P: Params<'params, C>,
{
let cs = &circuit.cs;

if (params.n() as usize) < cs.minimum_rows() {
return Err(Error::not_enough_rows_available(params.k()));
}

let fixed_polys: Vec<_> = circuit
.preprocessing
.fixed
.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_pk =
circuit
.preprocessing
.permutation
.clone()
.build_pk(params, &vk.domain, &cs.permutation);

// Compute l_0(X)
// TODO: this can be done more efficiently
let mut l0 = vk.domain.empty_lagrange();
l0[0] = C::Scalar::ONE;
let l0 = vk.domain.lagrange_to_coeff(l0);
let l0 = vk.domain.coeff_to_extended(l0);

// Compute l_blind(X) which evaluates to 1 for each blinding factor row
// and 0 otherwise over the domain.
let mut l_blind = vk.domain.empty_lagrange();
for evaluation in l_blind[..].iter_mut().rev().take(cs.blinding_factors()) {
*evaluation = C::Scalar::ONE;
}
let l_blind = vk.domain.lagrange_to_coeff(l_blind);
let l_blind = vk.domain.coeff_to_extended(l_blind);

// 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 l_last = vk.domain.lagrange_to_coeff(l_last);
let l_last = vk.domain.coeff_to_extended(l_last);

// Compute l_active_row(X)
let one = C::Scalar::ONE;
let mut l_active_row = vk.domain.empty_extended();
parallelize(&mut l_active_row, |values, start| {
for (i, value) in values.iter_mut().enumerate() {
let idx = i + start;
*value = one - (l_last[idx] + l_blind[idx]);
}
});

// Compute the optimized evaluation data structure
let ev = Evaluator::new_v2(&vk.cs);

Ok(ProvingKeyV2 {
vk,
l0,
l_last,
l_active_row,
fixed_values: circuit.preprocessing.fixed.clone(),
fixed_polys,
fixed_cosets,
permutation: permutation_pk,
ev,
})
}

/// Generate a `ProvingKey` from a `VerifyingKey` and an instance of `Circuit`.
pub fn keygen_pk<'params, C, P, ConcreteCircuit>(
params: &P,
Expand Down

0 comments on commit d318a9d

Please sign in to comment.