use plonky2::field::extension_field::Extendable; use plonky2::hash::hash_types::RichField; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::GenericConfig; use crate::config::StarkConfig; use crate::proof::StarkProofWithPublicInputsTarget; use crate::stark::Stark; pub fn verify_stark_proof< F: RichField + Extendable, C: GenericConfig, S: Stark, const D: usize, >( builder: &mut CircuitBuilder, stark: S, proof_with_pis: StarkProofWithPublicInputsTarget, inner_config: &StarkConfig ) { let StarkProofWithPublicInputsTarget { proof, public_inputs, } = proof_with_pis; assert_eq!(public_inputs.len(), inner_common_data.num_public_inputs); let public_inputs_hash = self.hash_n_to_hash_no_pad::(public_inputs); self.verify_proof( proof, public_inputs_hash, inner_verifier_data, inner_common_data, ); } /// Recursively verifies an inner proof. pub fn verify_proof>( &mut self, proof: ProofTarget, public_inputs_hash: HashOutTarget, inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where C::Hasher: AlgebraicHasher, { let one = self.one_extension(); let num_challenges = inner_common_data.config.num_challenges; let mut challenger = RecursiveChallenger::::new(self); let (betas, gammas, alphas, zeta) = with_context!(self, "observe proof and generates challenges", { // Observe the instance. let digest = HashOutTarget::from_vec( self.constants(&inner_common_data.circuit_digest.elements), ); challenger.observe_hash(&digest); challenger.observe_hash(&public_inputs_hash); challenger.observe_cap(&proof.wires_cap); let betas = challenger.get_n_challenges(self, num_challenges); let gammas = challenger.get_n_challenges(self, num_challenges); challenger.observe_cap(&proof.plonk_zs_partial_products_cap); let alphas = challenger.get_n_challenges(self, num_challenges); challenger.observe_cap(&proof.quotient_polys_cap); let zeta = challenger.get_extension_challenge(self); (betas, gammas, alphas, zeta) }); let local_constants = &proof.openings.constants; let local_wires = &proof.openings.wires; let vars = EvaluationTargets { local_constants, local_wires, public_inputs_hash: &public_inputs_hash, }; let local_zs = &proof.openings.plonk_zs; let next_zs = &proof.openings.plonk_zs_right; let s_sigmas = &proof.openings.plonk_sigmas; let partial_products = &proof.openings.partial_products; let zeta_pow_deg = self.exp_power_of_2_extension(zeta, inner_common_data.degree_bits); let vanishing_polys_zeta = with_context!( self, "evaluate the vanishing polynomial at our challenge point, zeta.", eval_vanishing_poly_recursively( self, inner_common_data, zeta, zeta_pow_deg, vars, local_zs, next_zs, partial_products, s_sigmas, &betas, &gammas, &alphas, ) ); with_context!(self, "check vanishing and quotient polynomials.", { let quotient_polys_zeta = &proof.openings.quotient_polys; let mut scale = ReducingFactorTarget::new(zeta_pow_deg); let z_h_zeta = self.sub_extension(zeta_pow_deg, one); for (i, chunk) in quotient_polys_zeta .chunks(inner_common_data.quotient_degree_factor) .enumerate() { let recombined_quotient = scale.reduce(chunk, self); let computed_vanishing_poly = self.mul_extension(z_h_zeta, recombined_quotient); self.connect_extension(vanishing_polys_zeta[i], computed_vanishing_poly); } }); let merkle_caps = &[ inner_verifier_data.constants_sigmas_cap.clone(), proof.wires_cap, proof.plonk_zs_partial_products_cap, proof.quotient_polys_cap, ]; let fri_instance = inner_common_data.get_fri_instance_target(self, zeta); with_context!( self, "verify FRI proof", self.verify_fri_proof::( &fri_instance, &proof.openings, merkle_caps, &proof.opening_proof, &mut challenger, &inner_common_data.fri_params, ) ); } pub fn add_virtual_proof_with_pis>( &mut self, common_data: &CommonCircuitData, ) -> ProofWithPublicInputsTarget { let proof = self.add_virtual_proof(common_data); let public_inputs = self.add_virtual_targets(common_data.num_public_inputs); ProofWithPublicInputsTarget { proof, public_inputs, } } fn add_virtual_proof>( &mut self, common_data: &CommonCircuitData, ) -> ProofTarget { let config = &common_data.config; let fri_params = &common_data.fri_params; let cap_height = fri_params.config.cap_height; let num_leaves_per_oracle = &[ common_data.num_preprocessed_polys(), config.num_wires, common_data.num_zs_partial_products_polys(), common_data.num_quotient_polys(), ]; ProofTarget { wires_cap: self.add_virtual_cap(cap_height), plonk_zs_partial_products_cap: self.add_virtual_cap(cap_height), quotient_polys_cap: self.add_virtual_cap(cap_height), openings: self.add_opening_set(common_data), opening_proof: self.add_virtual_fri_proof(num_leaves_per_oracle, fri_params), } } fn add_opening_set>( &mut self, common_data: &CommonCircuitData, ) -> OpeningSetTarget { let config = &common_data.config; let num_challenges = config.num_challenges; let total_partial_products = num_challenges * common_data.num_partial_products; OpeningSetTarget { constants: self.add_virtual_extension_targets(common_data.num_constants), plonk_sigmas: self.add_virtual_extension_targets(config.num_routed_wires), wires: self.add_virtual_extension_targets(config.num_wires), plonk_zs: self.add_virtual_extension_targets(num_challenges), plonk_zs_right: self.add_virtual_extension_targets(num_challenges), partial_products: self.add_virtual_extension_targets(total_partial_products), quotient_polys: self.add_virtual_extension_targets(common_data.num_quotient_polys()), } } }