diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 1e028255..503cdaf6 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -139,7 +139,13 @@ impl, const D: usize> CircuitBuilder { let precomputed_reduced_evals = with_context!( self, "precompute reduced evaluations", - PrecomputedReducedEvalsTarget::from_os_and_alpha(os, alpha, self) + PrecomputedReducedEvalsTarget::from_os_and_alpha( + os, + alpha, + common_data.degree_bits, + zeta, + self + ) ); for (i, round_proof) in proof.query_round_proofs.iter().enumerate() { @@ -204,8 +210,8 @@ impl, const D: usize> CircuitBuilder { &mut self, proof: &FriInitialTreeProofTarget, alpha: ExtensionTarget, - zeta: ExtensionTarget, subgroup_x: Target, + vanish_zeta: ExtensionTarget, precomputed_reduced_evals: PrecomputedReducedEvalsTarget, common_data: &CommonCircuitData, ) -> ExtensionTarget { @@ -218,7 +224,6 @@ impl, const D: usize> CircuitBuilder { - config.rate_bits ); let subgroup_x = self.convert_to_ext(subgroup_x); - let vanish_zeta = self.sub_extension(subgroup_x, zeta); let mut alpha = ReducingFactorTarget::new(alpha); let mut sum = self.zero_extension(); @@ -255,19 +260,19 @@ impl, const D: usize> CircuitBuilder { .collect::>(); let zs_composition_eval = alpha.reduce_base(&zs_evals, self); - let g = self.constant_extension(F::Extension::primitive_root_of_unity(degree_log)); - let zeta_right = self.mul_extension(g, zeta); - let interpol_val = self.interpolate2( - [ - (zeta, precomputed_reduced_evals.zs), - (zeta_right, precomputed_reduced_evals.zs_right), - ], - subgroup_x, + let interpol_val = self.mul_add_extension( + vanish_zeta, + precomputed_reduced_evals.slope, + precomputed_reduced_evals.zs, ); - let (zs_numerator, vanish_zeta_right) = - self.sub_two_extension(zs_composition_eval, interpol_val, subgroup_x, zeta_right); - let zs_denominator = self.mul_extension(vanish_zeta, vanish_zeta_right); - sum = alpha.shift(sum, self); + let (zs_numerator, vanish_zeta_right) = self.sub_two_extension( + zs_composition_eval, + interpol_val, + subgroup_x, + precomputed_reduced_evals.zeta_right, + ); + let (mut sum, zs_denominator) = + alpha.shift_and_mul(sum, vanish_zeta, vanish_zeta_right, self); sum = self.div_add_extension(zs_numerator, zs_denominator, sum); sum @@ -307,12 +312,26 @@ impl, const D: usize> CircuitBuilder { ); // `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::MULTIPLICATIVE_GROUP_GENERATOR); + let (mut subgroup_x, vanish_zeta) = with_context!(self, "compute x from its index", { + let g = self.constant(F::coset_shift()); let phi = self.constant(F::primitive_root_of_unity(n_log)); let phi = self.exp_from_bits(phi, x_index_bits.iter().rev()); - self.mul(g, phi) + let g_ext = self.convert_to_ext(g); + let phi_ext = self.convert_to_ext(phi); + let zero = self.zero_extension(); + // `subgroup_x = g*phi, vanish_zeta = g*phi - zeta` + let tmp = self.double_arithmetic_extension( + F::ONE, + F::NEG_ONE, + g_ext, + phi_ext, + zero, + g_ext, + phi_ext, + zeta, + ); + (tmp.0 .0[0], tmp.1) }); // old_eval is the last derived evaluation; it will be checked for consistency with its @@ -323,8 +342,8 @@ impl, const D: usize> CircuitBuilder { self.fri_combine_initial( &round_proof.initial_trees_proof, alpha, - zeta, subgroup_x, + vanish_zeta, precomputed_reduced_evals, common_data, ) @@ -393,12 +412,17 @@ struct PrecomputedReducedEvalsTarget { pub single: ExtensionTarget, pub zs: ExtensionTarget, pub zs_right: ExtensionTarget, + /// Slope of the line from `(zeta, zs)` to `(zeta_right, zs_right)`. + pub slope: ExtensionTarget, + pub zeta_right: ExtensionTarget, } impl PrecomputedReducedEvalsTarget { fn from_os_and_alpha>( os: &OpeningSetTarget, alpha: ExtensionTarget, + degree_log: usize, + zeta: ExtensionTarget, builder: &mut CircuitBuilder, ) -> Self { let mut alpha = ReducingFactorTarget::new(alpha); @@ -416,10 +440,16 @@ impl PrecomputedReducedEvalsTarget { let zs = alpha.reduce(&os.plonk_zs, builder); let zs_right = alpha.reduce(&os.plonk_zs_right, builder); + let g = builder.constant_extension(F::Extension::primitive_root_of_unity(degree_log)); + let zeta_right = builder.mul_extension(g, zeta); + let (numerator, denominator) = builder.sub_two_extension(zs_right, zs, zeta_right, zeta); + Self { single, zs, zs_right, + slope: builder.div_extension(numerator, denominator), + zeta_right, } } } diff --git a/src/plonk/vanishing_poly.rs b/src/plonk/vanishing_poly.rs index e2180552..a2a97d4b 100644 --- a/src/plonk/vanishing_poly.rs +++ b/src/plonk/vanishing_poly.rs @@ -363,8 +363,9 @@ pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( .chunks(max_degree) .zip(partial_product_check.iter_mut()) .for_each(|(d, q)| { - let tmp = builder.mul_many_extension(d); - *q = builder.mul_extension(*q, tmp); + let mut v = d.to_vec(); + v.push(*q); + *q = builder.mul_many_extension(&v); }); vanishing_partial_products_terms.extend(partial_product_check); diff --git a/src/util/reducing.rs b/src/util/reducing.rs index ce6827ba..d2f4fcf2 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -211,9 +211,25 @@ impl ReducingFactorTarget { F: Extendable, { let exp = builder.exp_u64_extension(self.base, self.count); - let tmp = builder.mul_extension(exp, x); self.count = 0; - tmp + builder.mul_extension(exp, x) + } + + /// Returns `(self.shift(x), a*b)`. + /// Used to take advantage of the second arithmetic operation in the `ArithmeticExtensionGate`. + pub fn shift_and_mul( + &mut self, + x: ExtensionTarget, + a: ExtensionTarget, + b: ExtensionTarget, + builder: &mut CircuitBuilder, + ) -> (ExtensionTarget, ExtensionTarget) + where + F: Extendable, + { + let exp = builder.exp_u64_extension(self.base, self.count); + self.count = 0; + builder.mul_two_extension(exp, x, a, b) } pub fn reset(&mut self) {