From 62ce94e26067aa250efa47336924cc2ee9726ffb Mon Sep 17 00:00:00 2001 From: Balazs Komuves Date: Mon, 9 Dec 2024 18:31:34 +0100 Subject: [PATCH] remove `batch_fri/*`: it's not used anywhere and that's just confusing --- plonky2/src/batch_fri/mod.rs | 4 - plonky2/src/batch_fri/oracle.rs | 612 -------------------- plonky2/src/batch_fri/prover.rs | 479 --------------- plonky2/src/batch_fri/recursive_verifier.rs | 332 ----------- plonky2/src/batch_fri/verifier.rs | 251 -------- plonky2/src/hash/merkle_proofs.rs | 2 + plonky2/src/lib.rs | 1 - 7 files changed, 2 insertions(+), 1679 deletions(-) delete mode 100644 plonky2/src/batch_fri/mod.rs delete mode 100644 plonky2/src/batch_fri/oracle.rs delete mode 100644 plonky2/src/batch_fri/prover.rs delete mode 100644 plonky2/src/batch_fri/recursive_verifier.rs delete mode 100644 plonky2/src/batch_fri/verifier.rs diff --git a/plonky2/src/batch_fri/mod.rs b/plonky2/src/batch_fri/mod.rs deleted file mode 100644 index 8d7cc5e1..00000000 --- a/plonky2/src/batch_fri/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod oracle; -pub mod prover; -pub mod recursive_verifier; -pub mod verifier; diff --git a/plonky2/src/batch_fri/oracle.rs b/plonky2/src/batch_fri/oracle.rs deleted file mode 100644 index 58deeaa3..00000000 --- a/plonky2/src/batch_fri/oracle.rs +++ /dev/null @@ -1,612 +0,0 @@ -#[cfg(not(feature = "std"))] -use alloc::{format, vec::Vec}; - -use itertools::Itertools; -use plonky2_field::extension::Extendable; -use plonky2_field::fft::FftRootTable; -use plonky2_field::packed::PackedField; -use plonky2_field::polynomial::{PolynomialCoeffs, PolynomialValues}; -use plonky2_field::types::Field; -use plonky2_maybe_rayon::*; -use plonky2_util::{log2_strict, reverse_index_bits_in_place}; - -use crate::batch_fri::prover::batch_fri_proof; -use crate::fri::oracle::PolynomialBatch; -use crate::fri::proof::FriProof; -use crate::fri::structure::{FriBatchInfo, FriInstanceInfo}; -use crate::fri::FriParams; -use crate::hash::batch_merkle_tree::BatchMerkleTree; -use crate::hash::hash_types::RichField; -use crate::iop::challenger::Challenger; -use crate::plonk::config::GenericConfig; -use crate::timed; -use crate::util::reducing::ReducingFactor; -use crate::util::timing::TimingTree; -use crate::util::{reverse_bits, transpose}; - -/// Represents a batch FRI oracle, i.e. a batch of polynomials with different degrees which have -/// been Merkle-ized in a [`BatchMerkleTree`]. -#[derive(Eq, PartialEq, Debug)] -pub struct BatchFriOracle, C: GenericConfig, const D: usize> -{ - pub polynomials: Vec>, - pub batch_merkle_tree: BatchMerkleTree, - // The degree bits of each polynomial group. - pub degree_bits: Vec, - pub rate_bits: usize, - pub blinding: bool, -} - -impl, C: GenericConfig, const D: usize> - BatchFriOracle -{ - /// Creates a list polynomial commitment for the polynomials interpolating the values in `values`. - pub fn from_values( - values: Vec>, - rate_bits: usize, - blinding: bool, - cap_height: usize, - timing: &mut TimingTree, - fft_root_table: &[Option<&FftRootTable>], - ) -> Self { - let coeffs = timed!( - timing, - "IFFT", - values.into_par_iter().map(|v| v.ifft()).collect::>() - ); - - Self::from_coeffs( - coeffs, - rate_bits, - blinding, - cap_height, - timing, - fft_root_table, - ) - } - - /// Creates a list polynomial commitment for the polynomials `polynomials`. - pub fn from_coeffs( - polynomials: Vec>, - rate_bits: usize, - blinding: bool, - cap_height: usize, - timing: &mut TimingTree, - fft_root_table: &[Option<&FftRootTable>], - ) -> Self { - let mut degree_bits = polynomials - .iter() - .map(|p| log2_strict(p.len())) - .collect_vec(); - assert!(degree_bits.windows(2).all(|pair| { pair[0] >= pair[1] })); - - let num_polynomials = polynomials.len(); - let mut group_start = 0; - let mut leaves = Vec::new(); - - for (i, d) in degree_bits.iter().enumerate() { - if i == num_polynomials - 1 || *d > degree_bits[i + 1] { - let lde_values = timed!( - timing, - "FFT + blinding", - PolynomialBatch::::lde_values( - &polynomials[group_start..i + 1], - rate_bits, - blinding, - fft_root_table[i] - ) - ); - - let mut leaf_group = timed!(timing, "transpose LDEs", transpose(&lde_values)); - reverse_index_bits_in_place(&mut leaf_group); - leaves.push(leaf_group); - - group_start = i + 1; - } - } - - let batch_merkle_tree = timed!( - timing, - "build Field Merkle tree", - BatchMerkleTree::new(leaves, cap_height) - ); - - degree_bits.sort_unstable(); - degree_bits.dedup(); - degree_bits.reverse(); - assert_eq!(batch_merkle_tree.leaves.len(), degree_bits.len()); - Self { - polynomials, - batch_merkle_tree, - degree_bits, - rate_bits, - blinding, - } - } - - /// Produces a batch opening proof. - pub fn prove_openings( - degree_bits: &[usize], - instances: &[FriInstanceInfo], - oracles: &[&Self], - challenger: &mut Challenger, - fri_params: &FriParams, - timing: &mut TimingTree, - ) -> FriProof { - assert_eq!(degree_bits.len(), instances.len()); - assert!(D > 1, "Not implemented for D=1."); - let alpha = challenger.get_extension_challenge::(); - let mut alpha = ReducingFactor::new(alpha); - - let mut final_lde_polynomial_coeff = Vec::with_capacity(instances.len()); - let mut final_lde_polynomial_values = Vec::with_capacity(instances.len()); - for (i, instance) in instances.iter().enumerate() { - // Final low-degree polynomial that goes into FRI. - let mut final_poly = PolynomialCoeffs::empty(); - - // Each batch `i` consists of an opening point `z_i` and polynomials `{f_ij}_j` to be opened at that point. - // For each batch, we compute the composition polynomial `F_i = sum alpha^j f_ij`, - // where `alpha` is a random challenge in the extension field. - // The final polynomial is then computed as `final_poly = sum_i alpha^(k_i) (F_i(X) - F_i(z_i))/(X-z_i)` - // where the `k_i`s are chosen such that each power of `alpha` appears only once in the final sum. - // There are usually two batches for the openings at `zeta` and `g * zeta`. - // The oracles used in Plonky2 are given in `FRI_ORACLES` in `plonky2/src/plonk/plonk_common.rs`. - for FriBatchInfo { point, polynomials } in &instance.batches { - // Collect the coefficients of all the polynomials in `polynomials`. - let polys_coeff = polynomials.iter().map(|fri_poly| { - &oracles[fri_poly.oracle_index].polynomials[fri_poly.polynomial_index] - }); - let composition_poly = timed!( - timing, - &format!("reduce batch of {} polynomials", polynomials.len()), - alpha.reduce_polys_base(polys_coeff) - ); - let mut quotient = composition_poly.divide_by_linear(*point); - quotient.coeffs.push(F::Extension::ZERO); // pad back to power of two - alpha.shift_poly(&mut final_poly); - final_poly += quotient; - } - - assert_eq!(final_poly.len(), 1 << degree_bits[i]); - let lde_final_poly = final_poly.lde(fri_params.config.rate_bits); - let lde_final_values = timed!( - timing, - &format!("perform final FFT {}", lde_final_poly.len()), - lde_final_poly.coset_fft(F::coset_shift().into()) - ); - final_lde_polynomial_coeff.push(lde_final_poly); - final_lde_polynomial_values.push(lde_final_values); - } - - batch_fri_proof::( - &oracles - .iter() - .map(|o| &o.batch_merkle_tree) - .collect::>(), - final_lde_polynomial_coeff[0].clone(), - &final_lde_polynomial_values, - challenger, - fri_params, - timing, - ) - } - - /// Fetches LDE values at the `index * step`th point. - pub fn get_lde_values( - &self, - degree_bits_index: usize, - index: usize, - step: usize, - slice_start: usize, - slice_len: usize, - ) -> &[F] { - let index = index * step; - let index = reverse_bits(index, self.degree_bits[degree_bits_index] + self.rate_bits); - let slice = &self.batch_merkle_tree.leaves[degree_bits_index][index]; - &slice[slice_start..slice_start + slice_len] - } - - /// Like `get_lde_values`, but fetches LDE values from a batch of `P::WIDTH` points, and returns - /// packed values. - pub fn get_lde_values_packed

( - &self, - degree_bits_index: usize, - index_start: usize, - step: usize, - slice_start: usize, - slice_len: usize, - ) -> Vec

- where - P: PackedField, - { - let row_wise = (0..P::WIDTH) - .map(|i| { - self.get_lde_values( - degree_bits_index, - index_start + i, - step, - slice_start, - slice_len, - ) - }) - .collect_vec(); - - // This is essentially a transpose, but we will not use the generic transpose method as we - // want inner lists to be of type P, not Vecs which would involve allocation. - let leaf_size = row_wise[0].len(); - (0..leaf_size) - .map(|j| { - let mut packed = P::ZEROS; - packed - .as_slice_mut() - .iter_mut() - .zip(&row_wise) - .for_each(|(packed_i, row_i)| *packed_i = row_i[j]); - packed - }) - .collect_vec() - } -} - -#[cfg(test)] -mod test { - #[cfg(not(feature = "std"))] - use alloc::vec; - - use plonky2_field::goldilocks_field::GoldilocksField; - use plonky2_field::types::Sample; - - use super::*; - use crate::batch_fri::oracle::BatchFriOracle; - use crate::batch_fri::verifier::verify_batch_fri_proof; - use crate::fri::reduction_strategies::FriReductionStrategy; - use crate::fri::structure::{ - FriBatchInfo, FriBatchInfoTarget, FriInstanceInfo, FriInstanceInfoTarget, FriOpeningBatch, - FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, FriOracleInfo, FriPolynomialInfo, - }; - use crate::fri::witness_util::set_fri_proof_target; - use crate::fri::FriConfig; - use crate::iop::challenger::RecursiveChallenger; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::PoseidonGoldilocksConfig; - use crate::plonk::prover::prove; - - const D: usize = 2; - - type C = PoseidonGoldilocksConfig; - type F = >::F; - type H = >::Hasher; - - #[test] - fn batch_prove_openings() -> anyhow::Result<()> { - let mut timing = TimingTree::default(); - - let k0 = 9; - let k1 = 8; - let k2 = 6; - let reduction_arity_bits = vec![1, 2, 1]; - let fri_params = FriParams { - config: FriConfig { - rate_bits: 1, - cap_height: 0, - proof_of_work_bits: 0, - reduction_strategy: FriReductionStrategy::Fixed(reduction_arity_bits.clone()), - num_query_rounds: 10, - }, - hiding: false, - degree_bits: k0, - reduction_arity_bits, - }; - - let n0 = 1 << k0; - let n1 = 1 << k1; - let n2 = 1 << k2; - let trace0 = PolynomialValues::new(F::rand_vec(n0)); - let trace1_0 = PolynomialValues::new(F::rand_vec(n1)); - let trace1_1 = PolynomialValues::new(F::rand_vec(n1)); - let trace2 = PolynomialValues::new(F::rand_vec(n2)); - - let trace_oracle: BatchFriOracle = BatchFriOracle::from_values( - vec![ - trace0.clone(), - trace1_0.clone(), - trace1_1.clone(), - trace2.clone(), - ], - fri_params.config.rate_bits, - fri_params.hiding, - fri_params.config.cap_height, - &mut timing, - &[None; 4], - ); - - let mut challenger = Challenger::::new(); - challenger.observe_cap(&trace_oracle.batch_merkle_tree.cap); - let zeta = challenger.get_extension_challenge::(); - let eta = challenger.get_extension_challenge::(); - let poly0 = &trace_oracle.polynomials[0]; - let poly1_0 = &trace_oracle.polynomials[1]; - let poly1_1 = &trace_oracle.polynomials[2]; - let poly2 = &trace_oracle.polynomials[3]; - - let mut challenger = Challenger::::new(); - let mut verifier_challenger = challenger.clone(); - - let fri_instance_0 = FriInstanceInfo { - oracles: vec![FriOracleInfo { - num_polys: 1, - blinding: false, - }], - batches: vec![ - FriBatchInfo { - point: zeta, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 0, - }], - }, - FriBatchInfo { - point: eta, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 0, - }], - }, - ], - }; - let fri_instance_1 = FriInstanceInfo { - oracles: vec![FriOracleInfo { - num_polys: 2, - blinding: false, - }], - batches: vec![ - FriBatchInfo { - point: zeta, - polynomials: vec![ - FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 1, - }, - FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 2, - }, - ], - }, - FriBatchInfo { - point: eta, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 2, - }], - }, - ], - }; - let fri_instance_2 = FriInstanceInfo { - oracles: vec![FriOracleInfo { - num_polys: 1, - blinding: false, - }], - batches: vec![FriBatchInfo { - point: zeta, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 3, - }], - }], - }; - let fri_instances = vec![fri_instance_0, fri_instance_1, fri_instance_2]; - let poly0_zeta = poly0.to_extension::().eval(zeta); - let poly0_eta = poly0.to_extension::().eval(eta); - let fri_opening_batch_0 = FriOpenings { - batches: vec![ - FriOpeningBatch { - values: vec![poly0_zeta], - }, - FriOpeningBatch { - values: vec![poly0_eta], - }, - ], - }; - let poly10_zeta = poly1_0.to_extension::().eval(zeta); - let poly11_zeta = poly1_1.to_extension::().eval(zeta); - let poly11_eta = poly1_1.to_extension::().eval(eta); - let fri_opening_batch_1 = FriOpenings { - batches: vec![ - FriOpeningBatch { - values: vec![poly10_zeta, poly11_zeta], - }, - FriOpeningBatch { - values: vec![poly11_eta], - }, - ], - }; - let poly2_zeta = poly2.to_extension::().eval(zeta); - let fri_opening_batch_2 = FriOpenings { - batches: vec![FriOpeningBatch { - values: vec![poly2_zeta], - }], - }; - let fri_openings = vec![ - fri_opening_batch_0, - fri_opening_batch_1, - fri_opening_batch_2, - ]; - - let proof = BatchFriOracle::prove_openings( - &[k0, k1, k2], - &fri_instances, - &[&trace_oracle], - &mut challenger, - &fri_params, - &mut timing, - ); - - let fri_challenges = verifier_challenger.fri_challenges::( - &proof.commit_phase_merkle_caps, - &proof.final_poly, - proof.pow_witness, - k0, - &fri_params.config, - None, - None, - ); - let degree_bits = [k0, k1, k2]; - let merkle_cap = trace_oracle.batch_merkle_tree.cap; - verify_batch_fri_proof::( - °ree_bits, - &fri_instances, - &fri_openings, - &fri_challenges, - &[merkle_cap.clone()], - &proof, - &fri_params, - )?; - - // Test recursive verifier - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - let num_leaves_per_oracle = vec![4]; - let fri_proof_target = builder.add_virtual_fri_proof(&num_leaves_per_oracle, &fri_params); - let zeta_target = builder.constant_extension(zeta); - let eta_target = builder.constant_extension(eta); - let fri_instance_info_target_0 = FriInstanceInfoTarget { - oracles: vec![FriOracleInfo { - num_polys: 1, - blinding: false, - }], - batches: vec![ - FriBatchInfoTarget { - point: zeta_target, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 0, - }], - }, - FriBatchInfoTarget { - point: eta_target, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 0, - }], - }, - ], - }; - let fri_instance_info_target_1 = FriInstanceInfoTarget { - oracles: vec![FriOracleInfo { - num_polys: 2, - blinding: false, - }], - batches: vec![ - FriBatchInfoTarget { - point: zeta_target, - polynomials: vec![ - FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 1, - }, - FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 2, - }, - ], - }, - FriBatchInfoTarget { - point: eta_target, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 2, - }], - }, - ], - }; - let fri_instance_info_target_2 = FriInstanceInfoTarget { - oracles: vec![FriOracleInfo { - num_polys: 1, - blinding: false, - }], - batches: vec![FriBatchInfoTarget { - point: zeta_target, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 3, - }], - }], - }; - - let poly0_zeta_target = builder.constant_extension(poly0_zeta); - let poly0_eta_target = builder.constant_extension(poly0_eta); - let fri_opening_batch_0 = FriOpeningsTarget { - batches: vec![ - FriOpeningBatchTarget { - values: vec![poly0_zeta_target], - }, - FriOpeningBatchTarget { - values: vec![poly0_eta_target], - }, - ], - }; - let poly10_zeta_target = builder.constant_extension(poly10_zeta); - let poly11_zeta_target = builder.constant_extension(poly11_zeta); - let poly11_eta_target = builder.constant_extension(poly11_eta); - let fri_opening_batch_1 = FriOpeningsTarget { - batches: vec![ - FriOpeningBatchTarget { - values: vec![poly10_zeta_target, poly11_zeta_target], - }, - FriOpeningBatchTarget { - values: vec![poly11_eta_target], - }, - ], - }; - let poly2_zeta_target = builder.constant_extension(poly2_zeta); - let fri_opening_batch_2 = FriOpeningsTarget { - batches: vec![FriOpeningBatchTarget { - values: vec![poly2_zeta_target], - }], - }; - let fri_openings_target = [ - fri_opening_batch_0, - fri_opening_batch_1, - fri_opening_batch_2, - ]; - - let mut challenger = RecursiveChallenger::::new(&mut builder); - let fri_challenges_target = challenger.fri_challenges( - &mut builder, - &fri_proof_target.commit_phase_merkle_caps, - &fri_proof_target.final_poly, - fri_proof_target.pow_witness, - &fri_params.config, - ); - - let merkle_cap_target = builder.constant_merkle_cap(&merkle_cap); - - let fri_instance_info_target = vec![ - fri_instance_info_target_0, - fri_instance_info_target_1, - fri_instance_info_target_2, - ]; - - builder.verify_batch_fri_proof::( - °ree_bits, - &fri_instance_info_target, - &fri_openings_target, - &fri_challenges_target, - &[merkle_cap_target], - &fri_proof_target, - &fri_params, - ); - - let mut pw = PartialWitness::new(); - set_fri_proof_target(&mut pw, &fri_proof_target, &proof)?; - - let data = builder.build::(); - let proof = prove::(&data.prover_only, &data.common, pw, &mut timing)?; - data.verify(proof.clone())?; - - Ok(()) - } -} diff --git a/plonky2/src/batch_fri/prover.rs b/plonky2/src/batch_fri/prover.rs deleted file mode 100644 index e71fe25b..00000000 --- a/plonky2/src/batch_fri/prover.rs +++ /dev/null @@ -1,479 +0,0 @@ -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; - -use plonky2_field::extension::flatten; -#[allow(unused_imports)] -use plonky2_field::types::Field; -use plonky2_maybe_rayon::*; -use plonky2_util::{log2_strict, reverse_index_bits_in_place}; - -use crate::field::extension::{unflatten, Extendable}; -use crate::field::polynomial::{PolynomialCoeffs, PolynomialValues}; -use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep}; -use crate::fri::prover::{fri_proof_of_work, FriCommitedTrees}; -use crate::fri::FriParams; -use crate::hash::batch_merkle_tree::BatchMerkleTree; -use crate::hash::hash_types::RichField; -use crate::hash::merkle_tree::MerkleTree; -use crate::iop::challenger::Challenger; -use crate::plonk::config::GenericConfig; -use crate::plonk::plonk_common::reduce_with_powers; -use crate::timed; -use crate::util::timing::TimingTree; - -/// Builds a batch FRI proof. -pub fn batch_fri_proof, C: GenericConfig, const D: usize>( - initial_merkle_trees: &[&BatchMerkleTree], - lde_polynomial_coeffs: PolynomialCoeffs, - lde_polynomial_values: &[PolynomialValues], - challenger: &mut Challenger, - fri_params: &FriParams, - timing: &mut TimingTree, -) -> FriProof { - let n = lde_polynomial_coeffs.len(); - assert_eq!(lde_polynomial_values[0].len(), n); - // The polynomial vectors should be sorted by degree, from largest to smallest, with no duplicate degrees. - assert!(lde_polynomial_values - .windows(2) - .all(|pair| { pair[0].len() > pair[1].len() })); - // Check that reduction_arity_bits covers all polynomials - let mut cur_n = log2_strict(n); - let mut cur_poly_index = 1; - for arity_bits in &fri_params.reduction_arity_bits { - cur_n -= arity_bits; - if cur_poly_index < lde_polynomial_values.len() - && cur_n == log2_strict(lde_polynomial_values[cur_poly_index].len()) - { - cur_poly_index += 1; - } - } - assert_eq!(cur_poly_index, lde_polynomial_values.len()); - - // Commit phase - let (trees, final_coeffs) = timed!( - timing, - "fold codewords in the commitment phase", - batch_fri_committed_trees::( - lde_polynomial_coeffs, - lde_polynomial_values, - challenger, - fri_params, - ) - ); - - // PoW phase - let pow_witness = timed!( - timing, - "find proof-of-work witness", - fri_proof_of_work::(challenger, &fri_params.config) - ); - - // Query phase - let query_round_proofs = batch_fri_prover_query_rounds::( - initial_merkle_trees, - &trees, - challenger, - n, - fri_params, - ); - - FriProof { - commit_phase_merkle_caps: trees.iter().map(|t| t.cap.clone()).collect(), - query_round_proofs, - final_poly: final_coeffs, - pow_witness, - } -} - -pub(crate) fn batch_fri_committed_trees< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - mut final_coeffs: PolynomialCoeffs, - values: &[PolynomialValues], - challenger: &mut Challenger, - fri_params: &FriParams, -) -> FriCommitedTrees { - let mut trees = Vec::with_capacity(fri_params.reduction_arity_bits.len()); - let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR; - let mut polynomial_index = 1; - let mut final_values = values[0].clone(); - for arity_bits in &fri_params.reduction_arity_bits { - let arity = 1 << arity_bits; - - reverse_index_bits_in_place(&mut final_values.values); - let chunked_values = final_values.values.par_chunks(arity).map(flatten).collect(); - let tree = MerkleTree::::new(chunked_values, fri_params.config.cap_height); - - challenger.observe_cap(&tree.cap); - trees.push(tree); - - let beta = challenger.get_extension_challenge::(); - // P(x) = sum_{i>(), - ); - shift = shift.exp_u64(arity as u64); - final_values = final_coeffs.coset_fft(shift.into()); - if polynomial_index != values.len() && final_values.len() == values[polynomial_index].len() - { - final_values = PolynomialValues::new( - final_values - .values - .iter() - .zip(&values[polynomial_index].values) - .map(|(&f, &v)| f * beta + v) - .collect::>(), - ); - polynomial_index += 1; - } - final_coeffs = final_values.clone().coset_ifft(shift.into()); - } - assert_eq!(polynomial_index, values.len()); - - // The coefficients being removed here should always be zero. - final_coeffs - .coeffs - .truncate(final_coeffs.len() >> fri_params.config.rate_bits); - - challenger.observe_extension_elements(&final_coeffs.coeffs); - (trees, final_coeffs) -} - -fn batch_fri_prover_query_rounds< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - initial_merkle_trees: &[&BatchMerkleTree], - trees: &[MerkleTree], - challenger: &mut Challenger, - n: usize, - fri_params: &FriParams, -) -> Vec> { - challenger - .get_n_challenges(fri_params.config.num_query_rounds) - .into_par_iter() - .map(|rand| { - let x_index = rand.to_canonical_u64() as usize % n; - batch_fri_prover_query_round::( - initial_merkle_trees, - trees, - x_index, - fri_params, - ) - }) - .collect() -} - -fn batch_fri_prover_query_round< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - initial_merkle_trees: &[&BatchMerkleTree], - trees: &[MerkleTree], - mut x_index: usize, - fri_params: &FriParams, -) -> FriQueryRound { - let mut query_steps = Vec::with_capacity(trees.len()); - let initial_proof = initial_merkle_trees - .iter() - .map(|t| { - ( - t.values(x_index) - .iter() - .flatten() - .cloned() - .collect::>(), - t.open_batch(x_index), - ) - }) - .collect::>(); - for (i, tree) in trees.iter().enumerate() { - let arity_bits = fri_params.reduction_arity_bits[i]; - let evals = unflatten(tree.get(x_index >> arity_bits)); - let merkle_proof = tree.prove(x_index >> arity_bits); - - query_steps.push(FriQueryStep { - evals, - merkle_proof, - }); - - x_index >>= arity_bits; - } - FriQueryRound { - initial_trees_proof: FriInitialTreeProof { - evals_proofs: initial_proof, - }, - steps: query_steps, - } -} - -#[cfg(test)] -mod tests { - #[cfg(not(feature = "std"))] - use alloc::vec; - - use anyhow::Result; - use itertools::Itertools; - use plonky2_field::goldilocks_field::GoldilocksField; - use plonky2_field::types::{Field64, Sample}; - - use super::*; - use crate::batch_fri::oracle::BatchFriOracle; - use crate::batch_fri::verifier::verify_batch_fri_proof; - use crate::fri::reduction_strategies::FriReductionStrategy; - use crate::fri::structure::{ - FriBatchInfo, FriInstanceInfo, FriOpeningBatch, FriOpenings, FriOracleInfo, - FriPolynomialInfo, - }; - use crate::fri::FriConfig; - use crate::plonk::config::PoseidonGoldilocksConfig; - - const D: usize = 2; - - type C = PoseidonGoldilocksConfig; - type F = >::F; - type H = >::Hasher; - - #[test] - fn single_polynomial() -> Result<()> { - let mut timing = TimingTree::default(); - - let k = 9; - let reduction_arity_bits = vec![1, 2, 1]; - let fri_params = FriParams { - config: FriConfig { - rate_bits: 1, - cap_height: 5, - proof_of_work_bits: 0, - reduction_strategy: FriReductionStrategy::Fixed(reduction_arity_bits.clone()), - num_query_rounds: 10, - }, - hiding: false, - degree_bits: k, - reduction_arity_bits, - }; - - let n = 1 << k; - let trace = PolynomialValues::new((1..n + 1).map(F::from_canonical_i64).collect_vec()); - - let polynomial_batch: BatchFriOracle = BatchFriOracle::from_values( - vec![trace.clone()], - fri_params.config.rate_bits, - fri_params.hiding, - fri_params.config.cap_height, - &mut timing, - &[None], - ); - let poly = &polynomial_batch.polynomials[0]; - let mut challenger = Challenger::::new(); - challenger.observe_cap(&polynomial_batch.batch_merkle_tree.cap); - let _alphas = challenger.get_n_challenges(2); - let zeta = challenger.get_extension_challenge::(); - challenger.observe_extension_element::(&poly.to_extension::().eval(zeta)); - let mut verifier_challenger = challenger.clone(); - - let fri_instance: FriInstanceInfo = FriInstanceInfo { - oracles: vec![FriOracleInfo { - num_polys: 1, - blinding: false, - }], - batches: vec![FriBatchInfo { - point: zeta, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index: 0, - }], - }], - }; - let _alpha = challenger.get_extension_challenge::(); - - let composition_poly = poly.mul_extension::(>::Extension::ONE); - let mut quotient = composition_poly.divide_by_linear(zeta); - quotient.coeffs.push(>::Extension::ZERO); - - let lde_final_poly = quotient.lde(fri_params.config.rate_bits); - let lde_final_values = lde_final_poly.coset_fft(F::coset_shift().into()); - - let proof = batch_fri_proof::( - &[&polynomial_batch.batch_merkle_tree], - lde_final_poly, - &[lde_final_values], - &mut challenger, - &fri_params, - &mut timing, - ); - - let fri_challenges = verifier_challenger.fri_challenges::( - &proof.commit_phase_merkle_caps, - &proof.final_poly, - proof.pow_witness, - k, - &fri_params.config, - None, - None, - ); - - let fri_opening_batch = FriOpeningBatch { - values: vec![poly.to_extension::().eval(zeta)], - }; - verify_batch_fri_proof::( - &[k], - &[fri_instance], - &[FriOpenings { - batches: vec![fri_opening_batch], - }], - &fri_challenges, - &[polynomial_batch.batch_merkle_tree.cap], - &proof, - &fri_params, - ) - } - - #[test] - fn multiple_polynomials() -> Result<()> { - let mut timing = TimingTree::default(); - - let k0 = 9; - let k1 = 8; - let k2 = 6; - let reduction_arity_bits = vec![1, 2, 1]; - let fri_params = FriParams { - config: FriConfig { - rate_bits: 1, - cap_height: 5, - proof_of_work_bits: 0, - reduction_strategy: FriReductionStrategy::Fixed(reduction_arity_bits.clone()), - num_query_rounds: 10, - }, - hiding: false, - degree_bits: k0, - reduction_arity_bits, - }; - - let n0 = 1 << k0; - let n1 = 1 << k1; - let n2 = 1 << k2; - let trace0 = PolynomialValues::new(F::rand_vec(n0)); - let trace1 = PolynomialValues::new(F::rand_vec(n1)); - let trace2 = PolynomialValues::new(F::rand_vec(n2)); - - let trace_oracle: BatchFriOracle = BatchFriOracle::from_values( - vec![trace0.clone(), trace1.clone(), trace2.clone()], - fri_params.config.rate_bits, - fri_params.hiding, - fri_params.config.cap_height, - &mut timing, - &[None; 3], - ); - - let mut challenger = Challenger::::new(); - challenger.observe_cap(&trace_oracle.batch_merkle_tree.cap); - let _alphas = challenger.get_n_challenges(2); - let zeta = challenger.get_extension_challenge::(); - let poly0 = &trace_oracle.polynomials[0]; - let poly1 = &trace_oracle.polynomials[1]; - let poly2 = &trace_oracle.polynomials[2]; - challenger.observe_extension_element::(&poly0.to_extension::().eval(zeta)); - challenger.observe_extension_element::(&poly1.to_extension::().eval(zeta)); - challenger.observe_extension_element::(&poly2.to_extension::().eval(zeta)); - let mut verifier_challenger = challenger.clone(); - - let _alpha = challenger.get_extension_challenge::(); - - let composition_poly = poly0.mul_extension::(>::Extension::ONE); - let mut quotient = composition_poly.divide_by_linear(zeta); - quotient.coeffs.push(>::Extension::ZERO); - let lde_final_poly_0 = quotient.lde(fri_params.config.rate_bits); - let lde_final_values_0 = lde_final_poly_0.coset_fft(F::coset_shift().into()); - - let composition_poly = poly1.mul_extension::(>::Extension::ONE); - let mut quotient = composition_poly.divide_by_linear(zeta); - quotient.coeffs.push(>::Extension::ZERO); - let lde_final_poly_1 = quotient.lde(fri_params.config.rate_bits); - let lde_final_values_1 = lde_final_poly_1.coset_fft(F::coset_shift().into()); - - let composition_poly = poly2.mul_extension::(>::Extension::ONE); - let mut quotient = composition_poly.divide_by_linear(zeta); - quotient.coeffs.push(>::Extension::ZERO); - let lde_final_poly_2 = quotient.lde(fri_params.config.rate_bits); - let lde_final_values_2 = lde_final_poly_2.coset_fft(F::coset_shift().into()); - - let proof = batch_fri_proof::( - &[&trace_oracle.batch_merkle_tree], - lde_final_poly_0, - &[lde_final_values_0, lde_final_values_1, lde_final_values_2], - &mut challenger, - &fri_params, - &mut timing, - ); - - let get_test_fri_instance = |polynomial_index: usize| -> FriInstanceInfo { - FriInstanceInfo { - oracles: vec![FriOracleInfo { - num_polys: 1, - blinding: false, - }], - batches: vec![FriBatchInfo { - point: zeta, - polynomials: vec![FriPolynomialInfo { - oracle_index: 0, - polynomial_index, - }], - }], - } - }; - let fri_instances = vec![ - get_test_fri_instance(0), - get_test_fri_instance(1), - get_test_fri_instance(2), - ]; - let fri_challenges = verifier_challenger.fri_challenges::( - &proof.commit_phase_merkle_caps, - &proof.final_poly, - proof.pow_witness, - k0, - &fri_params.config, - None, - None, - ); - let fri_opening_batch_0 = FriOpenings { - batches: vec![FriOpeningBatch { - values: vec![poly0.to_extension::().eval(zeta)], - }], - }; - let fri_opening_batch_1 = FriOpenings { - batches: vec![FriOpeningBatch { - values: vec![poly1.to_extension::().eval(zeta)], - }], - }; - let fri_opening_batch_2 = FriOpenings { - batches: vec![FriOpeningBatch { - values: vec![poly2.to_extension::().eval(zeta)], - }], - }; - let fri_openings = vec![ - fri_opening_batch_0, - fri_opening_batch_1, - fri_opening_batch_2, - ]; - - verify_batch_fri_proof::( - &[k0, k1, k2], - &fri_instances, - &fri_openings, - &fri_challenges, - &[trace_oracle.batch_merkle_tree.cap], - &proof, - &fri_params, - ) - } -} diff --git a/plonky2/src/batch_fri/recursive_verifier.rs b/plonky2/src/batch_fri/recursive_verifier.rs deleted file mode 100644 index 95731ba4..00000000 --- a/plonky2/src/batch_fri/recursive_verifier.rs +++ /dev/null @@ -1,332 +0,0 @@ -#[cfg(not(feature = "std"))] -use alloc::{format, vec::Vec}; - -use itertools::Itertools; - -use crate::field::extension::Extendable; -use crate::fri::proof::{ - FriChallengesTarget, FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, -}; -use crate::fri::recursive_verifier::PrecomputedReducedOpeningsTarget; -use crate::fri::structure::{FriBatchInfoTarget, FriInstanceInfoTarget, FriOpeningsTarget}; -use crate::fri::FriParams; -use crate::hash::hash_types::{MerkleCapTarget, RichField}; -use crate::iop::ext_target::{flatten_target, ExtensionTarget}; -use crate::iop::target::{BoolTarget, Target}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::config::{AlgebraicHasher, GenericConfig}; -use crate::util::reducing::ReducingFactorTarget; -use crate::with_context; - -impl, const D: usize> CircuitBuilder { - pub fn verify_batch_fri_proof>( - &mut self, - degree_bits: &[usize], - instance: &[FriInstanceInfoTarget], - openings: &[FriOpeningsTarget], - challenges: &FriChallengesTarget, - initial_merkle_caps: &[MerkleCapTarget], - proof: &FriProofTarget, - params: &FriParams, - ) where - C::Hasher: AlgebraicHasher, - { - if let Some(max_arity_bits) = params.max_arity_bits() { - self.check_recursion_config(max_arity_bits); - } - - debug_assert_eq!( - params.final_poly_len(), - proof.final_poly.len(), - "Final polynomial has wrong degree." - ); - - with_context!( - self, - "check PoW", - self.fri_verify_proof_of_work(challenges.fri_pow_response, ¶ms.config) - ); - - // Check that parameters are coherent. - debug_assert_eq!( - params.config.num_query_rounds, - proof.query_round_proofs.len(), - "Number of query rounds does not match config." - ); - - let mut precomputed_reduced_evals = Vec::with_capacity(openings.len()); - for opn in openings { - let pre = with_context!( - self, - "precompute reduced evaluations", - PrecomputedReducedOpeningsTarget::from_os_and_alpha( - opn, - challenges.fri_alpha, - self - ) - ); - precomputed_reduced_evals.push(pre); - } - let degree_bits = degree_bits - .iter() - .map(|d| d + params.config.rate_bits) - .collect_vec(); - - for (i, round_proof) in proof.query_round_proofs.iter().enumerate() { - // To minimize noise in our logs, we will only record a context for a single FRI query. - // The very first query will have some extra gates due to constants being registered, so - // the second query is a better representative. - let level = if i == 1 { - log::Level::Debug - } else { - log::Level::Trace - }; - - let num_queries = proof.query_round_proofs.len(); - with_context!( - self, - level, - &format!("verify one (of {num_queries}) query rounds"), - self.batch_fri_verifier_query_round::( - °ree_bits, - instance, - challenges, - &precomputed_reduced_evals, - initial_merkle_caps, - proof, - challenges.fri_query_indices[i], - round_proof, - params, - ) - ); - } - } - - fn batch_fri_verify_initial_proof>( - &mut self, - degree_bits: &[usize], - instances: &[FriInstanceInfoTarget], - x_index_bits: &[BoolTarget], - proof: &FriInitialTreeProofTarget, - initial_merkle_caps: &[MerkleCapTarget], - cap_index: Target, - ) { - for (i, ((evals, merkle_proof), cap)) in proof - .evals_proofs - .iter() - .zip(initial_merkle_caps) - .enumerate() - { - let leaves = instances - .iter() - .scan(0, |leaf_index, inst| { - let num_polys = inst.oracles[i].num_polys; - let leaves = (*leaf_index..*leaf_index + num_polys) - .map(|idx| evals[idx]) - .collect::>(); - *leaf_index += num_polys; - Some(leaves) - }) - .collect::>(); - - with_context!( - self, - &format!("verify {i}'th initial Merkle proof"), - self.verify_batch_merkle_proof_to_cap_with_cap_index::( - &leaves, - degree_bits, - x_index_bits, - cap_index, - cap, - merkle_proof - ) - ); - } - } - - fn batch_fri_combine_initial( - &mut self, - instance: &[FriInstanceInfoTarget], - index: usize, - proof: &FriInitialTreeProofTarget, - alpha: ExtensionTarget, - subgroup_x: Target, - precomputed_reduced_evals: &PrecomputedReducedOpeningsTarget, - params: &FriParams, - ) -> ExtensionTarget { - assert!(D > 1, "Not implemented for D=1."); - let degree_log = params.degree_bits; - debug_assert_eq!( - degree_log, - params.config.cap_height + proof.evals_proofs[0].1.siblings.len() - - params.config.rate_bits - ); - let subgroup_x = self.convert_to_ext(subgroup_x); - let mut alpha = ReducingFactorTarget::new(alpha); - let mut sum = self.zero_extension(); - - for (batch, reduced_openings) in instance[index] - .batches - .iter() - .zip(&precomputed_reduced_evals.reduced_openings_at_point) - { - let FriBatchInfoTarget { point, polynomials } = batch; - let evals = polynomials - .iter() - .map(|p| { - let poly_blinding = instance[index].oracles[p.oracle_index].blinding; - let salted = params.hiding && poly_blinding; - proof.unsalted_eval(p.oracle_index, p.polynomial_index, salted) - }) - .collect_vec(); - let reduced_evals = alpha.reduce_base(&evals, self); - let numerator = self.sub_extension(reduced_evals, *reduced_openings); - let denominator = self.sub_extension(subgroup_x, *point); - sum = alpha.shift(sum, self); - sum = self.div_add_extension(numerator, denominator, sum); - } - - sum - } - - fn batch_fri_verifier_query_round>( - &mut self, - degree_bits: &[usize], - instance: &[FriInstanceInfoTarget], - challenges: &FriChallengesTarget, - precomputed_reduced_evals: &[PrecomputedReducedOpeningsTarget], - initial_merkle_caps: &[MerkleCapTarget], - proof: &FriProofTarget, - x_index: Target, - round_proof: &FriQueryRoundTarget, - params: &FriParams, - ) where - C::Hasher: AlgebraicHasher, - { - let mut n = degree_bits[0]; - - // Note that this `low_bits` decomposition permits non-canonical binary encodings. Here we - // verify that this has a negligible impact on soundness error. - Self::assert_noncanonical_indices_ok(¶ms.config); - let mut x_index_bits = self.low_bits(x_index, n, F::BITS); - - let cap_index = - self.le_sum(x_index_bits[x_index_bits.len() - params.config.cap_height..].iter()); - with_context!( - self, - "check FRI initial proof", - self.batch_fri_verify_initial_proof::( - degree_bits, - instance, - &x_index_bits, - &round_proof.initial_trees_proof, - initial_merkle_caps, - cap_index - ) - ); - - // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. - let mut subgroup_x = with_context!(self, "compute x from its index", { - let g = self.constant(F::coset_shift()); - let phi = F::primitive_root_of_unity(n); - let phi = self.exp_from_bits_const_base(phi, x_index_bits.iter().rev()); - self.mul(g, phi) - }); - - let mut batch_index = 0; - - // old_eval is the last derived evaluation; it will be checked for consistency with its - // committed "parent" value in the next iteration. - let mut old_eval = with_context!( - self, - "combine initial oracles", - self.batch_fri_combine_initial( - instance, - batch_index, - &round_proof.initial_trees_proof, - challenges.fri_alpha, - subgroup_x, - &precomputed_reduced_evals[batch_index], - params, - ) - ); - batch_index += 1; - - for (i, &arity_bits) in params.reduction_arity_bits.iter().enumerate() { - let evals = &round_proof.steps[i].evals; - - // Split x_index into the index of the coset x is in, and the index of x within that coset. - let coset_index_bits = x_index_bits[arity_bits..].to_vec(); - let x_index_within_coset_bits = &x_index_bits[..arity_bits]; - let x_index_within_coset = self.le_sum(x_index_within_coset_bits.iter()); - - // Check consistency with our old evaluation from the previous round. - let new_eval = self.random_access_extension(x_index_within_coset, evals.clone()); - self.connect_extension(new_eval, old_eval); - - // Infer P(y) from {P(x)}_{x^arity=y}. - old_eval = with_context!( - self, - "infer evaluation using interpolation", - self.compute_evaluation( - subgroup_x, - x_index_within_coset_bits, - arity_bits, - evals, - challenges.fri_betas[i], - ) - ); - - with_context!( - self, - "verify FRI round Merkle proof.", - self.verify_merkle_proof_to_cap_with_cap_index::( - flatten_target(evals), - &coset_index_bits, - cap_index, - &proof.commit_phase_merkle_caps[i], - &round_proof.steps[i].merkle_proof, - ) - ); - - // Update the point x to x^arity. - subgroup_x = self.exp_power_of_2(subgroup_x, arity_bits); - - x_index_bits = coset_index_bits; - n -= arity_bits; - - if batch_index < degree_bits.len() && n == degree_bits[batch_index] { - let subgroup_x_init = with_context!(self, "compute init x from its index", { - let g = self.constant(F::coset_shift()); - let phi = F::primitive_root_of_unity(n); - let phi = self.exp_from_bits_const_base(phi, x_index_bits.iter().rev()); - self.mul(g, phi) - }); - let eval = self.batch_fri_combine_initial( - instance, - batch_index, - &round_proof.initial_trees_proof, - challenges.fri_alpha, - subgroup_x_init, - &precomputed_reduced_evals[batch_index], - params, - ); - old_eval = self.mul_extension(old_eval, challenges.fri_betas[i]); - old_eval = self.add_extension(old_eval, eval); - batch_index += 1; - } - } - - // Final check of FRI. After all the reductions, we check that the final polynomial is equal - // to the one sent by the prover. - let eval = with_context!( - self, - &format!( - "evaluate final polynomial of length {}", - proof.final_poly.len() - ), - proof.final_poly.eval_scalar(self, subgroup_x) - ); - self.connect_extension(eval, old_eval); - } -} diff --git a/plonky2/src/batch_fri/verifier.rs b/plonky2/src/batch_fri/verifier.rs deleted file mode 100644 index b7dd552b..00000000 --- a/plonky2/src/batch_fri/verifier.rs +++ /dev/null @@ -1,251 +0,0 @@ -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; - -use anyhow::ensure; -use itertools::Itertools; -use plonky2_field::extension::{flatten, Extendable, FieldExtension}; -use plonky2_field::types::Field; - -use crate::fri::proof::{FriChallenges, FriInitialTreeProof, FriProof, FriQueryRound}; -use crate::fri::structure::{FriBatchInfo, FriInstanceInfo, FriOpenings}; -use crate::fri::validate_shape::validate_batch_fri_proof_shape; -use crate::fri::verifier::{ - compute_evaluation, fri_verify_proof_of_work, PrecomputedReducedOpenings, -}; -use crate::fri::FriParams; -use crate::hash::hash_types::RichField; -use crate::hash::merkle_proofs::{verify_batch_merkle_proof_to_cap, verify_merkle_proof_to_cap}; -use crate::hash::merkle_tree::MerkleCap; -use crate::plonk::config::{GenericConfig, Hasher}; -use crate::util::reducing::ReducingFactor; -use crate::util::reverse_bits; - -pub fn verify_batch_fri_proof< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - degree_bits: &[usize], - instances: &[FriInstanceInfo], - openings: &[FriOpenings], - challenges: &FriChallenges, - initial_merkle_cap: &[MerkleCap], - proof: &FriProof, - params: &FriParams, -) -> anyhow::Result<()> { - validate_batch_fri_proof_shape::(proof, instances, params)?; - - // Check PoW. - fri_verify_proof_of_work(challenges.fri_pow_response, ¶ms.config)?; - - // Check that parameters are coherent. - ensure!( - params.config.num_query_rounds == proof.query_round_proofs.len(), - "Number of query rounds does not match config." - ); - - let mut precomputed_reduced_evals = Vec::with_capacity(openings.len()); - for opn in openings { - let pre = PrecomputedReducedOpenings::from_os_and_alpha(opn, challenges.fri_alpha); - precomputed_reduced_evals.push(pre); - } - let degree_bits = degree_bits - .iter() - .map(|d| d + params.config.rate_bits) - .collect_vec(); - for (&x_index, round_proof) in challenges - .fri_query_indices - .iter() - .zip(&proof.query_round_proofs) - { - batch_fri_verifier_query_round::( - °ree_bits, - instances, - challenges, - &precomputed_reduced_evals, - initial_merkle_cap, - proof, - x_index, - round_proof, - params, - )?; - } - - Ok(()) -} - -fn batch_fri_verify_initial_proof, H: Hasher, const D: usize>( - degree_bits: &[usize], - instances: &[FriInstanceInfo], - x_index: usize, - proof: &FriInitialTreeProof, - initial_merkle_caps: &[MerkleCap], -) -> anyhow::Result<()> { - for (oracle_index, ((evals, merkle_proof), cap)) in proof - .evals_proofs - .iter() - .zip(initial_merkle_caps) - .enumerate() - { - let leaves = instances - .iter() - .scan(0, |leaf_index, inst| { - let num_polys = inst.oracles[oracle_index].num_polys; - let leaves = (*leaf_index..*leaf_index + num_polys) - .map(|idx| evals[idx]) - .collect::>(); - *leaf_index += num_polys; - Some(leaves) - }) - .collect::>(); - - verify_batch_merkle_proof_to_cap::(&leaves, degree_bits, x_index, cap, merkle_proof)?; - } - - Ok(()) -} - -fn batch_fri_combine_initial< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - instances: &[FriInstanceInfo], - index: usize, - proof: &FriInitialTreeProof, - alpha: F::Extension, - subgroup_x: F, - precomputed_reduced_evals: &PrecomputedReducedOpenings, - params: &FriParams, -) -> F::Extension { - assert!(D > 1, "Not implemented for D=1."); - let subgroup_x = F::Extension::from_basefield(subgroup_x); - let mut alpha = ReducingFactor::new(alpha); - let mut sum = F::Extension::ZERO; - - for (batch, reduced_openings) in instances[index] - .batches - .iter() - .zip(&precomputed_reduced_evals.reduced_openings_at_point) - { - let FriBatchInfo { point, polynomials } = batch; - let evals = polynomials - .iter() - .map(|p| { - let poly_blinding = instances[index].oracles[p.oracle_index].blinding; - let salted = params.hiding && poly_blinding; - proof.unsalted_eval(p.oracle_index, p.polynomial_index, salted) - }) - .map(F::Extension::from_basefield); - let reduced_evals = alpha.reduce(evals); - let numerator = reduced_evals - *reduced_openings; - let denominator = subgroup_x - *point; - sum = alpha.shift(sum); - sum += numerator / denominator; - } - - sum -} - -fn batch_fri_verifier_query_round< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - degree_bits: &[usize], - instances: &[FriInstanceInfo], - challenges: &FriChallenges, - precomputed_reduced_evals: &[PrecomputedReducedOpenings], - initial_merkle_caps: &[MerkleCap], - proof: &FriProof, - mut x_index: usize, - round_proof: &FriQueryRound, - params: &FriParams, -) -> anyhow::Result<()> { - batch_fri_verify_initial_proof::( - degree_bits, - instances, - x_index, - &round_proof.initial_trees_proof, - initial_merkle_caps, - )?; - let mut n = degree_bits[0]; - // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. - let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR - * F::primitive_root_of_unity(n).exp_u64(reverse_bits(x_index, n) as u64); - - let mut batch_index = 0; - // old_eval is the last derived evaluation; it will be checked for consistency with its - // committed "parent" value in the next iteration. - let mut old_eval = batch_fri_combine_initial::( - instances, - batch_index, - &round_proof.initial_trees_proof, - challenges.fri_alpha, - subgroup_x, - &precomputed_reduced_evals[batch_index], - params, - ); - batch_index += 1; - - for (i, &arity_bits) in params.reduction_arity_bits.iter().enumerate() { - let arity = 1 << arity_bits; - let evals = &round_proof.steps[i].evals; - - // Split x_index into the index of the coset x is in, and the index of x within that coset. - let coset_index = x_index >> arity_bits; - let x_index_within_coset = x_index & (arity - 1); - - // Check consistency with our old evaluation from the previous round. - ensure!(evals[x_index_within_coset] == old_eval); - - old_eval = compute_evaluation( - subgroup_x, - x_index_within_coset, - arity_bits, - evals, - challenges.fri_betas[i], - ); - verify_merkle_proof_to_cap::( - flatten(evals), - coset_index, - &proof.commit_phase_merkle_caps[i], - &round_proof.steps[i].merkle_proof, - )?; - - // Update the point x to x^arity. - subgroup_x = subgroup_x.exp_power_of_2(arity_bits); - x_index = coset_index; - n -= arity_bits; - - if batch_index < degree_bits.len() && n == degree_bits[batch_index] { - let subgroup_x_init = F::MULTIPLICATIVE_GROUP_GENERATOR - * F::primitive_root_of_unity(n).exp_u64(reverse_bits(x_index, n) as u64); - let eval = batch_fri_combine_initial::( - instances, - batch_index, - &round_proof.initial_trees_proof, - challenges.fri_alpha, - subgroup_x_init, - &precomputed_reduced_evals[batch_index], - params, - ); - old_eval = old_eval * challenges.fri_betas[i] + eval; - batch_index += 1; - } - } - assert_eq!( - batch_index, - instances.len(), - "Wrong number of folded instances." - ); - - // Final check of FRI. After all the reductions, we check that the final polynomial is equal - // to the one sent by the prover. - ensure!( - proof.final_poly.eval(subgroup_x.into()) == old_eval, - "Final polynomial evaluation is invalid." - ); - - Ok(()) -} diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index 424e03ae..cb9b0b21 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -238,6 +238,7 @@ impl, const D: usize> CircuitBuilder { } } +/* /// Same as `verify_batch_merkle_proof_to_cap`, except with the final "cap index" as separate parameter, /// rather than being contained in `leaf_index_bits`. pub(crate) fn verify_batch_merkle_proof_to_cap_with_cap_index>( @@ -293,6 +294,7 @@ impl, const D: usize> CircuitBuilder { self.connect(result, state.elements[i]); } } +*/ pub fn connect_hashes(&mut self, x: HashOutTarget, y: HashOutTarget) { for i in 0..NUM_HASH_OUT_ELTS { diff --git a/plonky2/src/lib.rs b/plonky2/src/lib.rs index 8772ecfc..8955194f 100644 --- a/plonky2/src/lib.rs +++ b/plonky2/src/lib.rs @@ -11,7 +11,6 @@ pub extern crate alloc; #[doc(inline)] pub use plonky2_field as field; -pub mod batch_fri; pub mod fri; pub mod gadgets; pub mod gates;