From 58479fbcc395da64246f1602674a364d4765917b Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 14 Jan 2021 01:23:01 +0800 Subject: [PATCH] Refactor keygen to generate pk from vk. --- benches/plonk.rs | 3 +- examples/performance_model.rs | 3 +- src/plonk.rs | 3 +- src/plonk/keygen.rs | 184 ++++++++++++++++++++------------ src/plonk/permutation/keygen.rs | 48 ++++++--- 5 files changed, 152 insertions(+), 89 deletions(-) diff --git a/benches/plonk.rs b/benches/plonk.rs index 2d59b2b..06f6317 100644 --- a/benches/plonk.rs +++ b/benches/plonk.rs @@ -226,7 +226,8 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { let empty_circuit: MyCircuit = MyCircuit { a: None, k }; // Initialize the proving key - let pk = keygen(¶ms, &empty_circuit).expect("keygen should not fail"); + let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); let prover_name = name.to_string() + "-prover"; let verifier_name = name.to_string() + "-verifier"; diff --git a/examples/performance_model.rs b/examples/performance_model.rs index a23a4fb..15be99b 100644 --- a/examples/performance_model.rs +++ b/examples/performance_model.rs @@ -257,7 +257,8 @@ fn main() { let empty_circuit: MyCircuit = MyCircuit { a: None, k }; // Initialize the proving key - let pk = keygen(¶ms, &empty_circuit).expect("keygen should not fail"); + let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); println!("[Keygen] {}", recorder); recorder.clear(); diff --git a/src/plonk.rs b/src/plonk.rs index d2bf6c7..3a35fe4 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -485,7 +485,8 @@ fn test_proving() { }; // Initialize the proving key - let pk = keygen(¶ms, &empty_circuit).expect("keygen should not fail"); + let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); let mut pubinputs = pk.get_vk().get_domain().empty_lagrange(); pubinputs[0] = aux; diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index fa1b1c0..835acd7 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -2,12 +2,12 @@ use ff::Field; use super::{ circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed}, - permutation, Error, ProvingKey, VerifyingKey, + permutation, Error, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey, }; use crate::arithmetic::{Curve, CurveAffine}; use crate::poly::{ commitment::{Blind, Params}, - EvaluationDomain, LagrangeCoeff, Polynomial, Rotation, + EvaluationDomain, Rotation, }; pub(crate) fn create_domain( @@ -55,64 +55,66 @@ where (domain, cs, config) } -/// Generate a `ProvingKey` from an instance of `Circuit`. -pub fn keygen( +/// Assembly to be used in circuit synthesis. +#[derive(Clone, Debug)] +pub struct Assembly { + fixed: Vec>, + permutations: Vec, + _marker: std::marker::PhantomData, +} + +impl Assignment for Assembly { + fn assign_advice( + &mut self, + _: Column, + _: usize, + _: impl FnOnce() -> Result, + ) -> Result<(), Error> { + // We only care about fixed columns here + Ok(()) + } + + fn assign_fixed( + &mut self, + column: Column, + row: usize, + to: impl FnOnce() -> Result, + ) -> Result<(), Error> { + *self + .fixed + .get_mut(column.index()) + .and_then(|v| v.get_mut(row)) + .ok_or(Error::BoundsFailure)? = to()?; + + Ok(()) + } + + fn copy( + &mut self, + permutation: usize, + left_column: usize, + left_row: usize, + right_column: usize, + right_row: usize, + ) -> Result<(), Error> { + // Check bounds first + if permutation >= self.permutations.len() { + return Err(Error::BoundsFailure); + } + + self.permutations[permutation].copy(left_column, left_row, right_column, right_row) + } +} + +/// Generate a `VerifyingKey` from an instance of `Circuit`. +pub fn keygen_vk( params: &Params, circuit: &ConcreteCircuit, -) -> Result, Error> +) -> Result, Error> where C: CurveAffine, ConcreteCircuit: Circuit, { - struct Assembly { - fixed: Vec>, - permutations: Vec, - _marker: std::marker::PhantomData, - } - - impl Assignment for Assembly { - fn assign_advice( - &mut self, - _: Column, - _: usize, - _: impl FnOnce() -> Result, - ) -> Result<(), Error> { - // We only care about fixed columns here - Ok(()) - } - - fn assign_fixed( - &mut self, - column: Column, - row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), Error> { - *self - .fixed - .get_mut(column.index()) - .and_then(|v| v.get_mut(row)) - .ok_or(Error::BoundsFailure)? = to()?; - - Ok(()) - } - - fn copy( - &mut self, - permutation: usize, - left_column: usize, - left_row: usize, - right_column: usize, - right_row: usize, - ) -> Result<(), Error> { - // Check bounds first - if permutation >= self.permutations.len() { - return Err(Error::BoundsFailure); - } - - self.permutations[permutation].copy(left_column, left_row, right_column, right_row) - } - } - let (domain, cs, config) = create_domain::(params); let mut assembly: Assembly = Assembly { @@ -130,12 +132,12 @@ where let permutation_helper = permutation::keygen::Assembly::build_helper(params, &cs, &domain); - let (permutation_pks, permutation_vks) = cs + let permutation_vks = cs .permutations .iter() - .zip(assembly.permutations.into_iter()) - .map(|(p, assembly)| assembly.build_keys(params, &domain, &permutation_helper, p)) - .unzip(); + .zip(assembly.clone().permutations.into_iter()) + .map(|(p, assembly)| assembly.build_vk(params, &domain, &permutation_helper, p)) + .collect(); let fixed_commitments = assembly .fixed @@ -143,35 +145,77 @@ where .map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine()) .collect(); + Ok(VerifyingKey { + domain, + fixed_commitments, + permutations: permutation_vks, + cs, + }) +} + +/// Generate a `ProvingKey` from a `VerifyingKey` and an instance of `Circuit`. +pub fn keygen_pk( + params: &Params, + vk: VerifyingKey, + circuit: &ConcreteCircuit, +) -> Result, Error> +where + C: CurveAffine, + ConcreteCircuit: Circuit, +{ + let mut cs = ConstraintSystem::default(); + let config = ConcreteCircuit::configure(&mut cs); + + let mut assembly: Assembly = 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| domain.lagrange_to_coeff(poly.clone())) + .map(|poly| vk.domain.lagrange_to_coeff(poly.clone())) .collect(); - let fixed_cosets = cs + let fixed_cosets = vk + .cs .fixed_queries .iter() .map(|&(column, at)| { let poly = fixed_polys[column.index()].clone(); - domain.coeff_to_extended(poly, at) + 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 = domain.empty_lagrange(); + let mut l0 = vk.domain.empty_lagrange(); l0[0] = C::Scalar::one(); - let l0 = domain.lagrange_to_coeff(l0); - let l0 = domain.coeff_to_extended(l0, Rotation::cur()); + let l0 = vk.domain.lagrange_to_coeff(l0); + let l0 = vk.domain.coeff_to_extended(l0, Rotation::cur()); Ok(ProvingKey { - vk: VerifyingKey { - domain, - fixed_commitments, - permutations: permutation_vks, - cs, - }, + vk, l0, fixed_values: assembly.fixed, fixed_polys, diff --git a/src/plonk/permutation/keygen.rs b/src/plonk/permutation/keygen.rs index 017bf15..d527725 100644 --- a/src/plonk/permutation/keygen.rs +++ b/src/plonk/permutation/keygen.rs @@ -14,7 +14,7 @@ pub(crate) struct AssemblyHelper { deltaomega: Vec>, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub(crate) struct Assembly { pub(crate) mapping: Vec>, aux: Vec>, @@ -132,19 +132,15 @@ impl Assembly { AssemblyHelper { deltaomega } } - pub(crate) fn build_keys( + pub(crate) fn build_vk( self, params: &Params, domain: &EvaluationDomain, helper: &AssemblyHelper, p: &Argument, - ) -> (ProvingKey, VerifyingKey) { - // Compute permutation polynomials, convert to coset form and - // pre-compute commitments for the SRS. + ) -> VerifyingKey { + // Pre-compute commitments for the SRS. let mut commitments = vec![]; - 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. @@ -160,19 +156,39 @@ impl Assembly { .commit_lagrange(&permutation_poly, Blind::default()) .to_affine(), ); + } + VerifyingKey { commitments } + } + + pub(crate) fn build_pk( + self, + domain: &EvaluationDomain, + helper: &AssemblyHelper, + p: &Argument, + ) -> ProvingKey { + // 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 permutations.push(permutation_poly.clone()); let poly = domain.lagrange_to_coeff(permutation_poly); polys.push(poly.clone()); cosets.push(domain.coeff_to_extended(poly, Rotation::cur())); } - ( - ProvingKey { - permutations, - polys, - cosets, - }, - VerifyingKey { commitments }, - ) + ProvingKey { + permutations, + polys, + cosets, + } } }