From 322556260c250bd165187efa19be540279104507 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Jun 2021 16:06:41 +0200 Subject: [PATCH 01/26] Cosmetic changes --- src/generator.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/generator.rs b/src/generator.rs index 443809b6..b6534921 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -17,17 +17,13 @@ pub(crate) fn generate_partial_witness( for watch in generator.watch_list() { generator_indices_by_watches .entry(watch) - .or_insert_with(Vec::new) - .push(i); + .or_insert_with(|| vec![i]); } } // Build a list of "pending" generators which are queued to be run. Initially, all generators // are queued. - let mut pending_generator_indices = HashSet::new(); - for i in 0..generators.len() { - pending_generator_indices.insert(i); - } + let mut pending_generator_indices: HashSet<_> = (0..generators.len()).collect(); // We also track a list of "expired" generators which have already returned false. let mut expired_generator_indices = HashSet::new(); From ea6a724560392b2422be85cce1988093c6debfbf Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Jun 2021 17:02:52 +0200 Subject: [PATCH 02/26] Enforce copy constraints in partial witness generation. --- src/circuit_builder.rs | 11 ++++++++--- src/circuit_data.rs | 3 +++ src/gates/gmimc.rs | 10 +++++++++- src/generator.rs | 9 ++++++++- src/permutation_argument.rs | 21 +++++++++++++++++++++ src/plonk_challenger.rs | 9 +++++++-- src/prover.rs | 6 +++++- src/witness.rs | 4 ++++ 8 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 4150bb68..b9b2e533 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -236,7 +236,7 @@ impl, const D: usize> CircuitBuilder { .collect() } - fn sigma_vecs(&self, k_is: &[F]) -> Vec> { + fn sigma_vecs(&self, k_is: &[F]) -> (Vec>, TargetPartitions) { let degree = self.gate_instances.len(); let degree_log = log2_strict(degree); let mut target_partitions = TargetPartitions::new(); @@ -256,7 +256,11 @@ impl, const D: usize> CircuitBuilder { } let wire_partitions = target_partitions.to_wire_partitions(); - wire_partitions.get_sigma_polys(degree_log, k_is) + + ( + wire_partitions.get_sigma_polys(degree_log, k_is), + target_partitions, + ) } /// Builds a "full circuit", with both prover and verifier data. @@ -278,7 +282,7 @@ impl, const D: usize> CircuitBuilder { ); let k_is = get_unique_coset_shifts(degree, self.config.num_routed_wires); - let sigma_vecs = self.sigma_vecs(&k_is); + let (sigma_vecs, targets_partition) = self.sigma_vecs(&k_is); let sigmas_commitment = ListPolynomialCommitment::new( sigma_vecs.into_iter().map(|v| v.ifft()).collect(), self.config.fri_config.rate_bits, @@ -297,6 +301,7 @@ impl, const D: usize> CircuitBuilder { generators, constants_commitment, sigmas_commitment, + targets_partition, }; // The HashSet of gates will have a non-deterministic order. When converting to a Vec, we diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 4d9a7110..6b6d614a 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -5,6 +5,7 @@ use crate::field::field::Field; use crate::fri::FriConfig; use crate::gates::gate::GateRef; use crate::generator::WitnessGenerator; +use crate::permutation_argument::TargetPartitions; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::proof::{Hash, HashTarget, Proof}; use crate::prover::prove; @@ -104,6 +105,8 @@ pub(crate) struct ProverOnlyCircuitData { pub constants_commitment: ListPolynomialCommitment, /// Commitments to the sigma polynomial. pub sigmas_commitment: ListPolynomialCommitment, + /// Partition of the targets into copy-constrained sets. + pub targets_partition: TargetPartitions, } /// Circuit data required by the verifier, but not the prover. diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 19042d57..ac5741e4 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -323,6 +323,8 @@ mod tests { use crate::gates::gmimc::{GMiMCGate, W}; use crate::generator::generate_partial_witness; use crate::gmimc::gmimc_permute_naive; + use crate::permutation_argument::TargetPartitions; + use crate::target::Target; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -368,7 +370,13 @@ mod tests { } let generators = gate.0.generators(0, &[]); - generate_partial_witness(&mut witness, &generators); + let mut tp = TargetPartitions::new(); + for g in 0..10 { + for i in 0..config.num_routed_wires { + tp.add_partition(Target::wire(g, i)); + } + } + generate_partial_witness(&mut witness, &generators, &tp); let expected_outputs: [F; W] = gmimc_permute_naive(permutation_inputs.try_into().unwrap(), constants); diff --git a/src/generator.rs b/src/generator.rs index b6534921..b04442b5 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use crate::field::field::Field; +use crate::permutation_argument::TargetPartitions; use crate::target::Target; use crate::witness::PartialWitness; @@ -10,6 +11,7 @@ use crate::witness::PartialWitness; pub(crate) fn generate_partial_witness( witness: &mut PartialWitness, generators: &[Box>], + target_partition: &TargetPartitions, ) { // Index generator indices by their watched targets. let mut generator_indices_by_watches = HashMap::new(); @@ -21,6 +23,8 @@ pub(crate) fn generate_partial_witness( } } + target_partition.generate_copies(witness, &witness.all_populated_targets()); + // Build a list of "pending" generators which are queued to be run. Initially, all generators // are queued. let mut pending_generator_indices: HashSet<_> = (0..generators.len()).collect(); @@ -33,11 +37,14 @@ pub(crate) fn generate_partial_witness( let mut next_pending_generator_indices = HashSet::new(); for &generator_idx in &pending_generator_indices { - let (result, finished) = generators[generator_idx].run(&witness); + let (mut result, finished) = generators[generator_idx].run(&witness); if finished { expired_generator_indices.insert(generator_idx); } + let new_targets = result.all_populated_targets(); + target_partition.generate_copies(&mut result, &new_targets); + // Enqueue unfinished generators that were watching one of the newly populated targets. for watch in result.target_values.keys() { if let Some(watching_generator_indices) = generator_indices_by_watches.get(watch) { diff --git a/src/permutation_argument.rs b/src/permutation_argument.rs index 62ee63d4..f2739756 100644 --- a/src/permutation_argument.rs +++ b/src/permutation_argument.rs @@ -6,6 +6,7 @@ use crate::field::field::Field; use crate::polynomial::polynomial::PolynomialValues; use crate::target::Target; use crate::wire::Wire; +use crate::witness::PartialWitness; #[derive(Debug, Clone)] pub struct TargetPartitions { @@ -82,6 +83,26 @@ impl TargetPartitions { indices, } } + /// For the given set of targets, find any copy constraints involving those targets and populate + /// the witness with copies as needed. + pub fn generate_copies(&self, witness: &mut PartialWitness, targets: &[Target]) { + let mut result = PartialWitness::new(); + + for &target in targets { + let value = witness.get_target(target); + let partition = self.get_partition(target); + + for &sibling in partition { + if witness.contains(sibling) { + // This sibling's value was already set; make sure it has the same value. + assert_eq!(witness.get_target(sibling), value); + } else { + result.set_target(sibling, value); + } + } + } + witness.extend(result); + } } pub struct WirePartitions { diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index fd21ee0d..30d4cf70 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -289,6 +289,7 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::field::Field; use crate::generator::generate_partial_witness; + use crate::permutation_argument::TargetPartitions; use crate::plonk_challenger::{Challenger, RecursiveChallenger}; use crate::target::Target; use crate::witness::PartialWitness; @@ -337,7 +338,7 @@ mod tests { let config = CircuitConfig { num_wires: 12 + 12 + 3 + 101, - num_routed_wires: 27, + num_routed_wires: 200, ..CircuitConfig::default() }; let mut builder = CircuitBuilder::::new(config); @@ -351,7 +352,11 @@ mod tests { } let circuit = builder.build(); let mut witness = PartialWitness::new(); - generate_partial_witness(&mut witness, &circuit.prover_only.generators); + generate_partial_witness( + &mut witness, + &circuit.prover_only.generators, + &circuit.prover_only.targets_partition, + ); let recursive_output_values_per_round: Vec> = recursive_outputs_per_round .iter() .map(|outputs| witness.get_targets(outputs)) diff --git a/src/prover.rs b/src/prover.rs index 7a492eaa..fc4e6f38 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -34,7 +34,11 @@ pub(crate) fn prove, const D: usize>( let mut witness = inputs; info!("Running {} generators", prover_data.generators.len()); timed!( - generate_partial_witness(&mut witness, &prover_data.generators), + generate_partial_witness( + &mut witness, + &prover_data.generators, + &prover_data.targets_partition + ), "to generate witness" ); diff --git a/src/witness.rs b/src/witness.rs index a0b4b2a4..e71eebc9 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -59,6 +59,10 @@ impl PartialWitness { targets.iter().all(|&t| self.contains(t)) } + pub fn all_populated_targets(&self) -> Vec { + self.target_values.keys().cloned().collect() + } + pub fn set_target(&mut self, target: Target, value: F) { let opt_old_value = self.target_values.insert(target, value); if let Some(old_value) = opt_old_value { From 86b4b0ab41295df4d133c5803ccca8125dd25e98 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Jun 2021 17:06:53 +0200 Subject: [PATCH 03/26] Add check that all generators were run. --- src/generator.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/generator.rs b/src/generator.rs index b04442b5..a5ba4eaf 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -61,6 +61,11 @@ pub(crate) fn generate_partial_witness( pending_generator_indices = next_pending_generator_indices; } + assert_eq!( + expired_generator_indices.len(), + generators.len(), + "Some generators weren't run." + ); } /// A generator participates in the generation of the witness. From c22bc6261ed9c36288300acbf833fdaca0cefb84 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Jun 2021 21:03:50 +0200 Subject: [PATCH 04/26] Revert watch insertion --- src/generator.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/generator.rs b/src/generator.rs index a5ba4eaf..5b6a258a 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -19,7 +19,8 @@ pub(crate) fn generate_partial_witness( for watch in generator.watch_list() { generator_indices_by_watches .entry(watch) - .or_insert_with(|| vec![i]); + .or_insert_with(Vec::new) + .push(i) } } From bfd5f063842018594b2576802e72bb18522342ea Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 17 Jun 2021 11:54:31 +0200 Subject: [PATCH 05/26] Hardcode Plonk polynomials indices and blinding flags. --- src/bin/bench_recursion.rs | 2 -- src/circuit_data.rs | 4 +-- src/fri/mod.rs | 16 ----------- src/fri/recursive_verifier.rs | 19 ++++++++----- src/fri/verifier.rs | 20 ++++++++------ src/gadgets/arithmetic.rs | 1 - src/plonk_common.rs | 52 +++++++++++++++++++++++++++++++++++ src/polynomial/commitment.rs | 16 ++--------- src/proof.rs | 14 +++++----- src/prover.rs | 3 -- 10 files changed, 86 insertions(+), 61 deletions(-) diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index 19f7716c..9fab2456 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -8,7 +8,6 @@ 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::witness::PartialWitness; fn main() { @@ -41,7 +40,6 @@ fn bench_prove, const D: usize>() { rate_bits: 3, reduction_arity_bits: vec![1], num_query_rounds: 1, - blinding: PLONK_BLINDING.to_vec(), }, }; diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 7429e62a..c8477464 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -7,7 +7,7 @@ use crate::gates::gate::GateRef; use crate::generator::WitnessGenerator; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::proof::{Hash, HashTarget, Proof}; -use crate::prover::{prove, PLONK_BLINDING}; +use crate::prover::prove; use crate::verifier::verify; use crate::witness::PartialWitness; @@ -38,7 +38,6 @@ impl Default for CircuitConfig { rate_bits: 1, reduction_arity_bits: vec![1], num_query_rounds: 1, - blinding: vec![true], }, } } @@ -61,7 +60,6 @@ impl CircuitConfig { rate_bits: 3, reduction_arity_bits: vec![1], num_query_rounds: 1, - blinding: PLONK_BLINDING.to_vec(), }, } } diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 6351a2af..87fe3db5 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -1,5 +1,3 @@ -use crate::polynomial::commitment::SALT_SIZE; - pub mod prover; mod recursive_verifier; pub mod verifier; @@ -22,20 +20,6 @@ pub struct FriConfig { /// Number of query rounds to perform. pub num_query_rounds: usize, - - /// 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, -} - -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 { diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index b35098e1..7c04d4a2 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -6,6 +6,7 @@ use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::fri::FriConfig; use crate::plonk_challenger::RecursiveChallenger; +use crate::plonk_common::PlonkPolynomials; use crate::proof::{ FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, HashTarget, OpeningSetTarget, }; @@ -157,11 +158,15 @@ impl, const D: usize> CircuitBuilder { // - one for polynomials opened at `x` and `x.frobenius()` // Polynomials opened at `x`, i.e., the constants, sigmas and quotient polynomials. - let single_evals = [0, 1, 4] - .iter() - .flat_map(|&i| proof.unsalted_evals(i, config)) - .map(|&e| self.convert_to_ext(e)) - .collect::>(); + let single_evals = [ + PlonkPolynomials::CONSTANTS, + PlonkPolynomials::SIGMAS, + PlonkPolynomials::QUOTIENT, + ] + .iter() + .flat_map(|&p| proof.unsalted_evals(p)) + .map(|&e| self.convert_to_ext(e)) + .collect::>(); let single_openings = os .constants .iter() @@ -179,7 +184,7 @@ impl, const D: usize> CircuitBuilder { // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof - .unsalted_evals(3, config) + .unsalted_evals(PlonkPolynomials::ZS) .iter() .map(|&e| self.convert_to_ext(e)) .collect::>(); @@ -217,7 +222,7 @@ impl, const D: usize> CircuitBuilder { // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. let wire_evals = proof - .unsalted_evals(2, config) + .unsalted_evals(PlonkPolynomials::WIRES) .iter() .map(|&e| self.convert_to_ext(e)) .collect::>(); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index b5a650bb..d100797e 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -7,7 +7,7 @@ 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_iter; +use crate::plonk_common::{reduce_with_iter, PlonkPolynomials}; use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; @@ -157,13 +157,17 @@ fn fri_combine_initial, const D: usize>( // We will add three terms to `sum`: // - one for various polynomials which are opened at a single point `x` // - one for Zs, which are opened at `x` and `g x` - // - one for wire polynomials, which are opened at `x` and its conjugate + // - one for wire polynomials, which are opened at `x` and `x.frobenius()` // Polynomials opened at `x`, i.e., the constants, sigmas and quotient polynomials. - let single_evals = [0, 1, 4] - .iter() - .flat_map(|&i| proof.unsalted_evals(i, config)) - .map(|&e| F::Extension::from_basefield(e)); + let single_evals = [ + PlonkPolynomials::CONSTANTS, + PlonkPolynomials::SIGMAS, + PlonkPolynomials::QUOTIENT, + ] + .iter() + .flat_map(|&p| proof.unsalted_evals(p)) + .map(|&e| F::Extension::from_basefield(e)); let single_openings = os .constants .iter() @@ -176,7 +180,7 @@ fn fri_combine_initial, const D: usize>( // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof - .unsalted_evals(3, config) + .unsalted_evals(PlonkPolynomials::ZS) .iter() .map(|&e| F::Extension::from_basefield(e)); let zs_composition_eval = reduce_with_iter(zs_evals, alpha_powers.clone()); @@ -194,7 +198,7 @@ fn fri_combine_initial, const D: usize>( // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. let wire_evals = proof - .unsalted_evals(2, config) + .unsalted_evals(PlonkPolynomials::WIRES) .iter() .map(|&e| F::Extension::from_basefield(e)); let wire_composition_eval = reduce_with_iter(wire_evals, alpha_powers.clone()); diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 6250ea81..520f8cd9 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -371,7 +371,6 @@ mod tests { use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; use crate::fri::FriConfig; - use crate::prover::PLONK_BLINDING; use crate::witness::PartialWitness; #[test] diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 5c881fb1..c9f11b74 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -6,10 +6,62 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::gates::gate::GateRef; +use crate::polynomial::commitment::SALT_SIZE; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; +/// Holds the Merkle tree index and blinding flag of a set of polynomials used in FRI. +#[derive(Debug, Copy, Clone)] +pub struct PolynomialsIndexBlinding { + pub(crate) index: usize, + pub(crate) blinding: bool, +} +impl PolynomialsIndexBlinding { + pub fn salt_size(&self) -> usize { + if self.blinding { + SALT_SIZE + } else { + 0 + } + } +} +/// Holds the indices and blinding flags of the Plonk polynomials. +pub struct PlonkPolynomials; +impl PlonkPolynomials { + pub const CONSTANTS: PolynomialsIndexBlinding = PolynomialsIndexBlinding { + index: 0, + blinding: false, + }; + pub const SIGMAS: PolynomialsIndexBlinding = PolynomialsIndexBlinding { + index: 1, + blinding: false, + }; + pub const WIRES: PolynomialsIndexBlinding = PolynomialsIndexBlinding { + index: 2, + blinding: true, + }; + pub const ZS: PolynomialsIndexBlinding = PolynomialsIndexBlinding { + index: 3, + blinding: true, + }; + pub const QUOTIENT: PolynomialsIndexBlinding = PolynomialsIndexBlinding { + index: 4, + blinding: true, + }; + + pub fn polynomials(i: usize) -> PolynomialsIndexBlinding { + match i { + 0 => Self::CONSTANTS, + 1 => Self::SIGMAS, + 2 => Self::WIRES, + 3 => Self::ZS, + 4 => Self::QUOTIENT, + _ => panic!("There are only 5 sets of polynomials in Plonk."), + } + } +} + /// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random /// linear combination of gate constraints, plus some other terms relating to the permutation /// argument. All such terms should vanish on `H`. diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index c1fd08eb..caa61553 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -260,9 +260,9 @@ pub struct OpeningProofTarget { #[cfg(test)] mod tests { use anyhow::Result; - use rand::Rng; use super::*; + use crate::plonk_common::PlonkPolynomials; fn gen_random_test_case, const D: usize>( k: usize, @@ -288,17 +288,6 @@ mod tests { point } - fn gen_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; @@ -307,7 +296,6 @@ mod tests { rate_bits: 2, reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, - blinding: gen_random_blindings(), }; let lpcs = (0..5) @@ -315,7 +303,7 @@ mod tests { ListPolynomialCommitment::::new( gen_random_test_case(ks[i], degree_log), fri_config.rate_bits, - fri_config.blinding[i], + PlonkPolynomials::polynomials(i).blinding, ) }) .collect::>(); diff --git a/src/proof.rs b/src/proof.rs index e05e4093..7536f3ee 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -3,9 +3,9 @@ use std::convert::TryInto; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field::Field; -use crate::fri::FriConfig; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::merkle_proofs::{MerkleProof, MerkleProofTarget}; +use crate::plonk_common::PolynomialsIndexBlinding; use crate::polynomial::commitment::{ListPolynomialCommitment, OpeningProof, OpeningProofTarget}; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; @@ -99,9 +99,9 @@ pub struct FriInitialTreeProof { } 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)] + pub(crate) fn unsalted_evals(&self, polynomials: PolynomialsIndexBlinding) -> &[F] { + let evals = &self.evals_proofs[polynomials.index].0; + &evals[..evals.len() - polynomials.salt_size()] } } @@ -110,9 +110,9 @@ pub struct FriInitialTreeProofTarget { } impl FriInitialTreeProofTarget { - pub(crate) fn unsalted_evals(&self, i: usize, config: &FriConfig) -> &[Target] { - let evals = &self.evals_proofs[i].0; - &evals[..evals.len() - config.salt_size(i)] + pub(crate) fn unsalted_evals(&self, polynomials: PolynomialsIndexBlinding) -> &[Target] { + let evals = &self.evals_proofs[polynomials.index].0; + &evals[..evals.len() - polynomials.salt_size()] } } diff --git a/src/prover.rs b/src/prover.rs index df4d912a..5ea6ddfd 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -19,9 +19,6 @@ use crate::vars::EvaluationVarsBase; use crate::wire::Wire; use crate::witness::PartialWitness; -/// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments. -pub const PLONK_BLINDING: [bool; 5] = [false, false, true, true, true]; - pub(crate) fn prove, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, From f27620ca901c55f4b5ec71bb8e36476d998802d7 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 17 Jun 2021 19:40:41 +0200 Subject: [PATCH 06/26] First impl --- src/fri/verifier.rs | 44 ++++++++++++++++++++++++-------------------- src/proof.rs | 4 ++-- src/util/mod.rs | 1 + src/util/scaling.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 src/util/scaling.rs diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index b5a650bb..2ce33bd0 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -9,6 +9,7 @@ use crate::merkle_proofs::verify_merkle_proof; use crate::plonk_challenger::Challenger; use crate::plonk_common::reduce_with_iter; use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; +use crate::util::scaling::ScalingFactor; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; /// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity @@ -151,7 +152,7 @@ fn fri_combine_initial, const D: usize>( 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 alpha = ScalingFactor::new(alpha); let mut sum = F::Extension::ZERO; // We will add three terms to `sum`: @@ -160,53 +161,56 @@ fn fri_combine_initial, const D: usize>( // - one for wire polynomials, which are opened at `x` and its conjugate // Polynomials opened at `x`, i.e., the constants, sigmas and quotient polynomials. - let single_evals = [0, 1, 4] - .iter() - .flat_map(|&i| proof.unsalted_evals(i, config)) - .map(|&e| F::Extension::from_basefield(e)); + let single_evals = &proof + .unsalted_evals(0, config) + .into_iter() + .chain(proof.unsalted_evals(1, config)) + .chain(proof.unsalted_evals(4, config)) + .map(|e| F::Extension::from_basefield(e)); let single_openings = os .constants - .iter() - .chain(&os.plonk_s_sigmas) - .chain(&os.quotient_polys); - let single_diffs = single_evals.zip(single_openings).map(|(e, &o)| e - o); - let single_numerator = reduce_with_iter(single_diffs, &mut alpha_powers); + .clone() + .into_iter() + .chain(os.plonk_s_sigmas.clone()) + .chain(os.quotient_polys.clone()); + let single_diffs = single_evals.zip(single_openings).map(|(e, o)| e - o); + dbg!(single_diffs.rev()); + let single_numerator = alpha.scale(single_diffs); let single_denominator = subgroup_x - zeta; sum += single_numerator / single_denominator; + alpha.shift(sum); // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof .unsalted_evals(3, config) .iter() .map(|&e| F::Extension::from_basefield(e)); - let zs_composition_eval = reduce_with_iter(zs_evals, alpha_powers.clone()); + let zs_composition_eval = alpha.clone().scale(zs_evals); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; let zs_interpol = interpolant(&[ - (zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())), - ( - zeta_right, - reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), - ), + (zeta, alpha.clone().scale(&os.plonk_zs)), + (zeta_right, alpha.scale(&os.plonk_zs_right)), ]); let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x); let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); sum += zs_numerator / zs_denominator; + alpha.shift(sum); // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. let wire_evals = proof .unsalted_evals(2, config) .iter() .map(|&e| F::Extension::from_basefield(e)); - let wire_composition_eval = reduce_with_iter(wire_evals, alpha_powers.clone()); + let wire_composition_eval = alpha.clone().scale(wire_evals); let zeta_frob = zeta.frobenius(); - let wire_eval = reduce_with_iter(&os.wires, alpha_powers.clone()); + let wire_eval = alpha.clone().scale(&os.wires); // We want to compute `sum a^i*phi(w_i)`, where `phi` denotes the Frobenius automorphism. // Since `phi^D=id` and `phi` is a field automorphism, we have the following equalities: // `sum a^i*phi(w_i) = sum phi(phi^(D-1)(a^i)*w_i) = phi(sum phi^(D-1)(a)^i*w_i)` // So we can compute the original sum using only one call to the `D-1`-repeated Frobenius of alpha, // and one call at the end of the sum. - let alpha_powers_frob = alpha_powers.repeated_frobenius(D - 1); - let wire_eval_frob = reduce_with_iter(&os.wires, alpha_powers_frob).frobenius(); + let mut alpha_frob = alpha.repeated_frobenius(D - 1); + let wire_eval_frob = alpha_frob.scale(&os.wires).frobenius(); let wire_interpol = interpolant(&[(zeta, wire_eval), (zeta_frob, wire_eval_frob)]); let wire_numerator = wire_composition_eval - wire_interpol.eval(subgroup_x); let wire_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); diff --git a/src/proof.rs b/src/proof.rs index e05e4093..a029114a 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -99,9 +99,9 @@ pub struct FriInitialTreeProof { } impl FriInitialTreeProof { - pub(crate) fn unsalted_evals(&self, i: usize, config: &FriConfig) -> &[F] { + pub(crate) fn unsalted_evals(&self, i: usize, config: &FriConfig) -> Vec { let evals = &self.evals_proofs[i].0; - &evals[..evals.len() - config.salt_size(i)] + evals[..evals.len() - config.salt_size(i)].to_vec() } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 09bd4e72..f901b0af 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,4 @@ +pub mod scaling; pub(crate) mod timing; use crate::field::field::Field; diff --git a/src/util/scaling.rs b/src/util/scaling.rs new file mode 100644 index 00000000..36148d85 --- /dev/null +++ b/src/util/scaling.rs @@ -0,0 +1,41 @@ +use std::borrow::Borrow; + +use crate::field::extension_field::Frobenius; +use crate::field::field::Field; + +#[derive(Copy, Clone)] +pub struct ScalingFactor { + base: F, + count: u64, +} + +impl ScalingFactor { + pub fn new(base: F) -> Self { + Self { base, count: 0 } + } + + pub fn mul(&mut self, x: F) -> F { + self.count += 1; + self.base * x + } + + pub fn scale(&mut self, iter: impl DoubleEndedIterator>) -> F { + iter.rev().fold(F::ZERO, |acc, x| self.mul(acc) + x) + } + + pub fn shift(&mut self, x: F) -> F { + let tmp = self.base.exp(self.count) * x; + self.count = 0; + tmp + } + + pub fn repeated_frobenius(&self, count: usize) -> Self + where + F: Frobenius, + { + Self { + base: self.base.repeated_frobenius(count), + count: self.count, + } + } +} From fe9cd3f76b2da36fd4a8bfd84d830fe91f72d618 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 17 Jun 2021 21:34:04 +0200 Subject: [PATCH 07/26] Working commitments and verifier --- src/fri/verifier.rs | 26 +++++++++++-------- src/polynomial/commitment.rs | 48 +++++++++++++++++++++++------------- src/util/scaling.rs | 32 +++++++++++++++++++++--- 3 files changed, 76 insertions(+), 30 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index f27070b2..50537a9e 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -168,17 +168,22 @@ fn fri_combine_initial, const D: usize>( ] .iter() .flat_map(|&p| proof.unsalted_evals(p)) - .map(|&e| F::Extension::from_basefield(e)); + .map(|&e| F::Extension::from_basefield(e)) + .collect::>(); let single_openings = os .constants .iter() .chain(&os.plonk_s_sigmas) - .chain(&os.quotient_polys); - let single_diffs = single_evals.zip(single_openings).map(|(e, &o)| e - o); - let single_numerator = reduce_with_iter(single_diffs, &mut alpha_powers); + .chain(&os.quotient_polys) + .collect::>(); + let single_diffs = single_evals + .into_iter() + .zip(single_openings) + .map(|(e, &o)| e - o); + let single_numerator = alpha.scale(single_diffs); let single_denominator = subgroup_x - zeta; sum += single_numerator / single_denominator; - alpha.shift(sum); + alpha.reset(); // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof @@ -188,13 +193,13 @@ fn fri_combine_initial, const D: usize>( let zs_composition_eval = alpha.clone().scale(zs_evals); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; let zs_interpol = interpolant(&[ - (zeta, alpha.clone().scale(&os.plonk_zs)), - (zeta_right, alpha.scale(&os.plonk_zs_right)), + (zeta, alpha.clone().scale(os.plonk_zs.iter())), + (zeta_right, alpha.scale(os.plonk_zs_right.iter())), ]); let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x); let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); + sum = alpha.shift(sum); sum += zs_numerator / zs_denominator; - alpha.shift(sum); // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. let wire_evals = proof @@ -203,17 +208,18 @@ fn fri_combine_initial, const D: usize>( .map(|&e| F::Extension::from_basefield(e)); let wire_composition_eval = alpha.clone().scale(wire_evals); let zeta_frob = zeta.frobenius(); - let wire_eval = alpha.clone().scale(&os.wires); + let wire_eval = alpha.clone().scale(os.wires.iter()); // We want to compute `sum a^i*phi(w_i)`, where `phi` denotes the Frobenius automorphism. // Since `phi^D=id` and `phi` is a field automorphism, we have the following equalities: // `sum a^i*phi(w_i) = sum phi(phi^(D-1)(a^i)*w_i) = phi(sum phi^(D-1)(a)^i*w_i)` // So we can compute the original sum using only one call to the `D-1`-repeated Frobenius of alpha, // and one call at the end of the sum. let mut alpha_frob = alpha.repeated_frobenius(D - 1); - let wire_eval_frob = alpha_frob.scale(&os.wires).frobenius(); + let wire_eval_frob = alpha_frob.scale(os.wires.iter()).frobenius(); let wire_interpol = interpolant(&[(zeta, wire_eval), (zeta_frob, wire_eval_frob)]); let wire_numerator = wire_composition_eval - wire_interpol.eval(subgroup_x); let wire_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); + sum = alpha_frob.shift(sum); sum += wire_numerator / wire_denominator; sum diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index caa61553..9fa7bc01 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -8,10 +8,11 @@ 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_iter, reduce_with_iter}; +use crate::plonk_common::{reduce_polys_with_iter, reduce_with_iter, PlonkPolynomials}; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, FriProofTarget, Hash, OpeningSet}; use crate::timed; +use crate::util::scaling::ScalingFactor; use crate::util::{log2_strict, reverse_index_bits_in_place, transpose}; pub const SALT_SIZE: usize = 2; @@ -110,20 +111,24 @@ impl ListPolynomialCommitment { challenger.observe_opening_set(&os); let alpha = challenger.get_extension_challenge(); - let mut alpha_powers = alpha.powers(); + let mut alpha = ScalingFactor::new(alpha); // Final low-degree polynomial that goes into FRI. let mut final_poly = PolynomialCoeffs::empty(); // Polynomials opened at a single point. - let single_polys = [0, 1, 4] - .iter() - .flat_map(|&i| &commitments[i].polynomials) - .map(|p| p.to_extension()); + let single_polys = [ + PlonkPolynomials::CONSTANTS, + PlonkPolynomials::SIGMAS, + PlonkPolynomials::QUOTIENT, + ] + .iter() + .flat_map(|&p| &commitments[p.index].polynomials) + .map(|p| p.to_extension()); let single_os = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys]; let single_evals = single_os.iter().flat_map(|v| v.iter()); - let single_composition_poly = reduce_polys_with_iter(single_polys, alpha_powers.clone()); - let single_composition_eval = reduce_with_iter(single_evals, &mut alpha_powers); + let single_composition_poly = alpha.clone().scale_polys(single_polys); + let single_composition_eval = alpha.scale(single_evals); let single_quotient = Self::compute_quotient( &[zeta], @@ -131,13 +136,17 @@ impl ListPolynomialCommitment { &single_composition_poly, ); final_poly = &final_poly + &single_quotient; + alpha.reset(); // Zs polynomials are opened at `zeta` and `g*zeta`. - let zs_polys = commitments[3].polynomials.iter().map(|p| p.to_extension()); - let zs_composition_poly = reduce_polys_with_iter(zs_polys, alpha_powers.clone()); + let zs_polys = commitments[PlonkPolynomials::ZS.index] + .polynomials + .iter() + .map(|p| p.to_extension()); + let zs_composition_poly = alpha.clone().scale_polys(zs_polys); let zs_composition_evals = [ - reduce_with_iter(&os.plonk_zs, alpha_powers.clone()), - reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), + alpha.clone().scale(os.plonk_zs.iter()), + alpha.scale(os.plonk_zs_right.iter()), ]; let zs_quotient = Self::compute_quotient( @@ -145,17 +154,21 @@ impl ListPolynomialCommitment { &zs_composition_evals, &zs_composition_poly, ); + final_poly = alpha.shift_poly(final_poly); final_poly = &final_poly + &zs_quotient; // 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. - let wire_polys = commitments[2].polynomials.iter().map(|p| p.to_extension()); - let wire_composition_poly = reduce_polys_with_iter(wire_polys, alpha_powers.clone()); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wire_polys = commitments[PlonkPolynomials::WIRES.index] + .polynomials + .iter() + .map(|p| p.to_extension()); + let wire_composition_poly = alpha.clone().scale_polys(wire_polys); + let mut alpha_frob = alpha.repeated_frobenius(D - 1); let wire_composition_evals = [ - reduce_with_iter(&os.wires, alpha_powers.clone()), - reduce_with_iter(&wire_evals_frob, alpha_powers), + alpha.clone().scale(os.wires.iter()), + alpha_frob.scale(os.wires.iter()).frobenius(), ]; let wires_quotient = Self::compute_quotient( @@ -163,6 +176,7 @@ impl ListPolynomialCommitment { &wire_composition_evals, &wire_composition_poly, ); + final_poly = alpha_frob.shift_poly(final_poly); final_poly = &final_poly + &wires_quotient; let lde_final_poly = final_poly.lde(config.rate_bits); diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 36148d85..e29edf0e 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -2,8 +2,9 @@ use std::borrow::Borrow; use crate::field::extension_field::Frobenius; use crate::field::field::Field; +use crate::polynomial::polynomial::PolynomialCoeffs; -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct ScalingFactor { base: F, count: u64, @@ -14,13 +15,28 @@ impl ScalingFactor { Self { base, count: 0 } } - pub fn mul(&mut self, x: F) -> F { + fn mul(&mut self, x: F) -> F { self.count += 1; self.base * x } + fn mul_poly(&mut self, p: PolynomialCoeffs) -> PolynomialCoeffs { + self.count += 1; + &p * self.base + } + pub fn scale(&mut self, iter: impl DoubleEndedIterator>) -> F { - iter.rev().fold(F::ZERO, |acc, x| self.mul(acc) + x) + iter.rev() + .fold(F::ZERO, |acc, x| self.mul(acc) + *x.borrow()) + } + + pub fn scale_polys( + &mut self, + polys: impl DoubleEndedIterator>>, + ) -> PolynomialCoeffs { + polys.rev().fold(PolynomialCoeffs::empty(), |acc, x| { + &self.mul_poly(acc) + x.borrow() + }) } pub fn shift(&mut self, x: F) -> F { @@ -29,6 +45,16 @@ impl ScalingFactor { tmp } + pub fn shift_poly(&mut self, p: PolynomialCoeffs) -> PolynomialCoeffs { + let tmp = &p * self.base.exp(self.count); + self.count = 0; + tmp + } + + pub fn reset(&mut self) { + self.count = 0; + } + pub fn repeated_frobenius(&self, count: usize) -> Self where F: Frobenius, From 92e0f60c2318c4f7f92ce750229e540b5845604c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 17 Jun 2021 21:57:31 +0200 Subject: [PATCH 08/26] Clippy --- src/fri/verifier.rs | 2 +- src/polynomial/commitment.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 50537a9e..b94807f1 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -7,7 +7,7 @@ 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_iter, PlonkPolynomials}; +use crate::plonk_common::PlonkPolynomials; use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; use crate::util::scaling::ScalingFactor; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 9fa7bc01..c09e1e20 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -8,7 +8,7 @@ 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_iter, reduce_with_iter, PlonkPolynomials}; +use crate::plonk_common::PlonkPolynomials; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, FriProofTarget, Hash, OpeningSet}; use crate::timed; From 9db7dce738ded406ba23d99356c3a70be4e67bd9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 17 Jun 2021 22:06:53 +0200 Subject: [PATCH 09/26] scale -> reduce --- src/fri/verifier.rs | 18 +++++++++--------- src/polynomial/commitment.rs | 20 ++++++++++---------- src/util/scaling.rs | 8 ++++---- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index b94807f1..e2c8568f 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -9,7 +9,7 @@ use crate::merkle_proofs::verify_merkle_proof; use crate::plonk_challenger::Challenger; use crate::plonk_common::PlonkPolynomials; use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet}; -use crate::util::scaling::ScalingFactor; +use crate::util::scaling::ReducingFactor; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; /// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity @@ -152,7 +152,7 @@ fn fri_combine_initial, const D: usize>( 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 = ScalingFactor::new(alpha); + let mut alpha = ReducingFactor::new(alpha); let mut sum = F::Extension::ZERO; // We will add three terms to `sum`: @@ -180,7 +180,7 @@ fn fri_combine_initial, const D: usize>( .into_iter() .zip(single_openings) .map(|(e, &o)| e - o); - let single_numerator = alpha.scale(single_diffs); + let single_numerator = alpha.reduce(single_diffs); let single_denominator = subgroup_x - zeta; sum += single_numerator / single_denominator; alpha.reset(); @@ -190,11 +190,11 @@ fn fri_combine_initial, const D: usize>( .unsalted_evals(PlonkPolynomials::ZS) .iter() .map(|&e| F::Extension::from_basefield(e)); - let zs_composition_eval = alpha.clone().scale(zs_evals); + let zs_composition_eval = alpha.clone().reduce(zs_evals); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; let zs_interpol = interpolant(&[ - (zeta, alpha.clone().scale(os.plonk_zs.iter())), - (zeta_right, alpha.scale(os.plonk_zs_right.iter())), + (zeta, alpha.clone().reduce(os.plonk_zs.iter())), + (zeta_right, alpha.reduce(os.plonk_zs_right.iter())), ]); let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x); let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); @@ -206,16 +206,16 @@ fn fri_combine_initial, const D: usize>( .unsalted_evals(PlonkPolynomials::WIRES) .iter() .map(|&e| F::Extension::from_basefield(e)); - let wire_composition_eval = alpha.clone().scale(wire_evals); + let wire_composition_eval = alpha.clone().reduce(wire_evals); let zeta_frob = zeta.frobenius(); - let wire_eval = alpha.clone().scale(os.wires.iter()); + let wire_eval = alpha.clone().reduce(os.wires.iter()); // We want to compute `sum a^i*phi(w_i)`, where `phi` denotes the Frobenius automorphism. // Since `phi^D=id` and `phi` is a field automorphism, we have the following equalities: // `sum a^i*phi(w_i) = sum phi(phi^(D-1)(a^i)*w_i) = phi(sum phi^(D-1)(a)^i*w_i)` // So we can compute the original sum using only one call to the `D-1`-repeated Frobenius of alpha, // and one call at the end of the sum. let mut alpha_frob = alpha.repeated_frobenius(D - 1); - let wire_eval_frob = alpha_frob.scale(os.wires.iter()).frobenius(); + let wire_eval_frob = alpha_frob.reduce(os.wires.iter()).frobenius(); let wire_interpol = interpolant(&[(zeta, wire_eval), (zeta_frob, wire_eval_frob)]); let wire_numerator = wire_composition_eval - wire_interpol.eval(subgroup_x); let wire_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index c09e1e20..9d07975e 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -12,7 +12,7 @@ use crate::plonk_common::PlonkPolynomials; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, FriProofTarget, Hash, OpeningSet}; use crate::timed; -use crate::util::scaling::ScalingFactor; +use crate::util::scaling::ReducingFactor; use crate::util::{log2_strict, reverse_index_bits_in_place, transpose}; pub const SALT_SIZE: usize = 2; @@ -111,7 +111,7 @@ impl ListPolynomialCommitment { challenger.observe_opening_set(&os); let alpha = challenger.get_extension_challenge(); - let mut alpha = ScalingFactor::new(alpha); + let mut alpha = ReducingFactor::new(alpha); // Final low-degree polynomial that goes into FRI. let mut final_poly = PolynomialCoeffs::empty(); @@ -127,8 +127,8 @@ impl ListPolynomialCommitment { .map(|p| p.to_extension()); let single_os = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys]; let single_evals = single_os.iter().flat_map(|v| v.iter()); - let single_composition_poly = alpha.clone().scale_polys(single_polys); - let single_composition_eval = alpha.scale(single_evals); + let single_composition_poly = alpha.clone().reduce_polys(single_polys); + let single_composition_eval = alpha.reduce(single_evals); let single_quotient = Self::compute_quotient( &[zeta], @@ -143,10 +143,10 @@ impl ListPolynomialCommitment { .polynomials .iter() .map(|p| p.to_extension()); - let zs_composition_poly = alpha.clone().scale_polys(zs_polys); + let zs_composition_poly = alpha.clone().reduce_polys(zs_polys); let zs_composition_evals = [ - alpha.clone().scale(os.plonk_zs.iter()), - alpha.scale(os.plonk_zs_right.iter()), + alpha.clone().reduce(os.plonk_zs.iter()), + alpha.reduce(os.plonk_zs_right.iter()), ]; let zs_quotient = Self::compute_quotient( @@ -164,11 +164,11 @@ impl ListPolynomialCommitment { .polynomials .iter() .map(|p| p.to_extension()); - let wire_composition_poly = alpha.clone().scale_polys(wire_polys); + let wire_composition_poly = alpha.clone().reduce_polys(wire_polys); let mut alpha_frob = alpha.repeated_frobenius(D - 1); let wire_composition_evals = [ - alpha.clone().scale(os.wires.iter()), - alpha_frob.scale(os.wires.iter()).frobenius(), + alpha.clone().reduce(os.wires.iter()), + alpha_frob.reduce(os.wires.iter()).frobenius(), ]; let wires_quotient = Self::compute_quotient( diff --git a/src/util/scaling.rs b/src/util/scaling.rs index e29edf0e..7155cb37 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -5,12 +5,12 @@ use crate::field::field::Field; use crate::polynomial::polynomial::PolynomialCoeffs; #[derive(Debug, Copy, Clone)] -pub struct ScalingFactor { +pub struct ReducingFactor { base: F, count: u64, } -impl ScalingFactor { +impl ReducingFactor { pub fn new(base: F) -> Self { Self { base, count: 0 } } @@ -25,12 +25,12 @@ impl ScalingFactor { &p * self.base } - pub fn scale(&mut self, iter: impl DoubleEndedIterator>) -> F { + pub fn reduce(&mut self, iter: impl DoubleEndedIterator>) -> F { iter.rev() .fold(F::ZERO, |acc, x| self.mul(acc) + *x.borrow()) } - pub fn scale_polys( + pub fn reduce_polys( &mut self, polys: impl DoubleEndedIterator>>, ) -> PolynomialCoeffs { From 4f8ef2e17820ca5a1ce75c505fcf3e7859ee33e5 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 18 Jun 2021 11:10:33 +0200 Subject: [PATCH 10/26] Optimize some polynomial operations --- src/field/lagrange.rs | 41 ++++++++++++++++++- src/polynomial/commitment.rs | 77 +++++++++++++++++++----------------- src/polynomial/division.rs | 67 ++++++++++++++++++++++++++++++- src/polynomial/polynomial.rs | 22 ++++++++++- 4 files changed, 168 insertions(+), 39 deletions(-) diff --git a/src/field/lagrange.rs b/src/field/lagrange.rs index 8911feb0..97d6fb27 100644 --- a/src/field/lagrange.rs +++ b/src/field/lagrange.rs @@ -65,11 +65,35 @@ pub fn barycentric_weights(points: &[(F, F)]) -> Vec { ) } +/// Interpolate the linear polynomial passing through `points` on `x`. +pub fn interpolate2(points: [(F, F); 2], x: F) -> F { + // a0 -> a1 + // b0 -> b1 + // x -> a1 + (x-a0)*(b1-a1)/(b0-a0) + let (a0, a1) = points[0]; + let (b0, b1) = points[1]; + assert_ne!(a0, b0); + a1 + (x - a0) * (b1 - a1) / (b0 - a0) +} + +/// Returns the linear polynomial passing through `points`. +pub fn interpolant2(points: [(F, F); 2]) -> PolynomialCoeffs { + // a0 -> a1 + // b0 -> b1 + // x -> a1 + (x-a0)*(b1-a1)/(b0-a0) + let (a0, a1) = points[0]; + let (b0, b1) = points[1]; + assert_ne!(a0, b0); + let mult = (b1 - a1) / (b0 - a0); + vec![a1 - a0 * mult, mult].into() +} + #[cfg(test)] mod tests { + use super::*; use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; - use crate::field::lagrange::interpolant; use crate::polynomial::polynomial::PolynomialCoeffs; #[test] @@ -120,4 +144,19 @@ mod tests { fn eval_naive(coeffs: &PolynomialCoeffs, domain: &[F]) -> Vec<(F, F)> { domain.iter().map(|&x| (x, coeffs.eval(x))).collect() } + + #[test] + fn test_interpolant2() { + type F = QuarticCrandallField; + let points = [(F::rand(), F::rand()), (F::rand(), F::rand())]; + let x = F::rand(); + + let intepol0 = interpolant(&points); + let intepol1 = interpolant2(points); + assert_eq!(intepol0.trimmed(), intepol1.trimmed()); + + let ev0 = interpolate(&points, x, &barycentric_weights(&points)); + let ev1 = interpolate2(points, x); + assert_eq!(ev0, ev1); + } } diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index caa61553..45251e77 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,7 +4,7 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::interpolant; +use crate::field::lagrange::{interpolant, interpolant2}; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; @@ -122,15 +122,10 @@ impl ListPolynomialCommitment { .map(|p| p.to_extension()); let single_os = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys]; let single_evals = single_os.iter().flat_map(|v| v.iter()); - let single_composition_poly = reduce_polys_with_iter(single_polys, alpha_powers.clone()); - let single_composition_eval = reduce_with_iter(single_evals, &mut alpha_powers); + let single_composition_poly = reduce_polys_with_iter(single_polys, &mut alpha_powers); - let single_quotient = Self::compute_quotient( - &[zeta], - &[single_composition_eval], - &single_composition_poly, - ); - final_poly = &final_poly + &single_quotient; + let single_quotient = Self::compute_quotient1(zeta, single_composition_poly); + final_poly += single_quotient; // Zs polynomials are opened at `zeta` and `g*zeta`. let zs_polys = commitments[3].polynomials.iter().map(|p| p.to_extension()); @@ -140,12 +135,9 @@ impl ListPolynomialCommitment { reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), ]; - let zs_quotient = Self::compute_quotient( - &[zeta, g * zeta], - &zs_composition_evals, - &zs_composition_poly, - ); - final_poly = &final_poly + &zs_quotient; + let zs_quotient = + Self::compute_quotient2([zeta, g * zeta], zs_composition_evals, zs_composition_poly); + final_poly += zs_quotient; // 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 @@ -158,12 +150,12 @@ impl ListPolynomialCommitment { reduce_with_iter(&wire_evals_frob, alpha_powers), ]; - let wires_quotient = Self::compute_quotient( - &[zeta, zeta.frobenius()], - &wire_composition_evals, - &wire_composition_poly, + let wires_quotient = Self::compute_quotient2( + [zeta, zeta.frobenius()], + wire_composition_evals, + wire_composition_poly, ); - final_poly = &final_poly + &wires_quotient; + final_poly += wires_quotient; let lde_final_poly = final_poly.lde(config.rate_bits); let lde_final_values = lde_final_poly @@ -192,28 +184,41 @@ impl ListPolynomialCommitment { ) } - /// 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( - points: &[F::Extension], - evals: &[F::Extension], - poly: &PolynomialCoeffs, + /// Given `x` and `poly=P(X)`, computes the polynomial `Q=(P-P(x))/(X-x)`. + fn compute_quotient1( + point: F::Extension, + poly: PolynomialCoeffs, ) -> PolynomialCoeffs where F: Extendable, { - let pairs = points - .iter() - .zip(evals) - .map(|(&x, &e)| (x, e)) - .collect::>(); + let (quotient, _ev) = poly.divide_by_linear(point); + quotient.padded(quotient.degree_plus_one().next_power_of_two()) + } + + /// 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_quotient2( + points: [F::Extension; 2], + evals: [F::Extension; 2], + poly: PolynomialCoeffs, + ) -> PolynomialCoeffs + where + F: Extendable, + { + let pairs = [(points[0], evals[0]), (points[1], evals[1])]; debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e)); - let interpolant = interpolant(&pairs); - let denominator = points.iter().fold(PolynomialCoeffs::one(), |acc, &x| { - &acc * &PolynomialCoeffs::new(vec![-x, F::Extension::ONE]) - }); - let numerator = poly - &interpolant; + let interpolant = interpolant2(pairs); + let denominator = vec![ + points[0] * points[1], + -points[0] - points[1], + F::Extension::ONE, + ] + .into(); + + let mut numerator = poly; + numerator -= interpolant; let (quotient, rem) = numerator.div_rem(&denominator); debug_assert!(rem.is_zero()); diff --git a/src/polynomial/division.rs b/src/polynomial/division.rs index b74fd00f..db1606af 100644 --- a/src/polynomial/division.rs +++ b/src/polynomial/division.rs @@ -125,8 +125,25 @@ impl PolynomialCoeffs { p } + /// Let `self=p(X)`, this returns `(p(X)-p(z))/(X-z)` and `p(z)`. + /// See https://en.wikipedia.org/wiki/Horner%27s_method + pub(crate) fn divide_by_linear(&self, z: F) -> (PolynomialCoeffs, F) { + let mut bs = self + .coeffs + .iter() + .rev() + .scan(F::ZERO, |acc, &c| { + *acc = *acc * z + c; + Some(*acc) + }) + .collect::>(); + let ev = bs.pop().unwrap_or(F::ZERO); + bs.reverse(); + (Self { coeffs: bs }, ev) + } + /// Computes the inverse of `self` modulo `x^n`. - pub(crate) fn inv_mod_xn(&self, n: usize) -> Self { + pub fn inv_mod_xn(&self, n: usize) -> Self { assert!(self.coeffs[0].is_nonzero(), "Inverse doesn't exist."); let h = if self.len() < n { @@ -166,7 +183,10 @@ impl PolynomialCoeffs { #[cfg(test)] mod tests { + use std::time::Instant; + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; use crate::polynomial::polynomial::PolynomialCoeffs; @@ -199,4 +219,49 @@ mod tests { let computed_q = a.divide_by_z_h(4); assert_eq!(computed_q, q); } + + #[test] + #[ignore] + fn test_division_by_linear() { + type F = QuarticCrandallField; + let n = 1_000_000; + let poly = PolynomialCoeffs::new(F::rand_vec(n)); + let z = F::rand(); + let ev = poly.eval(z); + + let timer = Instant::now(); + let (quotient, ev2) = poly.div_rem(&PolynomialCoeffs::new(vec![-z, F::ONE])); + println!("{:.3}s for usual", timer.elapsed().as_secs_f32()); + assert_eq!(ev2.trimmed().coeffs, vec![ev]); + + let timer = Instant::now(); + let (quotient, ev3) = poly.div_rem_long_division(&PolynomialCoeffs::new(vec![-z, F::ONE])); + println!("{:.3}s for long division", timer.elapsed().as_secs_f32()); + assert_eq!(ev3.trimmed().coeffs, vec![ev]); + + let timer = Instant::now(); + let horn = poly.divide_by_linear(z); + println!("{:.3}s for Horner", timer.elapsed().as_secs_f32()); + assert_eq!((quotient, ev), horn); + } + + #[test] + #[ignore] + fn test_division_by_quadratic() { + type F = QuarticCrandallField; + let n = 1_000_000; + let poly = PolynomialCoeffs::new(F::rand_vec(n)); + let quad = PolynomialCoeffs::new(F::rand_vec(2)); + + let timer = Instant::now(); + let (quotient0, rem0) = poly.div_rem(&quad); + println!("{:.3}s for usual", timer.elapsed().as_secs_f32()); + + let timer = Instant::now(); + let (quotient1, rem1) = poly.div_rem_long_division(&quad); + println!("{:.3}s for long division", timer.elapsed().as_secs_f32()); + + assert_eq!(quotient0.trimmed(), quotient1.trimmed()); + assert_eq!(rem0.trimmed(), rem1.trimmed()); + } } diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index 9f605051..aefcc0c6 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -1,6 +1,6 @@ use std::cmp::max; use std::iter::Sum; -use std::ops::{Add, Mul, Sub}; +use std::ops::{Add, AddAssign, Mul, Sub, SubAssign}; use crate::field::extension_field::Extendable; use crate::field::fft::{fft, ifft}; @@ -243,6 +243,26 @@ impl Sub for &PolynomialCoeffs { } } +impl AddAssign for PolynomialCoeffs { + fn add_assign(&mut self, rhs: Self) { + let len = max(self.len(), rhs.len()); + self.coeffs.resize(len, F::ZERO); + for (l, r) in self.coeffs.iter_mut().zip(rhs.coeffs) { + *l += r; + } + } +} + +impl SubAssign for PolynomialCoeffs { + fn sub_assign(&mut self, rhs: Self) { + let len = max(self.len(), rhs.len()); + self.coeffs.resize(len, F::ZERO); + for (l, r) in self.coeffs.iter_mut().zip(rhs.coeffs) { + *l -= r; + } + } +} + impl Mul for &PolynomialCoeffs { type Output = PolynomialCoeffs; From 5a8d951590072207c8fc5420ab4232a03a416558 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 18 Jun 2021 11:16:22 +0200 Subject: [PATCH 11/26] Use `interpolate2` in the FRI verifier --- src/fri/verifier.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index d100797e..486e7174 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -2,7 +2,7 @@ use anyhow::{ensure, Result}; use crate::field::extension_field::{flatten, Extendable, FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::{barycentric_weights, interpolant, interpolate}; +use crate::field::lagrange::{barycentric_weights, interpolant, interpolate, interpolate2}; use crate::fri::FriConfig; use crate::hash::hash_n_to_1; use crate::merkle_proofs::verify_merkle_proof; @@ -185,14 +185,17 @@ fn fri_combine_initial, const D: usize>( .map(|&e| F::Extension::from_basefield(e)); let zs_composition_eval = reduce_with_iter(zs_evals, alpha_powers.clone()); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; - let zs_interpol = interpolant(&[ - (zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())), - ( - zeta_right, - reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), - ), - ]); - let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x); + let zs_interpol = interpolate2( + [ + (zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())), + ( + zeta_right, + reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), + ), + ], + subgroup_x, + ); + let zs_numerator = zs_composition_eval - zs_interpol; let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); sum += zs_numerator / zs_denominator; @@ -211,8 +214,8 @@ fn fri_combine_initial, const D: usize>( // and one call at the end of the sum. let alpha_powers_frob = alpha_powers.repeated_frobenius(D - 1); let wire_eval_frob = reduce_with_iter(&os.wires, alpha_powers_frob).frobenius(); - let wire_interpol = interpolant(&[(zeta, wire_eval), (zeta_frob, wire_eval_frob)]); - let wire_numerator = wire_composition_eval - wire_interpol.eval(subgroup_x); + let wire_interpol = interpolate2([(zeta, wire_eval), (zeta_frob, wire_eval_frob)], subgroup_x); + let wire_numerator = wire_composition_eval - wire_interpol; let wire_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); sum += wire_numerator / wire_denominator; From 621c046fe43d23c2f02d10636b8327718d11145d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 18 Jun 2021 11:17:15 +0200 Subject: [PATCH 12/26] Use long division when dividing by quadratic polynomial --- src/polynomial/commitment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 45251e77..1b7d611b 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -219,7 +219,7 @@ impl ListPolynomialCommitment { let mut numerator = poly; numerator -= interpolant; - let (quotient, rem) = numerator.div_rem(&denominator); + let (quotient, rem) = numerator.div_rem_long_division(&denominator); debug_assert!(rem.is_zero()); quotient.padded(quotient.degree_plus_one().next_power_of_two()) From 7d4e79f069aa5e043042b1f73bfb6f8d3717867d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 18 Jun 2021 11:22:38 +0200 Subject: [PATCH 13/26] Clippy --- src/fri/verifier.rs | 2 +- src/polynomial/commitment.rs | 4 +--- src/polynomial/division.rs | 7 +++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 486e7174..6320505e 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -2,7 +2,7 @@ use anyhow::{ensure, Result}; use crate::field::extension_field::{flatten, Extendable, FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::{barycentric_weights, interpolant, interpolate, interpolate2}; +use crate::field::lagrange::{barycentric_weights, interpolate, interpolate2}; use crate::fri::FriConfig; use crate::hash::hash_n_to_1; use crate::merkle_proofs::verify_merkle_proof; diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 1b7d611b..ce978d96 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,7 +4,7 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::{interpolant, interpolant2}; +use crate::field::lagrange::interpolant2; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; @@ -120,8 +120,6 @@ impl ListPolynomialCommitment { .iter() .flat_map(|&i| &commitments[i].polynomials) .map(|p| p.to_extension()); - let single_os = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys]; - let single_evals = single_os.iter().flat_map(|v| v.iter()); let single_composition_poly = reduce_polys_with_iter(single_polys, &mut alpha_powers); let single_quotient = Self::compute_quotient1(zeta, single_composition_poly); diff --git a/src/polynomial/division.rs b/src/polynomial/division.rs index db1606af..50e1f8a6 100644 --- a/src/polynomial/division.rs +++ b/src/polynomial/division.rs @@ -26,7 +26,7 @@ impl PolynomialCoeffs { .to_vec() .into(); let mut q = rev_q.rev(); - let mut qb = &q * b; + let qb = &q * b; let mut r = self - &qb; q.trim(); r.trim(); @@ -59,8 +59,7 @@ impl PolynomialCoeffs { quotient.coeffs[cur_q_degree] = cur_q_coeff; for (i, &div_coeff) in b.coeffs.iter().enumerate() { - remainder.coeffs[cur_q_degree + i] = - remainder.coeffs[cur_q_degree + i] - (cur_q_coeff * div_coeff); + remainder.coeffs[cur_q_degree + i] -= cur_q_coeff * div_coeff; } remainder.trim(); } @@ -97,7 +96,7 @@ impl PolynomialCoeffs { let denominators = (0..a_eval.len()) .map(|i| { if i != 0 { - root_pow = root_pow * root_n; + root_pow *= root_n; } denominator_g * root_pow - F::ONE }) From a4c86a6b081dfb540579fa16217d78d9d16e6448 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 18 Jun 2021 11:44:06 +0200 Subject: [PATCH 14/26] `lagrange.rs` -> `interpolation.rs` --- src/field/{lagrange.rs => interpolation.rs} | 0 src/field/mod.rs | 2 +- src/fri/verifier.rs | 2 +- src/gadgets/interpolation.rs | 8 +++++--- src/gates/interpolation.rs | 2 +- src/polynomial/commitment.rs | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) rename src/field/{lagrange.rs => interpolation.rs} (100%) diff --git a/src/field/lagrange.rs b/src/field/interpolation.rs similarity index 100% rename from src/field/lagrange.rs rename to src/field/interpolation.rs diff --git a/src/field/mod.rs b/src/field/mod.rs index 179fb10d..15efe280 100644 --- a/src/field/mod.rs +++ b/src/field/mod.rs @@ -3,7 +3,7 @@ pub mod crandall_field; pub mod extension_field; pub mod fft; pub mod field; -pub(crate) mod lagrange; +pub(crate) mod interpolation; #[cfg(test)] mod field_testing; diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 6320505e..4c8f4d8c 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -2,7 +2,7 @@ use anyhow::{ensure, Result}; use crate::field::extension_field::{flatten, Extendable, FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::{barycentric_weights, interpolate, interpolate2}; +use crate::field::interpolation::{barycentric_weights, interpolate, interpolate2}; use crate::fri::FriConfig; use crate::hash::hash_n_to_1; use crate::merkle_proofs::verify_merkle_proof; diff --git a/src/gadgets/interpolation.rs b/src/gadgets/interpolation.rs index a94eb582..40b91c1e 100644 --- a/src/gadgets/interpolation.rs +++ b/src/gadgets/interpolation.rs @@ -1,9 +1,10 @@ +use std::marker::PhantomData; + use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::gates::interpolation::InterpolationGate; use crate::target::Target; -use std::marker::PhantomData; impl, const D: usize> CircuitBuilder { /// Interpolate two points. No need for an `InterpolationGate` since the coefficients @@ -56,15 +57,16 @@ impl, const D: usize> CircuitBuilder { #[cfg(test)] mod tests { + use std::convert::TryInto; + use super::*; use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::FieldExtension; use crate::field::field::Field; - use crate::field::lagrange::{interpolant, interpolate}; + use crate::field::interpolation::{interpolant, interpolate}; use crate::witness::PartialWitness; - use std::convert::TryInto; #[test] fn test_interpolate() { diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index ac2ca49f..ccf8d57d 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -6,7 +6,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::algebra::PolynomialCoeffsAlgebra; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; -use crate::field::lagrange::interpolant; +use crate::field::interpolation::interpolant; use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{SimpleGenerator, WitnessGenerator}; diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index ce978d96..c67bed2f 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,7 +4,7 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::interpolant2; +use crate::field::interpolation::interpolant2; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; From 37171505c74a8db76991ead8fef7a7650bc0bd15 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 18 Jun 2021 12:49:40 +0200 Subject: [PATCH 15/26] Remove useless interpolation from `open_plonk` --- src/field/interpolation.rs | 23 +++--------- src/polynomial/commitment.rs | 73 +++++++++++------------------------- 2 files changed, 27 insertions(+), 69 deletions(-) diff --git a/src/field/interpolation.rs b/src/field/interpolation.rs index 97d6fb27..968eeca2 100644 --- a/src/field/interpolation.rs +++ b/src/field/interpolation.rs @@ -76,18 +76,6 @@ pub fn interpolate2(points: [(F, F); 2], x: F) -> F { a1 + (x - a0) * (b1 - a1) / (b0 - a0) } -/// Returns the linear polynomial passing through `points`. -pub fn interpolant2(points: [(F, F); 2]) -> PolynomialCoeffs { - // a0 -> a1 - // b0 -> b1 - // x -> a1 + (x-a0)*(b1-a1)/(b0-a0) - let (a0, a1) = points[0]; - let (b0, b1) = points[1]; - assert_ne!(a0, b0); - let mult = (b1 - a1) / (b0 - a0); - vec![a1 - a0 * mult, mult].into() -} - #[cfg(test)] mod tests { use super::*; @@ -146,17 +134,16 @@ mod tests { } #[test] - fn test_interpolant2() { + fn test_interpolate2() { type F = QuarticCrandallField; let points = [(F::rand(), F::rand()), (F::rand(), F::rand())]; let x = F::rand(); - let intepol0 = interpolant(&points); - let intepol1 = interpolant2(points); - assert_eq!(intepol0.trimmed(), intepol1.trimmed()); + let ev0 = interpolant(&points).eval(x); + let ev1 = interpolate(&points, x, &barycentric_weights(&points)); + let ev2 = interpolate2(points, x); - let ev0 = interpolate(&points, x, &barycentric_weights(&points)); - let ev1 = interpolate2(points, x); assert_eq!(ev0, ev1); + assert_eq!(ev0, ev2); } } diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index c67bed2f..1e4ba1b4 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,11 +4,10 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::interpolation::interpolant2; 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_iter, reduce_with_iter}; +use crate::plonk_common::reduce_polys_with_iter; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, FriProofTarget, Hash, OpeningSet}; use crate::timed; @@ -122,37 +121,24 @@ impl ListPolynomialCommitment { .map(|p| p.to_extension()); let single_composition_poly = reduce_polys_with_iter(single_polys, &mut alpha_powers); - let single_quotient = Self::compute_quotient1(zeta, single_composition_poly); + let single_quotient = Self::compute_quotient([zeta], single_composition_poly); final_poly += single_quotient; // Zs polynomials are opened at `zeta` and `g*zeta`. let zs_polys = commitments[3].polynomials.iter().map(|p| p.to_extension()); - let zs_composition_poly = reduce_polys_with_iter(zs_polys, alpha_powers.clone()); - let zs_composition_evals = [ - reduce_with_iter(&os.plonk_zs, alpha_powers.clone()), - reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), - ]; + let zs_composition_poly = reduce_polys_with_iter(zs_polys, &mut alpha_powers); - let zs_quotient = - Self::compute_quotient2([zeta, g * zeta], zs_composition_evals, zs_composition_poly); + let zs_quotient = Self::compute_quotient([zeta, g * zeta], zs_composition_poly); final_poly += zs_quotient; // 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. let wire_polys = commitments[2].polynomials.iter().map(|p| p.to_extension()); - let wire_composition_poly = reduce_polys_with_iter(wire_polys, alpha_powers.clone()); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); - let wire_composition_evals = [ - reduce_with_iter(&os.wires, alpha_powers.clone()), - reduce_with_iter(&wire_evals_frob, alpha_powers), - ]; + let wire_composition_poly = reduce_polys_with_iter(wire_polys, &mut alpha_powers); - let wires_quotient = Self::compute_quotient2( - [zeta, zeta.frobenius()], - wire_composition_evals, - wire_composition_poly, - ); + let wires_quotient = + Self::compute_quotient([zeta, zeta.frobenius()], wire_composition_poly); final_poly += wires_quotient; let lde_final_poly = final_poly.lde(config.rate_bits); @@ -182,43 +168,28 @@ impl ListPolynomialCommitment { ) } - /// Given `x` and `poly=P(X)`, computes the polynomial `Q=(P-P(x))/(X-x)`. - fn compute_quotient1( - point: F::Extension, - poly: PolynomialCoeffs, - ) -> PolynomialCoeffs - where - F: Extendable, - { - let (quotient, _ev) = poly.divide_by_linear(point); - quotient.padded(quotient.degree_plus_one().next_power_of_two()) - } - /// 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_quotient2( - points: [F::Extension; 2], - evals: [F::Extension; 2], + fn compute_quotient( + points: [F::Extension; N], poly: PolynomialCoeffs, ) -> PolynomialCoeffs where F: Extendable, { - let pairs = [(points[0], evals[0]), (points[1], evals[1])]; - debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e)); - - let interpolant = interpolant2(pairs); - let denominator = vec![ - points[0] * points[1], - -points[0] - points[1], - F::Extension::ONE, - ] - .into(); - - let mut numerator = poly; - numerator -= interpolant; - let (quotient, rem) = numerator.div_rem_long_division(&denominator); - debug_assert!(rem.is_zero()); + let quotient = if N == 1 { + poly.divide_by_linear(points[0]).0 + } else if N == 2 { + let denominator = vec![ + points[0] * points[1], + -points[0] - points[1], + F::Extension::ONE, + ] + .into(); + poly.div_rem_long_division(&denominator).0 // Could also use `divide_by_linear` twice. + } else { + unreachable!("This shouldn't happen. Plonk should open polynomials at 1 or 2 points.") + }; quotient.padded(quotient.degree_plus_one().next_power_of_two()) } From 15922d25189ff6af519a24777b8457bb68275d36 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 21 Jun 2021 10:32:32 +0200 Subject: [PATCH 16/26] Add comment for denominator polynomial --- src/polynomial/commitment.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 1e4ba1b4..bc17f3f3 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -180,6 +180,7 @@ impl ListPolynomialCommitment { let quotient = if N == 1 { poly.divide_by_linear(points[0]).0 } else if N == 2 { + // The denominator is `(X - p0)(X - p1) = p0 p1 - (p0 + p1) X + X^2`. let denominator = vec![ points[0] * points[1], -points[0] - points[1], From 01053ab96ae09293bc9b0a024d59181550727f88 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 11:30:57 +0200 Subject: [PATCH 17/26] Fix bug --- src/fri/verifier.rs | 25 ++++++----- src/polynomial/commitment.rs | 82 +++++++++++++----------------------- 2 files changed, 43 insertions(+), 64 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index e2c8568f..0e7c7c4d 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -2,7 +2,7 @@ use anyhow::{ensure, Result}; use crate::field::extension_field::{flatten, Extendable, FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::{barycentric_weights, interpolant, interpolate}; +use crate::field::interpolation::{barycentric_weights, interpolate, interpolate2}; use crate::fri::FriConfig; use crate::hash::hash_n_to_1; use crate::merkle_proofs::verify_merkle_proof; @@ -192,11 +192,14 @@ fn fri_combine_initial, const D: usize>( .map(|&e| F::Extension::from_basefield(e)); let zs_composition_eval = alpha.clone().reduce(zs_evals); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; - let zs_interpol = interpolant(&[ - (zeta, alpha.clone().reduce(os.plonk_zs.iter())), - (zeta_right, alpha.reduce(os.plonk_zs_right.iter())), - ]); - let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x); + let zs_interpol = interpolate2( + [ + (zeta, alpha.clone().reduce(os.plonk_zs.iter())), + (zeta_right, alpha.reduce(os.plonk_zs_right.iter())), + ], + subgroup_x, + ); + let zs_numerator = zs_composition_eval - zs_interpol; let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); sum = alpha.shift(sum); sum += zs_numerator / zs_denominator; @@ -208,18 +211,18 @@ fn fri_combine_initial, const D: usize>( .map(|&e| F::Extension::from_basefield(e)); let wire_composition_eval = alpha.clone().reduce(wire_evals); let zeta_frob = zeta.frobenius(); - let wire_eval = alpha.clone().reduce(os.wires.iter()); + let mut alpha_frob = alpha.repeated_frobenius(D - 1); + let wire_eval = alpha.reduce(os.wires.iter()); // We want to compute `sum a^i*phi(w_i)`, where `phi` denotes the Frobenius automorphism. // Since `phi^D=id` and `phi` is a field automorphism, we have the following equalities: // `sum a^i*phi(w_i) = sum phi(phi^(D-1)(a^i)*w_i) = phi(sum phi^(D-1)(a)^i*w_i)` // So we can compute the original sum using only one call to the `D-1`-repeated Frobenius of alpha, // and one call at the end of the sum. - let mut alpha_frob = alpha.repeated_frobenius(D - 1); let wire_eval_frob = alpha_frob.reduce(os.wires.iter()).frobenius(); - let wire_interpol = interpolant(&[(zeta, wire_eval), (zeta_frob, wire_eval_frob)]); - let wire_numerator = wire_composition_eval - wire_interpol.eval(subgroup_x); + let wire_interpol = interpolate2([(zeta, wire_eval), (zeta_frob, wire_eval_frob)], subgroup_x); + let wire_numerator = wire_composition_eval - wire_interpol; let wire_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); - sum = alpha_frob.shift(sum); + sum = alpha.shift(sum); sum += wire_numerator / wire_denominator; sum diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 9d07975e..df92a31b 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,7 +4,7 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::lagrange::interpolant; +use crate::field::interpolation::interpolate2; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; @@ -125,17 +125,10 @@ impl ListPolynomialCommitment { .iter() .flat_map(|&p| &commitments[p.index].polynomials) .map(|p| p.to_extension()); - let single_os = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys]; - let single_evals = single_os.iter().flat_map(|v| v.iter()); - let single_composition_poly = alpha.clone().reduce_polys(single_polys); - let single_composition_eval = alpha.reduce(single_evals); + let single_composition_poly = alpha.reduce_polys(single_polys); - let single_quotient = Self::compute_quotient( - &[zeta], - &[single_composition_eval], - &single_composition_poly, - ); - final_poly = &final_poly + &single_quotient; + let single_quotient = Self::compute_quotient([zeta], single_composition_poly); + final_poly += single_quotient; alpha.reset(); // Zs polynomials are opened at `zeta` and `g*zeta`. @@ -143,19 +136,11 @@ impl ListPolynomialCommitment { .polynomials .iter() .map(|p| p.to_extension()); - let zs_composition_poly = alpha.clone().reduce_polys(zs_polys); - let zs_composition_evals = [ - alpha.clone().reduce(os.plonk_zs.iter()), - alpha.reduce(os.plonk_zs_right.iter()), - ]; + let zs_composition_poly = alpha.reduce_polys(zs_polys); - let zs_quotient = Self::compute_quotient( - &[zeta, g * zeta], - &zs_composition_evals, - &zs_composition_poly, - ); + let zs_quotient = Self::compute_quotient([zeta, g * zeta], zs_composition_poly); final_poly = alpha.shift_poly(final_poly); - final_poly = &final_poly + &zs_quotient; + final_poly += zs_quotient; // 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 @@ -164,20 +149,12 @@ impl ListPolynomialCommitment { .polynomials .iter() .map(|p| p.to_extension()); - let wire_composition_poly = alpha.clone().reduce_polys(wire_polys); - let mut alpha_frob = alpha.repeated_frobenius(D - 1); - let wire_composition_evals = [ - alpha.clone().reduce(os.wires.iter()), - alpha_frob.reduce(os.wires.iter()).frobenius(), - ]; + let wire_composition_poly = alpha.reduce_polys(wire_polys); - let wires_quotient = Self::compute_quotient( - &[zeta, zeta.frobenius()], - &wire_composition_evals, - &wire_composition_poly, - ); - final_poly = alpha_frob.shift_poly(final_poly); - final_poly = &final_poly + &wires_quotient; + let wires_quotient = + Self::compute_quotient([zeta, zeta.frobenius()], wire_composition_poly); + final_poly = alpha.shift_poly(final_poly); + final_poly += wires_quotient; let lde_final_poly = final_poly.lde(config.rate_bits); let lde_final_values = lde_final_poly @@ -208,28 +185,27 @@ impl ListPolynomialCommitment { /// 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( - points: &[F::Extension], - evals: &[F::Extension], - poly: &PolynomialCoeffs, + fn compute_quotient( + points: [F::Extension; N], + poly: PolynomialCoeffs, ) -> PolynomialCoeffs where F: Extendable, { - let pairs = points - .iter() - .zip(evals) - .map(|(&x, &e)| (x, e)) - .collect::>(); - debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e)); - - let interpolant = interpolant(&pairs); - let denominator = points.iter().fold(PolynomialCoeffs::one(), |acc, &x| { - &acc * &PolynomialCoeffs::new(vec![-x, F::Extension::ONE]) - }); - let numerator = poly - &interpolant; - let (quotient, rem) = numerator.div_rem(&denominator); - debug_assert!(rem.is_zero()); + let quotient = if N == 1 { + poly.divide_by_linear(points[0]).0 + } else if N == 2 { + // The denominator is `(X - p0)(X - p1) = p0 p1 - (p0 + p1) X + X^2`. + let denominator = vec![ + points[0] * points[1], + -points[0] - points[1], + F::Extension::ONE, + ] + .into(); + poly.div_rem_long_division(&denominator).0 // Could also use `divide_by_linear` twice. + } else { + unreachable!("This shouldn't happen. Plonk should open polynomials at 1 or 2 points.") + }; quotient.padded(quotient.degree_plus_one().next_power_of_two()) } From 26e669ddeca3a440bbee65f3a85249a1478cd55e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 11:33:50 +0200 Subject: [PATCH 18/26] 2 `collect`s -> 1 `collect` --- src/fri/verifier.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 0e7c7c4d..d88e8e0b 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -168,19 +168,18 @@ fn fri_combine_initial, const D: usize>( ] .iter() .flat_map(|&p| proof.unsalted_evals(p)) - .map(|&e| F::Extension::from_basefield(e)) - .collect::>(); + .map(|&e| F::Extension::from_basefield(e)); let single_openings = os .constants .iter() .chain(&os.plonk_s_sigmas) - .chain(&os.quotient_polys) - .collect::>(); + .chain(&os.quotient_polys); let single_diffs = single_evals .into_iter() .zip(single_openings) - .map(|(e, &o)| e - o); - let single_numerator = alpha.reduce(single_diffs); + .map(|(e, &o)| e - o) + .collect::>(); + let single_numerator = alpha.reduce(single_diffs.iter()); let single_denominator = subgroup_x - zeta; sum += single_numerator / single_denominator; alpha.reset(); From 492b04843e026ed8a8d1bae048ebf50b72431025 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 11:41:32 +0200 Subject: [PATCH 19/26] Optimize some polynomial operations to avoid cloning. --- src/polynomial/commitment.rs | 5 ++--- src/polynomial/polynomial.rs | 28 +++++++++++++++++++++++++++- src/util/scaling.rs | 15 ++++++++------- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index df92a31b..4b2bf872 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,7 +4,6 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; -use crate::field::interpolation::interpolate2; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; @@ -139,7 +138,7 @@ impl ListPolynomialCommitment { let zs_composition_poly = alpha.reduce_polys(zs_polys); let zs_quotient = Self::compute_quotient([zeta, g * zeta], zs_composition_poly); - final_poly = alpha.shift_poly(final_poly); + alpha.shift_poly(&mut final_poly); final_poly += zs_quotient; // When working in an extension field, need to check that wires are in the base field. @@ -153,7 +152,7 @@ impl ListPolynomialCommitment { let wires_quotient = Self::compute_quotient([zeta, zeta.frobenius()], wire_composition_poly); - final_poly = alpha.shift_poly(final_poly); + alpha.shift_poly(&mut final_poly); final_poly += wires_quotient; let lde_final_poly = final_poly.lde(config.rate_bits); diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index aefcc0c6..02f66684 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -1,6 +1,6 @@ use std::cmp::max; use std::iter::Sum; -use std::ops::{Add, AddAssign, Mul, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; use crate::field::extension_field::Extendable; use crate::field::fft::{fft, ifft}; @@ -253,6 +253,16 @@ impl AddAssign for PolynomialCoeffs { } } +impl AddAssign<&Self> for PolynomialCoeffs { + fn add_assign(&mut self, rhs: &Self) { + let len = max(self.len(), rhs.len()); + self.coeffs.resize(len, F::ZERO); + for (l, &r) in self.coeffs.iter_mut().zip(&rhs.coeffs) { + *l += r; + } + } +} + impl SubAssign for PolynomialCoeffs { fn sub_assign(&mut self, rhs: Self) { let len = max(self.len(), rhs.len()); @@ -263,6 +273,16 @@ impl SubAssign for PolynomialCoeffs { } } +impl SubAssign<&Self> for PolynomialCoeffs { + fn sub_assign(&mut self, rhs: &Self) { + let len = max(self.len(), rhs.len()); + self.coeffs.resize(len, F::ZERO); + for (l, &r) in self.coeffs.iter_mut().zip(&rhs.coeffs) { + *l -= r; + } + } +} + impl Mul for &PolynomialCoeffs { type Output = PolynomialCoeffs; @@ -272,6 +292,12 @@ impl Mul for &PolynomialCoeffs { } } +impl MulAssign for PolynomialCoeffs { + fn mul_assign(&mut self, rhs: F) { + self.coeffs.iter_mut().for_each(|x| *x *= rhs); + } +} + impl Mul for &PolynomialCoeffs { type Output = PolynomialCoeffs; diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 7155cb37..25da24c7 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -20,9 +20,9 @@ impl ReducingFactor { self.base * x } - fn mul_poly(&mut self, p: PolynomialCoeffs) -> PolynomialCoeffs { + fn mul_poly(&mut self, p: &mut PolynomialCoeffs) { self.count += 1; - &p * self.base + *p *= self.base; } pub fn reduce(&mut self, iter: impl DoubleEndedIterator>) -> F { @@ -34,8 +34,10 @@ impl ReducingFactor { &mut self, polys: impl DoubleEndedIterator>>, ) -> PolynomialCoeffs { - polys.rev().fold(PolynomialCoeffs::empty(), |acc, x| { - &self.mul_poly(acc) + x.borrow() + polys.rev().fold(PolynomialCoeffs::empty(), |mut acc, x| { + self.mul_poly(&mut acc); + acc += x.borrow(); + acc }) } @@ -45,10 +47,9 @@ impl ReducingFactor { tmp } - pub fn shift_poly(&mut self, p: PolynomialCoeffs) -> PolynomialCoeffs { - let tmp = &p * self.base.exp(self.count); + pub fn shift_poly(&mut self, p: &mut PolynomialCoeffs) { + *p *= self.base.exp(self.count); self.count = 0; - tmp } pub fn reset(&mut self) { From 517c75abe2f442613d6d260ea21b294e8f0d8bcc Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 11:51:16 +0200 Subject: [PATCH 20/26] Add comment for `ReducingFactor` --- src/util/scaling.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 25da24c7..cea86195 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -4,6 +4,13 @@ use crate::field::extension_field::Frobenius; use crate::field::field::Field; use crate::polynomial::polynomial::PolynomialCoeffs; +/// When verifying the composition polynomial in FRI we have to compute sums of the form +/// `(sum_0^k a^i * x_i)/d_0 + (sum_k^r a^i * y_i)/d_1` +/// The most efficient way to do this is to compute both quotient separately using Horner's method, +/// scale the second one by `a^(r-1-k)`, and add them up. +/// This struct abstract away these operations by implementing Horner's method and keeping track +/// of the number of multiplications by `a` to compute the scaling factor. +/// See https://github.com/mir-protocol/plonky2/pull/69 for more details and discussions. #[derive(Debug, Copy, Clone)] pub struct ReducingFactor { base: F, From 3bc27c65ef49a149cdfb4e68dfe7d4dff8d13823 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 13:46:19 +0200 Subject: [PATCH 21/26] Rollback to previous semantics --- src/circuit_builder.rs | 10 +++------- src/circuit_data.rs | 3 --- src/gates/gmimc.rs | 8 +------- src/generator.rs | 10 ++-------- src/permutation_argument.rs | 21 --------------------- src/plonk_challenger.rs | 6 +----- src/prover.rs | 6 +----- src/witness.rs | 4 ---- 8 files changed, 8 insertions(+), 60 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index b9b2e533..8c7d0a72 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -236,7 +236,7 @@ impl, const D: usize> CircuitBuilder { .collect() } - fn sigma_vecs(&self, k_is: &[F]) -> (Vec>, TargetPartitions) { + fn sigma_vecs(&self, k_is: &[F]) -> Vec> { let degree = self.gate_instances.len(); let degree_log = log2_strict(degree); let mut target_partitions = TargetPartitions::new(); @@ -257,10 +257,7 @@ impl, const D: usize> CircuitBuilder { let wire_partitions = target_partitions.to_wire_partitions(); - ( - wire_partitions.get_sigma_polys(degree_log, k_is), - target_partitions, - ) + wire_partitions.get_sigma_polys(degree_log, k_is) } /// Builds a "full circuit", with both prover and verifier data. @@ -282,7 +279,7 @@ impl, const D: usize> CircuitBuilder { ); let k_is = get_unique_coset_shifts(degree, self.config.num_routed_wires); - let (sigma_vecs, targets_partition) = self.sigma_vecs(&k_is); + let sigma_vecs = self.sigma_vecs(&k_is); let sigmas_commitment = ListPolynomialCommitment::new( sigma_vecs.into_iter().map(|v| v.ifft()).collect(), self.config.fri_config.rate_bits, @@ -301,7 +298,6 @@ impl, const D: usize> CircuitBuilder { generators, constants_commitment, sigmas_commitment, - targets_partition, }; // The HashSet of gates will have a non-deterministic order. When converting to a Vec, we diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 6b6d614a..4d9a7110 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -5,7 +5,6 @@ use crate::field::field::Field; use crate::fri::FriConfig; use crate::gates::gate::GateRef; use crate::generator::WitnessGenerator; -use crate::permutation_argument::TargetPartitions; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::proof::{Hash, HashTarget, Proof}; use crate::prover::prove; @@ -105,8 +104,6 @@ pub(crate) struct ProverOnlyCircuitData { pub constants_commitment: ListPolynomialCommitment, /// Commitments to the sigma polynomial. pub sigmas_commitment: ListPolynomialCommitment, - /// Partition of the targets into copy-constrained sets. - pub targets_partition: TargetPartitions, } /// Circuit data required by the verifier, but not the prover. diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index ac5741e4..bdfade7c 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -370,13 +370,7 @@ mod tests { } let generators = gate.0.generators(0, &[]); - let mut tp = TargetPartitions::new(); - for g in 0..10 { - for i in 0..config.num_routed_wires { - tp.add_partition(Target::wire(g, i)); - } - } - generate_partial_witness(&mut witness, &generators, &tp); + generate_partial_witness(&mut witness, &generators); let expected_outputs: [F; W] = gmimc_permute_naive(permutation_inputs.try_into().unwrap(), constants); diff --git a/src/generator.rs b/src/generator.rs index 5b6a258a..db81172f 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -11,7 +11,6 @@ use crate::witness::PartialWitness; pub(crate) fn generate_partial_witness( witness: &mut PartialWitness, generators: &[Box>], - target_partition: &TargetPartitions, ) { // Index generator indices by their watched targets. let mut generator_indices_by_watches = HashMap::new(); @@ -20,12 +19,10 @@ pub(crate) fn generate_partial_witness( generator_indices_by_watches .entry(watch) .or_insert_with(Vec::new) - .push(i) + .push(i); } } - target_partition.generate_copies(witness, &witness.all_populated_targets()); - // Build a list of "pending" generators which are queued to be run. Initially, all generators // are queued. let mut pending_generator_indices: HashSet<_> = (0..generators.len()).collect(); @@ -38,14 +35,11 @@ pub(crate) fn generate_partial_witness( let mut next_pending_generator_indices = HashSet::new(); for &generator_idx in &pending_generator_indices { - let (mut result, finished) = generators[generator_idx].run(&witness); + let (result, finished) = generators[generator_idx].run(&witness); if finished { expired_generator_indices.insert(generator_idx); } - let new_targets = result.all_populated_targets(); - target_partition.generate_copies(&mut result, &new_targets); - // Enqueue unfinished generators that were watching one of the newly populated targets. for watch in result.target_values.keys() { if let Some(watching_generator_indices) = generator_indices_by_watches.get(watch) { diff --git a/src/permutation_argument.rs b/src/permutation_argument.rs index f2739756..62ee63d4 100644 --- a/src/permutation_argument.rs +++ b/src/permutation_argument.rs @@ -6,7 +6,6 @@ use crate::field::field::Field; use crate::polynomial::polynomial::PolynomialValues; use crate::target::Target; use crate::wire::Wire; -use crate::witness::PartialWitness; #[derive(Debug, Clone)] pub struct TargetPartitions { @@ -83,26 +82,6 @@ impl TargetPartitions { indices, } } - /// For the given set of targets, find any copy constraints involving those targets and populate - /// the witness with copies as needed. - pub fn generate_copies(&self, witness: &mut PartialWitness, targets: &[Target]) { - let mut result = PartialWitness::new(); - - for &target in targets { - let value = witness.get_target(target); - let partition = self.get_partition(target); - - for &sibling in partition { - if witness.contains(sibling) { - // This sibling's value was already set; make sure it has the same value. - assert_eq!(witness.get_target(sibling), value); - } else { - result.set_target(sibling, value); - } - } - } - witness.extend(result); - } } pub struct WirePartitions { diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index 30d4cf70..290b5231 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -352,11 +352,7 @@ mod tests { } let circuit = builder.build(); let mut witness = PartialWitness::new(); - generate_partial_witness( - &mut witness, - &circuit.prover_only.generators, - &circuit.prover_only.targets_partition, - ); + generate_partial_witness(&mut witness, &circuit.prover_only.generators); let recursive_output_values_per_round: Vec> = recursive_outputs_per_round .iter() .map(|outputs| witness.get_targets(outputs)) diff --git a/src/prover.rs b/src/prover.rs index fc4e6f38..81b02674 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -34,11 +34,7 @@ pub(crate) fn prove, const D: usize>( let mut witness = inputs; info!("Running {} generators", prover_data.generators.len()); timed!( - generate_partial_witness( - &mut witness, - &prover_data.generators, - &prover_data.targets_partition - ), + generate_partial_witness(&mut witness, &prover_data.generators,), "to generate witness" ); diff --git a/src/witness.rs b/src/witness.rs index e71eebc9..a0b4b2a4 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -59,10 +59,6 @@ impl PartialWitness { targets.iter().all(|&t| self.contains(t)) } - pub fn all_populated_targets(&self) -> Vec { - self.target_values.keys().cloned().collect() - } - pub fn set_target(&mut self, target: Target, value: F) { let opt_old_value = self.target_values.insert(target, value); if let Some(old_value) = opt_old_value { From bc90909fa34ca0c81b73d42545edecddc53ec01f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 14:16:05 +0200 Subject: [PATCH 22/26] Add check of copy constraints after witness generation --- src/circuit_builder.rs | 5 +++-- src/circuit_data.rs | 13 +++++++++---- src/prover.rs | 11 +++++++++-- src/witness.rs | 27 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 8c7d0a72..9be203bb 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -293,11 +293,12 @@ impl, const D: usize> CircuitBuilder { sigmas_root, }; - let generators = self.generators; let prover_only = ProverOnlyCircuitData { - generators, + generators: self.generators, constants_commitment, sigmas_commitment, + copy_constraints: self.copy_constraints, + gate_instances: self.gate_instances, }; // The HashSet of gates will have a non-deterministic order. When converting to a Vec, we diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 4d9a7110..37925c0c 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -3,11 +3,12 @@ use anyhow::Result; use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::fri::FriConfig; -use crate::gates::gate::GateRef; +use crate::gates::gate::{GateInstance, GateRef}; use crate::generator::WitnessGenerator; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::proof::{Hash, HashTarget, Proof}; use crate::prover::prove; +use crate::target::Target; use crate::verifier::verify; use crate::witness::PartialWitness; @@ -52,7 +53,7 @@ impl CircuitConfig { /// Circuit data required by the prover or the verifier. pub struct CircuitData, const D: usize> { - pub(crate) prover_only: ProverOnlyCircuitData, + pub(crate) prover_only: ProverOnlyCircuitData, pub(crate) verifier_only: VerifierOnlyCircuitData, pub(crate) common: CommonCircuitData, } @@ -75,7 +76,7 @@ impl, const D: usize> CircuitData { /// required, like LDEs of preprocessed polynomials. If more succinctness was desired, we could /// construct a more minimal prover structure and convert back and forth. pub struct ProverCircuitData, const D: usize> { - pub(crate) prover_only: ProverOnlyCircuitData, + pub(crate) prover_only: ProverOnlyCircuitData, pub(crate) common: CommonCircuitData, } @@ -98,12 +99,16 @@ impl, const D: usize> VerifierCircuitData { } /// Circuit data required by the prover, but not the verifier. -pub(crate) struct ProverOnlyCircuitData { +pub(crate) struct ProverOnlyCircuitData, const D: usize> { pub generators: Vec>>, /// Commitments to the constants polynomial. pub constants_commitment: ListPolynomialCommitment, /// Commitments to the sigma polynomial. pub sigmas_commitment: ListPolynomialCommitment, + /// The circuit's copy constraints. + pub copy_constraints: Vec<(Target, Target)>, + /// The concrete placement of each gate in the circuit. + pub gate_instances: Vec>, } /// Circuit data required by the verifier, but not the prover. diff --git a/src/prover.rs b/src/prover.rs index 81b02674..0215aa13 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -23,7 +23,7 @@ use crate::witness::PartialWitness; pub const PLONK_BLINDING: [bool; 5] = [false, false, true, true, true]; pub(crate) fn prove, const D: usize>( - prover_data: &ProverOnlyCircuitData, + prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, inputs: PartialWitness, ) -> Proof { @@ -38,6 +38,13 @@ pub(crate) fn prove, const D: usize>( "to generate witness" ); + timed!( + witness + .check_copy_constraints(&prover_data.copy_constraints, &prover_data.gate_instances) + .unwrap(), // TODO: Change return value to `Result` and use `?` here. + "to check copy constraints" + ); + let config = &common_data.config; let num_wires = config.num_wires; let num_challenges = config.num_challenges; @@ -162,7 +169,7 @@ fn compute_z, const D: usize>( fn compute_vanishing_polys, const D: usize>( common_data: &CommonCircuitData, - prover_data: &ProverOnlyCircuitData, + prover_data: &ProverOnlyCircuitData, wires_commitment: &ListPolynomialCommitment, plonk_zs_commitment: &ListPolynomialCommitment, betas: &[F], diff --git a/src/witness.rs b/src/witness.rs index a0b4b2a4..ff6a8a50 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; +use anyhow::{ensure, Result}; + use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; +use crate::gates::gate::GateInstance; use crate::target::Target; use crate::wire::Wire; @@ -97,6 +100,30 @@ impl PartialWitness { self.set_target(target, value); } } + + /// Checks that the copy constraints are satisfied in the witness. + pub fn check_copy_constraints( + &self, + copy_constraints: &[(Target, Target)], + gate_instances: &[GateInstance], + ) -> Result<()> + where + F: Extendable, + { + for &(a, b) in copy_constraints { + if let (Target::Wire(wa), Target::Wire(wb)) = (a, b) { + let va = self.target_values.get(&a).copied().unwrap_or(F::ZERO); + let vb = self.target_values.get(&b).copied().unwrap_or(F::ZERO); + ensure!( + va == vb, + "Copy constraint between wire {} of gate #{} (`{}`) and wire {} of gate #{} (`{}`) is not satisfied.\ + Got values of {} and {} respectively.", + wa.input, wa.gate, gate_instances[wa.gate].gate_type.0.id(), wb.input, wb.gate, + gate_instances[wb.gate].gate_type.0.id(), va, vb); + } + } + Ok(()) + } } impl Default for PartialWitness { From 8ae664d94fba60ea38d96dc55ca5353c3a40e72c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 14:22:42 +0200 Subject: [PATCH 23/26] Minor --- src/gadgets/arithmetic.rs | 2 -- src/witness.rs | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 520f8cd9..7a9fd441 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -385,8 +385,6 @@ mod tests { let x = FF::rand(); let y = FF::rand(); - let x = FF::TWO; - let y = FF::ONE; let z = x / y; let xt = builder.constant_extension(x); let yt = builder.constant_extension(y); diff --git a/src/witness.rs b/src/witness.rs index f55d4297..aff0192a 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::convert::TryInto; use anyhow::{ensure, Result}; @@ -139,8 +140,8 @@ impl PartialWitness { let vb = self.target_values.get(&b).copied().unwrap_or(F::ZERO); ensure!( va == vb, - "Copy constraint between wire {} of gate #{} (`{}`) and wire {} of gate #{} (`{}`) is not satisfied.\ - Got values of {} and {} respectively.", + "Copy constraint between wire {} of gate #{} (`{}`) and wire {} of gate #{} (`{}`) is not satisfied. \ + Got values of {} and {} respectively.", wa.input, wa.gate, gate_instances[wa.gate].gate_type.0.id(), wb.input, wb.gate, gate_instances[wb.gate].gate_type.0.id(), va, vb); } From 747f1875af0e76b3b44ed6c91dc19430bff7ac4a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 14:26:05 +0200 Subject: [PATCH 24/26] Add todo for public inputs --- src/circuit_builder.rs | 1 - src/witness.rs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 640e17a5..0a7041e5 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -274,7 +274,6 @@ impl, const D: usize> CircuitBuilder { } let wire_partitions = target_partitions.to_wire_partitions(); - wire_partitions.get_sigma_polys(degree_log, k_is) } diff --git a/src/witness.rs b/src/witness.rs index aff0192a..989ec2bc 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -135,6 +135,7 @@ impl PartialWitness { F: Extendable, { for &(a, b) in copy_constraints { + // TODO: Take care of public inputs once they land. if let (Target::Wire(wa), Target::Wire(wb)) = (a, b) { let va = self.target_values.get(&a).copied().unwrap_or(F::ZERO); let vb = self.target_values.get(&b).copied().unwrap_or(F::ZERO); From d69f11794e45034964a95d6f5069d88aaa4b9bc6 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 23 Jun 2021 19:15:52 +0200 Subject: [PATCH 25/26] Revert `num_routed_wires` to 27 --- src/plonk_challenger.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index d1141672..9af5e590 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; @@ -5,7 +7,6 @@ use crate::field::field::Field; use crate::hash::{permute, SPONGE_RATE, SPONGE_WIDTH}; use crate::proof::{Hash, HashTarget, OpeningSet}; use crate::target::Target; -use std::convert::TryInto; /// Observes prover messages, and generates challenges by hashing the transcript. #[derive(Clone)] @@ -369,7 +370,7 @@ mod tests { let config = CircuitConfig { num_wires: 12 + 12 + 3 + 101, - num_routed_wires: 200, + num_routed_wires: 27, ..CircuitConfig::default() }; let mut builder = CircuitBuilder::::new(config); From ac1179255a95aefd0dfacd3cd2c8e5d6403148ee Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Wed, 23 Jun 2021 15:45:48 -0700 Subject: [PATCH 26/26] Delete coset [I]FFT methods (#72) I think they had a mistake, and in any case we have a similar method in `polynomial.rs` now which has tests. --- src/field/fft.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/field/fft.rs b/src/field/fft.rs index 8bcde967..e1c1a097 100644 --- a/src/field/fft.rs +++ b/src/field/fft.rs @@ -126,32 +126,11 @@ pub(crate) fn fft_with_precomputation_power_of_2( PolynomialValues { values } } -pub(crate) fn coset_fft(poly: PolynomialCoeffs, shift: F) -> PolynomialValues { - let mut points = fft(poly); - let mut shift_exp_i = F::ONE; - for p in points.values.iter_mut() { - *p *= shift_exp_i; - shift_exp_i *= shift; - } - points -} - pub(crate) fn ifft(poly: PolynomialValues) -> PolynomialCoeffs { let precomputation = fft_precompute(poly.len()); ifft_with_precomputation_power_of_2(poly, &precomputation) } -pub(crate) fn coset_ifft(poly: PolynomialValues, shift: F) -> PolynomialCoeffs { - let shift_inv = shift.inverse(); - let mut shift_inv_exp_i = F::ONE; - let mut coeffs = ifft(poly); - for c in coeffs.coeffs.iter_mut() { - *c *= shift_inv_exp_i; - shift_inv_exp_i *= shift_inv; - } - coeffs -} - #[cfg(test)] mod tests { use crate::field::crandall_field::CrandallField;