From 845382b472fdb4768bf8c33cadfba437db519193 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 27 May 2021 17:20:26 +0200 Subject: [PATCH 01/11] Working base field check for (non-batch) opening --- src/bin/bench_recursion.rs | 3 ++- src/circuit_data.rs | 1 + src/fri/mod.rs | 5 +++++ src/fri/verifier.rs | 20 ++++++++++++++++++-- src/plonk_common.rs | 14 ++++++++++++++ src/polynomial/commitment.rs | 35 ++++++++++++++++++++++++++--------- src/polynomial/polynomial.rs | 11 ++++++++++- src/prover.rs | 3 +++ 8 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index efab1dd8..ff3a3ba2 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -9,7 +9,7 @@ use plonky2::fri::FriConfig; use plonky2::gates::constant::ConstantGate; use plonky2::gates::gmimc::GMiMCGate; use plonky2::hash::GMIMC_ROUNDS; -use plonky2::prover::PLONK_BLINDING; +use plonky2::prover::{PLONK_BLINDING, PLONK_CHECK_BASEFIELD}; use plonky2::witness::PartialWitness; fn main() { @@ -43,6 +43,7 @@ fn bench_prove, const D: usize>() { reduction_arity_bits: vec![1], num_query_rounds: 1, blinding: PLONK_BLINDING.to_vec(), + check_basefield: PLONK_CHECK_BASEFIELD.to_vec(), }, }; diff --git a/src/circuit_data.rs b/src/circuit_data.rs index d45192cb..87798044 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -38,6 +38,7 @@ impl Default for CircuitConfig { reduction_arity_bits: vec![1], num_query_rounds: 1, blinding: vec![true], + check_basefield: vec![false], }, } } diff --git a/src/fri/mod.rs b/src/fri/mod.rs index d701c421..37df9f94 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -23,6 +23,10 @@ pub struct FriConfig { /// Vector of the same length as the number of initial Merkle trees. /// `blinding[i]==true` iff the i-th tree is salted. pub blinding: Vec, + + /// Vector of the same length as the number of initial Merkle trees. + /// `check_basefield[i]==true` iff the polynomials in the i-th tree are checked to be in the base field. + pub check_basefield: Vec, } fn fri_delta(rate_log: usize, conjecture: bool) -> f64 { @@ -82,6 +86,7 @@ mod tests { proof_of_work_bits: 2, reduction_arity_bits, blinding: vec![false], + check_basefield: vec![false], }; let tree = { let mut leaves = coset_lde diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 80997956..4ca699a5 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -1,4 +1,4 @@ -use crate::field::extension_field::{flatten, Extendable, FieldExtension}; +use crate::field::extension_field::{flatten, Extendable, FieldExtension, OEF}; use crate::field::field::Field; use crate::field::lagrange::{barycentric_weights, interpolant, interpolate}; use crate::fri::FriConfig; @@ -159,7 +159,23 @@ fn fri_combine_initial, const D: usize>( .iter() .map(|&(x, _)| F::Extension::from_basefield(subgroup_x) - x) .product(); - numerator / denominator + let quotient = numerator / denominator; + let quotient = if config.check_basefield[0] { + let alpha_conj = alpha.frobenius(); + let comp_conj = proof + .evals_proofs + .iter() + .enumerate() + .flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }]) + .rev() + .fold(F::Extension::ZERO, |acc, &e| alpha_conj * acc + e.into()); + let numerator = comp_conj - points[0].1.frobenius(); + let denominator = F::Extension::from_basefield(subgroup_x) - points[0].0.frobenius(); + quotient + (numerator / denominator) * alpha.exp(proof.evals_proofs[0].0.len() as u64) + } else { + quotient + }; + quotient } fn fri_verifier_query_round, const D: usize>( diff --git a/src/plonk_common.rs b/src/plonk_common.rs index ed780817..ab28ce21 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -1,6 +1,8 @@ use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::gates::gate::GateRef; +use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars}; @@ -80,6 +82,18 @@ pub(crate) fn reduce_with_powers(terms: &[F], alpha: F) -> F { sum } +pub(crate) fn reduce_polys_with_powers, const D: usize>( + polynomials: &[PolynomialCoeffs], + alpha: F::Extension, +) -> PolynomialCoeffs { + polynomials + .iter() + .rev() + .fold(PolynomialCoeffs::empty(), |acc, p| { + &(&acc * alpha) + &p.to_extension() + }) +} + pub(crate) fn reduce_with_powers_recursive( builder: &mut CircuitBuilder, terms: Vec, diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index aa58c561..90331d33 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -1,14 +1,14 @@ use anyhow::Result; use rayon::prelude::*; -use crate::field::extension_field::Extendable; use crate::field::extension_field::FieldExtension; +use crate::field::extension_field::{Extendable, OEF}; use crate::field::field::Field; use crate::field::lagrange::interpolant; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; -use crate::plonk_common::reduce_with_powers; +use crate::plonk_common::{reduce_polys_with_powers, reduce_with_powers}; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, Hash, OpeningSet}; use crate::timed; @@ -86,6 +86,7 @@ impl ListPolynomialCommitment { F: Extendable, { assert_eq!(self.rate_bits, config.rate_bits); + assert_eq!(config.check_basefield.len(), 1); assert_eq!(config.blinding.len(), 1); assert_eq!(self.blinding, config.blinding[0]); for p in points { @@ -114,13 +115,7 @@ impl ListPolynomialCommitment { let alpha = challenger.get_extension_challenge(); // Scale polynomials by `alpha`. - let composition_poly = self - .polynomials - .iter() - .rev() - .fold(PolynomialCoeffs::zero(self.degree), |acc, p| { - &(&acc * alpha) + &p.to_extension() - }); + let composition_poly = reduce_polys_with_powers(&self.polynomials, alpha); // Scale evaluations by `alpha`. let composition_evals = evaluations .par_iter() @@ -129,6 +124,24 @@ impl ListPolynomialCommitment { let quotient = Self::compute_quotient(points, &composition_evals, &composition_poly); + let quotient = if config.check_basefield[0] { + let composition_poly_conj = PolynomialCoeffs::::frobenius(&composition_poly); + // This equality holds iff the polynomials in `self.polynomials` are defined over `F` and not `F::Extension`. + debug_assert_eq!( + composition_poly_conj.eval(points[0].frobenius()), + composition_evals[0].frobenius() + ); + let quotient_conj = Self::compute_quotient( + &[points[0].frobenius()], + &[composition_evals[0].frobenius()], + &composition_poly_conj, + ); + + &("ient_conj * alpha.exp(self.polynomials.len() as u64)) + "ient + } else { + quotient + }; + let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.rate_bits); let lde_quotient_values = lde_quotient .clone() @@ -391,6 +404,7 @@ mod tests { reduction_arity_bits: vec![3, 2, 1, 2], num_query_rounds: 3, blinding: vec![false], + check_basefield: vec![true], }; let (polys, points) = gen_random_test_case::(k, degree_log, num_points); @@ -416,6 +430,7 @@ mod tests { reduction_arity_bits: vec![3, 2, 1, 2], num_query_rounds: 3, blinding: vec![true], + check_basefield: vec![false], }; let (polys, points) = gen_random_test_case::(k, degree_log, num_points); @@ -442,6 +457,7 @@ mod tests { reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, blinding: vec![false, false, false], + check_basefield: vec![false, false, false], }; let (polys0, _) = gen_random_test_case::(k0, degree_log, num_points); let (polys1, _) = gen_random_test_case::(k1, degree_log, num_points); @@ -483,6 +499,7 @@ mod tests { reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, blinding: vec![true, false, true], + check_basefield: vec![true, false, true], }; let (polys0, _) = gen_random_test_case::(k0, degree_log, num_points); let (polys1, _) = gen_random_test_case::(k1, degree_log, num_points); diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index 5e3dd9f0..80c22db8 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -1,7 +1,7 @@ use std::cmp::max; use std::ops::{Add, Mul, Sub}; -use crate::field::extension_field::Extendable; +use crate::field::extension_field::{Extendable, OEF}; use crate::field::fft::{fft, ifft}; use crate::field::field::Field; use crate::util::log2_strict; @@ -186,6 +186,15 @@ impl PolynomialCoeffs { { PolynomialCoeffs::new(self.coeffs.iter().map(|&c| c.into()).collect()) } + + pub fn frobenius( + poly: &PolynomialCoeffs, + ) -> PolynomialCoeffs + where + F: Extendable, + { + PolynomialCoeffs::new(poly.coeffs.iter().map(|&c| c.frobenius()).collect()) + } } impl PartialEq for PolynomialCoeffs { diff --git a/src/prover.rs b/src/prover.rs index a90d81f1..be100160 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -22,6 +22,9 @@ use crate::witness::PartialWitness; /// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments. pub const PLONK_BLINDING: [bool; 5] = [false, false, true, true, true]; +/// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments. +pub const PLONK_CHECK_BASEFIELD: [bool; 5] = [false, false, true, false, false]; + pub(crate) fn prove, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, From abc0ca3bf19ecced009f7934875a3bb28951242f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 31 May 2021 17:49:04 +0200 Subject: [PATCH 02/11] Rewrite LPC code to be more PLONK-specific --- src/fri/mod.rs | 266 +++++++-------- src/fri/verifier.rs | 156 ++++++--- src/plonk_challenger.rs | 26 +- src/polynomial/commitment.rs | 605 +++++++++++++++++++++-------------- src/proof.rs | 30 +- src/prover.rs | 9 +- 6 files changed, 657 insertions(+), 435 deletions(-) diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 37df9f94..dcd458fd 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -52,136 +52,136 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 { } } -#[cfg(test)] -mod tests { - use super::*; - use crate::field::crandall_field::CrandallField; - use crate::field::extension_field::quadratic::QuadraticCrandallField; - use crate::field::extension_field::quartic::QuarticCrandallField; - use crate::field::extension_field::{flatten, Extendable, FieldExtension}; - use crate::field::fft::ifft; - use crate::field::field::Field; - use crate::fri::prover::fri_proof; - use crate::fri::verifier::verify_fri_proof; - use crate::merkle_tree::MerkleTree; - use crate::plonk_challenger::Challenger; - use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; - use crate::util::reverse_index_bits_in_place; - use anyhow::Result; - use rand::rngs::ThreadRng; - use rand::Rng; - - fn check_fri, const D: usize>( - degree_log: usize, - rate_bits: usize, - reduction_arity_bits: Vec, - num_query_rounds: usize, - ) -> Result<()> { - let n = 1 << degree_log; - let coeffs = PolynomialCoeffs::new(F::rand_vec(n)).lde(rate_bits); - let coset_lde = coeffs.clone().coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR); - let config = FriConfig { - num_query_rounds, - rate_bits, - proof_of_work_bits: 2, - reduction_arity_bits, - blinding: vec![false], - check_basefield: vec![false], - }; - let tree = { - let mut leaves = coset_lde - .values - .iter() - .map(|&x| vec![x]) - .collect::>(); - reverse_index_bits_in_place(&mut leaves); - MerkleTree::new(leaves, false) - }; - let coset_lde = PolynomialValues::new( - coset_lde - .values - .into_iter() - .map(F::Extension::from) - .collect(), - ); - let root = tree.root; - let mut challenger = Challenger::new(); - let proof = fri_proof::( - &[&tree], - &coeffs.to_extension::(), - &coset_lde, - &mut challenger, - &config, - ); - - let mut challenger = Challenger::new(); - verify_fri_proof( - degree_log, - &[], - F::Extension::ONE, - &[root], - &proof, - &mut challenger, - &config, - )?; - - Ok(()) - } - - fn gen_arities(degree_log: usize, rng: &mut ThreadRng) -> Vec { - let mut arities = Vec::new(); - let mut remaining = degree_log; - while remaining > 0 { - let arity = rng.gen_range(0, remaining + 1); - arities.push(arity); - remaining -= arity; - } - arities - } - - fn check_fri_multi_params, const D: usize>() -> Result<()> { - let mut rng = rand::thread_rng(); - for degree_log in 1..6 { - for rate_bits in 0..3 { - for num_query_round in 0..4 { - for _ in 0..3 { - check_fri::( - degree_log, - rate_bits, - gen_arities(degree_log, &mut rng), - num_query_round, - )?; - } - } - } - } - Ok(()) - } - - mod base { - use super::*; - - #[test] - fn test_fri_multi_params() -> Result<()> { - check_fri_multi_params::() - } - } - - mod quadratic { - use super::*; - - #[test] - fn test_fri_multi_params() -> Result<()> { - check_fri_multi_params::() - } - } - - mod quartic { - use super::*; - - #[test] - fn test_fri_multi_params() -> Result<()> { - check_fri_multi_params::() - } - } -} +// #[cfg(test)] +// mod tests { +// use super::*; +// use crate::field::crandall_field::CrandallField; +// use crate::field::extension_field::quadratic::QuadraticCrandallField; +// use crate::field::extension_field::quartic::QuarticCrandallField; +// use crate::field::extension_field::{flatten, Extendable, FieldExtension}; +// use crate::field::fft::ifft; +// use crate::field::field::Field; +// use crate::fri::prover::fri_proof; +// use crate::fri::verifier::verify_fri_proof; +// use crate::merkle_tree::MerkleTree; +// use crate::plonk_challenger::Challenger; +// use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; +// use crate::util::reverse_index_bits_in_place; +// use anyhow::Result; +// use rand::rngs::ThreadRng; +// use rand::Rng; +// +// fn check_fri, const D: usize>( +// degree_log: usize, +// rate_bits: usize, +// reduction_arity_bits: Vec, +// num_query_rounds: usize, +// ) -> Result<()> { +// let n = 1 << degree_log; +// let coeffs = PolynomialCoeffs::new(F::rand_vec(n)).lde(rate_bits); +// let coset_lde = coeffs.clone().coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR); +// let config = FriConfig { +// num_query_rounds, +// rate_bits, +// proof_of_work_bits: 2, +// reduction_arity_bits, +// blinding: vec![false], +// check_basefield: vec![false], +// }; +// let tree = { +// let mut leaves = coset_lde +// .values +// .iter() +// .map(|&x| vec![x]) +// .collect::>(); +// reverse_index_bits_in_place(&mut leaves); +// MerkleTree::new(leaves, false) +// }; +// let coset_lde = PolynomialValues::new( +// coset_lde +// .values +// .into_iter() +// .map(F::Extension::from) +// .collect(), +// ); +// let root = tree.root; +// let mut challenger = Challenger::new(); +// let proof = fri_proof::( +// &[&tree], +// &coeffs.to_extension::(), +// &coset_lde, +// &mut challenger, +// &config, +// ); +// +// let mut challenger = Challenger::new(); +// verify_fri_proof( +// degree_log, +// &[], +// F::Extension::ONE, +// &[root], +// &proof, +// &mut challenger, +// &config, +// )?; +// +// Ok(()) +// } +// +// fn gen_arities(degree_log: usize, rng: &mut ThreadRng) -> Vec { +// let mut arities = Vec::new(); +// let mut remaining = degree_log; +// while remaining > 0 { +// let arity = rng.gen_range(0, remaining + 1); +// arities.push(arity); +// remaining -= arity; +// } +// arities +// } +// +// fn check_fri_multi_params, const D: usize>() -> Result<()> { +// let mut rng = rand::thread_rng(); +// for degree_log in 1..6 { +// for rate_bits in 0..3 { +// for num_query_round in 0..4 { +// for _ in 0..3 { +// check_fri::( +// degree_log, +// rate_bits, +// gen_arities(degree_log, &mut rng), +// num_query_round, +// )?; +// } +// } +// } +// } +// Ok(()) +// } +// +// mod base { +// use super::*; +// +// #[test] +// fn test_fri_multi_params() -> Result<()> { +// check_fri_multi_params::() +// } +// } +// +// mod quadratic { +// use super::*; +// +// #[test] +// fn test_fri_multi_params() -> Result<()> { +// check_fri_multi_params::() +// } +// } +// +// mod quartic { +// use super::*; +// +// #[test] +// fn test_fri_multi_params() -> Result<()> { +// check_fri_multi_params::() +// } +// } +// } diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 4ca699a5..7d77625e 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -5,9 +5,10 @@ use crate::fri::FriConfig; use crate::hash::hash_n_to_1; use crate::merkle_proofs::verify_merkle_proof; use crate::plonk_challenger::Challenger; +use crate::plonk_common::reduce_with_powers; use crate::polynomial::commitment::SALT_SIZE; use crate::polynomial::polynomial::PolynomialCoeffs; -use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash}; +use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; use anyhow::{ensure, Result}; @@ -65,8 +66,10 @@ fn fri_verify_proof_of_work, const D: usize>( pub fn verify_fri_proof, const D: usize>( purported_degree_log: usize, - // Point-evaluation pairs for polynomial commitments. - points: &[(F::Extension, F::Extension)], + // Openings of the PLONK polynomials. + os: &OpeningSet, + // Point at which the PLONK polynomials are opened. + zeta: F::Extension, // Scaling factor to combine polynomials. alpha: F::Extension, initial_merkle_roots: &[Hash], @@ -108,11 +111,10 @@ pub fn verify_fri_proof, const D: usize>( "Number of reductions should be non-zero." ); - let interpolant = interpolant(points); for round_proof in &proof.query_round_proofs { fri_verifier_query_round( - &interpolant, - points, + os, + zeta, alpha, initial_merkle_roots, &proof, @@ -139,48 +141,128 @@ fn fri_verify_initial_proof( Ok(()) } +// fn fri_combine_initial, const D: usize>( +// proof: &FriInitialTreeProof, +// alpha: F::Extension, +// opening_set: &OpeningSet, +// zeta: F::Extension, +// subgroup_x: F, +// config: &FriConfig, +// ) -> F::Extension { +// let e = proof +// .evals_proofs +// .iter() +// .enumerate() +// .flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }]) +// .rev() +// .fold(F::Extension::ZERO, |acc, &e| alpha * acc + e.into()); +// let numerator = e - interpolant.eval(subgroup_x.into()); +// let denominator = points +// .iter() +// .map(|&(x, _)| F::Extension::from_basefield(subgroup_x) - x) +// .product(); +// let quotient = numerator / denominator; +// let quotient = if config.check_basefield[0] { +// let alpha_conj = alpha.frobenius(); +// let comp_conj = proof +// .evals_proofs +// .iter() +// .enumerate() +// .flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }]) +// .rev() +// .fold(F::Extension::ZERO, |acc, &e| alpha_conj * acc + e.into()); +// let numerator = comp_conj - points[0].1.frobenius(); +// let denominator = F::Extension::from_basefield(subgroup_x) - points[0].0.frobenius(); +// quotient + (numerator / denominator) * alpha.exp(proof.evals_proofs[0].0.len() as u64) +// } else { +// quotient +// }; +// quotient +// } fn fri_combine_initial, const D: usize>( proof: &FriInitialTreeProof, alpha: F::Extension, - interpolant: &PolynomialCoeffs, - points: &[(F::Extension, F::Extension)], + os: &OpeningSet, + zeta: F::Extension, subgroup_x: F, config: &FriConfig, ) -> F::Extension { - let e = proof - .evals_proofs + let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; + + let mut cur_alpha = F::Extension::ONE; + + let mut poly_count = 0; + let mut e = F::Extension::ZERO; + + let ev = [0, 1, 4] .iter() + .map(|&i| &proof.evals_proofs[i]) .enumerate() - .flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }]) + .flat_map(|(j, (v, _))| &v[..v.len() - if config.blinding[j] { SALT_SIZE } else { 0 }]) .rev() - .fold(F::Extension::ZERO, |acc, &e| alpha * acc + e.into()); - let numerator = e - interpolant.eval(subgroup_x.into()); - let denominator = points + .fold(F::Extension::ZERO, |acc, &e| { + poly_count += 1; + alpha * acc + e.into() + }); + let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] .iter() - .map(|&(x, _)| F::Extension::from_basefield(subgroup_x) - x) - .product(); - let quotient = numerator / denominator; - let quotient = if config.check_basefield[0] { - let alpha_conj = alpha.frobenius(); - let comp_conj = proof - .evals_proofs - .iter() - .enumerate() - .flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }]) - .rev() - .fold(F::Extension::ZERO, |acc, &e| alpha_conj * acc + e.into()); - let numerator = comp_conj - points[0].1.frobenius(); - let denominator = F::Extension::from_basefield(subgroup_x) - points[0].0.frobenius(); - quotient + (numerator / denominator) * alpha.exp(proof.evals_proofs[0].0.len() as u64) - } else { - quotient - }; - quotient + .flat_map(|v| v.iter()) + .rev() + .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); + let numerator = ev - composition_eval; + let denominator = F::Extension::from_basefield(subgroup_x) - zeta; + e += cur_alpha * numerator / denominator; + cur_alpha = alpha.exp(poly_count); + dbg!(e); + + let ev = proof.evals_proofs[3].0 + [..proof.evals_proofs[3].0.len() - if config.blinding[3] { SALT_SIZE } else { 0 }] + .iter() + .rev() + .fold(F::Extension::ZERO, |acc, &e| { + poly_count += 1; + alpha * acc + e.into() + }); + let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; + dbg!(degree_log); + let zs_interpol = interpolant(&[ + (zeta, reduce_with_powers(&os.plonk_zs, alpha)), + (zeta_right, reduce_with_powers(&os.plonk_zs_right, alpha)), + ]); + let numerator = ev - zs_interpol.eval(subgroup_x.into()); + let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) + * (F::Extension::from_basefield(subgroup_x) - zeta_right); + e += cur_alpha * numerator / denominator; + dbg!(e); + dbg!(cur_alpha); + cur_alpha = alpha.exp(poly_count); + + let ev = proof.evals_proofs[2].0 + [..proof.evals_proofs[2].0.len() - if config.blinding[2] { SALT_SIZE } else { 0 }] + .iter() + .rev() + .fold(F::Extension::ZERO, |acc, &e| { + poly_count += 1; + alpha * acc + e.into() + }); + let zeta_frob = zeta.frobenius(); + let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wires_interpol = interpolant(&[ + (zeta, reduce_with_powers(&os.wires, alpha)), + (zeta_frob, reduce_with_powers(&wire_evals_frob, alpha)), + ]); + let numerator = ev - wires_interpol.eval(subgroup_x.into()); + let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) + * (F::Extension::from_basefield(subgroup_x) - zeta_frob); + e += cur_alpha * numerator / denominator; + cur_alpha = alpha.exp(poly_count); + + e } fn fri_verifier_query_round, const D: usize>( - interpolant: &PolynomialCoeffs, - points: &[(F::Extension, F::Extension)], + os: &OpeningSet, + zeta: F::Extension, alpha: F::Extension, initial_merkle_roots: &[Hash], proof: &FriProof, @@ -211,8 +293,8 @@ fn fri_verifier_query_round, const D: usize>( fri_combine_initial( &round_proof.initial_trees_proof, alpha, - interpolant, - points, + os, + zeta, subgroup_x, config, ) diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index 6a1a8888..3a35878f 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -2,7 +2,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::hash::{permute, SPONGE_RATE, SPONGE_WIDTH}; -use crate::proof::{Hash, HashTarget}; +use crate::proof::{Hash, HashTarget, OpeningSet}; use crate::target::Target; /// Observes prover messages, and generates challenges by hashing the transcript. @@ -61,6 +61,30 @@ impl Challenger { } } + pub fn observe_opening_set(&mut self, os: &OpeningSet) + where + F: Extendable, + { + let OpeningSet { + constants, + plonk_sigmas, + wires, + plonk_zs, + plonk_zs_right, + quotient_polys, + } = os; + for v in &[ + constants, + plonk_sigmas, + wires, + plonk_zs, + plonk_zs_right, + quotient_polys, + ] { + self.observe_extension_elements(v); + } + } + pub fn observe_hash(&mut self, hash: &Hash) { self.observe_elements(&hash.elements) } diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 90331d33..7325a206 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -10,7 +10,7 @@ use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; use crate::plonk_common::{reduce_polys_with_powers, reduce_with_powers}; use crate::polynomial::polynomial::PolynomialCoeffs; -use crate::proof::{FriProof, Hash, OpeningSet}; +use crate::proof::{FriInitialTreeProof, FriProof, Hash, OpeningSet}; use crate::timed; use crate::util::{log2_strict, reverse_index_bits_in_place, transpose}; @@ -164,91 +164,282 @@ impl ListPolynomialCommitment { ) } - pub fn batch_open( - commitments: &[&Self], - points: &[F::Extension], + // pub fn batch_open( + // commitments: &[&Self], + // opening_config: &OpeningConfig, + // fri_config: &FriConfig, + // challenger: &mut Challenger, + // ) -> (OpeningProof, Vec>>>) + // where + // F: Extendable, + // { + // let degree = commitments[0].degree; + // assert_eq!(fri_config.blinding.len(), commitments.len()); + // for (i, commitment) in commitments.iter().enumerate() { + // assert_eq!(commitment.rate_bits, fri_config.rate_bits, "Invalid rate."); + // assert_eq!( + // commitment.blinding, fri_config.blinding[i], + // "Invalid blinding paramater." + // ); + // assert_eq!( + // commitment.degree, degree, + // "Trying to open polynomial commitments of different degrees." + // ); + // } + // for &p in opening_config.points.iter().flat_map(|(v, _)| v) { + // assert_ne!( + // p.exp(degree as u64), + // F::Extension::ONE, + // "Opening point is in the subgroup." + // ); + // } + // + // let evaluations = opening_config + // .points + // .iter() + // .map(|(xs, is)| { + // xs.iter() + // .map(|&x| { + // is.iter() + // .map(|&i| { + // commitments[i] + // .polynomials + // .iter() + // .map(|p| p.to_extension().eval(x)) + // .collect::>() + // }) + // .collect::>() + // }) + // .collect::>() + // }) + // .collect::>(); + // for evals_per_point_vec in &evaluations { + // for evals_per_point in evals_per_point_vec { + // for evals in evals_per_point { + // challenger.observe_extension_elements(evals); + // } + // } + // } + // + // let alpha = challenger.get_extension_challenge(); + // let mut cur_alpha = F::Extension::ONE; + // + // // Final low-degree polynomial that goes into FRI. + // let mut final_poly = PolynomialCoeffs::empty(); + // + // for ((ps, is), evals) in opening_config.points.iter().zip(&evaluations) { + // let mut poly_count = 0; + // // Scale polynomials by `alpha`. + // let composition_poly = is + // .iter() + // .flat_map(|&i| &commitments[i].polynomials) + // .rev() + // .fold(PolynomialCoeffs::zero(degree), |acc, p| { + // poly_count += 1; + // &(&acc * alpha) + &p.to_extension() + // }); + // // Scale evaluations by `alpha`. + // let composition_evals = &evals + // .iter() + // .map(|v| { + // v.iter() + // .flatten() + // .rev() + // .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e) + // }) + // .collect::>(); + // + // let quotient = Self::compute_quotient(ps, &composition_evals, &composition_poly); + // final_poly = &final_poly + &("ient * cur_alpha); + // cur_alpha *= alpha.exp(poly_count); + // } + // + // for &i in &opening_config.check_base_field { + // let commitment = commitments[i]; + // let x = opening_config + // .points + // .iter() + // .find(|(xs, is)| is.contains(&i)) + // .expect("Polynomial is never opened.") + // .0[0]; + // let x_conj = x.frobenius(); + // let mut poly_count = 0; + // let poly = commitment.polynomials.iter().rev().fold( + // PolynomialCoeffs::zero(degree), + // |acc, p| { + // poly_count += 1; + // &(&acc * alpha) + &p.to_extension() + // }, + // ); + // let e = poly.eval(x_conj); + // let quotient = Self::compute_quotient(&[x_conj], &[e], &poly); + // final_poly = &final_poly + &("ient * cur_alpha); + // cur_alpha *= alpha.exp(poly_count); + // } + // + // let lde_final_poly = final_poly.lde(fri_config.rate_bits); + // let lde_final_values = lde_final_poly + // .clone() + // .coset_fft(F::Extension::from_basefield( + // F::MULTIPLICATIVE_GROUP_GENERATOR, + // )); + // + // let fri_proof = fri_proof( + // &commitments + // .par_iter() + // .map(|c| &c.merkle_tree) + // .collect::>(), + // &lde_final_poly, + // &lde_final_values, + // challenger, + // &fri_config, + // ); + // + // ( + // OpeningProof { + // fri_proof, + // quotient_degree: final_poly.len(), + // }, + // evaluations, + // ) + // } + + pub fn open_plonk( + commitments: &[&Self; 5], + zeta: F::Extension, + degree_log: usize, challenger: &mut Challenger, config: &FriConfig, - ) -> (OpeningProof, Vec>>) + ) -> (OpeningProof, OpeningSet) where F: Extendable, { - let degree = commitments[0].degree; - assert_eq!(config.blinding.len(), commitments.len()); - for (i, commitment) in commitments.iter().enumerate() { - assert_eq!(commitment.rate_bits, config.rate_bits, "Invalid rate."); - assert_eq!( - commitment.blinding, config.blinding[i], - "Invalid blinding paramater." - ); - assert_eq!( - commitment.degree, degree, - "Trying to open polynomial commitments of different degrees." - ); - } - for p in points { + let g = F::Extension::primitive_root_of_unity(degree_log); + dbg!(degree_log); + for &p in &[zeta, g * zeta] { assert_ne!( - p.exp(degree as u64), + p.exp(1 << degree_log as u64), F::Extension::ONE, "Opening point is in the subgroup." ); } - let evaluations = points - .par_iter() - .map(|&x| { - commitments - .iter() - .map(move |c| { - c.polynomials - .iter() - .map(|p| p.to_extension().eval(x)) - .collect::>() - }) - .collect::>() - }) - .collect::>(); - for evals_per_point in &evaluations { - for evals in evals_per_point { - challenger.observe_extension_elements(evals); - } - } + let os = OpeningSet::new( + zeta, + g, + commitments[0], + commitments[1], + commitments[2], + commitments[3], + commitments[4], + ); + challenger.observe_opening_set(&os); let alpha = challenger.get_extension_challenge(); + dbg!(alpha); + let mut cur_alpha = F::Extension::ONE; - // Scale polynomials by `alpha`. - let composition_poly = commitments + // Final low-degree polynomial that goes into FRI. + let mut final_poly = PolynomialCoeffs::empty(); + // Count the total number of polynomials accumulated into `final_poly`. + let mut poly_count = 0; + + let composition_poly = [0, 1, 4] .iter() - .flat_map(|c| &c.polynomials) + .flat_map(|&i| &commitments[i].polynomials) .rev() - .fold(PolynomialCoeffs::zero(degree), |acc, p| { + .fold(PolynomialCoeffs::empty(), |acc, p| { + poly_count += 1; &(&acc * alpha) + &p.to_extension() }); - // Scale evaluations by `alpha`. - let composition_evals = &evaluations - .par_iter() - .map(|v| { - v.iter() - .flatten() - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e) - }) - .collect::>(); + let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] + .iter() + .flat_map(|v| v.iter()) + .rev() + .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); - let quotient = Self::compute_quotient(points, &composition_evals, &composition_poly); + let quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly); + final_poly = &final_poly + &("ient * cur_alpha); + { + let lde_final_poly = final_poly.lde(config.rate_bits); + let lde_final_values = lde_final_poly + .clone() + .coset_fft(F::Extension::from_basefield( + F::MULTIPLICATIVE_GROUP_GENERATOR, + )); + dbg!(lde_final_values); + } + cur_alpha = alpha.exp(poly_count); - let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(config.rate_bits); - let lde_quotient_values = lde_quotient.clone().coset_fft(F::Extension::from_basefield( - F::MULTIPLICATIVE_GROUP_GENERATOR, - )); + let zs_composition_poly = + commitments[3] + .polynomials + .iter() + .rev() + .fold(PolynomialCoeffs::empty(), |acc, p| { + poly_count += 1; + &(&acc * alpha) + &p.to_extension() + }); + let zs_composition_evals = [ + reduce_with_powers(&os.plonk_zs, alpha), + reduce_with_powers(&os.plonk_zs_right, alpha), + ]; + + let zs_quotient = Self::compute_quotient( + &[zeta, g * zeta], + &zs_composition_evals, + &zs_composition_poly, + ); + final_poly = &final_poly + &(&zs_quotient * cur_alpha); + { + let lde_final_poly = final_poly.lde(config.rate_bits); + let lde_final_values = lde_final_poly + .clone() + .coset_fft(F::Extension::from_basefield( + F::MULTIPLICATIVE_GROUP_GENERATOR, + )); + dbg!(lde_final_values); + dbg!(cur_alpha); + } + cur_alpha = alpha.exp(poly_count); + + let wires_composition_poly = + commitments[2] + .polynomials + .iter() + .rev() + .fold(PolynomialCoeffs::empty(), |acc, p| { + poly_count += 1; + &(&acc * alpha) + &p.to_extension() + }); + let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wires_composition_evals = [ + reduce_with_powers(&os.wires, alpha), + reduce_with_powers(&wire_evals_frob, alpha), + ]; + + let wires_quotient = Self::compute_quotient( + &[zeta, zeta.frobenius()], + &wires_composition_evals, + &wires_composition_poly, + ); + final_poly = &final_poly + &(&wires_quotient * cur_alpha); + + dbg!(final_poly.coeffs.len()); + let lde_final_poly = final_poly.lde(config.rate_bits); + let lde_final_values = lde_final_poly + .clone() + .coset_fft(F::Extension::from_basefield( + F::MULTIPLICATIVE_GROUP_GENERATOR, + )); let fri_proof = fri_proof( &commitments .par_iter() .map(|c| &c.merkle_tree) .collect::>(), - &lde_quotient, - &lde_quotient_values, + &lde_final_poly, + &lde_final_values, challenger, &config, ); @@ -256,38 +447,12 @@ impl ListPolynomialCommitment { ( OpeningProof { fri_proof, - quotient_degree: quotient.len(), + quotient_degree: final_poly.len(), }, - evaluations, + os, ) } - pub fn batch_open_plonk( - commitments: &[&Self; 5], - points: &[F::Extension], - challenger: &mut Challenger, - config: &FriConfig, - ) -> (OpeningProof, Vec>) - where - F: Extendable, - { - let (op, mut evaluations) = Self::batch_open(commitments, points, challenger, config); - let opening_sets = evaluations - .par_iter_mut() - .map(|evals| { - evals.reverse(); - OpeningSet { - constants: evals.pop().unwrap(), - plonk_sigmas: evals.pop().unwrap(), - wires: evals.pop().unwrap(), - plonk_zs: evals.pop().unwrap(), - quotient_polys: evals.pop().unwrap(), - } - }) - .collect(); - (op, opening_sets) - } - /// Given `points=(x_i)`, `evals=(y_i)` and `poly=P` with `P(x_i)=y_i`, computes the polynomial /// `Q=(P-I)/Z` where `I` interpolates `(x_i, y_i)` and `Z` is the vanishing polynomial on `(x_i)`. fn compute_quotient( @@ -305,6 +470,7 @@ impl ListPolynomialCommitment { .collect::>(); debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e)); + dbg!(&pairs); let interpolant = interpolant(&pairs); let denominator = points.iter().fold(PolynomialCoeffs::one(), |acc, &x| { &acc * &PolynomialCoeffs::new(vec![-x, F::Extension::ONE]) @@ -326,39 +492,21 @@ pub struct OpeningProof, const D: usize> { impl, const D: usize> OpeningProof { pub fn verify( &self, - points: &[F::Extension], - evaluations: &[Vec>], + zeta: F::Extension, + os: &OpeningSet, merkle_roots: &[Hash], challenger: &mut Challenger, fri_config: &FriConfig, ) -> Result<()> { - for evals_per_point in evaluations { - for evals in evals_per_point { - challenger.observe_extension_elements(evals); - } - } + challenger.observe_opening_set(os); let alpha = challenger.get_extension_challenge(); - - let scaled_evals = evaluations - .par_iter() - .map(|v| { - v.iter() - .flatten() - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e) - }) - .collect::>(); - - let pairs = points - .iter() - .zip(&scaled_evals) - .map(|(&x, &e)| (x, e)) - .collect::>(); + dbg!(alpha); verify_fri_proof( log2_strict(self.quotient_degree), - &pairs, + &os, + zeta, alpha, merkle_roots, &self.fri_proof, @@ -375,182 +523,143 @@ mod tests { use crate::field::crandall_field::CrandallField; use super::*; + use std::convert::TryInto; fn gen_random_test_case, const D: usize>( k: usize, degree_log: usize, - num_points: usize, - ) -> (Vec>, Vec) { + ) -> Vec> { let degree = 1 << degree_log; - let polys = (0..k) + (0..k) .map(|_| PolynomialCoeffs::new(F::rand_vec(degree))) - .collect(); - let mut points = F::Extension::rand_vec(num_points); - while points.iter().any(|&x| x.exp(degree as u64).is_one()) { - points = F::Extension::rand_vec(num_points); + .collect() + } + + fn gen_random_point, const D: usize>( + degree_log: usize, + ) -> F::Extension { + let degree = 1 << degree_log; + + let mut point = F::Extension::rand(); + while point.exp(degree as u64).is_one() { + point = F::Extension::rand(); } - (polys, points) - } - - fn check_polynomial_commitment, const D: usize>() -> Result<()> { - let k = 10; - let degree_log = 11; - let num_points = 3; - let fri_config = FriConfig { - proof_of_work_bits: 2, - rate_bits: 2, - reduction_arity_bits: vec![3, 2, 1, 2], - num_query_rounds: 3, - blinding: vec![false], - check_basefield: vec![true], - }; - let (polys, points) = gen_random_test_case::(k, degree_log, num_points); - - let lpc = ListPolynomialCommitment::new(polys, fri_config.rate_bits, false); - let (proof, evaluations) = lpc.open::(&points, &mut Challenger::new(), &fri_config); - proof.verify( - &points, - &evaluations.into_iter().map(|e| vec![e]).collect::>(), - &[lpc.merkle_tree.root], - &mut Challenger::new(), - &fri_config, - ) - } - - fn check_polynomial_commitment_blinding, const D: usize>() -> Result<()> - { - let k = 10; - let degree_log = 11; - let num_points = 3; - let fri_config = FriConfig { - proof_of_work_bits: 2, - rate_bits: 2, - reduction_arity_bits: vec![3, 2, 1, 2], - num_query_rounds: 3, - blinding: vec![true], - check_basefield: vec![false], - }; - let (polys, points) = gen_random_test_case::(k, degree_log, num_points); - - let lpc = ListPolynomialCommitment::new(polys, fri_config.rate_bits, true); - let (proof, evaluations) = lpc.open::(&points, &mut Challenger::new(), &fri_config); - proof.verify( - &points, - &evaluations.into_iter().map(|e| vec![e]).collect::>(), - &[lpc.merkle_tree.root], - &mut Challenger::new(), - &fri_config, - ) + point } fn check_batch_polynomial_commitment, const D: usize>() -> Result<()> { - let k0 = 10; - let k1 = 3; - let k2 = 7; - let degree_log = 11; - let num_points = 5; + let ks = [1, 2, 3, 5, 8]; + let degree_log = 2; let fri_config = FriConfig { proof_of_work_bits: 2, - rate_bits: 2, - reduction_arity_bits: vec![2, 3, 1, 2], + rate_bits: 1, + // reduction_arity_bits: vec![2, 3, 1, 2], + reduction_arity_bits: vec![1], num_query_rounds: 3, - blinding: vec![false, false, false], + blinding: vec![false, false, false, false, false], check_basefield: vec![false, false, false], }; - let (polys0, _) = gen_random_test_case::(k0, degree_log, num_points); - let (polys1, _) = gen_random_test_case::(k1, degree_log, num_points); - let (polys2, points) = gen_random_test_case::(k2, degree_log, num_points); - let lpc0 = ListPolynomialCommitment::new(polys0, fri_config.rate_bits, false); - let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false); - let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, false); + let lpcs = ks + .iter() + .map(|&k| { + ListPolynomialCommitment::::new( + gen_random_test_case(k, degree_log), + fri_config.rate_bits, + false, + ) + }) + .collect::>(); - let (proof, evaluations) = ListPolynomialCommitment::batch_open::( - &[&lpc0, &lpc1, &lpc2], - &points, + let zeta = gen_random_point::(degree_log); + let (proof, os) = ListPolynomialCommitment::open_plonk::( + &[&lpcs[0], &lpcs[1], &lpcs[2], &lpcs[3], &lpcs[4]], + zeta, + degree_log, &mut Challenger::new(), &fri_config, ); + let os = OpeningSet::new( + zeta, + F::Extension::primitive_root_of_unity(degree_log), + &lpcs[0], + &lpcs[1], + &lpcs[2], + &lpcs[3], + &lpcs[4], + ); proof.verify( - &points, - &evaluations, + zeta, + &os, &[ - lpc0.merkle_tree.root, - lpc1.merkle_tree.root, - lpc2.merkle_tree.root, + lpcs[0].merkle_tree.root, + lpcs[1].merkle_tree.root, + lpcs[2].merkle_tree.root, + lpcs[3].merkle_tree.root, + lpcs[4].merkle_tree.root, ], &mut Challenger::new(), &fri_config, ) } - fn check_batch_polynomial_commitment_blinding, const D: usize>( - ) -> Result<()> { - let k0 = 10; - let k1 = 3; - let k2 = 7; - let degree_log = 11; - let num_points = 5; - let fri_config = FriConfig { - proof_of_work_bits: 2, - rate_bits: 2, - reduction_arity_bits: vec![2, 3, 1, 2], - num_query_rounds: 3, - blinding: vec![true, false, true], - check_basefield: vec![true, false, true], - }; - let (polys0, _) = gen_random_test_case::(k0, degree_log, num_points); - let (polys1, _) = gen_random_test_case::(k1, degree_log, num_points); - let (polys2, points) = gen_random_test_case::(k2, degree_log, num_points); - - let lpc0 = ListPolynomialCommitment::new(polys0, fri_config.rate_bits, true); - let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false); - let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, true); - - let (proof, evaluations) = ListPolynomialCommitment::batch_open::( - &[&lpc0, &lpc1, &lpc2], - &points, - &mut Challenger::new(), - &fri_config, - ); - proof.verify( - &points, - &evaluations, - &[ - lpc0.merkle_tree.root, - lpc1.merkle_tree.root, - lpc2.merkle_tree.root, - ], - &mut Challenger::new(), - &fri_config, - ) - } + // fn check_batch_polynomial_commitment_blinding, const D: usize>( + // ) -> Result<()> { + // let k0 = 10; + // let k1 = 3; + // let k2 = 7; + // let degree_log = 11; + // let num_points = 5; + // let fri_config = FriConfig { + // proof_of_work_bits: 2, + // rate_bits: 2, + // reduction_arity_bits: vec![2, 3, 1, 2], + // num_query_rounds: 3, + // blinding: vec![true, false, true], + // check_basefield: vec![true, false, true], + // }; + // let (polys0, _) = gen_random_test_case::(k0, degree_log, num_points); + // let (polys1, _) = gen_random_test_case::(k1, degree_log, num_points); + // let (polys2, points) = gen_random_test_case::(k2, degree_log, num_points); + // + // let lpc0 = ListPolynomialCommitment::new(polys0, fri_config.rate_bits, true); + // let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false); + // let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, true); + // + // let (proof, evaluations) = ListPolynomialCommitment::batch_open::( + // &[&lpc0, &lpc1, &lpc2], + // &points, + // &fri_config, + // &mut Challenger::new(), + // ); + // proof.verify( + // &points, + // &evaluations, + // &[ + // lpc0.merkle_tree.root, + // lpc1.merkle_tree.root, + // lpc2.merkle_tree.root, + // ], + // &mut Challenger::new(), + // &fri_config, + // ) + // } macro_rules! tests_commitments { ($F:ty, $D:expr) => { use super::*; - #[test] - fn test_polynomial_commitment() -> Result<()> { - check_polynomial_commitment::<$F, $D>() - } - - #[test] - fn test_polynomial_commitment_blinding() -> Result<()> { - check_polynomial_commitment_blinding::<$F, $D>() - } - #[test] fn test_batch_polynomial_commitment() -> Result<()> { check_batch_polynomial_commitment::<$F, $D>() } - #[test] - fn test_batch_polynomial_commitment_blinding() -> Result<()> { - check_batch_polynomial_commitment_blinding::<$F, $D>() - } + // #[test] + // fn test_batch_polynomial_commitment_blinding() -> Result<()> { + // check_batch_polynomial_commitment_blinding::<$F, $D>() + // } }; } diff --git a/src/proof.rs b/src/proof.rs index b12c24ec..46b1a071 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -63,8 +63,8 @@ pub struct Proof, const D: usize> { /// Merkle root of LDEs of the quotient polynomial components. pub quotient_polys_root: Hash, - /// Purported values of each polynomial at each challenge point. - pub openings: Vec>, + /// Purported values of each polynomial at the challenge point. + pub openings: OpeningSet, /// A FRI argument for each FRI query. pub opening_proof: OpeningProof, @@ -130,31 +130,37 @@ pub struct FriProofTarget { } /// The purported values of each polynomial at a single point. -pub struct OpeningSet { - pub constants: Vec, - pub plonk_sigmas: Vec, - pub wires: Vec, - pub plonk_zs: Vec, - pub quotient_polys: Vec, +pub struct OpeningSet, const D: usize> { + pub constants: Vec, + pub plonk_sigmas: Vec, + pub wires: Vec, + pub plonk_zs: Vec, + pub plonk_zs_right: Vec, + pub quotient_polys: Vec, } -impl OpeningSet { +impl, const D: usize> OpeningSet { pub fn new( - z: F, + z: F::Extension, + g: F::Extension, constant_commitment: &ListPolynomialCommitment, plonk_sigmas_commitment: &ListPolynomialCommitment, wires_commitment: &ListPolynomialCommitment, plonk_zs_commitment: &ListPolynomialCommitment, quotient_polys_commitment: &ListPolynomialCommitment, ) -> Self { - let eval_commitment = |z: F, c: &ListPolynomialCommitment| { - c.polynomials.iter().map(|p| p.eval(z)).collect::>() + let eval_commitment = |z: F::Extension, c: &ListPolynomialCommitment| { + c.polynomials + .iter() + .map(|p| p.to_extension().eval(z)) + .collect::>() }; Self { constants: eval_commitment(z, constant_commitment), plonk_sigmas: eval_commitment(z, plonk_sigmas_commitment), wires: eval_commitment(z, wires_commitment), plonk_zs: eval_commitment(z, plonk_zs_commitment), + plonk_zs_right: eval_commitment(g * z, plonk_zs_commitment), quotient_polys: eval_commitment(z, quotient_polys_commitment), } } diff --git a/src/prover.rs b/src/prover.rs index be100160..19f3b87d 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -14,7 +14,7 @@ use crate::polynomial::commitment::ListPolynomialCommitment; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::Proof; use crate::timed; -use crate::util::transpose; +use crate::util::{log2_strict, transpose}; use crate::vars::EvaluationVars; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -116,10 +116,10 @@ pub(crate) fn prove, const D: usize>( challenger.observe_hash("ient_polys_commitment.merkle_tree.root); - let zetas = challenger.get_n_extension_challenges(config.num_challenges); + let zeta = challenger.get_extension_challenge(); let (opening_proof, openings) = timed!( - ListPolynomialCommitment::batch_open_plonk( + ListPolynomialCommitment::open_plonk( &[ &prover_data.constants_commitment, &prover_data.sigmas_commitment, @@ -127,7 +127,8 @@ pub(crate) fn prove, const D: usize>( &plonk_zs_commitment, "ient_polys_commitment, ], - &zetas, + zeta, + log2_strict(degree), &mut challenger, &common_data.config.fri_config ), From 6ee9ceacd593bd22061efb504a40653ce47d664a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 31 May 2021 18:00:53 +0200 Subject: [PATCH 03/11] Don't check Frobenius if `D=1`. --- src/fri/verifier.rs | 40 +++++++++++++++++---------------- src/polynomial/commitment.rs | 43 ++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 7d77625e..12940174 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -237,25 +237,27 @@ fn fri_combine_initial, const D: usize>( dbg!(cur_alpha); cur_alpha = alpha.exp(poly_count); - let ev = proof.evals_proofs[2].0 - [..proof.evals_proofs[2].0.len() - if config.blinding[2] { SALT_SIZE } else { 0 }] - .iter() - .rev() - .fold(F::Extension::ZERO, |acc, &e| { - poly_count += 1; - alpha * acc + e.into() - }); - let zeta_frob = zeta.frobenius(); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); - let wires_interpol = interpolant(&[ - (zeta, reduce_with_powers(&os.wires, alpha)), - (zeta_frob, reduce_with_powers(&wire_evals_frob, alpha)), - ]); - let numerator = ev - wires_interpol.eval(subgroup_x.into()); - let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) - * (F::Extension::from_basefield(subgroup_x) - zeta_frob); - e += cur_alpha * numerator / denominator; - cur_alpha = alpha.exp(poly_count); + if D > 1 { + let ev = proof.evals_proofs[2].0 + [..proof.evals_proofs[2].0.len() - if config.blinding[2] { SALT_SIZE } else { 0 }] + .iter() + .rev() + .fold(F::Extension::ZERO, |acc, &e| { + poly_count += 1; + alpha * acc + e.into() + }); + let zeta_frob = zeta.frobenius(); + let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wires_interpol = interpolant(&[ + (zeta, reduce_with_powers(&os.wires, alpha)), + (zeta_frob, reduce_with_powers(&wire_evals_frob, alpha)), + ]); + let numerator = ev - wires_interpol.eval(subgroup_x.into()); + let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) + * (F::Extension::from_basefield(subgroup_x) - zeta_frob); + e += cur_alpha * numerator / denominator; + cur_alpha = alpha.exp(poly_count); + } e } diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 7325a206..12ce3623 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -403,27 +403,27 @@ impl ListPolynomialCommitment { } cur_alpha = alpha.exp(poly_count); - let wires_composition_poly = - commitments[2] - .polynomials - .iter() - .rev() - .fold(PolynomialCoeffs::empty(), |acc, p| { + if D > 1 { + let wires_composition_poly = commitments[2].polynomials.iter().rev().fold( + PolynomialCoeffs::empty(), + |acc, p| { poly_count += 1; &(&acc * alpha) + &p.to_extension() - }); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); - let wires_composition_evals = [ - reduce_with_powers(&os.wires, alpha), - reduce_with_powers(&wire_evals_frob, alpha), - ]; + }, + ); + let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wires_composition_evals = [ + reduce_with_powers(&os.wires, alpha), + reduce_with_powers(&wire_evals_frob, alpha), + ]; - let wires_quotient = Self::compute_quotient( - &[zeta, zeta.frobenius()], - &wires_composition_evals, - &wires_composition_poly, - ); - final_poly = &final_poly + &(&wires_quotient * cur_alpha); + let wires_quotient = Self::compute_quotient( + &[zeta, zeta.frobenius()], + &wires_composition_evals, + &wires_composition_poly, + ); + final_poly = &final_poly + &(&wires_quotient * cur_alpha); + } dbg!(final_poly.coeffs.len()); let lde_final_poly = final_poly.lde(config.rate_bits); @@ -551,12 +551,11 @@ mod tests { fn check_batch_polynomial_commitment, const D: usize>() -> Result<()> { let ks = [1, 2, 3, 5, 8]; - let degree_log = 2; + let degree_log = 11; let fri_config = FriConfig { proof_of_work_bits: 2, - rate_bits: 1, - // reduction_arity_bits: vec![2, 3, 1, 2], - reduction_arity_bits: vec![1], + rate_bits: 2, + reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, blinding: vec![false, false, false, false, false], check_basefield: vec![false, false, false], From d882283761b69667e42f744395b1327e648b4e02 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 31 May 2021 18:19:44 +0200 Subject: [PATCH 04/11] Working with blindings --- src/fri/verifier.rs | 49 +++--------------------------------- src/polynomial/commitment.rs | 47 +++++++++++++--------------------- 2 files changed, 21 insertions(+), 75 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 12940174..acbea061 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -141,44 +141,6 @@ fn fri_verify_initial_proof( Ok(()) } -// fn fri_combine_initial, const D: usize>( -// proof: &FriInitialTreeProof, -// alpha: F::Extension, -// opening_set: &OpeningSet, -// zeta: F::Extension, -// subgroup_x: F, -// config: &FriConfig, -// ) -> F::Extension { -// let e = proof -// .evals_proofs -// .iter() -// .enumerate() -// .flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }]) -// .rev() -// .fold(F::Extension::ZERO, |acc, &e| alpha * acc + e.into()); -// let numerator = e - interpolant.eval(subgroup_x.into()); -// let denominator = points -// .iter() -// .map(|&(x, _)| F::Extension::from_basefield(subgroup_x) - x) -// .product(); -// let quotient = numerator / denominator; -// let quotient = if config.check_basefield[0] { -// let alpha_conj = alpha.frobenius(); -// let comp_conj = proof -// .evals_proofs -// .iter() -// .enumerate() -// .flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }]) -// .rev() -// .fold(F::Extension::ZERO, |acc, &e| alpha_conj * acc + e.into()); -// let numerator = comp_conj - points[0].1.frobenius(); -// let denominator = F::Extension::from_basefield(subgroup_x) - points[0].0.frobenius(); -// quotient + (numerator / denominator) * alpha.exp(proof.evals_proofs[0].0.len() as u64) -// } else { -// quotient -// }; -// quotient -// } fn fri_combine_initial, const D: usize>( proof: &FriInitialTreeProof, alpha: F::Extension, @@ -196,9 +158,10 @@ fn fri_combine_initial, const D: usize>( let ev = [0, 1, 4] .iter() - .map(|&i| &proof.evals_proofs[i]) - .enumerate() - .flat_map(|(j, (v, _))| &v[..v.len() - if config.blinding[j] { SALT_SIZE } else { 0 }]) + .flat_map(|&i| { + let v = &proof.evals_proofs[i].0; + &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }] + }) .rev() .fold(F::Extension::ZERO, |acc, &e| { poly_count += 1; @@ -213,7 +176,6 @@ fn fri_combine_initial, const D: usize>( let denominator = F::Extension::from_basefield(subgroup_x) - zeta; e += cur_alpha * numerator / denominator; cur_alpha = alpha.exp(poly_count); - dbg!(e); let ev = proof.evals_proofs[3].0 [..proof.evals_proofs[3].0.len() - if config.blinding[3] { SALT_SIZE } else { 0 }] @@ -224,7 +186,6 @@ fn fri_combine_initial, const D: usize>( alpha * acc + e.into() }); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; - dbg!(degree_log); let zs_interpol = interpolant(&[ (zeta, reduce_with_powers(&os.plonk_zs, alpha)), (zeta_right, reduce_with_powers(&os.plonk_zs_right, alpha)), @@ -233,8 +194,6 @@ fn fri_combine_initial, const D: usize>( let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) * (F::Extension::from_basefield(subgroup_x) - zeta_right); e += cur_alpha * numerator / denominator; - dbg!(e); - dbg!(cur_alpha); cur_alpha = alpha.exp(poly_count); if D > 1 { diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 12ce3623..30f15265 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -315,7 +315,6 @@ impl ListPolynomialCommitment { F: Extendable, { let g = F::Extension::primitive_root_of_unity(degree_log); - dbg!(degree_log); for &p in &[zeta, g * zeta] { assert_ne!( p.exp(1 << degree_log as u64), @@ -336,7 +335,6 @@ impl ListPolynomialCommitment { challenger.observe_opening_set(&os); let alpha = challenger.get_extension_challenge(); - dbg!(alpha); let mut cur_alpha = F::Extension::ONE; // Final low-degree polynomial that goes into FRI. @@ -360,15 +358,6 @@ impl ListPolynomialCommitment { let quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly); final_poly = &final_poly + &("ient * cur_alpha); - { - let lde_final_poly = final_poly.lde(config.rate_bits); - let lde_final_values = lde_final_poly - .clone() - .coset_fft(F::Extension::from_basefield( - F::MULTIPLICATIVE_GROUP_GENERATOR, - )); - dbg!(lde_final_values); - } cur_alpha = alpha.exp(poly_count); let zs_composition_poly = @@ -391,16 +380,6 @@ impl ListPolynomialCommitment { &zs_composition_poly, ); final_poly = &final_poly + &(&zs_quotient * cur_alpha); - { - let lde_final_poly = final_poly.lde(config.rate_bits); - let lde_final_values = lde_final_poly - .clone() - .coset_fft(F::Extension::from_basefield( - F::MULTIPLICATIVE_GROUP_GENERATOR, - )); - dbg!(lde_final_values); - dbg!(cur_alpha); - } cur_alpha = alpha.exp(poly_count); if D > 1 { @@ -425,7 +404,6 @@ impl ListPolynomialCommitment { final_poly = &final_poly + &(&wires_quotient * cur_alpha); } - dbg!(final_poly.coeffs.len()); let lde_final_poly = final_poly.lde(config.rate_bits); let lde_final_values = lde_final_poly .clone() @@ -470,7 +448,6 @@ impl ListPolynomialCommitment { .collect::>(); debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e)); - dbg!(&pairs); let interpolant = interpolant(&pairs); let denominator = points.iter().fold(PolynomialCoeffs::one(), |acc, &x| { &acc * &PolynomialCoeffs::new(vec![-x, F::Extension::ONE]) @@ -501,7 +478,6 @@ impl, const D: usize> OpeningProof { challenger.observe_opening_set(os); let alpha = challenger.get_extension_challenge(); - dbg!(alpha); verify_fri_proof( log2_strict(self.quotient_degree), @@ -523,6 +499,7 @@ mod tests { use crate::field::crandall_field::CrandallField; use super::*; + use rand::Rng; use std::convert::TryInto; fn gen_random_test_case, const D: usize>( @@ -549,6 +526,17 @@ mod tests { point } + fn random_blindings() -> Vec { + let mut rng = rand::thread_rng(); + vec![ + rng.gen_bool(0.5), + rng.gen_bool(0.5), + rng.gen_bool(0.5), + rng.gen_bool(0.5), + rng.gen_bool(0.5), + ] + } + fn check_batch_polynomial_commitment, const D: usize>() -> Result<()> { let ks = [1, 2, 3, 5, 8]; let degree_log = 11; @@ -557,17 +545,16 @@ mod tests { rate_bits: 2, reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, - blinding: vec![false, false, false, false, false], + blinding: random_blindings(), check_basefield: vec![false, false, false], }; - let lpcs = ks - .iter() - .map(|&k| { + let lpcs = (0..5) + .map(|i| { ListPolynomialCommitment::::new( - gen_random_test_case(k, degree_log), + gen_random_test_case(ks[i], degree_log), fri_config.rate_bits, - false, + fri_config.blinding[i], ) }) .collect::>(); From e09a6179fbc91d44ac7ce877160a87450ce0e9f4 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 31 May 2021 18:21:42 +0200 Subject: [PATCH 05/11] Remove useless field --- src/bin/bench_recursion.rs | 3 +- src/circuit_data.rs | 1 - src/fri/mod.rs | 4 - src/polynomial/commitment.rs | 229 ----------------------------------- src/prover.rs | 3 - 5 files changed, 1 insertion(+), 239 deletions(-) diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index ff3a3ba2..efab1dd8 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -9,7 +9,7 @@ use plonky2::fri::FriConfig; use plonky2::gates::constant::ConstantGate; use plonky2::gates::gmimc::GMiMCGate; use plonky2::hash::GMIMC_ROUNDS; -use plonky2::prover::{PLONK_BLINDING, PLONK_CHECK_BASEFIELD}; +use plonky2::prover::PLONK_BLINDING; use plonky2::witness::PartialWitness; fn main() { @@ -43,7 +43,6 @@ fn bench_prove, const D: usize>() { reduction_arity_bits: vec![1], num_query_rounds: 1, blinding: PLONK_BLINDING.to_vec(), - check_basefield: PLONK_CHECK_BASEFIELD.to_vec(), }, }; diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 87798044..d45192cb 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -38,7 +38,6 @@ impl Default for CircuitConfig { reduction_arity_bits: vec![1], num_query_rounds: 1, blinding: vec![true], - check_basefield: vec![false], }, } } diff --git a/src/fri/mod.rs b/src/fri/mod.rs index dcd458fd..57fd2ecf 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -23,10 +23,6 @@ pub struct FriConfig { /// Vector of the same length as the number of initial Merkle trees. /// `blinding[i]==true` iff the i-th tree is salted. pub blinding: Vec, - - /// Vector of the same length as the number of initial Merkle trees. - /// `check_basefield[i]==true` iff the polynomials in the i-th tree are checked to be in the base field. - pub check_basefield: Vec, } fn fri_delta(rate_log: usize, conjecture: bool) -> f64 { diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 30f15265..1ee1fb2b 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -76,234 +76,6 @@ impl ListPolynomialCommitment { &leaf[0..leaf.len() - if self.blinding { SALT_SIZE } else { 0 }] } - pub fn open( - &self, - points: &[F::Extension], - challenger: &mut Challenger, - config: &FriConfig, - ) -> (OpeningProof, Vec>) - where - F: Extendable, - { - assert_eq!(self.rate_bits, config.rate_bits); - assert_eq!(config.check_basefield.len(), 1); - assert_eq!(config.blinding.len(), 1); - assert_eq!(self.blinding, config.blinding[0]); - for p in points { - assert_ne!( - p.exp(self.degree as u64), - F::Extension::ONE, - "Opening point is in the subgroup." - ); - } - - let evaluations = points - .par_iter() - .map(|&x| { - self.polynomials - .iter() - .map(|p| p.to_extension().eval(x)) - .collect::>() - }) - .collect::>(); - for evals in &evaluations { - for e in evals { - challenger.observe_extension_element(e); - } - } - - let alpha = challenger.get_extension_challenge(); - - // Scale polynomials by `alpha`. - let composition_poly = reduce_polys_with_powers(&self.polynomials, alpha); - // Scale evaluations by `alpha`. - let composition_evals = evaluations - .par_iter() - .map(|e| reduce_with_powers(e, alpha)) - .collect::>(); - - let quotient = Self::compute_quotient(points, &composition_evals, &composition_poly); - - let quotient = if config.check_basefield[0] { - let composition_poly_conj = PolynomialCoeffs::::frobenius(&composition_poly); - // This equality holds iff the polynomials in `self.polynomials` are defined over `F` and not `F::Extension`. - debug_assert_eq!( - composition_poly_conj.eval(points[0].frobenius()), - composition_evals[0].frobenius() - ); - let quotient_conj = Self::compute_quotient( - &[points[0].frobenius()], - &[composition_evals[0].frobenius()], - &composition_poly_conj, - ); - - &("ient_conj * alpha.exp(self.polynomials.len() as u64)) + "ient - } else { - quotient - }; - - let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.rate_bits); - let lde_quotient_values = lde_quotient - .clone() - .coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR.into()); - - let fri_proof = fri_proof( - &[&self.merkle_tree], - &lde_quotient, - &lde_quotient_values, - challenger, - &config, - ); - - ( - OpeningProof { - fri_proof, - quotient_degree: quotient.len(), - }, - evaluations, - ) - } - - // pub fn batch_open( - // commitments: &[&Self], - // opening_config: &OpeningConfig, - // fri_config: &FriConfig, - // challenger: &mut Challenger, - // ) -> (OpeningProof, Vec>>>) - // where - // F: Extendable, - // { - // let degree = commitments[0].degree; - // assert_eq!(fri_config.blinding.len(), commitments.len()); - // for (i, commitment) in commitments.iter().enumerate() { - // assert_eq!(commitment.rate_bits, fri_config.rate_bits, "Invalid rate."); - // assert_eq!( - // commitment.blinding, fri_config.blinding[i], - // "Invalid blinding paramater." - // ); - // assert_eq!( - // commitment.degree, degree, - // "Trying to open polynomial commitments of different degrees." - // ); - // } - // for &p in opening_config.points.iter().flat_map(|(v, _)| v) { - // assert_ne!( - // p.exp(degree as u64), - // F::Extension::ONE, - // "Opening point is in the subgroup." - // ); - // } - // - // let evaluations = opening_config - // .points - // .iter() - // .map(|(xs, is)| { - // xs.iter() - // .map(|&x| { - // is.iter() - // .map(|&i| { - // commitments[i] - // .polynomials - // .iter() - // .map(|p| p.to_extension().eval(x)) - // .collect::>() - // }) - // .collect::>() - // }) - // .collect::>() - // }) - // .collect::>(); - // for evals_per_point_vec in &evaluations { - // for evals_per_point in evals_per_point_vec { - // for evals in evals_per_point { - // challenger.observe_extension_elements(evals); - // } - // } - // } - // - // let alpha = challenger.get_extension_challenge(); - // let mut cur_alpha = F::Extension::ONE; - // - // // Final low-degree polynomial that goes into FRI. - // let mut final_poly = PolynomialCoeffs::empty(); - // - // for ((ps, is), evals) in opening_config.points.iter().zip(&evaluations) { - // let mut poly_count = 0; - // // Scale polynomials by `alpha`. - // let composition_poly = is - // .iter() - // .flat_map(|&i| &commitments[i].polynomials) - // .rev() - // .fold(PolynomialCoeffs::zero(degree), |acc, p| { - // poly_count += 1; - // &(&acc * alpha) + &p.to_extension() - // }); - // // Scale evaluations by `alpha`. - // let composition_evals = &evals - // .iter() - // .map(|v| { - // v.iter() - // .flatten() - // .rev() - // .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e) - // }) - // .collect::>(); - // - // let quotient = Self::compute_quotient(ps, &composition_evals, &composition_poly); - // final_poly = &final_poly + &("ient * cur_alpha); - // cur_alpha *= alpha.exp(poly_count); - // } - // - // for &i in &opening_config.check_base_field { - // let commitment = commitments[i]; - // let x = opening_config - // .points - // .iter() - // .find(|(xs, is)| is.contains(&i)) - // .expect("Polynomial is never opened.") - // .0[0]; - // let x_conj = x.frobenius(); - // let mut poly_count = 0; - // let poly = commitment.polynomials.iter().rev().fold( - // PolynomialCoeffs::zero(degree), - // |acc, p| { - // poly_count += 1; - // &(&acc * alpha) + &p.to_extension() - // }, - // ); - // let e = poly.eval(x_conj); - // let quotient = Self::compute_quotient(&[x_conj], &[e], &poly); - // final_poly = &final_poly + &("ient * cur_alpha); - // cur_alpha *= alpha.exp(poly_count); - // } - // - // let lde_final_poly = final_poly.lde(fri_config.rate_bits); - // let lde_final_values = lde_final_poly - // .clone() - // .coset_fft(F::Extension::from_basefield( - // F::MULTIPLICATIVE_GROUP_GENERATOR, - // )); - // - // let fri_proof = fri_proof( - // &commitments - // .par_iter() - // .map(|c| &c.merkle_tree) - // .collect::>(), - // &lde_final_poly, - // &lde_final_values, - // challenger, - // &fri_config, - // ); - // - // ( - // OpeningProof { - // fri_proof, - // quotient_degree: final_poly.len(), - // }, - // evaluations, - // ) - // } - pub fn open_plonk( commitments: &[&Self; 5], zeta: F::Extension, @@ -546,7 +318,6 @@ mod tests { reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, blinding: random_blindings(), - check_basefield: vec![false, false, false], }; let lpcs = (0..5) diff --git a/src/prover.rs b/src/prover.rs index 19f3b87d..44b2ef18 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -22,9 +22,6 @@ use crate::witness::PartialWitness; /// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments. pub const PLONK_BLINDING: [bool; 5] = [false, false, true, true, true]; -/// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments. -pub const PLONK_CHECK_BASEFIELD: [bool; 5] = [false, false, true, false, false]; - pub(crate) fn prove, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, From 59dfe5db2f1a106bfc89c0988208f509ffe60e06 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 1 Jun 2021 09:02:43 +0200 Subject: [PATCH 06/11] Remove old tests --- src/fri/mod.rs | 134 ------------------------------------------------- 1 file changed, 134 deletions(-) diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 57fd2ecf..d6e369da 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -47,137 +47,3 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 { 1.0 / (2.0 * EPSILON * rate.sqrt()) } } - -// #[cfg(test)] -// mod tests { -// use super::*; -// use crate::field::crandall_field::CrandallField; -// use crate::field::extension_field::quadratic::QuadraticCrandallField; -// use crate::field::extension_field::quartic::QuarticCrandallField; -// use crate::field::extension_field::{flatten, Extendable, FieldExtension}; -// use crate::field::fft::ifft; -// use crate::field::field::Field; -// use crate::fri::prover::fri_proof; -// use crate::fri::verifier::verify_fri_proof; -// use crate::merkle_tree::MerkleTree; -// use crate::plonk_challenger::Challenger; -// use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; -// use crate::util::reverse_index_bits_in_place; -// use anyhow::Result; -// use rand::rngs::ThreadRng; -// use rand::Rng; -// -// fn check_fri, const D: usize>( -// degree_log: usize, -// rate_bits: usize, -// reduction_arity_bits: Vec, -// num_query_rounds: usize, -// ) -> Result<()> { -// let n = 1 << degree_log; -// let coeffs = PolynomialCoeffs::new(F::rand_vec(n)).lde(rate_bits); -// let coset_lde = coeffs.clone().coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR); -// let config = FriConfig { -// num_query_rounds, -// rate_bits, -// proof_of_work_bits: 2, -// reduction_arity_bits, -// blinding: vec![false], -// check_basefield: vec![false], -// }; -// let tree = { -// let mut leaves = coset_lde -// .values -// .iter() -// .map(|&x| vec![x]) -// .collect::>(); -// reverse_index_bits_in_place(&mut leaves); -// MerkleTree::new(leaves, false) -// }; -// let coset_lde = PolynomialValues::new( -// coset_lde -// .values -// .into_iter() -// .map(F::Extension::from) -// .collect(), -// ); -// let root = tree.root; -// let mut challenger = Challenger::new(); -// let proof = fri_proof::( -// &[&tree], -// &coeffs.to_extension::(), -// &coset_lde, -// &mut challenger, -// &config, -// ); -// -// let mut challenger = Challenger::new(); -// verify_fri_proof( -// degree_log, -// &[], -// F::Extension::ONE, -// &[root], -// &proof, -// &mut challenger, -// &config, -// )?; -// -// Ok(()) -// } -// -// fn gen_arities(degree_log: usize, rng: &mut ThreadRng) -> Vec { -// let mut arities = Vec::new(); -// let mut remaining = degree_log; -// while remaining > 0 { -// let arity = rng.gen_range(0, remaining + 1); -// arities.push(arity); -// remaining -= arity; -// } -// arities -// } -// -// fn check_fri_multi_params, const D: usize>() -> Result<()> { -// let mut rng = rand::thread_rng(); -// for degree_log in 1..6 { -// for rate_bits in 0..3 { -// for num_query_round in 0..4 { -// for _ in 0..3 { -// check_fri::( -// degree_log, -// rate_bits, -// gen_arities(degree_log, &mut rng), -// num_query_round, -// )?; -// } -// } -// } -// } -// Ok(()) -// } -// -// mod base { -// use super::*; -// -// #[test] -// fn test_fri_multi_params() -> Result<()> { -// check_fri_multi_params::() -// } -// } -// -// mod quadratic { -// use super::*; -// -// #[test] -// fn test_fri_multi_params() -> Result<()> { -// check_fri_multi_params::() -// } -// } -// -// mod quartic { -// use super::*; -// -// #[test] -// fn test_fri_multi_params() -> Result<()> { -// check_fri_multi_params::() -// } -// } -// } From 2794cb9a954cb4e1a15d8be6a3c6915cbca2c088 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 1 Jun 2021 11:03:04 +0200 Subject: [PATCH 07/11] Open wires at single point if D=1 --- src/fri/verifier.rs | 45 +++++++++++++++++++++++------------- src/polynomial/commitment.rs | 39 ++++++++++++++++++++----------- 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index acbea061..ef4cfba3 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -156,22 +156,35 @@ fn fri_combine_initial, const D: usize>( let mut poly_count = 0; let mut e = F::Extension::ZERO; - let ev = [0, 1, 4] - .iter() - .flat_map(|&i| { - let v = &proof.evals_proofs[i].0; - &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }] - }) - .rev() - .fold(F::Extension::ZERO, |acc, &e| { - poly_count += 1; - alpha * acc + e.into() - }); - let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] - .iter() - .flat_map(|v| v.iter()) - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); + let ev = if D == 1 { + vec![0, 1, 2, 4] + } else { + vec![0, 1, 4] + } + .iter() + .flat_map(|&i| { + let v = &proof.evals_proofs[i].0; + &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }] + }) + .rev() + .fold(F::Extension::ZERO, |acc, &e| { + poly_count += 1; + alpha * acc + e.into() + }); + let composition_eval = if D == 1 { + vec![ + &os.constants, + &os.plonk_sigmas, + &os.wires, + &os.quotient_polys, + ] + } else { + vec![&os.constants, &os.plonk_sigmas, &os.quotient_polys] + } + .iter() + .flat_map(|v| v.iter()) + .rev() + .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); let numerator = ev - composition_eval; let denominator = F::Extension::from_basefield(subgroup_x) - zeta; e += cur_alpha * numerator / denominator; diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 1ee1fb2b..a183f379 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -114,19 +114,32 @@ impl ListPolynomialCommitment { // Count the total number of polynomials accumulated into `final_poly`. let mut poly_count = 0; - let composition_poly = [0, 1, 4] - .iter() - .flat_map(|&i| &commitments[i].polynomials) - .rev() - .fold(PolynomialCoeffs::empty(), |acc, p| { - poly_count += 1; - &(&acc * alpha) + &p.to_extension() - }); - let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] - .iter() - .flat_map(|v| v.iter()) - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); + let composition_poly = if D == 1 { + vec![0, 1, 2, 4] + } else { + vec![0, 1, 4] + } + .iter() + .flat_map(|&i| &commitments[i].polynomials) + .rev() + .fold(PolynomialCoeffs::empty(), |acc, p| { + poly_count += 1; + &(&acc * alpha) + &p.to_extension() + }); + let composition_eval = if D == 1 { + vec![ + &os.constants, + &os.plonk_sigmas, + &os.wires, + &os.quotient_polys, + ] + } else { + vec![&os.constants, &os.plonk_sigmas, &os.quotient_polys] + + .iter() + .flat_map(|v| v.iter()) + .rev() + .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); let quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly); final_poly = &final_poly + &("ient * cur_alpha); From b465bcd8be6de1ce125b838a2171580e0f57c1ba Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 1 Jun 2021 11:17:54 +0200 Subject: [PATCH 08/11] Clippy + comments --- src/fri/verifier.rs | 2 - src/plonk_common.rs | 12 ------ src/polynomial/commitment.rs | 84 ++++++++++++------------------------ 3 files changed, 28 insertions(+), 70 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index ef4cfba3..981db38a 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -7,7 +7,6 @@ use crate::merkle_proofs::verify_merkle_proof; use crate::plonk_challenger::Challenger; use crate::plonk_common::reduce_with_powers; use crate::polynomial::commitment::SALT_SIZE; -use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; use anyhow::{ensure, Result}; @@ -228,7 +227,6 @@ fn fri_combine_initial, const D: usize>( let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) * (F::Extension::from_basefield(subgroup_x) - zeta_frob); e += cur_alpha * numerator / denominator; - cur_alpha = alpha.exp(poly_count); } e diff --git a/src/plonk_common.rs b/src/plonk_common.rs index ab28ce21..b620bb6f 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -82,18 +82,6 @@ pub(crate) fn reduce_with_powers(terms: &[F], alpha: F) -> F { sum } -pub(crate) fn reduce_polys_with_powers, const D: usize>( - polynomials: &[PolynomialCoeffs], - alpha: F::Extension, -) -> PolynomialCoeffs { - polynomials - .iter() - .rev() - .fold(PolynomialCoeffs::empty(), |acc, p| { - &(&acc * alpha) + &p.to_extension() - }) -} - pub(crate) fn reduce_with_powers_recursive( builder: &mut CircuitBuilder, terms: Vec, diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index a183f379..5fa6c091 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -8,9 +8,9 @@ use crate::field::lagrange::interpolant; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{reduce_polys_with_powers, reduce_with_powers}; +use crate::plonk_common::reduce_with_powers; use crate::polynomial::polynomial::PolynomialCoeffs; -use crate::proof::{FriInitialTreeProof, FriProof, Hash, OpeningSet}; +use crate::proof::{FriProof, Hash, OpeningSet}; use crate::timed; use crate::util::{log2_strict, reverse_index_bits_in_place, transpose}; @@ -76,6 +76,8 @@ impl ListPolynomialCommitment { &leaf[0..leaf.len() - if self.blinding { SALT_SIZE } else { 0 }] } + /// Takes the commitments to the constants - sigmas - wires - zs - quotient — polynomials, + /// and an opening point `zeta` and produces a batched opening proof + opening set. pub fn open_plonk( commitments: &[&Self; 5], zeta: F::Extension, @@ -86,6 +88,7 @@ impl ListPolynomialCommitment { where F: Extendable, { + debug_assert!(commitments.iter().all(|c| c.degree == 1 << degree_log)); let g = F::Extension::primitive_root_of_unity(degree_log); for &p in &[zeta, g * zeta] { assert_ne!( @@ -114,6 +117,7 @@ impl ListPolynomialCommitment { // Count the total number of polynomials accumulated into `final_poly`. let mut poly_count = 0; + // Polynomials opened at a single point. let composition_poly = if D == 1 { vec![0, 1, 2, 4] } else { @@ -135,7 +139,7 @@ impl ListPolynomialCommitment { ] } else { vec![&os.constants, &os.plonk_sigmas, &os.quotient_polys] - + } .iter() .flat_map(|v| v.iter()) .rev() @@ -145,6 +149,7 @@ impl ListPolynomialCommitment { final_poly = &final_poly + &("ient * cur_alpha); cur_alpha = alpha.exp(poly_count); + // Zs polynomials are opened at `zeta` and `g*zeta`. let zs_composition_poly = commitments[3] .polynomials @@ -167,6 +172,9 @@ impl ListPolynomialCommitment { final_poly = &final_poly + &(&zs_quotient * cur_alpha); cur_alpha = alpha.exp(poly_count); + // If working in an extension field, need to check that wires are in the base field. + // Check this by opening the wires polynomials at `zeta` and `zeta.frobenius()` and using the fact that + // a polynomial `f` is over the base field iff `f(z).frobenius()=f(z.frobenius())` with high probability. if D > 1 { let wires_composition_poly = commitments[2].polynomials.iter().rev().fold( PolynomialCoeffs::empty(), @@ -238,7 +246,7 @@ impl ListPolynomialCommitment { &acc * &PolynomialCoeffs::new(vec![-x, F::Extension::ONE]) }); let numerator = poly - &interpolant; - let (mut quotient, rem) = numerator.div_rem(&denominator); + let (quotient, rem) = numerator.div_rem(&denominator); debug_assert!(rem.is_zero()); quotient.padded(quotient.degree_plus_one().next_power_of_two()) @@ -311,7 +319,7 @@ mod tests { point } - fn random_blindings() -> Vec { + fn gen_random_blindings() -> Vec { let mut rng = rand::thread_rng(); vec![ rng.gen_bool(0.5), @@ -330,7 +338,7 @@ mod tests { rate_bits: 2, reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, - blinding: random_blindings(), + blinding: gen_random_blindings(), }; let lpcs = (0..5) @@ -375,48 +383,6 @@ mod tests { ) } - // fn check_batch_polynomial_commitment_blinding, const D: usize>( - // ) -> Result<()> { - // let k0 = 10; - // let k1 = 3; - // let k2 = 7; - // let degree_log = 11; - // let num_points = 5; - // let fri_config = FriConfig { - // proof_of_work_bits: 2, - // rate_bits: 2, - // reduction_arity_bits: vec![2, 3, 1, 2], - // num_query_rounds: 3, - // blinding: vec![true, false, true], - // check_basefield: vec![true, false, true], - // }; - // let (polys0, _) = gen_random_test_case::(k0, degree_log, num_points); - // let (polys1, _) = gen_random_test_case::(k1, degree_log, num_points); - // let (polys2, points) = gen_random_test_case::(k2, degree_log, num_points); - // - // let lpc0 = ListPolynomialCommitment::new(polys0, fri_config.rate_bits, true); - // let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false); - // let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, true); - // - // let (proof, evaluations) = ListPolynomialCommitment::batch_open::( - // &[&lpc0, &lpc1, &lpc2], - // &points, - // &fri_config, - // &mut Challenger::new(), - // ); - // proof.verify( - // &points, - // &evaluations, - // &[ - // lpc0.merkle_tree.root, - // lpc1.merkle_tree.root, - // lpc2.merkle_tree.root, - // ], - // &mut Challenger::new(), - // &fri_config, - // ) - // } - macro_rules! tests_commitments { ($F:ty, $D:expr) => { use super::*; @@ -425,24 +391,30 @@ mod tests { fn test_batch_polynomial_commitment() -> Result<()> { check_batch_polynomial_commitment::<$F, $D>() } - - // #[test] - // fn test_batch_polynomial_commitment_blinding() -> Result<()> { - // check_batch_polynomial_commitment_blinding::<$F, $D>() - // } }; } mod base { - tests_commitments!(crate::field::crandall_field::CrandallField, 1); + use super::*; + #[test] + fn test_batch_polynomial_commitment() -> Result<()> { + check_batch_polynomial_commitment::() + } } mod quadratic { - tests_commitments!(crate::field::crandall_field::CrandallField, 2); + use super::*; + #[test] + fn test_batch_polynomial_commitment() -> Result<()> { + check_batch_polynomial_commitment::() + } } mod quartic { use super::*; - tests_commitments!(crate::field::crandall_field::CrandallField, 4); + #[test] + fn test_batch_polynomial_commitment() -> Result<()> { + check_batch_polynomial_commitment::() + } } } From 60e9464416a17da4e4bcaf82a352fe31500f42b6 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 1 Jun 2021 11:32:06 +0200 Subject: [PATCH 09/11] Remove unused --- src/polynomial/polynomial.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index 80c22db8..5e3dd9f0 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -1,7 +1,7 @@ use std::cmp::max; use std::ops::{Add, Mul, Sub}; -use crate::field::extension_field::{Extendable, OEF}; +use crate::field::extension_field::Extendable; use crate::field::fft::{fft, ifft}; use crate::field::field::Field; use crate::util::log2_strict; @@ -186,15 +186,6 @@ impl PolynomialCoeffs { { PolynomialCoeffs::new(self.coeffs.iter().map(|&c| c.into()).collect()) } - - pub fn frobenius( - poly: &PolynomialCoeffs, - ) -> PolynomialCoeffs - where - F: Extendable, - { - PolynomialCoeffs::new(poly.coeffs.iter().map(|&c| c.frobenius()).collect()) - } } impl PartialEq for PolynomialCoeffs { From 9eb35c3c8290a587974a599fb2ead8ac1919a88a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 1 Jun 2021 21:55:05 +0200 Subject: [PATCH 10/11] Remove D=1 case --- src/fri/verifier.rs | 84 ++++++++++++++-------------------- src/polynomial/commitment.rs | 88 ++++++++++++++---------------------- 2 files changed, 68 insertions(+), 104 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 981db38a..2ff6b7b8 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -148,6 +148,7 @@ fn fri_combine_initial, const D: usize>( subgroup_x: F, config: &FriConfig, ) -> F::Extension { + assert!(D > 1, "Not implemented for D=1."); let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; let mut cur_alpha = F::Extension::ONE; @@ -155,35 +156,22 @@ fn fri_combine_initial, const D: usize>( let mut poly_count = 0; let mut e = F::Extension::ZERO; - let ev = if D == 1 { - vec![0, 1, 2, 4] - } else { - vec![0, 1, 4] - } - .iter() - .flat_map(|&i| { - let v = &proof.evals_proofs[i].0; - &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }] - }) - .rev() - .fold(F::Extension::ZERO, |acc, &e| { - poly_count += 1; - alpha * acc + e.into() - }); - let composition_eval = if D == 1 { - vec![ - &os.constants, - &os.plonk_sigmas, - &os.wires, - &os.quotient_polys, - ] - } else { - vec![&os.constants, &os.plonk_sigmas, &os.quotient_polys] - } - .iter() - .flat_map(|v| v.iter()) - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); + let ev = vec![0, 1, 4] + .iter() + .flat_map(|&i| { + let v = &proof.evals_proofs[i].0; + &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }] + }) + .rev() + .fold(F::Extension::ZERO, |acc, &e| { + poly_count += 1; + alpha * acc + e.into() + }); + let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] + .iter() + .flat_map(|v| v.iter()) + .rev() + .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); let numerator = ev - composition_eval; let denominator = F::Extension::from_basefield(subgroup_x) - zeta; e += cur_alpha * numerator / denominator; @@ -208,26 +196,24 @@ fn fri_combine_initial, const D: usize>( e += cur_alpha * numerator / denominator; cur_alpha = alpha.exp(poly_count); - if D > 1 { - let ev = proof.evals_proofs[2].0 - [..proof.evals_proofs[2].0.len() - if config.blinding[2] { SALT_SIZE } else { 0 }] - .iter() - .rev() - .fold(F::Extension::ZERO, |acc, &e| { - poly_count += 1; - alpha * acc + e.into() - }); - let zeta_frob = zeta.frobenius(); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); - let wires_interpol = interpolant(&[ - (zeta, reduce_with_powers(&os.wires, alpha)), - (zeta_frob, reduce_with_powers(&wire_evals_frob, alpha)), - ]); - let numerator = ev - wires_interpol.eval(subgroup_x.into()); - let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) - * (F::Extension::from_basefield(subgroup_x) - zeta_frob); - e += cur_alpha * numerator / denominator; - } + let ev = proof.evals_proofs[2].0 + [..proof.evals_proofs[2].0.len() - if config.blinding[2] { SALT_SIZE } else { 0 }] + .iter() + .rev() + .fold(F::Extension::ZERO, |acc, &e| { + poly_count += 1; + alpha * acc + e.into() + }); + let zeta_frob = zeta.frobenius(); + let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wires_interpol = interpolant(&[ + (zeta, reduce_with_powers(&os.wires, alpha)), + (zeta_frob, reduce_with_powers(&wire_evals_frob, alpha)), + ]); + let numerator = ev - wires_interpol.eval(subgroup_x.into()); + let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) + * (F::Extension::from_basefield(subgroup_x) - zeta_frob); + e += cur_alpha * numerator / denominator; e } diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index f7906e18..06194ad9 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -87,6 +87,7 @@ impl ListPolynomialCommitment { where F: Extendable, { + assert!(D > 1, "Not implemented for D=1."); let degree_log = log2_strict(commitments[0].degree); let g = F::Extension::primitive_root_of_unity(degree_log); for &p in &[zeta, g * zeta] { @@ -117,32 +118,19 @@ impl ListPolynomialCommitment { let mut poly_count = 0; // Polynomials opened at a single point. - let composition_poly = if D == 1 { - vec![0, 1, 2, 4] - } else { - vec![0, 1, 4] - } - .iter() - .flat_map(|&i| &commitments[i].polynomials) - .rev() - .fold(PolynomialCoeffs::empty(), |acc, p| { - poly_count += 1; - &(&acc * alpha) + &p.to_extension() - }); - let composition_eval = if D == 1 { - vec![ - &os.constants, - &os.plonk_sigmas, - &os.wires, - &os.quotient_polys, - ] - } else { - vec![&os.constants, &os.plonk_sigmas, &os.quotient_polys] - } - .iter() - .flat_map(|v| v.iter()) - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); + let composition_poly = [0, 1, 4] + .iter() + .flat_map(|&i| &commitments[i].polynomials) + .rev() + .fold(PolynomialCoeffs::empty(), |acc, p| { + poly_count += 1; + &(&acc * alpha) + &p.to_extension() + }); + let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] + .iter() + .flat_map(|v| v.iter()) + .rev() + .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); let quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly); final_poly = &final_poly + &("ient * cur_alpha); @@ -171,30 +159,30 @@ impl ListPolynomialCommitment { final_poly = &final_poly + &(&zs_quotient * cur_alpha); cur_alpha = alpha.exp(poly_count); - // If working in an extension field, need to check that wires are in the base field. + // When working in an extension field, need to check that wires are in the base field. // Check this by opening the wires polynomials at `zeta` and `zeta.frobenius()` and using the fact that // a polynomial `f` is over the base field iff `f(z).frobenius()=f(z.frobenius())` with high probability. - if D > 1 { - let wires_composition_poly = commitments[2].polynomials.iter().rev().fold( - PolynomialCoeffs::empty(), - |acc, p| { + let wires_composition_poly = + commitments[2] + .polynomials + .iter() + .rev() + .fold(PolynomialCoeffs::empty(), |acc, p| { poly_count += 1; &(&acc * alpha) + &p.to_extension() - }, - ); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); - let wires_composition_evals = [ - reduce_with_powers(&os.wires, alpha), - reduce_with_powers(&wire_evals_frob, alpha), - ]; + }); + let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wires_composition_evals = [ + reduce_with_powers(&os.wires, alpha), + reduce_with_powers(&wire_evals_frob, alpha), + ]; - let wires_quotient = Self::compute_quotient( - &[zeta, zeta.frobenius()], - &wires_composition_evals, - &wires_composition_poly, - ); - final_poly = &final_poly + &(&wires_quotient * cur_alpha); - } + let wires_quotient = Self::compute_quotient( + &[zeta, zeta.frobenius()], + &wires_composition_evals, + &wires_composition_poly, + ); + final_poly = &final_poly + &(&wires_quotient * cur_alpha); let lde_final_poly = final_poly.lde(config.rate_bits); let lde_final_values = lde_final_poly @@ -370,16 +358,6 @@ mod tests { ) } - mod base { - use super::*; - use crate::field::crandall_field::CrandallField; - - #[test] - fn test_batch_polynomial_commitment() -> Result<()> { - check_batch_polynomial_commitment::() - } - } - mod quadratic { use super::*; use crate::field::crandall_field::CrandallField; From 7334341cfa057517bb6d02a912d28c0495540ba6 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 1 Jun 2021 19:13:22 -0700 Subject: [PATCH 11/11] Attempt at simplification --- Cargo.toml | 1 + src/field/field.rs | 1 + src/fri/mod.rs | 12 ++++++ src/fri/verifier.rs | 100 +++++++++++++++++++++----------------------- src/plonk_common.rs | 11 +++++ src/proof.rs | 8 ++++ 6 files changed, 80 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 72c827ab..21708d41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ default-run = "bench_recursion" [dependencies] env_logger = "0.8.3" log = "0.4.14" +itertools = "0.10.0" num = "0.3" rand = "0.7.3" rand_chacha = "0.2.2" diff --git a/src/field/field.rs b/src/field/field.rs index 92d1f675..3c6f0e47 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -268,6 +268,7 @@ pub trait Field: } /// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`. +#[derive(Clone)] pub struct Powers { base: F, current: F, diff --git a/src/fri/mod.rs b/src/fri/mod.rs index d6e369da..c147e8c6 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -1,3 +1,5 @@ +use crate::polynomial::commitment::SALT_SIZE; + pub mod prover; pub mod verifier; @@ -25,6 +27,16 @@ pub struct FriConfig { pub blinding: Vec, } +impl FriConfig { + pub(crate) fn salt_size(&self, i: usize) -> usize { + if self.blinding[i] { + SALT_SIZE + } else { + 0 + } + } +} + fn fri_delta(rate_log: usize, conjecture: bool) -> f64 { let rate = (1 << rate_log) as f64; if conjecture { diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 2ff6b7b8..e6e8cae7 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -1,3 +1,6 @@ +use anyhow::{ensure, Result}; +use itertools::izip; + use crate::field::extension_field::{flatten, Extendable, FieldExtension, OEF}; use crate::field::field::Field; use crate::field::lagrange::{barycentric_weights, interpolant, interpolate}; @@ -5,11 +8,9 @@ use crate::fri::FriConfig; use crate::hash::hash_n_to_1; use crate::merkle_proofs::verify_merkle_proof; use crate::plonk_challenger::Challenger; -use crate::plonk_common::reduce_with_powers; -use crate::polynomial::commitment::SALT_SIZE; +use crate::plonk_common::reduce_with_iter; use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; -use anyhow::{ensure, Result}; /// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity /// and P' is the FRI reduced polynomial. @@ -150,72 +151,65 @@ fn fri_combine_initial, const D: usize>( ) -> F::Extension { assert!(D > 1, "Not implemented for D=1."); let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; + let subgroup_x = F::Extension::from_basefield(subgroup_x); + let mut alpha_powers = alpha.powers(); + let mut sum = F::Extension::ZERO; - let mut cur_alpha = F::Extension::ONE; + // We will add three terms to `sum`: + // - one for polynomials opened at `x` only + // - one for polynomials opened at `x` and `g x` + // - one for polynomials opened at `x` and its conjugate - let mut poly_count = 0; - let mut e = F::Extension::ZERO; - - let ev = vec![0, 1, 4] + let evals = [0, 1, 4] .iter() - .flat_map(|&i| { - let v = &proof.evals_proofs[i].0; - &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }] - }) - .rev() - .fold(F::Extension::ZERO, |acc, &e| { - poly_count += 1; - alpha * acc + e.into() - }); - let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] + .flat_map(|&i| proof.unsalted_evals(i, config)) + .map(|&e| F::Extension::from_basefield(e)); + let openings = os + .constants .iter() - .flat_map(|v| v.iter()) - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); - let numerator = ev - composition_eval; - let denominator = F::Extension::from_basefield(subgroup_x) - zeta; - e += cur_alpha * numerator / denominator; - cur_alpha = alpha.exp(poly_count); + .chain(&os.plonk_sigmas) + .chain(&os.quotient_polys); + let numerator = izip!(evals, openings, &mut alpha_powers) + .map(|(e, &o, a)| a * (e - o)) + .sum::(); + let denominator = subgroup_x - zeta; + sum += numerator / denominator; - let ev = proof.evals_proofs[3].0 - [..proof.evals_proofs[3].0.len() - if config.blinding[3] { SALT_SIZE } else { 0 }] + let ev: F::Extension = proof + .unsalted_evals(3, config) .iter() - .rev() - .fold(F::Extension::ZERO, |acc, &e| { - poly_count += 1; - alpha * acc + e.into() - }); + .zip(alpha_powers.clone()) + .map(|(&e, a)| a * e.into()) + .sum(); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; let zs_interpol = interpolant(&[ - (zeta, reduce_with_powers(&os.plonk_zs, alpha)), - (zeta_right, reduce_with_powers(&os.plonk_zs_right, alpha)), + (zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())), + ( + zeta_right, + reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), + ), ]); - let numerator = ev - zs_interpol.eval(subgroup_x.into()); - let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) - * (F::Extension::from_basefield(subgroup_x) - zeta_right); - e += cur_alpha * numerator / denominator; - cur_alpha = alpha.exp(poly_count); + let numerator = ev - zs_interpol.eval(subgroup_x); + let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); + sum += numerator / denominator; - let ev = proof.evals_proofs[2].0 - [..proof.evals_proofs[2].0.len() - if config.blinding[2] { SALT_SIZE } else { 0 }] + let ev: F::Extension = proof + .unsalted_evals(2, config) .iter() - .rev() - .fold(F::Extension::ZERO, |acc, &e| { - poly_count += 1; - alpha * acc + e.into() - }); + .zip(alpha_powers.clone()) + .map(|(&e, a)| a * e.into()) + .sum(); let zeta_frob = zeta.frobenius(); let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); let wires_interpol = interpolant(&[ - (zeta, reduce_with_powers(&os.wires, alpha)), - (zeta_frob, reduce_with_powers(&wire_evals_frob, alpha)), + (zeta, reduce_with_iter(&os.wires, alpha_powers.clone())), + (zeta_frob, reduce_with_iter(&wire_evals_frob, alpha_powers)), ]); - let numerator = ev - wires_interpol.eval(subgroup_x.into()); - let denominator = (F::Extension::from_basefield(subgroup_x) - zeta) - * (F::Extension::from_basefield(subgroup_x) - zeta_frob); - e += cur_alpha * numerator / denominator; + let numerator = ev - wires_interpol.eval(subgroup_x); + let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); + sum += numerator / denominator; - e + sum } fn fri_verifier_query_round, const D: usize>( diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 73c6d65c..990e6ea7 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -108,3 +108,14 @@ pub(crate) fn reduce_with_powers_recursive, const D: usize>( ) -> Target { todo!() } + +pub(crate) fn reduce_with_iter(terms: &[F], coeffs: I) -> F +where + I: IntoIterator, +{ + let mut sum = F::ZERO; + for (&term, coeff) in terms.iter().zip(coeffs) { + sum += coeff * term; + } + sum +} diff --git a/src/proof.rs b/src/proof.rs index 46b1a071..46288808 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -1,5 +1,6 @@ use crate::field::extension_field::Extendable; use crate::field::field::Field; +use crate::fri::FriConfig; use crate::merkle_proofs::{MerkleProof, MerkleProofTarget}; use crate::polynomial::commitment::{ListPolynomialCommitment, OpeningProof}; use crate::polynomial::polynomial::PolynomialCoeffs; @@ -99,6 +100,13 @@ pub struct FriInitialTreeProof { pub evals_proofs: Vec<(Vec, MerkleProof)>, } +impl FriInitialTreeProof { + pub(crate) fn unsalted_evals(&self, i: usize, config: &FriConfig) -> &[F] { + let evals = &self.evals_proofs[i].0; + &evals[..evals.len() - config.salt_size(i)] + } +} + /// Proof for a FRI query round. // TODO: Implement FriQueryRoundTarget pub struct FriQueryRound, const D: usize> {