diff --git a/starky/src/constraint_consumer.rs b/starky/src/constraint_consumer.rs index adb88e41..922475c3 100644 --- a/starky/src/constraint_consumer.rs +++ b/starky/src/constraint_consumer.rs @@ -14,6 +14,9 @@ pub struct ConstraintConsumer { /// Running sums of constraints that have been emitted so far, scaled by powers of alpha. constraint_accs: Vec

, + /// The evaluation of `X - g^(n-1)`. + z_last: P, + /// The evaluation of the Lagrange basis polynomial which is nonzero at the point associated /// with the first trace row, and zero at other points in the subgroup. lagrange_basis_first: P, @@ -24,10 +27,16 @@ pub struct ConstraintConsumer { } impl ConstraintConsumer

{ - pub fn new(alphas: Vec, lagrange_basis_first: P, lagrange_basis_last: P) -> Self { + pub fn new( + alphas: Vec, + z_last: P, + lagrange_basis_first: P, + lagrange_basis_last: P, + ) -> Self { Self { constraint_accs: vec![P::ZEROS; alphas.len()], alphas, + z_last, lagrange_basis_first, lagrange_basis_last, } @@ -41,31 +50,29 @@ impl ConstraintConsumer

{ .collect() } - /// Add one constraint. - pub fn one(&mut self, constraint: P) { + /// Add one constraint valid on all rows except the last. + pub fn constraint(&mut self, constraint: P) { + self.constraint_wrapping(constraint * self.z_last); + } + + /// Add one constraint on all rows. + pub fn constraint_wrapping(&mut self, constraint: P) { for (&alpha, acc) in self.alphas.iter().zip(&mut self.constraint_accs) { *acc *= alpha; *acc += constraint; } } - /// Add a series of constraints. - pub fn many(&mut self, constraints: impl IntoIterator) { - constraints - .into_iter() - .for_each(|constraint| self.one(constraint)); - } - /// Add one constraint, but first multiply it by a filter such that it will only apply to the /// first row of the trace. - pub fn one_first_row(&mut self, constraint: P) { - self.one(constraint * self.lagrange_basis_first); + pub fn constraint_first_row(&mut self, constraint: P) { + self.constraint_wrapping(constraint * self.lagrange_basis_first); } /// Add one constraint, but first multiply it by a filter such that it will only apply to the /// last row of the trace. - pub fn one_last_row(&mut self, constraint: P) { - self.one(constraint * self.lagrange_basis_last); + pub fn constraint_last_row(&mut self, constraint: P) { + self.constraint_wrapping(constraint * self.lagrange_basis_last); } } @@ -76,6 +83,9 @@ pub struct RecursiveConstraintConsumer, const D: us /// A running sum of constraints that have been emitted so far, scaled by powers of alpha. constraint_acc: ExtensionTarget, + /// The evaluation of `X - g^(n-1)`. + z_last: ExtensionTarget, + /// The evaluation of the Lagrange basis polynomial which is nonzero at the point associated /// with the first trace row, and zero at other points in the subgroup. lagrange_basis_first: ExtensionTarget, @@ -88,42 +98,45 @@ pub struct RecursiveConstraintConsumer, const D: us } impl, const D: usize> RecursiveConstraintConsumer { - /// Add one constraint. - pub fn one(&mut self, builder: &mut CircuitBuilder, constraint: ExtensionTarget) { + /// Add one constraint valid on all rows except the last. + pub fn constraint( + &mut self, + builder: &mut CircuitBuilder, + constraint: ExtensionTarget, + ) { self.constraint_acc = builder.scalar_mul_add_extension(self.alpha, self.constraint_acc, constraint); } - /// Add a series of constraints. - pub fn many( + /// Add one constraint valid on all rows. + pub fn constraint_wrapping( &mut self, builder: &mut CircuitBuilder, - constraints: impl IntoIterator>, + constraint: ExtensionTarget, ) { - constraints - .into_iter() - .for_each(|constraint| self.one(builder, constraint)); + let filtered_constraint = builder.mul_extension(constraint, self.z_last); + self.constraint(builder, filtered_constraint); } /// Add one constraint, but first multiply it by a filter such that it will only apply to the /// first row of the trace. - pub fn one_first_row( + pub fn constraint_first_row( &mut self, builder: &mut CircuitBuilder, constraint: ExtensionTarget, ) { let filtered_constraint = builder.mul_extension(constraint, self.lagrange_basis_first); - self.one(builder, filtered_constraint); + self.constraint(builder, filtered_constraint); } /// Add one constraint, but first multiply it by a filter such that it will only apply to the /// last row of the trace. - pub fn one_last_row( + pub fn constraint_last_row( &mut self, builder: &mut CircuitBuilder, constraint: ExtensionTarget, ) { let filtered_constraint = builder.mul_extension(constraint, self.lagrange_basis_last); - self.one(builder, filtered_constraint); + self.constraint(builder, filtered_constraint); } } diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index dc6d676a..f3ffd8a2 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -60,14 +60,17 @@ impl, const D: usize> Stark for FibonacciStar P: PackedField, { // Check public inputs. - yield_constr.one_first_row(vars.local_values[0] - vars.public_inputs[Self::PI_INDEX_X0]); - yield_constr.one_first_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_X1]); - yield_constr.one_last_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_RES]); + yield_constr + .constraint_first_row(vars.local_values[0] - vars.public_inputs[Self::PI_INDEX_X0]); + yield_constr + .constraint_first_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_X1]); + yield_constr + .constraint_last_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_RES]); // x0 <- x1 - yield_constr.one(vars.next_values[0] - vars.local_values[1]); + yield_constr.constraint(vars.next_values[0] - vars.local_values[1]); // x1 <- x0 + x1 - yield_constr.one(vars.next_values[1] - vars.local_values[0] - vars.local_values[1]); + yield_constr.constraint(vars.next_values[1] - vars.local_values[0] - vars.local_values[1]); } fn eval_ext_recursively( diff --git a/starky/src/prover.rs b/starky/src/prover.rs index d6543dae..4d7f8c3f 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -197,6 +197,7 @@ where // TODO: Set `P` to a genuine `PackedField` here. let mut consumer = ConstraintConsumer::::new( alphas.clone(), + coset[i] - last, lagrange_first.values[i], lagrange_last.values[i], ); @@ -214,9 +215,8 @@ where // We divide the constraints evaluations by `Z_H(x) / x - last`, i.e., the vanishing // polynomial of `H` without it's last element. let denominator_inv = z_h_on_coset.eval_inverse(i); - let z_last = coset[i] - last; for eval in &mut constraints_evals { - *eval *= denominator_inv * z_last; + *eval *= denominator_inv; } constraints_evals }) diff --git a/starky/src/verifier.rs b/starky/src/verifier.rs index 6a4464e1..5753f21f 100644 --- a/starky/src/verifier.rs +++ b/starky/src/verifier.rs @@ -72,24 +72,25 @@ where }; let (l_1, l_last) = eval_l_1_and_l_last(degree_bits, challenges.stark_zeta); + let last = F::primitive_root_of_unity(degree_bits).inverse(); + let z_last = challenges.stark_zeta - last.into(); let mut consumer = ConstraintConsumer::::new( challenges .stark_alphas .iter() .map(|&alpha| F::Extension::from_basefield(alpha)) .collect::>(), + z_last, l_1, l_last, ); stark.eval_ext(vars, &mut consumer); let acc = consumer.accumulators(); - // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x) / (x - last)`, at zeta. + // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta. let quotient_polys_zeta = &proof.openings.quotient_polys; let zeta_pow_deg = challenges.stark_zeta.exp_power_of_2(degree_bits); let z_h_zeta = zeta_pow_deg - F::Extension::ONE; - let last = F::primitive_root_of_unity(degree_bits).inverse(); - let z_last = challenges.stark_zeta - last.into(); // `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations. // Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)` // where the "real" quotient polynomial is `t(X) = t_0(X) + t_1(X)*X^n + t_2(X)*X^{2n} + ...`. @@ -99,7 +100,7 @@ where .chunks(1 << config.fri_config.rate_bits) .enumerate() { - ensure!(acc[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg) / z_last); + ensure!(acc[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg)); } let merkle_caps = &[proof.trace_cap, proof.quotient_polys_cap]; diff --git a/system_zero/src/core_registers.rs b/system_zero/src/core_registers.rs index 249c16a3..21faa288 100644 --- a/system_zero/src/core_registers.rs +++ b/system_zero/src/core_registers.rs @@ -55,16 +55,16 @@ impl, const D: usize> SystemZero { let local_clock = vars.local_values[COL_CLOCK]; let next_clock = vars.next_values[COL_CLOCK]; let delta_clock = next_clock - local_clock; - yield_constr.one_first_row(local_clock); - yield_constr.one(delta_clock - FE::ONE); + yield_constr.constraint_first_row(local_clock); + yield_constr.constraint(delta_clock - FE::ONE); // The 16-bit table must start with 0, end with 2^16 - 1, and increment by 0 or 1. let local_range_16 = vars.local_values[COL_RANGE_16]; let next_range_16 = vars.next_values[COL_RANGE_16]; let delta_range_16 = next_range_16 - local_range_16; - yield_constr.one_first_row(local_range_16); - yield_constr.one_last_row(local_range_16 - FE::from_canonical_u64((1 << 16) - 1)); - yield_constr.one(delta_range_16 * (delta_range_16 - FE::ONE)); + yield_constr.constraint_first_row(local_range_16); + yield_constr.constraint_last_row(local_range_16 - FE::from_canonical_u64((1 << 16) - 1)); + yield_constr.constraint(delta_range_16 * (delta_range_16 - FE::ONE)); todo!() } diff --git a/system_zero/src/permutation_unit.rs b/system_zero/src/permutation_unit.rs index a490b49d..43883fca 100644 --- a/system_zero/src/permutation_unit.rs +++ b/system_zero/src/permutation_unit.rs @@ -53,7 +53,7 @@ impl, const D: usize> SystemZero { // Assert that the computed output matches the outputs in the trace. for i in 0..SPONGE_WIDTH { let out = local_values[col_permutation_output(i)]; - yield_constr.one(state[i] - out); + yield_constr.constraint(state[i] - out); } } @@ -80,7 +80,7 @@ impl, const D: usize> SystemZero { for i in 0..SPONGE_WIDTH { let out = local_values[col_permutation_output(i)]; let diff = builder.sub_extension(state[i], out); - yield_constr.one(builder, diff); + yield_constr.constraint(builder, diff); } } }