refactor(math): dead-code & structural cleanup of the math crate#598
Conversation
…r 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).
`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.
`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.
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.
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.
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.
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).
Review: Cleanup/math dead codeClean structural refactor — removes ~830 lines of dead code and flattens the Medium — Breaking API changesThree previously-public methods are now gated by
If the goal is to hide these from external crates, Low — Pre-existing panic surfaced by the move
Removed public API (no objection, just noting)The following public items are removed with no replacement:
The removed No issues with the restructuring itselfThe |
Codex Code ReviewNo issues found in the PR diff for security, correctness, significant performance, or simplicity. I attempted to run tests, but the sandbox could not resolve/fetch Cargo dependencies and also hit read-only Cargo/Rustup cache paths. Static review only. |
…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.
Codex Code ReviewFindings
Security No Critical/High/Medium/Low security vulnerabilities found in the diff. Verification I attempted |
Code Review: Cleanup/math dead codeSummary: This PR removes dead code and restructures the Medium — Reduced cross-validation coverage for a security-critical algorithmThe deleted
These cross-checks were the strongest correctness guarantee for the FFT. Removing both the reference implementation and the cross-check tests simultaneously means Bowers FFT is now only validated against the naive O(n²) DFT — a different algorithm family, not an independent implementation of the same algorithm. For a ZK proving system, FFT correctness is directly tied to proof soundness. Consider keeping at least the proptest cross-check by extracting the reference NR FFT into a test-only helper instead of deleting it entirely. Low — Panic on zero offset in public API (
|
…set 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.
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.
…/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.
|
/bench 5 |
Benchmark — fib_iterative_8M (median of 5)Table parallelism: auto (cores / 3)
Commit: 54aac43 · Baseline: cached · Runner: self-hosted bench |
#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.
Summary
Dead-code and structural cleanup of the
mathcrate. Removes unused publicAPI, flattens the FFT module layout, and consolidates tests into one place.
No behavior changes — every removed item has zero production callers.
Changes
Dead code removal
Deserializabletrait and the unreachable error variantsit fed:
DeserializationError,PairingError,ByteConversionError::{InvalidValue, PointNotInSubgroup, ValueNotCompressed},CreationError::InvalidDecString.helpersmodule (next_power_of_two,resize_to_next_power_of_two) — unused.Visibility tightening
Polynomial::{truncate, reverse}andPolynomial::evaluate_fft_bit_reversedbehind
#[cfg(test)]. Every caller is test-only (truncate/reversearereached only through the already-
cfg(test)fast_division/invert_polynomial_mod;evaluate_fft_bit_reversedonly from the FFTproperty tests), so this keeps them out of the production binary.
Structural
fft/cpu/*up tofft/*— thecpulayer had nogpusibling.polynomial/folder into a singlepolynomial.rs; delete thestale
polynomial/README.md.tests/directory.
Folded in (commit 48762cf)
reference_fft.rs(the reference radix-2 FFT) and its fourcomparison tests. It existed only to cross-check the production Bowers FFT,
which is already verified directly against a naive O(n^2) DFT at the same
sizes — the reference oracle was redundant.
get_powers_of_primitive_rootas test-only; production twiddlegeneration goes through
bowers_fft::LayerTwiddles.evaluate_fft_cpu/interpolate_fft_cpuone-line wrappersinto their sole callers; narrow
coset_lde_full_intotopub(crate).bit_reversing.rs,goldilocks.rsand
extensions_goldilocks.rsintotests/.Footprint
25 files in
crypto/math, +674 / -1113. The insertions are mostly thepolynomial/mod.rscontent relocating intopolynomial.rs.Test plan
cargo test -p math— 211 passmake lint(clippy--workspace --all-targets -D warnings) — clean