diff --git a/src/fri/proof.rs b/src/fri/proof.rs index 03239629..f6875fcc 100644 --- a/src/fri/proof.rs +++ b/src/fri/proof.rs @@ -14,7 +14,7 @@ use crate::hash::path_compression::{compress_merkle_proofs, decompress_merkle_pr use crate::iop::target::Target; use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::plonk_common::PolynomialsIndexBlinding; -use crate::plonk::proof::ProofChallenges; +use crate::plonk::proof::{FriInferredElements, ProofChallenges}; use crate::polynomial::polynomial::PolynomialCoeffs; /// Evaluations and Merkle proof produced by the prover in a FRI query step. @@ -236,6 +236,7 @@ impl, const D: usize> CompressedFriProof { pub(crate) fn decompress( self, challenges: &ProofChallenges, + fri_inferred_elements: FriInferredElements, common_data: &CommonCircuitData, ) -> FriProof { let CompressedFriProof { @@ -247,14 +248,9 @@ impl, const D: usize> CompressedFriProof { } = self; let ProofChallenges { fri_query_indices: indices, - fri_query_inferred_elements, .. } = challenges; - let mut fri_query_inferred_elements = if let Some(v) = fri_query_inferred_elements { - v.iter().copied() - } else { - panic!("Proof challenges must be computed with `CompressedProofWithPublicInputs::get_challenges()`.") - }; + let mut fri_inferred_elements = fri_inferred_elements.0.into_iter(); let cap_height = common_data.config.cap_height; let reduction_arity_bits = &common_data.fri_params.reduction_arity_bits; let num_reductions = reduction_arity_bits.len(); @@ -309,10 +305,7 @@ impl, const D: usize> CompressedFriProof { evals = v.to_vec(); } else { // Otherwise insert the next inferred element. - evals.insert( - index_within_coset, - fri_query_inferred_elements.next().unwrap(), - ); + evals.insert(index_within_coset, fri_inferred_elements.next().unwrap()); evals_by_depth[i].insert(index, evals.clone()); } steps_evals[i].push(flatten(&evals)); diff --git a/src/plonk/get_challenges.rs b/src/plonk/get_challenges.rs index 8981e263..63802689 100644 --- a/src/plonk/get_challenges.rs +++ b/src/plonk/get_challenges.rs @@ -7,7 +7,7 @@ use crate::hash::hashing::hash_n_to_1; use crate::iop::challenger::Challenger; use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::proof::{ - CompressedProofWithPublicInputs, ProofChallenges, ProofWithPublicInputs, + CompressedProofWithPublicInputs, FriInferredElements, ProofChallenges, ProofWithPublicInputs, }; use crate::util::reverse_bits; @@ -87,7 +87,6 @@ impl, const D: usize> ProofWithPublicInputs { fri_betas, fri_pow_response, fri_query_indices, - fri_query_inferred_elements: None, }) } } @@ -152,16 +151,39 @@ impl, const D: usize> CompressedProofWithPublicInpu .map(|_| challenger.get_challenge().to_canonical_u64() as usize % lde_size) .collect::>(); - let mut fri_query_inferred_elements = Vec::new(); + Ok(ProofChallenges { + plonk_betas, + plonk_gammas, + plonk_alphas, + plonk_zeta, + fri_alpha, + fri_betas, + fri_pow_response, + fri_query_indices, + }) + } + pub(crate) fn get_inferred_elements( + &self, + challenges: &ProofChallenges, + common_data: &CommonCircuitData, + ) -> FriInferredElements { + let ProofChallenges { + plonk_zeta, + fri_alpha, + fri_betas, + fri_query_indices, + .. + } = challenges; + let mut fri_inferred_elements = Vec::new(); // Holds the indices that have already been seen at each reduction depth. let mut seen_indices_by_depth = vec![HashSet::new(); common_data.fri_params.reduction_arity_bits.len()]; let precomputed_reduced_evals = - PrecomputedReducedEvals::from_os_and_alpha(&self.proof.openings, fri_alpha); + PrecomputedReducedEvals::from_os_and_alpha(&self.proof.openings, *fri_alpha); let log_n = common_data.degree_bits + common_data.config.rate_bits; // Simulate the proof verification and collect the inferred elements. // The content of the loop is basically the same as the `fri_verifier_query_round` function. - for &(mut x_index) in &fri_query_indices { + for &(mut x_index) in fri_query_indices { let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR * F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64); let mut old_eval = fri_combine_initial( @@ -170,8 +192,8 @@ impl, const D: usize> CompressedProofWithPublicInpu .opening_proof .query_round_proofs .initial_trees_proofs[&x_index], - fri_alpha, - plonk_zeta, + *fri_alpha, + *plonk_zeta, subgroup_x, precomputed_reduced_evals, common_data, @@ -186,7 +208,7 @@ impl, const D: usize> CompressedProofWithPublicInpu // If this index has already been seen, we can skip the rest of the reductions. break; } - fri_query_inferred_elements.push(old_eval); + fri_inferred_elements.push(old_eval); let arity = 1 << arity_bits; let mut evals = self.proof.opening_proof.query_round_proofs.steps[i] [&(x_index >> arity_bits)] @@ -205,17 +227,6 @@ impl, const D: usize> CompressedProofWithPublicInpu x_index >>= arity_bits; } } - - Ok(ProofChallenges { - plonk_betas, - plonk_gammas, - plonk_alphas, - plonk_zeta, - fri_alpha, - fri_betas, - fri_pow_response, - fri_query_indices, - fri_query_inferred_elements: Some(fri_query_inferred_elements), - }) + FriInferredElements(fri_inferred_elements) } } diff --git a/src/plonk/proof.rs b/src/plonk/proof.rs index 29cac3cc..4dfa26bd 100644 --- a/src/plonk/proof.rs +++ b/src/plonk/proof.rs @@ -122,6 +122,7 @@ impl, const D: usize> CompressedProof { pub(crate) fn decompress( self, challenges: &ProofChallenges, + fri_inferred_elements: FriInferredElements, common_data: &CommonCircuitData, ) -> Proof { let CompressedProof { @@ -137,7 +138,11 @@ impl, const D: usize> CompressedProof { plonk_zs_partial_products_cap, quotient_polys_cap, openings, - opening_proof: opening_proof.decompress(challenges, common_data), + opening_proof: opening_proof.decompress( + &challenges, + fri_inferred_elements, + common_data, + ), } } } @@ -155,7 +160,10 @@ impl, const D: usize> CompressedProofWithPublicInpu common_data: &CommonCircuitData, ) -> anyhow::Result> { let challenges = self.get_challenges(common_data)?; - let compressed_proof = self.proof.decompress(&challenges, common_data); + let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); + let compressed_proof = + self.proof + .decompress(&challenges, fri_inferred_elements, common_data); Ok(ProofWithPublicInputs { public_inputs: self.public_inputs, proof: compressed_proof, @@ -168,7 +176,10 @@ impl, const D: usize> CompressedProofWithPublicInpu common_data: &CommonCircuitData, ) -> anyhow::Result<()> { let challenges = self.get_challenges(common_data)?; - let compressed_proof = self.proof.decompress(&challenges, common_data); + let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); + let compressed_proof = + self.proof + .decompress(&challenges, fri_inferred_elements, common_data); verify_with_challenges( ProofWithPublicInputs { public_inputs: self.public_inputs, @@ -223,12 +234,13 @@ pub(crate) struct ProofChallenges, const D: usize> // Indices at which the oracle is queried in FRI. pub fri_query_indices: Vec, - - // Coset element that can be inferred in the FRI reduction step. - // Is typically set to None iff the challenges are computed from a non-compressed proof. - pub fri_query_inferred_elements: Option>, } +/// Coset element that can be inferred in the FRI reduction step. +pub(crate) struct FriInferredElements, const D: usize>( + pub Vec, +); + pub struct ProofWithPublicInputsTarget { pub proof: ProofTarget, pub public_inputs: Vec,