Reimplement keygen_pk for fe-be split as keygen_pk_v2

This commit is contained in:
Eduard S. 2023-12-13 17:48:26 +01:00
parent eb5d1aadbe
commit d318a9d03d
3 changed files with 192 additions and 39 deletions

View File

@ -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>,
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)]

View File

@ -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 {
@ -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();

View File

@ -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},
@ -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
@ -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,