From e51ab7eaa752d175791420d321cc9a16f3dda047 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 3 Dec 2020 11:56:22 +0800 Subject: [PATCH] Linearise state transition from Argument -> Permuted -> Committed --- src/plonk/lookup/prover.rs | 215 ++++++++++++++++--------------------- src/plonk/prover.rs | 60 +++-------- 2 files changed, 105 insertions(+), 170 deletions(-) diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index 87cdf18..e2f5728 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -15,14 +15,18 @@ use crate::{ use ff::Field; use std::{collections::BTreeMap, convert::TryFrom, iter}; -#[derive(Clone, Debug)] -pub(crate) struct Permuted { +#[derive(Debug)] +pub(crate) struct Permuted<'a, C: CurveAffine> { + unpermuted_input_values: Vec<&'a Polynomial>, + unpermuted_input_cosets: Vec<&'a Polynomial>, permuted_input_value: Polynomial, permuted_input_poly: Polynomial, permuted_input_coset: Polynomial, permuted_input_inv_coset: Polynomial, permuted_input_blind: Blind, permuted_input_commitment: C, + unpermuted_table_values: Vec<&'a Polynomial>, + unpermuted_table_cosets: Vec<&'a Polynomial>, permuted_table_value: Polynomial, permuted_table_poly: Polynomial, permuted_table_coset: Polynomial, @@ -30,8 +34,9 @@ pub(crate) struct Permuted { permuted_table_commitment: C, } -#[derive(Clone, Debug)] -pub(crate) struct Product { +#[derive(Debug)] +pub(crate) struct Committed<'a, C: CurveAffine> { + permuted: Permuted<'a, C>, product_poly: Polynomial, product_coset: Polynomial, product_inv_coset: Polynomial, @@ -39,12 +44,6 @@ pub(crate) struct Product { product_commitment: C, } -#[derive(Clone, Debug)] -pub(crate) struct Committed { - pub permuted: Permuted, - pub product: Product, -} - pub(crate) struct Constructed { permuted_input_poly: Polynomial, permuted_input_blind: Blind, @@ -77,6 +76,7 @@ impl Argument { /// permuted_table_value = S'. /// The Permuted struct is used to update the Lookup, and is then returned. pub(in crate::plonk) fn commit_permuted< + 'a, C: CurveAffine, HBase: Hasher, HScalar: Hasher, @@ -86,21 +86,42 @@ impl Argument { params: &Params, domain: &EvaluationDomain, theta: ChallengeTheta, - advice_values: &[Polynomial], - fixed_values: &[Polynomial], - aux_values: &[Polynomial], + advice_values: &'a [Polynomial], + fixed_values: &'a [Polynomial], + aux_values: &'a [Polynomial], + advice_cosets: &'a [Polynomial], + fixed_cosets: &'a [Polynomial], + aux_cosets: &'a [Polynomial], transcript: &mut Transcript, - ) -> Result, Error> { + ) -> Result, Error> { // Values of input columns involved in the lookup - let unpermuted_input_values: Vec> = self + let (unpermuted_input_values, unpermuted_input_cosets): (Vec<_>, Vec<_>) = self .input_columns .iter() .map(|&input| match input.column_type() { - Any::Advice => advice_values[input.index()].clone(), - Any::Fixed => fixed_values[input.index()].clone(), - Any::Aux => aux_values[input.index()].clone(), + Any::Advice => ( + &advice_values[input.index()], + &advice_cosets[pk + .vk + .cs + .get_advice_query_index(Column::::try_from(input).unwrap(), 0)], + ), + Any::Fixed => ( + &fixed_values[input.index()], + &fixed_cosets[pk + .vk + .cs + .get_fixed_query_index(Column::::try_from(input).unwrap(), 0)], + ), + Any::Aux => ( + &aux_values[input.index()], + &aux_cosets[pk + .vk + .cs + .get_aux_query_index(Column::::try_from(input).unwrap(), 0)], + ), }) - .collect(); + .unzip(); // Compressed version of input columns let compressed_input_value = unpermuted_input_values @@ -108,15 +129,33 @@ impl Argument { .fold(domain.empty_lagrange(), |acc, input| acc * *theta + input); // Values of table columns involved in the lookup - let unpermuted_table_values: Vec> = self + let (unpermuted_table_values, unpermuted_table_cosets): (Vec<_>, Vec<_>) = self .table_columns .iter() .map(|&table| match table.column_type() { - Any::Advice => advice_values[table.index()].clone(), - Any::Fixed => fixed_values[table.index()].clone(), - Any::Aux => aux_values[table.index()].clone(), + Any::Advice => ( + &advice_values[table.index()], + &advice_cosets[pk + .vk + .cs + .get_advice_query_index(Column::::try_from(table).unwrap(), 0)], + ), + Any::Fixed => ( + &fixed_values[table.index()], + &fixed_cosets[pk + .vk + .cs + .get_fixed_query_index(Column::::try_from(table).unwrap(), 0)], + ), + Any::Aux => ( + &aux_values[table.index()], + &aux_cosets[pk + .vk + .cs + .get_aux_query_index(Column::::try_from(table).unwrap(), 0)], + ), }) - .collect(); + .unzip(); // Compressed version of table columns let compressed_table_value = unpermuted_table_values @@ -164,12 +203,16 @@ impl Argument { .map_err(|_| Error::TranscriptError)?; Ok(Permuted { + unpermuted_input_values, + unpermuted_input_cosets, permuted_input_value, permuted_input_poly, permuted_input_coset, permuted_input_inv_coset, permuted_input_blind, permuted_input_commitment, + unpermuted_table_values, + unpermuted_table_cosets, permuted_table_value, permuted_table_poly, permuted_table_coset, @@ -177,50 +220,23 @@ impl Argument { permuted_table_commitment, }) } +} +impl<'a, C: CurveAffine> Permuted<'a, C> { /// Given a Lookup with input columns, table columns, and the permuted /// input column and permuted table column, this method constructs the /// grand product polynomial over the lookup. The grand product polynomial /// is used to populate the Product struct. The Product struct is /// added to the Lookup and finally returned by the method. - pub(in crate::plonk) fn commit_product< - C: CurveAffine, - HBase: Hasher, - HScalar: Hasher, - >( - &self, - permuted: &Permuted, + pub(in crate::plonk) fn commit_product, HScalar: Hasher>( + self, pk: &ProvingKey, params: &Params, theta: ChallengeTheta, beta: ChallengeBeta, gamma: ChallengeGamma, - advice_values: &[Polynomial], - fixed_values: &[Polynomial], - aux_values: &[Polynomial], transcript: &mut Transcript, - ) -> Result, Error> { - let permuted = permuted.clone(); - let unpermuted_input_values: Vec> = self - .input_columns - .iter() - .map(|&input| match input.column_type() { - Any::Advice => advice_values[input.index()].clone(), - Any::Fixed => fixed_values[input.index()].clone(), - Any::Aux => aux_values[input.index()].clone(), - }) - .collect(); - - let unpermuted_table_values: Vec> = self - .table_columns - .iter() - .map(|&table| match table.column_type() { - Any::Advice => advice_values[table.index()].clone(), - Any::Fixed => fixed_values[table.index()].clone(), - Any::Aux => aux_values[table.index()].clone(), - }) - .collect(); - + ) -> Result, Error> { // Goal is to compute the products of fractions // // (a_1(\omega^i) + \theta a_2(\omega^i) + ... + beta)(s_1(\omega^i) + \theta(\omega^i) + ... + \gamma) / @@ -237,8 +253,8 @@ impl Argument { parallelize(&mut lookup_product, |lookup_product, start| { for ((lookup_product, permuted_input_value), permuted_table_value) in lookup_product .iter_mut() - .zip(permuted.permuted_input_value[start..].iter()) - .zip(permuted.permuted_table_value[start..].iter()) + .zip(self.permuted_input_value[start..].iter()) + .zip(self.permuted_table_value[start..].iter()) { *lookup_product *= &(*beta + permuted_input_value); *lookup_product *= &(*gamma + permuted_table_value); @@ -253,7 +269,7 @@ impl Argument { // (a_1(X) + \theta a_2(X) + ... + \beta) (s_1(X) + \theta s_2(X) + ... + \gamma) // Compress unpermuted input columns let mut input_term = vec![C::Scalar::zero(); params.n as usize]; - for unpermuted_input_value in unpermuted_input_values.iter() { + for unpermuted_input_value in self.unpermuted_input_values.iter() { parallelize(&mut input_term, |input_term, start| { for (input_term, input_value) in input_term .iter_mut() @@ -267,7 +283,7 @@ impl Argument { // Compress unpermuted table columns let mut table_term = vec![C::Scalar::zero(); params.n as usize]; - for unpermuted_table_value in unpermuted_table_values.iter() { + for unpermuted_table_value in self.unpermuted_table_values.iter() { parallelize(&mut table_term, |table_term, start| { for (table_term, fixed_value) in table_term .iter_mut() @@ -325,19 +341,19 @@ impl Argument { let prev_idx = (n + i - 1) % n; let mut left = z[i]; - let permuted_input_value = &permuted.permuted_input_value[i]; + let permuted_input_value = &self.permuted_input_value[i]; - let permuted_table_value = &permuted.permuted_table_value[i]; + let permuted_table_value = &self.permuted_table_value[i]; left *= &(*beta + permuted_input_value); left *= &(*gamma + permuted_table_value); let mut right = z[prev_idx]; - let mut input_term = unpermuted_input_values + let mut input_term = self.unpermuted_input_values .iter() .fold(C::Scalar::zero(), |acc, input| acc * &theta + &input[i]); - let mut table_term = unpermuted_table_values + let mut table_term = self.unpermuted_table_values .iter() .fold(C::Scalar::zero(), |acc, table| acc * &theta + &table[i]); @@ -363,7 +379,8 @@ impl Argument { .absorb_point(&product_commitment) .map_err(|_| Error::TranscriptError)?; - Ok(Product:: { + Ok(Committed::<'a, C> { + permuted: self, product_poly: z, product_coset, product_inv_coset, @@ -373,22 +390,18 @@ impl Argument { } } -impl Committed { +impl<'a, C: CurveAffine> Committed<'a, C> { /// Given a Lookup with input columns, table columns, permuted input /// column, permuted table column, and grand product polynomial, this /// method constructs constraints that must hold between these values. /// This method returns the constraints as a vector of polynomials in /// the extended evaluation domain. - pub(in crate::plonk) fn construct<'a>( + pub(in crate::plonk) fn construct( self, pk: &'a ProvingKey, theta: ChallengeTheta, beta: ChallengeBeta, gamma: ChallengeGamma, - argument: &'a Argument, - advice_cosets: &'a [Polynomial], - fixed_cosets: &'a [Polynomial], - aux_cosets: &'a [Polynomial], ) -> Result< ( Constructed, @@ -397,61 +410,17 @@ impl Committed { Error, > { let permuted = self.permuted; - let product = self.product; - let unpermuted_input_cosets: Vec> = argument - .input_columns - .iter() - .map(|&input| match input.column_type() { - Any::Advice => advice_cosets[pk - .vk - .cs - .get_advice_query_index(Column::::try_from(input).unwrap(), 0)] - .clone(), - Any::Fixed => fixed_cosets[pk - .vk - .cs - .get_fixed_query_index(Column::::try_from(input).unwrap(), 0)] - .clone(), - Any::Aux => aux_cosets[pk - .vk - .cs - .get_aux_query_index(Column::::try_from(input).unwrap(), 0)] - .clone(), - }) - .collect(); - - let unpermuted_table_cosets: Vec> = argument - .table_columns - .iter() - .map(|&table| match table.column_type() { - Any::Advice => advice_cosets[pk - .vk - .cs - .get_advice_query_index(Column::::try_from(table).unwrap(), 0)] - .clone(), - Any::Fixed => fixed_cosets[pk - .vk - .cs - .get_fixed_query_index(Column::::try_from(table).unwrap(), 0)] - .clone(), - Any::Aux => aux_cosets[pk - .vk - .cs - .get_aux_query_index(Column::::try_from(table).unwrap(), 0)] - .clone(), - }) - .collect(); let expressions = iter::empty() // l_0(X) * (1 - z'(X)) = 0 .chain(Some( - Polynomial::one_minus(product.product_coset.clone()) * &pk.l0, + Polynomial::one_minus(self.product_coset.clone()) * &pk.l0, )) // z'(X) (a'(X) + \beta) (s'(X) + \gamma) // - z'(\omega^{-1} X) (a_1(X) + \theta a_2(X) + ... + \beta) (s_1(X) + \theta s_2(X) + ... + \gamma) .chain({ // z'(X) (a'(X) + \beta) (s'(X) + \gamma) - let mut left = product.product_coset.clone(); + let mut left = self.product_coset.clone(); parallelize(&mut left, |left, start| { for ((left, permuted_input), permuted_table) in left .iter_mut() @@ -464,11 +433,11 @@ impl Committed { }); // z'(\omega^{-1} X) (a_1(X) + \theta a_2(X) + ... + \beta) (s_1(X) + \theta s_2(X) + ... + \gamma) - let mut right = product.product_inv_coset; + let mut right = self.product_inv_coset; let mut input_terms = pk.vk.domain.empty_extended(); // Compress the unpermuted input columns - for input in unpermuted_input_cosets.iter() { + for input in permuted.unpermuted_input_cosets.iter() { // (a_1(X) + \theta a_2(X) + ...) parallelize(&mut input_terms, |input_term, start| { for (input_term, input) in input_term.iter_mut().zip(input[start..].iter()) @@ -481,7 +450,7 @@ impl Committed { let mut table_terms = pk.vk.domain.empty_extended(); // Compress the unpermuted table columns - for table in unpermuted_table_cosets.iter() { + for table in permuted.unpermuted_table_cosets.iter() { // (s_1(X) + \theta s_2(X) + ...) parallelize(&mut table_terms, |table_term, start| { for (table_term, table) in table_term.iter_mut().zip(table[start..].iter()) @@ -529,9 +498,9 @@ impl Committed { permuted_table_poly: permuted.permuted_table_poly, permuted_table_blind: permuted.permuted_table_blind, permuted_table_commitment: permuted.permuted_table_commitment, - product_poly: product.product_poly, - product_blind: product.product_blind, - product_commitment: product.product_commitment, + product_poly: self.product_poly, + product_blind: self.product_blind, + product_commitment: self.product_commitment, }, expressions, )) diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index ea826cf..5f3b13e 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -3,8 +3,8 @@ use std::iter; use super::{ circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed}, - lookup, permutation, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, - Error, Proof, ProvingKey, + permutation, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, + Proof, ProvingKey, }; use crate::arithmetic::{eval_polynomial, Curve, CurveAffine, FieldExt}; use crate::poly::{ @@ -172,8 +172,8 @@ impl Proof { // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::::get(&mut transcript); - // Construct permuted values for each lookup - let lookups_permuted = pk + // Construct and commit to permuted values for each lookup + let lookups = pk .vk .cs .lookups @@ -188,6 +188,9 @@ impl Proof { &witness.advice, &pk.fixed_values, &aux, + &advice_cosets, + &pk.fixed_cosets, + &aux_cosets, &mut transcript, ) .unwrap() @@ -214,40 +217,16 @@ impl Proof { None }; - // Construct products for each lookup - let lookups_products = pk - .vk - .cs - .lookups - .iter() - .zip(lookups_permuted.iter()) - .map(|(lookup, permuted)| { + // Construct and commit to products for each lookup + let lookups = lookups + .into_iter() + .map(|lookup| { lookup - .commit_product( - permuted, - &pk, - ¶ms, - theta, - beta, - gamma, - &witness.advice, - &pk.fixed_values, - &aux, - &mut transcript, - ) + .commit_product(&pk, ¶ms, theta, beta, gamma, &mut transcript) .unwrap() }) .collect::>(); - let lookups = lookups_permuted - .iter() - .zip(lookups_products.iter()) - .map(|(permuted, product)| lookup::prover::Committed { - permuted: permuted.clone(), - product: product.clone(), - }) - .collect::>(); - // Obtain challenge for keeping all separate gates linearly independent let y = ChallengeY::::get(&mut transcript); @@ -261,20 +240,7 @@ impl Proof { // Evaluate the h(X) polynomial's constraint system expressions for the lookup constraints, if any. let (lookups, lookup_expressions): (Vec<_>, Vec<_>) = lookups .into_iter() - .zip(pk.vk.cs.lookups.iter()) - .map(|(p, argument)| { - p.construct( - pk, - theta, - beta, - gamma, - argument, - &advice_cosets, - &pk.fixed_cosets, - &aux_cosets, - ) - .unwrap() - }) + .map(|p| p.construct(pk, theta, beta, gamma).unwrap()) .unzip(); // Evaluate the h(X) polynomial's constraint system expressions for the constraints provided