diff --git a/crates/prover/src/examples/wide_fibonacci/component.rs b/crates/prover/src/examples/wide_fibonacci/component.rs index d9ce2cb96..3bfa3f9a0 100644 --- a/crates/prover/src/examples/wide_fibonacci/component.rs +++ b/crates/prover/src/examples/wide_fibonacci/component.rs @@ -91,13 +91,14 @@ impl WideFibComponent { } } - fn evaluate_lookup_boundary_constraint_at_point( + fn evaluate_lookup_boundary_constraints_at_point( &self, point: CirclePoint, mask: &TreeVec>>, evaluation_accumulator: &mut PointEvaluationAccumulator, constraint_zero_domain: Coset, interaction_elements: &InteractionElements, + lookup_values: &LookupValues, ) { let (alpha, z) = (interaction_elements[ALPHA_ID], interaction_elements[Z_ID]); let value = @@ -116,6 +117,29 @@ impl WideFibComponent { - shifted_secure_combination(&[mask[0][0][0], mask[0][1][0]], alpha, z); let denom = point_vanishing(constraint_zero_domain.at(0), point); evaluation_accumulator.accumulate(numerator / denom); + + let numerator = (value + * shifted_secure_combination( + &[ + lookup_values[LOOKUP_VALUE_N_MINUS_2_ID], + lookup_values[LOOKUP_VALUE_N_MINUS_1_ID], + ], + alpha, + z, + )) + - shifted_secure_combination( + &[ + lookup_values[LOOKUP_VALUE_0_ID], + lookup_values[LOOKUP_VALUE_1_ID], + ], + alpha, + z, + ); + let denom = point_vanishing( + constraint_zero_domain.at(constraint_zero_domain.size() - 1), + point, + ); + evaluation_accumulator.accumulate(numerator / denom); } fn evaluate_lookup_step_constraints_at_point( @@ -163,7 +187,7 @@ impl Air for WideFibAir { impl Component for WideFibComponent { fn n_constraints(&self) -> usize { - self.n_columns() + 4 + self.n_columns() + 5 } fn max_constraint_log_degree_bound(&self) -> u32 { @@ -219,12 +243,13 @@ impl Component for WideFibComponent { constraint_zero_domain, interaction_elements, ); - self.evaluate_lookup_boundary_constraint_at_point( + self.evaluate_lookup_boundary_constraints_at_point( point, mask, evaluation_accumulator, constraint_zero_domain, interaction_elements, + lookup_values, ); self.evaluate_trace_step_constraints_at_point( point, diff --git a/crates/prover/src/examples/wide_fibonacci/constraint_eval.rs b/crates/prover/src/examples/wide_fibonacci/constraint_eval.rs index 394adb403..b4d15c65e 100644 --- a/crates/prover/src/examples/wide_fibonacci/constraint_eval.rs +++ b/crates/prover/src/examples/wide_fibonacci/constraint_eval.rs @@ -88,19 +88,23 @@ impl WideFibComponent { BaseField::batch_inverse(&last_point_denoms, &mut last_point_denom_inverses); let mut first_point_numerators = vec![SecureField::zero(); 1 << (max_constraint_degree)]; let mut last_point_numerators = vec![SecureField::zero(); 1 << (max_constraint_degree)]; + let (lookup_value_0, lookup_value_1, lookup_value_n_minus_2, lookup_value_n_minus_1) = ( + lookup_values[LOOKUP_VALUE_0_ID], + lookup_values[LOOKUP_VALUE_1_ID], + lookup_values[LOOKUP_VALUE_N_MINUS_2_ID], + lookup_values[LOOKUP_VALUE_N_MINUS_1_ID], + ); #[allow(clippy::needless_range_loop)] for i in 0..trace_eval_domain.size() { - first_point_numerators[i] = accum.random_coeff_powers[self.n_columns() + 3] - * (trace_evals[0][0][i] - lookup_values[LOOKUP_VALUE_0_ID]) - + accum.random_coeff_powers[self.n_columns() + 2] - * (trace_evals[0][1][i] - lookup_values[LOOKUP_VALUE_1_ID]); - last_point_numerators[i] = accum.random_coeff_powers[self.n_columns() + 1] - * (trace_evals[0][self.n_columns() - 2][i] - - lookup_values[LOOKUP_VALUE_N_MINUS_2_ID]) - + accum.random_coeff_powers[self.n_columns()] - * (trace_evals[0][self.n_columns() - 1][i] - - lookup_values[LOOKUP_VALUE_N_MINUS_1_ID]); + first_point_numerators[i] = accum.random_coeff_powers[self.n_columns() + 4] + * (trace_evals[0][0][i] - lookup_value_0) + + accum.random_coeff_powers[self.n_columns() + 3] + * (trace_evals[0][1][i] - lookup_value_1); + last_point_numerators[i] = accum.random_coeff_powers[self.n_columns() + 2] + * (trace_evals[0][self.n_columns() - 2][i] - lookup_value_n_minus_2) + + accum.random_coeff_powers[self.n_columns() + 1] + * (trace_evals[0][self.n_columns() - 1][i] - lookup_value_n_minus_1); } for (i, (num, denom_inverse)) in first_point_numerators .iter() @@ -148,24 +152,40 @@ impl WideFibComponent { } } - fn evaluate_lookup_boundary_constraint( + fn evaluate_lookup_boundary_constraints( &self, trace_evals: &TreeVec>>, trace_eval_domain: CircleDomain, zero_domain: Coset, accum: &mut ColumnAccumulator<'_, CpuBackend>, interaction_elements: &InteractionElements, + lookup_values: &LookupValues, ) { let max_constraint_degree = self.max_constraint_log_degree_bound(); - let mut denoms = vec![]; + let mut first_point_denoms = vec![]; + let mut last_point_denoms = vec![]; for point in trace_eval_domain.iter() { - denoms.push(point_vanishing(zero_domain.at(0), point)); + first_point_denoms.push(point_vanishing(zero_domain.at(0), point)); + last_point_denoms.push(point_vanishing( + zero_domain.at(zero_domain.size() - 1), + point, + )); } - bit_reverse(&mut denoms); - let mut denom_inverses = vec![BaseField::zero(); 1 << (max_constraint_degree)]; - BaseField::batch_inverse(&denoms, &mut denom_inverses); - let mut numerators = vec![SecureField::zero(); 1 << (max_constraint_degree)]; + bit_reverse(&mut first_point_denoms); + bit_reverse(&mut last_point_denoms); + let mut first_point_denom_inverses = vec![BaseField::zero(); 1 << (max_constraint_degree)]; + let mut last_point_denom_inverses = vec![BaseField::zero(); 1 << (max_constraint_degree)]; + BaseField::batch_inverse(&first_point_denoms, &mut first_point_denom_inverses); + BaseField::batch_inverse(&last_point_denoms, &mut last_point_denom_inverses); + let mut first_point_numerators = vec![SecureField::zero(); 1 << (max_constraint_degree)]; + let mut last_point_numerators = vec![SecureField::zero(); 1 << (max_constraint_degree)]; let (alpha, z) = (interaction_elements[ALPHA_ID], interaction_elements[Z_ID]); + let (lookup_value_0, lookup_value_1, lookup_value_n_minus_2, lookup_value_n_minus_1) = ( + lookup_values[LOOKUP_VALUE_0_ID], + lookup_values[LOOKUP_VALUE_1_ID], + lookup_values[LOOKUP_VALUE_N_MINUS_2_ID], + lookup_values[LOOKUP_VALUE_N_MINUS_1_ID], + ); #[allow(clippy::needless_range_loop)] for i in 0..trace_eval_domain.size() { @@ -173,7 +193,7 @@ impl WideFibComponent { SecureCirclePoly::::eval_from_partial_evals(std::array::from_fn(|j| { trace_evals[1][j][i].into() })); - numerators[i] = accum.random_coeff_powers[self.n_columns() - 2] + first_point_numerators[i] = accum.random_coeff_powers[self.n_columns() - 1] * ((value * shifted_secure_combination( &[ @@ -188,8 +208,27 @@ impl WideFibComponent { alpha, z, )); + last_point_numerators[i] = accum.random_coeff_powers[self.n_columns() - 2] + * ((value + * shifted_secure_combination( + &[lookup_value_n_minus_2, lookup_value_n_minus_1], + alpha, + z, + )) + - shifted_secure_combination(&[lookup_value_0, lookup_value_1], alpha, z)); } - for (i, (num, denom_inverse)) in numerators.iter().zip(denom_inverses.iter()).enumerate() { + for (i, (num, denom_inverse)) in first_point_numerators + .iter() + .zip(first_point_denom_inverses.iter()) + .enumerate() + { + accum.accumulate(i, *num * *denom_inverse); + } + for (i, (num, denom_inverse)) in last_point_numerators + .iter() + .zip(last_point_denom_inverses.iter()) + .enumerate() + { accum.accumulate(i, *num * *denom_inverse); } } @@ -231,7 +270,7 @@ impl WideFibComponent { SecureCirclePoly::::eval_from_partial_evals(std::array::from_fn(|j| { trace_evals[1][j][prev_index].into() })); - numerators[i] = accum.random_coeff_powers[self.n_columns() - 1] + numerators[i] = accum.random_coeff_powers[self.n_columns()] * ((value * shifted_secure_combination( &[ @@ -269,6 +308,8 @@ impl ComponentProver for WideFibComponent { let [mut accum] = evaluation_accumulator.columns([(max_constraint_degree, self.n_constraints())]); + // TODO(AlonH): Evaluate the numerators together and the denominators together (i.e. in the + // same for loop) self.evaluate_trace_boundary_constraints( trace_evals, trace_eval_domain, @@ -276,26 +317,27 @@ impl ComponentProver for WideFibComponent { &mut accum, lookup_values, ); - self.evaluate_trace_step_constraints( + self.evaluate_lookup_step_constraints( trace_evals, trace_eval_domain, zero_domain, &mut accum, + interaction_elements, ); - self.evaluate_lookup_boundary_constraint( + self.evaluate_lookup_boundary_constraints( trace_evals, trace_eval_domain, zero_domain, &mut accum, interaction_elements, + lookup_values, ); - self.evaluate_lookup_step_constraints( + self.evaluate_trace_step_constraints( trace_evals, trace_eval_domain, zero_domain, &mut accum, - interaction_elements, - ) + ); } fn lookup_values(&self, trace: &ComponentTrace<'_, CpuBackend>) -> LookupValues {