Skip to content

cleanup(stark/constraints): drop coefficient-form leftovers, dedupe eval#604

Merged
diegokingston merged 6 commits into
mainfrom
cleanup/constraints
May 22, 2026
Merged

cleanup(stark/constraints): drop coefficient-form leftovers, dedupe eval#604
diegokingston merged 6 commits into
mainfrom
cleanup/constraints

Conversation

@diegokingston
Copy link
Copy Markdown
Collaborator

Behaviour-preserving cleanup of crypto/stark/src/constraints (plan items 1-5). The eval-form STARK migration left several pieces of coefficient-form scaffolding behind.

boundary.rs — remove vestigial pre-eval-form code

  • The eval-form prover evaluates boundaries on-the-fly in evaluator.rs (trace[col] - value); it never interpolates boundary polynomials. Deleted the now-unused steps, steps_for_boundary, cols_for_boundary, generate_roots_of_unity, values, compute_zerofier, and the dead new_simple_aux. Production keeps only the BoundaryConstraint / BoundaryConstraints structs, new_main/new_aux/new_simple_main and from_constraints. 153 -> 57 LOC; drops the itertools use.
  • tests/boundary_tests.rs only exercised compute_zerofier; removed.

evaluator.rs — remove a no-op debug check

  • check_boundary_polys_divisibility was called with two always-empty vecs, so it iterated nothing — a check that checked nothing. Removed the dead #[cfg(debug_assertions)] block (boundary_polys, boundary_zerofiers, the unused _transition_evaluations), the function from debug.rs (no other caller), and the imports it needed. This also clears the unused import: Polynomial warning in release builds.

evaluator.rs — deduplicate evaluate_transitions

  • The parallel and sequential arms repeated ~32 lines of identical per-row accumulation. Extracted a shared eval_row closure; only the iterator (into_par_iter().map_init vs into_iter().map) now differs. Per-thread buffer reuse is unchanged.

transition.rs — hygiene

  • evaluate_zerofier used unsafe { …unwrap_unchecked() } while the sibling branch used a safe .unwrap() on the same invariant. Replaced with .expect(...) — no unsafe for skipping one zero-check.
  • std::ops::Div / std::iter::zip -> core:: to match the module.

123 stark lib tests pass (124 minus the deleted compute_zerofier test); 273 prover lib tests pass; all build configs + lint clean.

Behaviour-preserving cleanup of `crypto/stark/src/constraints` (plan
items 1-5). The eval-form STARK migration left several pieces of
coefficient-form scaffolding behind.

boundary.rs — remove vestigial pre-eval-form code
- The eval-form prover evaluates boundaries on-the-fly in `evaluator.rs`
  (`trace[col] - value`); it never interpolates boundary polynomials.
  Deleted the now-unused `steps`, `steps_for_boundary`, `cols_for_boundary`,
  `generate_roots_of_unity`, `values`, `compute_zerofier`, and the dead
  `new_simple_aux`. Production keeps only the `BoundaryConstraint` /
  `BoundaryConstraints` structs, `new_main`/`new_aux`/`new_simple_main`
  and `from_constraints`. 153 -> 57 LOC; drops the `itertools` use.
- `tests/boundary_tests.rs` only exercised `compute_zerofier`; removed.

evaluator.rs — remove a no-op debug check
- `check_boundary_polys_divisibility` was called with two always-empty
  vecs, so it iterated nothing — a check that checked nothing. Removed
  the dead `#[cfg(debug_assertions)]` block (`boundary_polys`,
  `boundary_zerofiers`, the unused `_transition_evaluations`), the
  function from `debug.rs` (no other caller), and the imports it needed.
  This also clears the `unused import: Polynomial` warning in release
  builds.

evaluator.rs — deduplicate `evaluate_transitions`
- The parallel and sequential arms repeated ~32 lines of identical
  per-row accumulation. Extracted a shared `eval_row` closure; only the
  iterator (`into_par_iter().map_init` vs `into_iter().map`) now differs.
  Per-thread buffer reuse is unchanged.

transition.rs — hygiene
- `evaluate_zerofier` used `unsafe { …unwrap_unchecked() }` while the
  sibling branch used a safe `.unwrap()` on the same invariant. Replaced
  with `.expect(...)` — no `unsafe` for skipping one zero-check.
- `std::ops::Div` / `std::iter::zip` -> `core::` to match the module.

123 stark lib tests pass (124 minus the deleted compute_zerofier test);
273 prover lib tests pass; all build configs + lint clean.
@github-actions
Copy link
Copy Markdown

Codex Code Review

No findings in the PR diff.

I reviewed the changed constraint evaluator, boundary cleanup, unsafe-to-expect replacement, and removed tests/helpers. I did not see security, correctness, significant performance, or simplicity issues introduced by these changes.

Verification note: I attempted to run cargo test -p stark --lib, but the environment could not initialize Rust toolchain state due read-only rustup storage, then network DNS failure when redirected to /tmp. git diff --check passed.

@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

Review

Clean, well-scoped refactor. The deletions are confirmed dead code (no remaining callers), the eval_row closure typing is correct (auto-deref from &mut Vec<T>&mut [T] and &mut Frame&Frame for new_prover), and the parallel/sequential semantics are preserved identically.

Low – inconsistency in transition.rs (not introduced by this PR, but adjacent to the fix)

The PR correctly replaces unsafe { numerator.div(denominator).unwrap_unchecked() } (the exemptions_period branch) with .expect("zerofier denominator is non-zero: z is sampled out-of-domain"). The non-exemptions path immediately below has the same invariant but still uses a bare .unwrap():

// transition.rs ~line 286-289
(-trace_primitive_root.pow(self.offset() * trace_length / self.period())
    + z.pow(trace_length / self.period()))
.inv()
.unwrap()   // ← same invariant; should be .expect(…) for consistency

Worth a one-line follow-up, but not a blocker.

Everything else: LGTM

  • No remaining callers for any deleted public API (new_simple_aux, compute_zerofier, steps, steps_for_boundary, cols_for_boundary, generate_roots_of_unity, values, check_boundary_polys_divisibility).
  • The no-op debug check (check_boundary_polys_divisibility called with two empty Vecs) is correctly identified and removed.
  • std::core:: is a trivially correct portability improvement.
  • eval_row closure captures are all shared references; rayon Sync requirements were already present in the old code.

@diegokingston diegokingston marked this pull request as ready for review May 21, 2026 19:54
@github-actions
Copy link
Copy Markdown

Codex Code Review

No issues found in the PR diff.

Security: no Critical/High/Medium/Low vulnerabilities identified in the changed code. The removal of unsafe { unwrap_unchecked() } in transition zerofier evaluation is a net safety improvement.

I could not run cargo test -p stark: rustup/Cargo attempted to write under read-only /home/runner/.rustup / /home/runner/.cargo, and then needed network/git access, which is unavailable in this sandbox.

@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

Clean, behaviour-preserving refactor. No security issues or bugs found.

@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

unsafe removal (transition.rs) - Replacing unsafe unwrap_unchecked with .expect() is a genuine safety improvement. The original invokes UB if the invariant ever breaks; the new code panics cleanly instead.

@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

Dead debug code removal (evaluator.rs, debug.rs) - check_boundary_polys_divisibility was called with two always-empty Vec::new() vectors so the loop body never executed. Removing it is correct and eliminates the misleading impression that boundary divisibility was being checked in debug builds.

@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

eval_row closure extraction (evaluator.rs) - The parallel and sequential arms are structurally identical to their originals. All captured variables are immutable borrows so Sync constraints for the parallel path are unchanged. The coercions from &mut Vec to &mut slice on the call sites are standard.

@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

Minor - public API break: BoundaryConstraints::new_simple_aux is pub on a pub struct. Removing it is a semver-breaking change for external consumers. If this crate is purely internal or semver is managed separately, no action needed - just note it in the changelog.

@diegokingston diegokingston added this pull request to the merge queue May 22, 2026
Merged via the queue into main with commit 8af4e92 May 22, 2026
12 checks passed
@diegokingston diegokingston deleted the cleanup/constraints branch May 22, 2026 21:54
diegokingston added a commit that referenced this pull request May 22, 2026
Replaces the coefficient-form `end_exemptions_poly: Polynomial<F>` with
two eval-form helpers, removing transition.rs's last dependency on
`Polynomial` arithmetic. Stacks on #604 (which removed boundary.rs's
`Polynomial` dependency). With both landed, no production code in the
prover uses `Polynomial` operators.

- `end_exemptions_roots` returns the roots r_i of prod(x - r_i)
  (<= 2 in the example AIRs, 0 in every VM table).
- `end_exemptions_lde_evaluations(domain)` evaluates the product over
  the precomputed LDE coset directly: an O(N * end_exemptions) loop
  replaces an O(N log N) FFT.
- `evaluate_zerofier`'s OOD path computes prod(z - r_i) directly
  instead of `Polynomial::evaluate`.

Performance: the VM's dominant path (end_exemptions == 0) is unchanged
- the existing else-branch early-return is preserved bit-for-bit, so
that case still returns the short cyclic vector instead of expanding it.
The k > 0 path (example AIRs only) goes from FFT to direct product,
strictly faster.

Correctness verified by `cargo test -p stark` (125/125, includes the
fibonacci and read-only-memory AIRs with end_exemptions = 1 and 2 -
exactly the eval-form k > 0 path). VM prover lib test counts are
identical to the #604 baseline (273 pass, 77 pre-existing failures
unrelated to constraints).
diegokingston added a commit that referenced this pull request May 26, 2026
After #604 (boundary.rs eval-form) and #621 (end_exemptions_poly eval-form)
landed on main, no production code in the prover uses `Polynomial`
operators anymore. The only remaining user was `Polynomial::interpolate`
(test-only Lagrange interpolation, gated `#[cfg(test)]` and used as a
naive reference by the FFT cross-check tests). With both production
references gone, the operators + the naive interpolant can go too.

Removed:
- All 14 operator `impl`s (Add P+/-P, Neg P, Mul P*P, Sub P-FieldElement);
  the previous PR kept these four families because `transition.rs` and
  `boundary.rs` used them. They are now fully unreachable.
- `Polynomial::interpolate` and `InterpolateError` from `polynomial.rs`.
- Operator unit tests in `polynomial_tests.rs` (adding_, negating_,
  multiply_*) and their helpers (`polynomial_a`, `polynomial_b`,
  `polynomial_minus_a`, `polynomial_a_plus_b`).
- `compose` test helper + `composition_works` test (depended on the
  removed `interpolate`).
- Direct `interpolate_x_*_y_*` tests (tested the removed function).

Rewrote:
- FFT correctness tests (both `fft_tests.rs` and
  `fft_friendly_u64_goldilocks_tests.rs`): the
  `gen_fft_and_naive_interpolate` / `_coset_` helpers cross-checked
  `interpolate_fft` against naive Lagrange. Replaced with FFT
  round-trip via direct Horner evaluation — interpolate via FFT, then
  re-evaluate at every twiddle with `Polynomial::evaluate` (a different
  algorithm). Same independence property, no naive Lagrange needed.
- `simple_interpolating_polynomial_by_hand_works`: swapped `*` for
  `mul_with_ref(&...)` (the only remaining call site that needed it).

Verified:
- `cargo build --workspace` clean.
- `cargo test -p math` -> 178 passing.
- `cargo test -p lambda-vm-prover --lib` -> 281 pass / 77 pre-existing
  failures unrelated to constraints (same baseline as main).
- `make lint` clean across all three clippy configs.
diegokingston added a commit that referenced this pull request May 26, 2026
After #604 (boundary.rs eval-form) and #621 (end_exemptions_poly eval-form)
landed on main, no production code in the prover uses `Polynomial`
operators anymore. The only remaining user was `Polynomial::interpolate`
(test-only Lagrange interpolation, gated `#[cfg(test)]` and used as a
naive reference by the FFT cross-check tests). With both production
references gone, the operators + the naive interpolant can go too.

Removed:
- All 14 operator `impl`s (Add P+/-P, Neg P, Mul P*P, Sub P-FieldElement);
  the previous PR kept these four families because `transition.rs` and
  `boundary.rs` used them. They are now fully unreachable.
- `Polynomial::interpolate` and `InterpolateError` from `polynomial.rs`.
- Operator unit tests in `polynomial_tests.rs` (adding_, negating_,
  multiply_*) and their helpers (`polynomial_a`, `polynomial_b`,
  `polynomial_minus_a`, `polynomial_a_plus_b`).
- `compose` test helper + `composition_works` test (depended on the
  removed `interpolate`).
- Direct `interpolate_x_*_y_*` tests (tested the removed function).

Rewrote:
- FFT correctness tests (both `fft_tests.rs` and
  `fft_friendly_u64_goldilocks_tests.rs`): the
  `gen_fft_and_naive_interpolate` / `_coset_` helpers cross-checked
  `interpolate_fft` against naive Lagrange. Replaced with FFT
  round-trip via direct Horner evaluation — interpolate via FFT, then
  re-evaluate at every twiddle with `Polynomial::evaluate` (a different
  algorithm). Same independence property, no naive Lagrange needed.
- `simple_interpolating_polynomial_by_hand_works`: swapped `*` for
  `mul_with_ref(&...)` (the only remaining call site that needed it).

Verified:
- `cargo build --workspace` clean.
- `cargo test -p math` -> 178 passing.
- `cargo test -p lambda-vm-prover --lib` -> 281 pass / 77 pre-existing
  failures unrelated to constraints (same baseline as main).
- `make lint` clean across all three clippy configs.
diegokingston added a commit that referenced this pull request May 26, 2026
#618)

After #604 (boundary.rs eval-form) and #621 (end_exemptions_poly eval-form)
landed on main, no production code in the prover uses `Polynomial`
operators anymore. The only remaining user was `Polynomial::interpolate`
(test-only Lagrange interpolation, gated `#[cfg(test)]` and used as a
naive reference by the FFT cross-check tests). With both production
references gone, the operators + the naive interpolant can go too.

Removed:
- All 14 operator `impl`s (Add P+/-P, Neg P, Mul P*P, Sub P-FieldElement);
  the previous PR kept these four families because `transition.rs` and
  `boundary.rs` used them. They are now fully unreachable.
- `Polynomial::interpolate` and `InterpolateError` from `polynomial.rs`.
- Operator unit tests in `polynomial_tests.rs` (adding_, negating_,
  multiply_*) and their helpers (`polynomial_a`, `polynomial_b`,
  `polynomial_minus_a`, `polynomial_a_plus_b`).
- `compose` test helper + `composition_works` test (depended on the
  removed `interpolate`).
- Direct `interpolate_x_*_y_*` tests (tested the removed function).

Rewrote:
- FFT correctness tests (both `fft_tests.rs` and
  `fft_friendly_u64_goldilocks_tests.rs`): the
  `gen_fft_and_naive_interpolate` / `_coset_` helpers cross-checked
  `interpolate_fft` against naive Lagrange. Replaced with FFT
  round-trip via direct Horner evaluation — interpolate via FFT, then
  re-evaluate at every twiddle with `Polynomial::evaluate` (a different
  algorithm). Same independence property, no naive Lagrange needed.
- `simple_interpolating_polynomial_by_hand_works`: swapped `*` for
  `mul_with_ref(&...)` (the only remaining call site that needed it).

Verified:
- `cargo build --workspace` clean.
- `cargo test -p math` -> 178 passing.
- `cargo test -p lambda-vm-prover --lib` -> 281 pass / 77 pre-existing
  failures unrelated to constraints (same baseline as main).
- `make lint` clean across all three clippy configs.
github-merge-queue Bot pushed a commit that referenced this pull request May 26, 2026
* refactor(math): remove dead Deserializable trait and unreachable error variants

`Deserializable` had a single impl (`Proof<T>`) whose only `deserialize`
call site was inside that impl itself — a recursion with no external
entry point. Production deserialization uses `bincode`/serde everywhere.
Delete the trait and the `Proof<T>` impl.

`merkle_tree/proof.rs` also carried a dead `Serializable` impl behind
`#[cfg(feature = "alloc")]` — a feature the `crypto` crate does not even
define, so the block never compiled. It referenced `math::traits::Serializable`,
which does not exist. Remove it.

Error cleanup (none constructed anywhere in the workspace):
- `DeserializationError` enum + `From<ByteConversionError>` impl — only
  reachable through the now-deleted `Deserializable`.
- `PairingError` enum — lambda_vm has no pairings.
- `ByteConversionError::{InvalidValue, PointNotInSubgroup, ValueNotCompressed}`
  — the latter two are elliptic-curve concepts; there is no EC here.
- `CreationError::InvalidDecString`.

Pure dead-code removal; `cargo build`/`cargo test -p math` unchanged
(216 tests pass).

* refactor(math): remove vestigial helpers module

`helpers::next_power_of_two(u64)` was bit-for-bit equivalent to stdlib
`u64::next_power_of_two()`. Its only caller, `resize_to_next_power_of_two`,
was used solely by the `fibonacci_rap` example — production trace sizing
already calls stdlib `.next_power_of_two()` directly everywhere.

Move `resize_to_next_power_of_two` into `examples/fibonacci_rap.rs` as a
local helper (rewritten on `usize` with the stdlib call, dropping the old
`try_into().unwrap()` TODO), and delete the `helpers` module.

* refactor(math): gate evaluate_fft_bit_reversed behind cfg(test)

`evaluate_fft_bit_reversed` was a non-gated `pub fn` but is only called
from the FFT property tests — no production caller in stark or prover.
Gate it `#[cfg(test)]` so it stops appearing in the production API
surface. Restore the gate (or remove it) when a real caller appears.

* refactor(math): gate test-only Polynomial::{truncate, reverse}

Both methods are called only from `fast_division` / `invert_polynomial_mod`,
which are themselves already `#[cfg(test)]`. No production caller in stark
or prover. Gate them `#[cfg(test)]` so they leave the production API surface.

`long_division_with_remainder` is left public — it is used by the
debug-checks path (`check_boundary_polys_divisibility`) and is a
legitimate general polynomial operation other code could want.

* refactor(math): flatten fft/cpu/* up to fft/*

The `fft/cpu/` directory implied a `fft/gpu/` sibling that never existed —
GPU code lives in the separate `crypto/math-cuda` crate. The `cpu` nesting
was a vestigial holdover.

Move `bit_reversing`, `bowers_fft`, `roots_of_unity`, `fft`, and
`bowers_fft_tests` from `fft/cpu/` up to `fft/`; delete `fft/cpu/mod.rs`
and merge its declarations into `fft/mod.rs`. Update every
`fft::cpu::...` / `super::cpu::...` path across math, stark, prover, and
math-cuda to `fft::...`.

Pure module move — no logic change. 216 math tests pass; stark, prover,
math-cuda all build.

* refactor(math): collapse polynomial/ folder into one polynomial.rs

Two problems compounded:
1. `polynomial/` was a folder holding a single file (`mod.rs`) — the
   directory level served no purpose.
2. Two files were named `polynomial` (`polynomial/mod.rs` and
   `fft/polynomial.rs`), both defining `impl Polynomial<...>` blocks.

Merge `fft/polynomial.rs` (the FFT-specific `impl Polynomial` blocks plus
the `evaluate_fft_cpu` / `interpolate_fft_cpu` free functions) into
`polynomial/mod.rs`, then rename it to a top-level `crypto/math/src/polynomial.rs`
and delete the folder.

Result: one `polynomial.rs` holding the `Polynomial` type and all of its
methods (core ring ops + FFT). `fft/` is now purely the FFT *algorithm*
layer (Bowers, twiddles, bit-reversal, roots of unity).

Also delete the stale `polynomial/README.md` — inherited lambdaworks
docs referencing multilinear-polynomial files that don't exist in
lambda_vm.

Updated the one external path (`fft::polynomial::compose_fft` ->
`polynomial::compose_fft`). 216 math + 124 stark tests pass.

* refactor(math): consolidate scattered tests into tests/ directory

Three test conventions coexisted: the `tests/` directory, a sibling
`bowers_fft_tests.rs` next to source, and an inline `#[cfg(test)] mod`
in the polynomial module. Unify on the `tests/` directory.

- Move `fft/bowers_fft_tests.rs` -> `tests/bowers_fft_tests.rs`, register
  it in `tests/mod.rs`, drop the `mod bowers_fft_tests;` from `fft/mod.rs`.
- Move the inline coset-LDE `mod tests` out of `polynomial.rs` into a new
  `coset_lde_tests` module in `tests/fft_tests.rs`.
- Rename `fft/fft.rs` -> `fft/reference_fft.rs`: after the Step 6 flatten
  it collided with its own parent module name (`fft::fft`), which clippy
  rejects. The new name also says what it is — the reference radix-2 FFT
  used only to cross-check the production Bowers FFT. Gate the module
  `#[cfg(test)] pub(crate)` since its whole content is test-only.

216 math tests pass (same count — no tests lost in the move).

* refactor(math): drop redundant FFT cross-check code, relocate inline tests

The reference radix-2 FFT existed only to cross-check the production Bowers
FFT. Bowers is already verified directly against a naive O(n^2) DFT at the
same sizes, so reference_fft.rs and its four comparison tests are dead
weight. gate get_powers_of_primitive_root as test-only (production twiddles
go through LayerTwiddles), collapse the evaluate_fft_cpu / interpolate_fft_cpu
wrappers into their sole callers, and narrow coset_lde_full_into to
pub(crate).

Move the inline test modules from bit_reversing.rs, goldilocks.rs and
extensions_goldilocks.rs into the dedicated tests/ directory.

* refactor(math): remove dead polynomial-division cluster, fix zero-offset panic

Addresses PR review feedback.

Reviewers flagged that `#[cfg(test)]`-gating previously-public methods is a
breaking change. Rather than keep them as `pub(crate)` dead code, the cluster
is removed outright — none of it has a production caller:

- Delete `Polynomial::{fast_division, invert_polynomial_mod,
  fast_fft_multiplication, truncate, reverse}` and `evaluate_fft_bit_reversed`,
  plus their 8 tests. The fast polynomial-division algorithm had no production
  use; it existed only to be tested.
- `get_powers_of_primitive_root` stays `#[cfg(test)]` — it is a genuine test
  helper used to validate the production FFT, not dead code.

Also fixes the pre-existing panic reviewers noted in `interpolate_offset_fft`:
`offset.inv().unwrap()` panicked on a zero coset offset. Add
`FFTError::InvalidCosetOffset` and propagate it instead.

* refactor(math): remove dead Polynomial APIs and self-referential tests

Continues the dead-code audit of polynomial.rs. Every item removed here
has no production caller — each is a function reachable only from its own
tests, or a test-file algorithm that tests itself.

Removed from polynomial.rs:
- to_extension (zero callers anywhere)
- long_division_with_remainder, leading_coefficient
- ruffini_division_inplace
- interpolate_coset_eval_with_g_n_inv (base-field variant)

Removed the matching self-referential tests/helpers from
polynomial_tests.rs (division_works, division_by_zero_degree_polynomial_works,
test_xgcd, ruffini_inplace_* and the div_with_ref / xgcd / ruffini_division
helpers).

The 3 barycentric tests that exercised the base-field
interpolate_coset_eval_with_g_n_inv now call the production-used
interpolate_coset_eval_ext_with_g_n_inv (instantiated E=F), so they keep
covering the real code path.

* refactor(math): keep Deserializable in math; leave crypto/merkle_tree/proof.rs untouched

The earlier dead-code sweep removed `Deserializable` + `DeserializationError`
from `math` because its only out-of-crate user was the `impl Deserializable`
in `crypto/crypto/src/merkle_tree/proof.rs`, so the PR also dropped those
impls. PR #611 (arity-4 FRI + Merkle caps) explicitly asks this PR to leave
`proof.rs` alone, so revert that pair of deletions:

- Restore `proof.rs` to main's contents (diff vs main: empty).
- Restore `DeserializationError` enum and `From<ByteConversionError>` impl
  in `math/src/errors.rs`.
- Restore `Deserializable` trait + the `DeserializationError` import in
  `math/src/traits.rs`.

The `Serializable` half of the impl block in `proof.rs` is gated on
`crypto/crypto`'s `alloc` feature, which no consumer in this repo
enables — that code path was already non-compiling and is unchanged here.

Tests: `cargo test -p math -p crypto` → 46 + 198 green. `make lint` clean.

* refactor(math): drop all 14 Polynomial operator impls + naive Lagrange (#618)

After #604 (boundary.rs eval-form) and #621 (end_exemptions_poly eval-form)
landed on main, no production code in the prover uses `Polynomial`
operators anymore. The only remaining user was `Polynomial::interpolate`
(test-only Lagrange interpolation, gated `#[cfg(test)]` and used as a
naive reference by the FFT cross-check tests). With both production
references gone, the operators + the naive interpolant can go too.

Removed:
- All 14 operator `impl`s (Add P+/-P, Neg P, Mul P*P, Sub P-FieldElement);
  the previous PR kept these four families because `transition.rs` and
  `boundary.rs` used them. They are now fully unreachable.
- `Polynomial::interpolate` and `InterpolateError` from `polynomial.rs`.
- Operator unit tests in `polynomial_tests.rs` (adding_, negating_,
  multiply_*) and their helpers (`polynomial_a`, `polynomial_b`,
  `polynomial_minus_a`, `polynomial_a_plus_b`).
- `compose` test helper + `composition_works` test (depended on the
  removed `interpolate`).
- Direct `interpolate_x_*_y_*` tests (tested the removed function).

Rewrote:
- FFT correctness tests (both `fft_tests.rs` and
  `fft_friendly_u64_goldilocks_tests.rs`): the
  `gen_fft_and_naive_interpolate` / `_coset_` helpers cross-checked
  `interpolate_fft` against naive Lagrange. Replaced with FFT
  round-trip via direct Horner evaluation — interpolate via FFT, then
  re-evaluate at every twiddle with `Polynomial::evaluate` (a different
  algorithm). Same independence property, no naive Lagrange needed.
- `simple_interpolating_polynomial_by_hand_works`: swapped `*` for
  `mul_with_ref(&...)` (the only remaining call site that needed it).

Verified:
- `cargo build --workspace` clean.
- `cargo test -p math` -> 178 passing.
- `cargo test -p lambda-vm-prover --lib` -> 281 pass / 77 pre-existing
  failures unrelated to constraints (same baseline as main).
- `make lint` clean across all three clippy configs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants