Refactor keygen to generate pk from vk.

This commit is contained in:
therealyingtong 2021-01-14 01:23:01 +08:00
parent b9737ada93
commit 58479fbcc3
5 changed files with 152 additions and 89 deletions

View File

@ -226,7 +226,8 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) {
let empty_circuit: MyCircuit<Fp> = MyCircuit { a: None, k }; let empty_circuit: MyCircuit<Fp> = MyCircuit { a: None, k };
// Initialize the proving key // Initialize the proving key
let pk = keygen(&params, &empty_circuit).expect("keygen should not fail"); let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");
let prover_name = name.to_string() + "-prover"; let prover_name = name.to_string() + "-prover";
let verifier_name = name.to_string() + "-verifier"; let verifier_name = name.to_string() + "-verifier";

View File

@ -257,7 +257,8 @@ fn main() {
let empty_circuit: MyCircuit<Fp> = MyCircuit { a: None, k }; let empty_circuit: MyCircuit<Fp> = MyCircuit { a: None, k };
// Initialize the proving key // Initialize the proving key
let pk = keygen(&params, &empty_circuit).expect("keygen should not fail"); let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");
println!("[Keygen] {}", recorder); println!("[Keygen] {}", recorder);
recorder.clear(); recorder.clear();

View File

@ -485,7 +485,8 @@ fn test_proving() {
}; };
// Initialize the proving key // Initialize the proving key
let pk = keygen(&params, &empty_circuit).expect("keygen should not fail"); let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");
let mut pubinputs = pk.get_vk().get_domain().empty_lagrange(); let mut pubinputs = pk.get_vk().get_domain().empty_lagrange();
pubinputs[0] = aux; pubinputs[0] = aux;

View File

@ -2,12 +2,12 @@ use ff::Field;
use super::{ use super::{
circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed}, circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed},
permutation, Error, ProvingKey, VerifyingKey, permutation, Error, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey,
}; };
use crate::arithmetic::{Curve, CurveAffine}; use crate::arithmetic::{Curve, CurveAffine};
use crate::poly::{ use crate::poly::{
commitment::{Blind, Params}, commitment::{Blind, Params},
EvaluationDomain, LagrangeCoeff, Polynomial, Rotation, EvaluationDomain, Rotation,
}; };
pub(crate) fn create_domain<C, ConcreteCircuit>( pub(crate) fn create_domain<C, ConcreteCircuit>(
@ -55,16 +55,9 @@ where
(domain, cs, config) (domain, cs, config)
} }
/// Generate a `ProvingKey` from an instance of `Circuit`. /// Assembly to be used in circuit synthesis.
pub fn keygen<C, ConcreteCircuit>( #[derive(Clone, Debug)]
params: &Params<C>, pub struct Assembly<F: Field> {
circuit: &ConcreteCircuit,
) -> Result<ProvingKey<C>, Error>
where
C: CurveAffine,
ConcreteCircuit: Circuit<C::Scalar>,
{
struct Assembly<F: Field> {
fixed: Vec<Polynomial<F, LagrangeCoeff>>, fixed: Vec<Polynomial<F, LagrangeCoeff>>,
permutations: Vec<permutation::keygen::Assembly>, permutations: Vec<permutation::keygen::Assembly>,
_marker: std::marker::PhantomData<F>, _marker: std::marker::PhantomData<F>,
@ -113,6 +106,15 @@ where
} }
} }
/// Generate a `VerifyingKey` from an instance of `Circuit`.
pub fn keygen_vk<C, ConcreteCircuit>(
params: &Params<C>,
circuit: &ConcreteCircuit,
) -> Result<VerifyingKey<C>, Error>
where
C: CurveAffine,
ConcreteCircuit: Circuit<C::Scalar>,
{
let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(params); let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(params);
let mut assembly: Assembly<C::Scalar> = Assembly { let mut assembly: Assembly<C::Scalar> = Assembly {
@ -130,12 +132,12 @@ where
let permutation_helper = permutation::keygen::Assembly::build_helper(params, &cs, &domain); let permutation_helper = permutation::keygen::Assembly::build_helper(params, &cs, &domain);
let (permutation_pks, permutation_vks) = cs let permutation_vks = cs
.permutations .permutations
.iter() .iter()
.zip(assembly.permutations.into_iter()) .zip(assembly.clone().permutations.into_iter())
.map(|(p, assembly)| assembly.build_keys(params, &domain, &permutation_helper, p)) .map(|(p, assembly)| assembly.build_vk(params, &domain, &permutation_helper, p))
.unzip(); .collect();
let fixed_commitments = assembly let fixed_commitments = assembly
.fixed .fixed
@ -143,35 +145,77 @@ where
.map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine()) .map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
.collect(); .collect();
let fixed_polys: Vec<_> = assembly Ok(VerifyingKey {
.fixed
.iter()
.map(|poly| domain.lagrange_to_coeff(poly.clone()))
.collect();
let fixed_cosets = cs
.fixed_queries
.iter()
.map(|&(column, at)| {
let poly = fixed_polys[column.index()].clone();
domain.coeff_to_extended(poly, at)
})
.collect();
// Compute l_0(X)
// TODO: this can be done more efficiently
let mut l0 = domain.empty_lagrange();
l0[0] = C::Scalar::one();
let l0 = domain.lagrange_to_coeff(l0);
let l0 = domain.coeff_to_extended(l0, Rotation::cur());
Ok(ProvingKey {
vk: VerifyingKey {
domain, domain,
fixed_commitments, fixed_commitments,
permutations: permutation_vks, permutations: permutation_vks,
cs, cs,
}, })
}
/// Generate a `ProvingKey` from a `VerifyingKey` and an instance of `Circuit`.
pub fn keygen_pk<C, ConcreteCircuit>(
params: &Params<C>,
vk: VerifyingKey<C>,
circuit: &ConcreteCircuit,
) -> Result<ProvingKey<C>, Error>
where
C: CurveAffine,
ConcreteCircuit: Circuit<C::Scalar>,
{
let mut cs = ConstraintSystem::default();
let config = ConcreteCircuit::configure(&mut cs);
let mut assembly: Assembly<C::Scalar> = Assembly {
fixed: vec![vk.domain.empty_lagrange(); vk.cs.num_fixed_columns],
permutations: vk
.cs
.permutations
.iter()
.map(|p| permutation::keygen::Assembly::new(params.n as usize, p))
.collect(),
_marker: std::marker::PhantomData,
};
// Synthesize the circuit to obtain SRS
circuit.synthesize(&mut assembly, config)?;
let fixed_polys: Vec<_> = assembly
.fixed
.iter()
.map(|poly| vk.domain.lagrange_to_coeff(poly.clone()))
.collect();
let fixed_cosets = vk
.cs
.fixed_queries
.iter()
.map(|&(column, at)| {
let poly = fixed_polys[column.index()].clone();
vk.domain.coeff_to_extended(poly, at)
})
.collect();
let permutation_helper =
permutation::keygen::Assembly::build_helper(params, &vk.cs, &vk.domain);
let permutation_pks = vk
.cs
.permutations
.iter()
.zip(assembly.permutations.into_iter())
.map(|(p, assembly)| assembly.build_pk(&vk.domain, &permutation_helper, p))
.collect();
// 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, Rotation::cur());
Ok(ProvingKey {
vk,
l0, l0,
fixed_values: assembly.fixed, fixed_values: assembly.fixed,
fixed_polys, fixed_polys,

View File

@ -14,7 +14,7 @@ pub(crate) struct AssemblyHelper<C: CurveAffine> {
deltaomega: Vec<Vec<C::Scalar>>, deltaomega: Vec<Vec<C::Scalar>>,
} }
#[derive(Debug)] #[derive(Clone, Debug)]
pub(crate) struct Assembly { pub(crate) struct Assembly {
pub(crate) mapping: Vec<Vec<(usize, usize)>>, pub(crate) mapping: Vec<Vec<(usize, usize)>>,
aux: Vec<Vec<(usize, usize)>>, aux: Vec<Vec<(usize, usize)>>,
@ -132,19 +132,15 @@ impl Assembly {
AssemblyHelper { deltaomega } AssemblyHelper { deltaomega }
} }
pub(crate) fn build_keys<C: CurveAffine>( pub(crate) fn build_vk<C: CurveAffine>(
self, self,
params: &Params<C>, params: &Params<C>,
domain: &EvaluationDomain<C::Scalar>, domain: &EvaluationDomain<C::Scalar>,
helper: &AssemblyHelper<C>, helper: &AssemblyHelper<C>,
p: &Argument, p: &Argument,
) -> (ProvingKey<C>, VerifyingKey<C>) { ) -> VerifyingKey<C> {
// Compute permutation polynomials, convert to coset form and // Pre-compute commitments for the SRS.
// pre-compute commitments for the SRS.
let mut commitments = vec![]; let mut commitments = vec![];
let mut permutations = vec![];
let mut polys = vec![];
let mut cosets = vec![];
for i in 0..p.columns.len() { for i in 0..p.columns.len() {
// Computes the permutation polynomial based on the permutation // Computes the permutation polynomial based on the permutation
// description in the assembly. // description in the assembly.
@ -160,19 +156,39 @@ impl Assembly {
.commit_lagrange(&permutation_poly, Blind::default()) .commit_lagrange(&permutation_poly, Blind::default())
.to_affine(), .to_affine(),
); );
}
VerifyingKey { commitments }
}
pub(crate) fn build_pk<C: CurveAffine>(
self,
domain: &EvaluationDomain<C::Scalar>,
helper: &AssemblyHelper<C>,
p: &Argument,
) -> ProvingKey<C> {
// Compute permutation polynomials, convert to coset form.
let mut permutations = vec![];
let mut polys = vec![];
let mut cosets = vec![];
for i in 0..p.columns.len() {
// Computes the permutation polynomial based on the permutation
// description in the assembly.
let mut permutation_poly = domain.empty_lagrange();
for (j, p) in permutation_poly.iter_mut().enumerate() {
let (permuted_i, permuted_j) = self.mapping[i][j];
*p = helper.deltaomega[permuted_i][permuted_j];
}
// Store permutation polynomial and precompute its coset evaluation // Store permutation polynomial and precompute its coset evaluation
permutations.push(permutation_poly.clone()); permutations.push(permutation_poly.clone());
let poly = domain.lagrange_to_coeff(permutation_poly); let poly = domain.lagrange_to_coeff(permutation_poly);
polys.push(poly.clone()); polys.push(poly.clone());
cosets.push(domain.coeff_to_extended(poly, Rotation::cur())); cosets.push(domain.coeff_to_extended(poly, Rotation::cur()));
} }
(
ProvingKey { ProvingKey {
permutations, permutations,
polys, polys,
cosets, cosets,
}, }
VerifyingKey { commitments },
)
} }
} }