Merge pull request #37 from zcash/remove-srs

Remove SRS and replace with ProvingKey/VerifyingKey abstractions
This commit is contained in:
ebfull 2020-09-29 08:29:17 -06:00 committed by GitHub
commit e5fd7914b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 337 additions and 313 deletions

View File

@ -12,30 +12,37 @@ use crate::poly::{
use crate::transcript::Hasher;
mod circuit;
mod keygen;
mod prover;
mod srs;
mod verifier;
pub use circuit::*;
pub use keygen::*;
pub use prover::*;
pub use srs::*;
pub use verifier::*;
/// This is a structured reference string (SRS) that is (deterministically)
/// computed from a specific circuit and parameters for the polynomial
/// commitment scheme.
/// This is a verifying key which allows for the verification of proofs for a
/// particular circuit.
#[derive(Debug)]
pub struct SRS<C: CurveAffine> {
pub struct VerifyingKey<C: CurveAffine> {
domain: EvaluationDomain<C::Scalar>,
l0: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
fixed_commitments: Vec<C>,
permutation_commitments: Vec<Vec<C>>,
cs: ConstraintSystem<C::Scalar>,
}
/// This is a proving key which allows for the creation of proofs for a
/// particular circuit.
#[derive(Debug)]
pub struct ProvingKey<C: CurveAffine> {
vk: VerifyingKey<C>,
// TODO: get rid of this?
l0: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
fixed_polys: Vec<Polynomial<C::Scalar, Coeff>>,
fixed_cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
permutation_commitments: Vec<Vec<C>>,
permutations: Vec<Vec<Polynomial<C::Scalar, LagrangeCoeff>>>,
permutation_polys: Vec<Vec<Polynomial<C::Scalar, Coeff>>>,
permutation_cosets: Vec<Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>>,
cs: ConstraintSystem<C::Scalar>,
}
/// This is an object which represents a (Turbo)PLONK proof.
@ -75,6 +82,20 @@ pub enum Error {
OpeningError,
}
impl<C: CurveAffine> ProvingKey<C> {
/// Get the underlying [`VerifyingKey`].
pub fn get_vk(&self) -> &VerifyingKey<C> {
&self.vk
}
}
impl<C: CurveAffine> VerifyingKey<C> {
/// Get the underlying [`EvaluationDomain`].
pub fn get_domain(&self) -> &EvaluationDomain<C::Scalar> {
&self.domain
}
}
fn hash_point<C: CurveAffine, H: Hasher<C::Base>>(
transcript: &mut H,
point: &C,
@ -368,10 +389,10 @@ fn test_proving() {
let empty_circuit: MyCircuit<Fp> = MyCircuit { a: None };
// Initialize the SRS
let srs = SRS::generate(&params, &empty_circuit).expect("SRS generation should not fail");
// Initialize the proving key
let pk = keygen(&params, &empty_circuit).expect("keygen should not fail");
let mut pubinputs = srs.domain.empty_lagrange();
let mut pubinputs = pk.get_vk().get_domain().empty_lagrange();
pubinputs[0] = Fp::one();
pubinputs[0] += Fp::one();
let pubinput = params
@ -382,7 +403,7 @@ fn test_proving() {
// Create a proof
let proof = Proof::create::<DummyHash<Fq>, DummyHash<Fp>, _>(
&params,
&srs,
&pk,
&circuit,
&[pubinputs.clone()],
)
@ -390,7 +411,7 @@ fn test_proving() {
let msm = params.empty_msm();
let guard = proof
.verify::<DummyHash<Fq>, DummyHash<Fp>>(&params, &srs, msm, &[pubinput])
.verify::<DummyHash<Fq>, DummyHash<Fp>>(&params, pk.get_vk(), msm, &[pubinput])
.unwrap();
{
let msm = guard.clone().use_challenges();
@ -404,7 +425,7 @@ fn test_proving() {
let msm = guard.clone().use_challenges();
assert!(msm.clone().eval());
let guard = proof
.verify::<DummyHash<Fq>, DummyHash<Fp>>(&params, &srs, msm, &[pubinput])
.verify::<DummyHash<Fq>, DummyHash<Fp>>(&params, pk.get_vk(), msm, &[pubinput])
.unwrap();
{
let msm = guard.clone().use_challenges();

259
src/plonk/keygen.rs Normal file
View File

@ -0,0 +1,259 @@
use super::{
circuit::{AdviceWire, Assignment, Circuit, ConstraintSystem, FixedWire},
Error, ProvingKey, VerifyingKey,
};
use crate::arithmetic::{Curve, CurveAffine, Field};
use crate::poly::{
commitment::{Blind, Params},
EvaluationDomain, LagrangeCoeff, Polynomial, Rotation,
};
/// Generate a `ProvingKey` from an instance of `Circuit`.
pub fn keygen<C, ConcreteCircuit>(
params: &Params<C>,
circuit: &ConcreteCircuit,
) -> Result<ProvingKey<C>, Error>
where
C: CurveAffine,
ConcreteCircuit: Circuit<C::Scalar>,
{
struct Assembly<F: Field> {
fixed: Vec<Polynomial<F, LagrangeCoeff>>,
mapping: Vec<Vec<Vec<(usize, usize)>>>,
aux: Vec<Vec<Vec<(usize, usize)>>>,
sizes: Vec<Vec<Vec<usize>>>,
_marker: std::marker::PhantomData<F>,
}
impl<F: Field> Assignment<F> for Assembly<F> {
fn assign_advice(
&mut self,
_: AdviceWire,
_: usize,
_: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
// We only care about fixed wires here
Ok(())
}
fn assign_fixed(
&mut self,
wire: FixedWire,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
*self
.fixed
.get_mut(wire.0)
.and_then(|v| v.get_mut(row))
.ok_or(Error::BoundsFailure)? = to()?;
Ok(())
}
fn copy(
&mut self,
permutation: usize,
left_wire: usize,
left_row: usize,
right_wire: usize,
right_row: usize,
) -> Result<(), Error> {
// Check bounds first
if permutation >= self.mapping.len()
|| left_wire >= self.mapping[permutation].len()
|| left_row >= self.mapping[permutation][left_wire].len()
|| right_wire >= self.mapping[permutation].len()
|| right_row >= self.mapping[permutation][right_wire].len()
{
return Err(Error::BoundsFailure);
}
let mut left_cycle = self.aux[permutation][left_wire][left_row];
let mut right_cycle = self.aux[permutation][right_wire][right_row];
if left_cycle == right_cycle {
return Ok(());
}
if self.sizes[permutation][left_cycle.0][left_cycle.1]
< self.sizes[permutation][right_cycle.0][right_cycle.1]
{
std::mem::swap(&mut left_cycle, &mut right_cycle);
}
self.sizes[permutation][left_cycle.0][left_cycle.1] +=
self.sizes[permutation][right_cycle.0][right_cycle.1];
let mut i = right_cycle;
loop {
self.aux[permutation][i.0][i.1] = left_cycle;
i = self.mapping[permutation][i.0][i.1];
if i == right_cycle {
break;
}
}
let tmp = self.mapping[permutation][left_wire][left_row];
self.mapping[permutation][left_wire][left_row] =
self.mapping[permutation][right_wire][right_row];
self.mapping[permutation][right_wire][right_row] = tmp;
Ok(())
}
}
let mut cs = ConstraintSystem::default();
let config = ConcreteCircuit::configure(&mut cs);
// Get the largest permutation argument length in terms of the number of
// advice wires involved.
let mut largest_permutation_length = 0;
for permutation in &cs.permutations {
largest_permutation_length = std::cmp::max(permutation.len(), largest_permutation_length);
}
// The permutation argument will serve alongside the gates, so must be
// accounted for.
let mut degree = largest_permutation_length + 1;
// Account for each gate to ensure our quotient polynomial is the
// correct degree and that our extended domain is the right size.
for poly in cs.gates.iter() {
degree = std::cmp::max(degree, poly.degree());
}
let domain = EvaluationDomain::new(degree as u32, params.k);
// Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
let mut omega_powers = Vec::with_capacity(params.n as usize);
{
let mut cur = C::Scalar::one();
for _ in 0..params.n {
omega_powers.push(cur);
cur *= &domain.get_omega();
}
}
// Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
let mut deltaomega = Vec::with_capacity(largest_permutation_length);
{
let mut cur = C::Scalar::one();
for _ in 0..largest_permutation_length {
let mut omega_powers = omega_powers.clone();
for o in &mut omega_powers {
*o *= &cur;
}
deltaomega.push(omega_powers);
cur *= &C::Scalar::DELTA;
}
}
let mut assembly: Assembly<C::Scalar> = Assembly {
fixed: vec![domain.empty_lagrange(); cs.num_fixed_wires],
mapping: vec![],
aux: vec![],
sizes: vec![],
_marker: std::marker::PhantomData,
};
// Initialize the copy vector to keep track of copy constraints in all
// the permutation arguments.
for permutation in &cs.permutations {
let mut wires = vec![];
for i in 0..permutation.len() {
// Computes [(i, 0), (i, 1), ..., (i, n - 1)]
wires.push((0..params.n).map(|j| (i, j as usize)).collect());
}
assembly.mapping.push(wires.clone());
assembly.aux.push(wires);
assembly
.sizes
.push(vec![vec![1usize; params.n as usize]; permutation.len()]);
}
// Synthesize the circuit to obtain SRS
circuit.synthesize(&mut assembly, config)?;
// Compute permutation polynomials, convert to coset form and
// pre-compute commitments for the SRS.
let mut permutation_commitments = vec![];
let mut permutations = vec![];
let mut permutation_polys = vec![];
let mut permutation_cosets = vec![];
for (permutation_index, permutation) in cs.permutations.iter().enumerate() {
let mut commitments = vec![];
let mut inner_permutations = vec![];
let mut polys = vec![];
let mut cosets = vec![];
for i in 0..permutation.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) = assembly.mapping[permutation_index][i][j];
*p = deltaomega[permuted_i][permuted_j];
}
// Compute commitment to permutation polynomial
commitments.push(
params
.commit_lagrange(&permutation_poly, Blind::default())
.to_affine(),
);
// Store permutation polynomial and precompute its coset evaluation
inner_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::default()));
}
permutation_commitments.push(commitments);
permutations.push(inner_permutations);
permutation_polys.push(polys);
permutation_cosets.push(cosets);
}
let fixed_commitments = assembly
.fixed
.iter()
.map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
.collect();
let fixed_polys: Vec<_> = assembly
.fixed
.into_iter()
.map(|poly| domain.lagrange_to_coeff(poly))
.collect();
let fixed_cosets = cs
.fixed_queries
.iter()
.map(|&(wire, at)| {
let poly = fixed_polys[wire.0].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::default());
Ok(ProvingKey {
vk: VerifyingKey {
domain,
fixed_commitments,
permutation_commitments,
cs,
},
l0,
fixed_polys,
fixed_cosets,
permutations,
permutation_polys,
permutation_cosets,
})
}

View File

@ -1,6 +1,6 @@
use super::{
circuit::{AdviceWire, Assignment, Circuit, ConstraintSystem, FixedWire},
hash_point, Error, Proof, SRS,
hash_point, Error, Proof, ProvingKey,
};
use crate::arithmetic::{
eval_polynomial, get_challenge_scalar, kate_division, parallelize, BatchInvert, Challenge,
@ -14,19 +14,19 @@ use crate::transcript::Hasher;
impl<C: CurveAffine> Proof<C> {
/// This creates a proof for the provided `circuit` when given the public
/// parameters `params` and the structured reference string `srs` that was
/// previously computed for the same circuit.
/// parameters `params` and the proving key [`ProvingKey`] that was
/// generated previously for the same circuit.
pub fn create<
HBase: Hasher<C::Base>,
HScalar: Hasher<C::Scalar>,
ConcreteCircuit: Circuit<C::Scalar>,
>(
params: &Params<C>,
srs: &SRS<C>,
pk: &ProvingKey<C>,
circuit: &ConcreteCircuit,
aux: &[Polynomial<C::Scalar, LagrangeCoeff>],
) -> Result<Self, Error> {
if aux.len() != srs.cs.num_aux_wires {
if aux.len() != pk.vk.cs.num_aux_wires {
return Err(Error::IncompatibleParams);
}
@ -76,7 +76,7 @@ impl<C: CurveAffine> Proof<C> {
}
}
let domain = &srs.domain;
let domain = &pk.vk.domain;
let mut meta = ConstraintSystem::default();
let config = ConcreteCircuit::configure(&mut meta);
@ -176,7 +176,7 @@ impl<C: CurveAffine> Proof<C> {
// Iterate over each permutation
let mut permutation_modified_advice = vec![];
for (wires, permuted_values) in srs.cs.permutations.iter().zip(srs.permutations.iter()) {
for (wires, permuted_values) in pk.vk.cs.permutations.iter().zip(pk.permutations.iter()) {
// Goal is to compute the products of fractions
//
// (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) /
@ -209,7 +209,8 @@ impl<C: CurveAffine> Proof<C> {
.flat_map(|v| v.iter_mut())
.batch_invert();
for (wires, mut modified_advice) in srs
for (wires, mut modified_advice) in pk
.vk
.cs
.permutations
.iter()
@ -287,7 +288,7 @@ impl<C: CurveAffine> Proof<C> {
h_poly = h_poly * x_2;
let evaluation = poly.evaluate(
&|index| srs.fixed_cosets[index].clone(),
&|index| pk.fixed_cosets[index].clone(),
&|index| advice_cosets[index].clone(),
&|index| aux_cosets[index].clone(),
&|a, b| a + &b,
@ -304,7 +305,7 @@ impl<C: CurveAffine> Proof<C> {
for ((h, c), l0) in h
.iter_mut()
.zip(coset[start..].iter())
.zip(srs.l0[start..].iter())
.zip(pk.l0[start..].iter())
{
*h *= &x_2;
*h += &(*l0 * &(C::Scalar::one() - c));
@ -313,14 +314,14 @@ impl<C: CurveAffine> Proof<C> {
}
// z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
for (permutation_index, wires) in srs.cs.permutations.iter().enumerate() {
for (permutation_index, wires) in pk.vk.cs.permutations.iter().enumerate() {
h_poly = h_poly * x_2;
let mut left = permutation_product_cosets[permutation_index].clone();
for (advice, permutation) in wires
.iter()
.map(|&(_, index)| &advice_cosets[index])
.zip(srs.permutation_cosets[permutation_index].iter())
.zip(pk.permutation_cosets[permutation_index].iter())
{
parallelize(&mut left, |left, start| {
for ((left, advice), permutation) in left
@ -402,7 +403,7 @@ impl<C: CurveAffine> Proof<C> {
.fixed_queries
.iter()
.map(|&(wire, at)| {
eval_polynomial(&srs.fixed_polys[wire.0], domain.rotate_omega(x_3, at))
eval_polynomial(&pk.fixed_polys[wire.0], domain.rotate_omega(x_3, at))
})
.collect();
@ -416,7 +417,7 @@ impl<C: CurveAffine> Proof<C> {
.map(|poly| eval_polynomial(poly, domain.rotate_omega(x_3, Rotation(-1))))
.collect();
let permutation_evals: Vec<Vec<C::Scalar>> = srs
let permutation_evals: Vec<Vec<C::Scalar>> = pk
.permutation_polys
.iter()
.map(|polys| {
@ -511,7 +512,7 @@ impl<C: CurveAffine> Proof<C> {
accumulate(
point_index,
&srs.fixed_polys[wire.0],
&pk.fixed_polys[wire.0],
Blind::default(),
fixed_evals[query_index],
);
@ -528,7 +529,7 @@ impl<C: CurveAffine> Proof<C> {
}
// Handle permutation arguments, if any exist
if !srs.cs.permutations.is_empty() {
if !pk.vk.cs.permutations.is_empty() {
// Open permutation product commitments at x_3
for ((poly, blind), eval) in permutation_product_polys
.iter()
@ -539,7 +540,7 @@ impl<C: CurveAffine> Proof<C> {
}
// Open permutation polynomial commitments at x_3
for (poly, eval) in srs
for (poly, eval) in pk
.permutation_polys
.iter()
.zip(permutation_evals.iter())
@ -548,7 +549,7 @@ impl<C: CurveAffine> Proof<C> {
accumulate(current_index, poly, Blind::default(), *eval);
}
let current_index = (*srs.cs.rotations.get(&Rotation(-1)).unwrap()).0;
let current_index = (*pk.vk.cs.rotations.get(&Rotation(-1)).unwrap()).0;
// Open permutation product commitments at \omega^{-1} x_3
for ((poly, blind), eval) in permutation_product_polys
.iter()

View File

@ -1,257 +0,0 @@
use super::{
circuit::{AdviceWire, Assignment, Circuit, ConstraintSystem, FixedWire},
Error, SRS,
};
use crate::arithmetic::{Curve, CurveAffine, Field};
use crate::poly::{
commitment::{Blind, Params},
EvaluationDomain, LagrangeCoeff, Polynomial, Rotation,
};
impl<C: CurveAffine> SRS<C> {
/// This generates a structured reference string for the provided `circuit`
/// and `params`.
pub fn generate<ConcreteCircuit: Circuit<C::Scalar>>(
params: &Params<C>,
circuit: &ConcreteCircuit,
) -> Result<Self, Error> {
struct Assembly<F: Field> {
fixed: Vec<Polynomial<F, LagrangeCoeff>>,
mapping: Vec<Vec<Vec<(usize, usize)>>>,
aux: Vec<Vec<Vec<(usize, usize)>>>,
sizes: Vec<Vec<Vec<usize>>>,
_marker: std::marker::PhantomData<F>,
}
impl<F: Field> Assignment<F> for Assembly<F> {
fn assign_advice(
&mut self,
_: AdviceWire,
_: usize,
_: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
// We only care about fixed wires here
Ok(())
}
fn assign_fixed(
&mut self,
wire: FixedWire,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
*self
.fixed
.get_mut(wire.0)
.and_then(|v| v.get_mut(row))
.ok_or(Error::BoundsFailure)? = to()?;
Ok(())
}
fn copy(
&mut self,
permutation: usize,
left_wire: usize,
left_row: usize,
right_wire: usize,
right_row: usize,
) -> Result<(), Error> {
// Check bounds first
if permutation >= self.mapping.len()
|| left_wire >= self.mapping[permutation].len()
|| left_row >= self.mapping[permutation][left_wire].len()
|| right_wire >= self.mapping[permutation].len()
|| right_row >= self.mapping[permutation][right_wire].len()
{
return Err(Error::BoundsFailure);
}
let mut left_cycle = self.aux[permutation][left_wire][left_row];
let mut right_cycle = self.aux[permutation][right_wire][right_row];
if left_cycle == right_cycle {
return Ok(());
}
if self.sizes[permutation][left_cycle.0][left_cycle.1]
< self.sizes[permutation][right_cycle.0][right_cycle.1]
{
std::mem::swap(&mut left_cycle, &mut right_cycle);
}
self.sizes[permutation][left_cycle.0][left_cycle.1] +=
self.sizes[permutation][right_cycle.0][right_cycle.1];
let mut i = right_cycle;
loop {
self.aux[permutation][i.0][i.1] = left_cycle;
i = self.mapping[permutation][i.0][i.1];
if i == right_cycle {
break;
}
}
let tmp = self.mapping[permutation][left_wire][left_row];
self.mapping[permutation][left_wire][left_row] =
self.mapping[permutation][right_wire][right_row];
self.mapping[permutation][right_wire][right_row] = tmp;
Ok(())
}
}
let mut cs = ConstraintSystem::default();
let config = ConcreteCircuit::configure(&mut cs);
// Get the largest permutation argument length in terms of the number of
// advice wires involved.
let mut largest_permutation_length = 0;
for permutation in &cs.permutations {
largest_permutation_length =
std::cmp::max(permutation.len(), largest_permutation_length);
}
// The permutation argument will serve alongside the gates, so must be
// accounted for.
let mut degree = largest_permutation_length + 1;
// Account for each gate to ensure our quotient polynomial is the
// correct degree and that our extended domain is the right size.
for poly in cs.gates.iter() {
degree = std::cmp::max(degree, poly.degree());
}
let domain = EvaluationDomain::new(degree as u32, params.k);
// Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
let mut omega_powers = Vec::with_capacity(params.n as usize);
{
let mut cur = C::Scalar::one();
for _ in 0..params.n {
omega_powers.push(cur);
cur *= &domain.get_omega();
}
}
// Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
let mut deltaomega = Vec::with_capacity(largest_permutation_length);
{
let mut cur = C::Scalar::one();
for _ in 0..largest_permutation_length {
let mut omega_powers = omega_powers.clone();
for o in &mut omega_powers {
*o *= &cur;
}
deltaomega.push(omega_powers);
cur *= &C::Scalar::DELTA;
}
}
let mut assembly: Assembly<C::Scalar> = Assembly {
fixed: vec![domain.empty_lagrange(); cs.num_fixed_wires],
mapping: vec![],
aux: vec![],
sizes: vec![],
_marker: std::marker::PhantomData,
};
// Initialize the copy vector to keep track of copy constraints in all
// the permutation arguments.
for permutation in &cs.permutations {
let mut wires = vec![];
for i in 0..permutation.len() {
// Computes [(i, 0), (i, 1), ..., (i, n - 1)]
wires.push((0..params.n).map(|j| (i, j as usize)).collect());
}
assembly.mapping.push(wires.clone());
assembly.aux.push(wires);
assembly
.sizes
.push(vec![vec![1usize; params.n as usize]; permutation.len()]);
}
// Synthesize the circuit to obtain SRS
circuit.synthesize(&mut assembly, config)?;
// Compute permutation polynomials, convert to coset form and
// pre-compute commitments for the SRS.
let mut permutation_commitments = vec![];
let mut permutations = vec![];
let mut permutation_polys = vec![];
let mut permutation_cosets = vec![];
for (permutation_index, permutation) in cs.permutations.iter().enumerate() {
let mut commitments = vec![];
let mut inner_permutations = vec![];
let mut polys = vec![];
let mut cosets = vec![];
for i in 0..permutation.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) = assembly.mapping[permutation_index][i][j];
*p = deltaomega[permuted_i][permuted_j];
}
// Compute commitment to permutation polynomial
commitments.push(
params
.commit_lagrange(&permutation_poly, Blind::default())
.to_affine(),
);
// Store permutation polynomial and precompute its coset evaluation
inner_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::default()));
}
permutation_commitments.push(commitments);
permutations.push(inner_permutations);
permutation_polys.push(polys);
permutation_cosets.push(cosets);
}
let fixed_commitments = assembly
.fixed
.iter()
.map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
.collect();
let fixed_polys: Vec<_> = assembly
.fixed
.into_iter()
.map(|poly| domain.lagrange_to_coeff(poly))
.collect();
let fixed_cosets = cs
.fixed_queries
.iter()
.map(|&(wire, at)| {
let poly = fixed_polys[wire.0].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::default());
Ok(SRS {
domain,
l0,
fixed_commitments,
fixed_polys,
fixed_cosets,
permutation_commitments,
permutations,
permutation_polys,
permutation_cosets,
cs,
})
}
}

View File

@ -1,4 +1,4 @@
use super::{hash_point, Error, Proof, SRS};
use super::{hash_point, Error, Proof, VerifyingKey};
use crate::arithmetic::{get_challenge_scalar, Challenge, CurveAffine, Field};
use crate::poly::{
commitment::{Guard, Params, MSM},
@ -11,14 +11,14 @@ impl<'a, C: CurveAffine> Proof<C> {
pub fn verify<HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
&self,
params: &'a Params<C>,
srs: &SRS<C>,
vk: &VerifyingKey<C>,
mut msm: MSM<'a, C>,
aux_commitments: &[C],
) -> Result<Guard<'a, C>, Error> {
// Check that aux_commitments matches the expected number of aux_wires
// and self.aux_evals
if aux_commitments.len() != srs.cs.num_aux_wires
|| self.aux_evals.len() != srs.cs.num_aux_wires
if aux_commitments.len() != vk.cs.num_aux_wires
|| self.aux_evals.len() != vk.cs.num_aux_wires
{
return Err(Error::IncompatibleParams);
}
@ -88,7 +88,7 @@ impl<'a, C: CurveAffine> Proof<C> {
// Evaluate the circuit using the custom gates provided
let mut h_eval = C::Scalar::zero();
for poly in srs.cs.gates.iter() {
for poly in vk.cs.gates.iter() {
h_eval *= &x_2;
let evaluation: C::Scalar = poly.evaluate(
@ -114,7 +114,7 @@ impl<'a, C: CurveAffine> Proof<C> {
let mut tmp = denominator; // 1 / (x_3 - 1)
tmp *= &(x_3n - &C::Scalar::one()); // (x_3^n - 1) / (x_3 - 1)
tmp *= &srs.domain.get_barycentric_weight(); // l_0(x_3)
tmp *= &vk.domain.get_barycentric_weight(); // l_0(x_3)
tmp *= &(C::Scalar::one() - &eval); // l_0(X) * (1 - z(X))
h_eval += &tmp;
@ -122,7 +122,7 @@ impl<'a, C: CurveAffine> Proof<C> {
}
// z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
for (permutation_index, wires) in srs.cs.permutations.iter().enumerate() {
for (permutation_index, wires) in vk.cs.permutations.iter().enumerate() {
h_eval *= &x_2;
let mut left = self.permutation_product_evals[permutation_index];
@ -168,8 +168,8 @@ impl<'a, C: CurveAffine> Proof<C> {
// Compress the commitments and expected evaluations at x_3 together
// using the challenge x_4
let mut q_commitments: Vec<_> = vec![params.empty_msm(); srs.cs.rotations.len()];
let mut q_evals: Vec<_> = vec![C::Scalar::zero(); srs.cs.rotations.len()];
let mut q_commitments: Vec<_> = vec![params.empty_msm(); vk.cs.rotations.len()];
let mut q_evals: Vec<_> = vec![C::Scalar::zero(); vk.cs.rotations.len()];
{
let mut accumulate = |point_index: usize, new_commitment, eval| {
q_commitments[point_index].scale(x_4);
@ -178,8 +178,8 @@ impl<'a, C: CurveAffine> Proof<C> {
q_evals[point_index] += &eval;
};
for (query_index, &(wire, ref at)) in srs.cs.advice_queries.iter().enumerate() {
let point_index = (*srs.cs.rotations.get(at).unwrap()).0;
for (query_index, &(wire, ref at)) in vk.cs.advice_queries.iter().enumerate() {
let point_index = (*vk.cs.rotations.get(at).unwrap()).0;
accumulate(
point_index,
self.advice_commitments[wire.0],
@ -187,8 +187,8 @@ impl<'a, C: CurveAffine> Proof<C> {
);
}
for (query_index, &(wire, ref at)) in srs.cs.aux_queries.iter().enumerate() {
let point_index = (*srs.cs.rotations.get(at).unwrap()).0;
for (query_index, &(wire, ref at)) in vk.cs.aux_queries.iter().enumerate() {
let point_index = (*vk.cs.rotations.get(at).unwrap()).0;
accumulate(
point_index,
aux_commitments[wire.0],
@ -196,22 +196,22 @@ impl<'a, C: CurveAffine> Proof<C> {
);
}
for (query_index, &(wire, ref at)) in srs.cs.fixed_queries.iter().enumerate() {
let point_index = (*srs.cs.rotations.get(at).unwrap()).0;
for (query_index, &(wire, ref at)) in vk.cs.fixed_queries.iter().enumerate() {
let point_index = (*vk.cs.rotations.get(at).unwrap()).0;
accumulate(
point_index,
srs.fixed_commitments[wire.0],
vk.fixed_commitments[wire.0],
self.fixed_evals[query_index],
);
}
let current_index = (*srs.cs.rotations.get(&Rotation::default()).unwrap()).0;
let current_index = (*vk.cs.rotations.get(&Rotation::default()).unwrap()).0;
for (commitment, eval) in self.h_commitments.iter().zip(self.h_evals.iter()) {
accumulate(current_index, *commitment, *eval);
}
// Handle permutation arguments, if any exist
if !srs.cs.permutations.is_empty() {
if !vk.cs.permutations.is_empty() {
// Open permutation product commitments at x_3
for (commitment, eval) in self
.permutation_product_commitments
@ -221,7 +221,7 @@ impl<'a, C: CurveAffine> Proof<C> {
accumulate(current_index, *commitment, *eval);
}
// Open permutation commitments for each permutation argument at x_3
for (commitment, eval) in srs
for (commitment, eval) in vk
.permutation_commitments
.iter()
.zip(self.permutation_evals.iter())
@ -229,7 +229,7 @@ impl<'a, C: CurveAffine> Proof<C> {
{
accumulate(current_index, *commitment, *eval);
}
let current_index = (*srs.cs.rotations.get(&Rotation(-1)).unwrap()).0;
let current_index = (*vk.cs.rotations.get(&Rotation(-1)).unwrap()).0;
// Open permutation product commitments at \omega^{-1} x_3
for (commitment, eval) in self
.permutation_product_commitments
@ -263,10 +263,10 @@ impl<'a, C: CurveAffine> Proof<C> {
// We can compute the expected msm_eval at x_6 using the q_evals provided
// by the prover and from x_5
let mut msm_eval = C::Scalar::zero();
for (&row, point_index) in srs.cs.rotations.iter() {
for (&row, point_index) in vk.cs.rotations.iter() {
let mut eval = self.q_evals[point_index.0];
let point = srs.domain.rotate_omega(x_3, row);
let point = vk.domain.rotate_omega(x_3, row);
eval = eval - &q_evals[point_index.0];
eval = eval * &(x_6 - &point).invert().unwrap();
@ -281,7 +281,7 @@ impl<'a, C: CurveAffine> Proof<C> {
// Compute the final commitment that has to be opened
let mut commitment_msm = params.empty_msm();
commitment_msm.add_term(C::Scalar::one(), self.f_commitment);
for (_, &point_index) in srs.cs.rotations.iter() {
for (_, &point_index) in vk.cs.rotations.iter() {
commitment_msm.scale(x_7);
commitment_msm.add_msm(&q_commitments[point_index.0]);
msm_eval *= &x_7;