use plonky2::field::extension_field::Extendable; use plonky2::field::polynomial::PolynomialCoeffs; use plonky2::fri::proof::{FriProof, FriProofTarget}; use plonky2::gadgets::polynomial::PolynomialCoeffsExtTarget; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::target::Target; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use crate::all_stark::AllStark; use crate::config::StarkConfig; use crate::permutation::{ get_grand_product_challenge_set, get_n_grand_product_challenge_sets, get_n_permutation_challenge_sets_target, }; use crate::proof::*; use crate::stark::Stark; fn get_challenges( challenger: &mut Challenger, stark: &S, trace_cap: &MerkleCap, permutation_ctl_zs_cap: Option<&MerkleCap>, quotient_polys_cap: &MerkleCap, openings: &StarkOpeningSet, commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, config: &StarkConfig, degree_bits: usize, ) -> StarkProofChallenges where F: RichField + Extendable, C: GenericConfig, S: Stark, { let num_challenges = config.num_challenges; let permutation_challenge_sets = stark.uses_permutation_args().then(|| { get_n_grand_product_challenge_sets( challenger, num_challenges, stark.permutation_batch_size(), ) }); if let Some(cap) = permutation_ctl_zs_cap { challenger.observe_cap(cap); } let stark_alphas = challenger.get_n_challenges(num_challenges); challenger.observe_cap(quotient_polys_cap); let stark_zeta = challenger.get_extension_challenge::(); challenger.observe_openings(&openings.to_fri_openings()); StarkProofChallenges { permutation_challenge_sets, stark_alphas, stark_zeta, fri_challenges: challenger.fri_challenges::( commit_phase_merkle_caps, final_poly, pow_witness, degree_bits, &config.fri_config, ), } } impl, C: GenericConfig, const D: usize> AllProof { /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges( &self, all_stark: &AllStark, config: &StarkConfig, ) -> AllProofChallenges { let mut challenger = Challenger::::new(); for proof in self.proofs() { challenger.observe_cap(&proof.proof.trace_cap); } let ctl_challenges = get_grand_product_challenge_set(&mut challenger, config.num_challenges); AllProofChallenges { cpu_challenges: self.cpu_proof.get_challenges( &mut challenger, &all_stark.cpu_stark, config, ), keccak_challenges: self.keccak_proof.get_challenges( &mut challenger, &all_stark.keccak_stark, config, ), ctl_challenges, } } } impl StarkProofWithPublicInputs where F: RichField + Extendable, C: GenericConfig, { // TODO: Should be used later in compression? #![allow(dead_code)] pub(crate) fn fri_query_indices>( &self, stark: &S, config: &StarkConfig, ) -> Vec { let mut challenger = Challenger::new(); self.get_challenges(&mut challenger, stark, config) .fri_challenges .fri_query_indices } /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges>( &self, challenger: &mut Challenger, stark: &S, config: &StarkConfig, ) -> StarkProofChallenges { let degree_bits = self.proof.recover_degree_bits(config); let StarkProof { trace_cap, permutation_ctl_zs_cap, quotient_polys_cap, openings, opening_proof: FriProof { commit_phase_merkle_caps, final_poly, pow_witness, .. }, } = &self.proof; get_challenges::( challenger, stark, trace_cap, permutation_ctl_zs_cap.as_ref(), quotient_polys_cap, openings, commit_phase_merkle_caps, final_poly, *pow_witness, config, degree_bits, ) } } #[allow(clippy::too_many_arguments)] pub(crate) fn get_challenges_target< F: RichField + Extendable, C: GenericConfig, S: Stark, const D: usize, >( builder: &mut CircuitBuilder, stark: &S, trace_cap: &MerkleCapTarget, permutation_zs_cap: Option<&MerkleCapTarget>, quotient_polys_cap: &MerkleCapTarget, openings: &StarkOpeningSetTarget, commit_phase_merkle_caps: &[MerkleCapTarget], final_poly: &PolynomialCoeffsExtTarget, pow_witness: Target, config: &StarkConfig, ) -> StarkProofChallengesTarget where C::Hasher: AlgebraicHasher, { let num_challenges = config.num_challenges; let mut challenger = RecursiveChallenger::::new(builder); challenger.observe_cap(trace_cap); let permutation_challenge_sets = permutation_zs_cap.map(|permutation_zs_cap| { let tmp = get_n_permutation_challenge_sets_target( builder, &mut challenger, num_challenges, stark.permutation_batch_size(), ); challenger.observe_cap(permutation_zs_cap); tmp }); let stark_alphas = challenger.get_n_challenges(builder, num_challenges); challenger.observe_cap(quotient_polys_cap); let stark_zeta = challenger.get_extension_challenge(builder); challenger.observe_openings(&openings.to_fri_openings()); StarkProofChallengesTarget { permutation_challenge_sets, stark_alphas, stark_zeta, fri_challenges: challenger.fri_challenges::( builder, commit_phase_merkle_caps, final_poly, pow_witness, &config.fri_config, ), } } impl StarkProofWithPublicInputsTarget { pub(crate) fn get_challenges< F: RichField + Extendable, C: GenericConfig, S: Stark, >( &self, builder: &mut CircuitBuilder, stark: &S, config: &StarkConfig, ) -> StarkProofChallengesTarget where C::Hasher: AlgebraicHasher, { let StarkProofTarget { trace_cap, permutation_zs_cap, quotient_polys_cap, openings, opening_proof: FriProofTarget { commit_phase_merkle_caps, final_poly, pow_witness, .. }, } = &self.proof; get_challenges_target::( builder, stark, trace_cap, permutation_zs_cap.as_ref(), quotient_polys_cap, openings, commit_phase_merkle_caps, final_poly, *pow_witness, config, ) } } // TODO: Deal with the compressed stuff. // impl, C: GenericConfig, const D: usize> // CompressedProofWithPublicInputs // { // /// Computes all Fiat-Shamir challenges used in the Plonk proof. // pub(crate) fn get_challenges( // &self, // common_data: &CommonCircuitData, // ) -> anyhow::Result> { // let CompressedProof { // wires_cap, // plonk_zs_partial_products_cap, // quotient_polys_cap, // openings, // opening_proof: // CompressedFriProof { // commit_phase_merkle_caps, // final_poly, // pow_witness, // .. // }, // } = &self.proof; // // get_challenges( // self.get_public_inputs_hash(), // wires_cap, // plonk_zs_partial_products_cap, // quotient_polys_cap, // openings, // commit_phase_merkle_caps, // final_poly, // *pow_witness, // common_data, // ) // } // // /// Computes all coset elements that can be inferred in the FRI reduction steps. // 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 = PrecomputedReducedOpenings::from_os_and_alpha( // &self.proof.openings.to_fri_openings(), // *fri_alpha, // ); // let log_n = common_data.degree_bits + common_data.config.fri_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 { // 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::( // &common_data.get_fri_instance(*plonk_zeta), // &self // .proof // .opening_proof // .query_round_proofs // .initial_trees_proofs[&x_index], // *fri_alpha, // subgroup_x, // &precomputed_reduced_evals, // &common_data.fri_params, // ); // for (i, &arity_bits) in common_data // .fri_params // .reduction_arity_bits // .iter() // .enumerate() // { // let coset_index = x_index >> arity_bits; // if !seen_indices_by_depth[i].insert(coset_index) { // // If this index has already been seen, we can skip the rest of the reductions. // break; // } // fri_inferred_elements.push(old_eval); // let arity = 1 << arity_bits; // let mut evals = self.proof.opening_proof.query_round_proofs.steps[i][&coset_index] // .evals // .clone(); // let x_index_within_coset = x_index & (arity - 1); // evals.insert(x_index_within_coset, old_eval); // old_eval = compute_evaluation( // subgroup_x, // x_index_within_coset, // arity_bits, // &evals, // fri_betas[i], // ); // subgroup_x = subgroup_x.exp_power_of_2(arity_bits); // x_index = coset_index; // } // } // FriInferredElements(fri_inferred_elements) // } // }