diff --git a/plonky2/src/fri/challenges.rs b/plonky2/src/fri/challenges.rs index 1252f54cad..b261a55e31 100644 --- a/plonky2/src/fri/challenges.rs +++ b/plonky2/src/fri/challenges.rs @@ -33,7 +33,7 @@ impl> Challenger { degree_bits: usize, config: &FriConfig, final_poly_coeff_len: Option, - query_round_step_count: Option, + max_num_query_steps: Option, ) -> FriChallenges where F: RichField + Extendable, @@ -54,7 +54,7 @@ impl> Challenger { // When this proof was generated in a circuit with a different number of query steps, // the challenger needs to observe the additional hash caps. - if let Some(step_count) = query_round_step_count { + if let Some(step_count) = max_num_query_steps { let cap_len = (1 << config.cap_height) * NUM_HASH_OUT_ELTS; let zero_cap = vec![F::ZERO; cap_len]; for _ in commit_phase_merkle_caps.len()..step_count { diff --git a/plonky2/src/fri/oracle.rs b/plonky2/src/fri/oracle.rs index aca68d672d..e413071a45 100644 --- a/plonky2/src/fri/oracle.rs +++ b/plonky2/src/fri/oracle.rs @@ -179,7 +179,7 @@ impl, C: GenericConfig, const D: usize> challenger: &mut Challenger, fri_params: &FriParams, final_poly_coeff_len: Option, - query_round_step_count: Option, + max_num_query_steps: Option, timing: &mut TimingTree, ) -> FriProof { assert!(D > 1, "Not implemented for D=1."); @@ -229,7 +229,7 @@ impl, C: GenericConfig, const D: usize> challenger, fri_params, final_poly_coeff_len, - query_round_step_count, + max_num_query_steps, timing, ); diff --git a/plonky2/src/fri/prover.rs b/plonky2/src/fri/prover.rs index 44f67a136a..24c88ced70 100644 --- a/plonky2/src/fri/prover.rs +++ b/plonky2/src/fri/prover.rs @@ -30,7 +30,7 @@ pub fn fri_proof, C: GenericConfig, const challenger: &mut Challenger, fri_params: &FriParams, final_poly_coeff_len: Option, - query_round_step_count: Option, + max_num_query_steps: Option, timing: &mut TimingTree, ) -> FriProof { let n = lde_polynomial_values.len(); @@ -46,7 +46,7 @@ pub fn fri_proof, C: GenericConfig, const challenger, fri_params, final_poly_coeff_len, - query_round_step_count, + max_num_query_steps, ) ); @@ -87,7 +87,7 @@ fn fri_committed_trees, C: GenericConfig, challenger: &mut Challenger, fri_params: &FriParams, final_poly_coeff_len: Option, - query_round_step_count: Option, + max_num_query_steps: Option, ) -> FriCommitedTrees { let mut trees = Vec::with_capacity(fri_params.reduction_arity_bits.len()); @@ -120,8 +120,9 @@ fn fri_committed_trees, C: GenericConfig, } // When verifying this proof in a circuit with a different number of query steps, - // the challenger needs to observe the additional hash caps. - if let Some(step_count) = query_round_step_count { + // we need the challenger to stay in sync with the verifier. Therefore, the challenger + // must observe the additional hash caps and generate dummy challenges. + if let Some(step_count) = max_num_query_steps { let cap_len = (1 << fri_params.config.cap_height) * NUM_HASH_OUT_ELTS; let zero_cap = vec![F::ZERO; cap_len]; for _ in fri_params.reduction_arity_bits.len()..step_count { diff --git a/plonky2/src/fri/recursive_verifier.rs b/plonky2/src/fri/recursive_verifier.rs index dd5d147088..f2880f678f 100644 --- a/plonky2/src/fri/recursive_verifier.rs +++ b/plonky2/src/fri/recursive_verifier.rs @@ -180,6 +180,12 @@ impl, const D: usize> CircuitBuilder { } } + /// Verifies the current FRI proof with `current_degree_bits`, which may differ from the + /// circuit's `degree_bits` in `params`. + /// The circuit uses random access gates to select and connect the current hash/evaluation + /// values with those in the proof. It is designed with the maximum number of query/folding + /// steps and final polynomial length at `degree_bits`, "skipping" steps when the actual proof + /// has fewer. pub fn verify_fri_proof_with_multiple_degree_bits>( &mut self, instance: &FriInstanceInfoTarget, @@ -208,7 +214,7 @@ impl, const D: usize> CircuitBuilder { let log_n = params.config.rate_bits + params.degree_bits; let mut current_log_n = self.constant(F::from_canonical_usize(params.config.rate_bits)); current_log_n = self.add(current_log_n, current_degree_bits); - let min_log_n_to_support = log_n - (params.degree_bits - min_degree_bits_to_support); + let min_log_n_to_support = params.config.rate_bits + min_degree_bits_to_support; with_context!( self, @@ -517,7 +523,7 @@ impl, const D: usize> CircuitBuilder { self.le_sum(x_index_bits[slice_start..n].iter()) }) .collect(); - let cap_index = self.random_access_with_padding(n_index, cap_indices); + let cap_index = self.random_access(n_index, cap_indices); with_context!( self, "check FRI initial proof", @@ -545,7 +551,7 @@ impl, const D: usize> CircuitBuilder { }) .collect(); - let mut subgroup_x = self.random_access_with_padding(n_index, subgroup_x_vec); + let mut subgroup_x = self.random_access(n_index, subgroup_x_vec); // old_eval is the last derived evaluation; it will be checked for consistency with its // committed "parent" value in the next iteration. @@ -564,8 +570,8 @@ impl, const D: usize> CircuitBuilder { let mut index_in_degree_sub_one_bits_vec = { let mut degree_bits_len = degree_sub_one_bits_vec.len(); - for artity_bits in ¶ms.reduction_arity_bits { - degree_bits_len -= artity_bits; + for arity_bits in ¶ms.reduction_arity_bits { + degree_bits_len -= arity_bits; } degree_bits_len }; @@ -578,8 +584,7 @@ impl, const D: usize> CircuitBuilder { 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_with_padding(x_index_within_coset, evals.clone()); + let new_eval = self.random_access_extension(x_index_within_coset, evals.clone()); let step_active = degree_sub_one_bits_vec[index_in_degree_sub_one_bits_vec]; self.conditional_assert_eq_ext(step_active.target, new_eval, old_eval); diff --git a/plonky2/src/gadgets/random_access.rs b/plonky2/src/gadgets/random_access.rs index f740b6a6bb..543248bf4f 100644 --- a/plonky2/src/gadgets/random_access.rs +++ b/plonky2/src/gadgets/random_access.rs @@ -15,6 +15,15 @@ use crate::util::log2_strict; impl, const D: usize> CircuitBuilder { /// Checks that a `Target` matches a vector at a particular index. pub fn random_access(&mut self, access_index: Target, v: Vec) -> Target { + let mut v = v; + let current_len = v.len(); + let next_power_of_two = current_len.next_power_of_two(); + if current_len < next_power_of_two { + // Get the last element (if there is one) and extend with it + if let Some(&last) = v.last() { + v.extend(repeat_n(last, next_power_of_two - current_len)); + } + } let vec_size = v.len(); let bits = log2_strict(vec_size); debug_assert!(vec_size > 0); @@ -41,38 +50,11 @@ impl, const D: usize> CircuitBuilder { claimed_element } - /// Like `random_access`, but padding `v` with the last element to a power of two. - pub fn random_access_with_padding(&mut self, access_index: Target, v: Vec) -> Target { - let mut v = v; - let current_len = v.len(); - let next_power_of_two = current_len.next_power_of_two(); - if current_len < next_power_of_two { - // Get the last element (if there is one) and extend with it - if let Some(&last) = v.last() { - v.extend(repeat_n(last, next_power_of_two - current_len)); - } - } - self.random_access(access_index, v) - } - /// Like `random_access`, but with `ExtensionTarget`s rather than simple `Target`s. pub fn random_access_extension( &mut self, access_index: Target, v: Vec>, - ) -> ExtensionTarget { - let selected: Vec<_> = (0..D) - .map(|i| self.random_access(access_index, v.iter().map(|et| et.0[i]).collect())) - .collect(); - - ExtensionTarget(selected.try_into().unwrap()) - } - - /// Like `random_access_extension`, but padding `v` with the last element to a power of two. - pub fn random_access_extension_with_padding( - &mut self, - access_index: Target, - v: Vec>, ) -> ExtensionTarget { let mut v = v; let current_len = v.len(); @@ -83,7 +65,11 @@ impl, const D: usize> CircuitBuilder { v.extend(repeat_n(last, next_power_of_two - current_len)); } } - self.random_access_extension(access_index, v) + let selected: Vec<_> = (0..D) + .map(|i| self.random_access(access_index, v.iter().map(|et| et.0[i]).collect())) + .collect(); + + ExtensionTarget(selected.try_into().unwrap()) } /// Like `random_access`, but with `HashOutTarget`s rather than simple `Target`s. diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index 21a822fa19..424e03ae64 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -226,11 +226,11 @@ impl, const D: usize> CircuitBuilder { } for i in 0..NUM_HASH_OUT_ELTS { - let result = self.random_access_with_padding( + let result = self.random_access( cap_index, merkle_cap.0.iter().map(|h| h.elements[i]).collect(), ); - let state = self.random_access_with_padding( + let state = self.random_access( n_index, final_states.iter().map(|s| s.elements[i]).collect(), ); diff --git a/starky/src/get_challenges.rs b/starky/src/get_challenges.rs index c14cb80904..7766e4403f 100644 --- a/starky/src/get_challenges.rs +++ b/starky/src/get_challenges.rs @@ -70,7 +70,7 @@ where challenger.observe_openings(&openings.to_fri_openings()); - let (final_poly_coeff_len, query_round_step_count) = + let (final_poly_coeff_len, max_num_query_steps) = if let Some(verifier_circuit_fri_params) = verifier_circuit_fri_params { ( Some(final_poly_coeff_len( @@ -94,7 +94,7 @@ where degree_bits, &config.fri_config, final_poly_coeff_len, - query_round_step_count, + max_num_query_steps, ), } } diff --git a/starky/src/prover.rs b/starky/src/prover.rs index a889719b20..b3e0f90fef 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -59,7 +59,7 @@ where fri_params.total_arities() <= degree_bits + rate_bits - cap_height, "FRI total reduction arity is too large.", ); - let (final_poly_coeff_len, query_round_step_count) = + let (final_poly_coeff_len, max_num_query_steps) = if let Some(verifier_circuit_fri_params) = verifier_circuit_fri_params { assert_eq!(verifier_circuit_fri_params.config, fri_params.config); match &config.fri_config.reduction_strategy { @@ -107,7 +107,7 @@ where &mut challenger, public_inputs, final_poly_coeff_len, - query_round_step_count, + max_num_query_steps, timing, ) } @@ -129,7 +129,7 @@ pub fn prove_with_commitment( challenger: &mut Challenger, public_inputs: &[F], final_poly_coeff_len: Option, - query_round_step_count: Option, + max_num_query_steps: Option, timing: &mut TimingTree, ) -> Result> where @@ -347,7 +347,7 @@ where challenger, &fri_params, final_poly_coeff_len, - query_round_step_count, + max_num_query_steps, timing, ) );