Skip to content

faster table sumcheck - #652

Merged
TomWambsgans merged 1 commit into
mainfrom
faster-table-sumcheck
Nov 1, 2026
Merged

TomWambsgans merged 1 commit into
mainfrom
faster-table-sumcheck

Conversation

@TomWambsgans

@TomWambsgans TomWambsgans commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Faster table sumcheck

Each table's constraint is a quadratic polynomial in its columns, for example P = 3a + 5b + a·c + a·d. Each round, the sumcheck folds the table (halves its rows, mixing pairs with the round's challenge) and evaluates P on the folded rows. It used to fold every column and evaluate P row by row.

Now P is first rewritten with its products grouped by a shared column: P = L + a·R, with L = 3a + 5b and R = c + d. Folding is linear, so folding L gives the same result as folding a and b and then combining them. The sumcheck therefore folds just L, a and R, built once from the original columns when the table joins. On real tables that's a handful of columns instead of dozens, so each round moves far less memory. At the end, each original column is evaluated once to give its claim.

The proof is unchanged, byte for byte. Only the prover changes, and the three verifiers are untouched.

Also in this PR

  • Removes the old base-field path (ColVal, eval_constraint_k, RowForm) and the primitives only it used.
  • JUMP's identities are now stated as data (Table::constraint) instead of a closure.

Adapted from gattaca-com/leanVM's keccak-opt branch, without their bus rewrite (for now).

Benchmarks

Proving time and peak memory against main, paired A/B. Aggregate is --xmss 900, recursion is --n 2 --xmss-per-leaf 900.

machine aggregate recursion peak memory (aggregate)
M4 Max −1.6% −4.0% 6.31 → 5.78 GiB
Zen 4 −6.2% −5.1% 5.00 → 4.51 GiB
Zen 5 −4.8% −3.2% 5.07 → 4.60 GiB
Zen 4, AVX2 only −2.6% −2.8% 4.92 → 4.51 GiB

🤖 Generated with Claude Code

Each table's constraint is a quadratic polynomial in its columns, for
example  P = 3a + 5b + a*c + a*d.  Each round, the sumcheck folds the
table (halves its rows, mixing pairs with the round's challenge) and
evaluates P on the folded rows. It used to fold every column (a, b, c,
d, ...) and evaluate P row by row.

Now P is first rewritten with the products grouped by a shared column:
P = L + a*R, with L = 3a + 5b and R = c + d. Folding is linear, so
folding L gives the same result as folding a and b and then combining
them. The sumcheck therefore folds just the three columns L, a and R,
built once from the original columns when the table joins. On real
tables that is a handful of columns instead of dozens, so each round
reads and writes far less memory. At the end, each original column is
evaluated once to give its claim. The proof is unchanged, byte for byte.

This removes the old base-field path (ColVal, eval_constraint_k,
RowForm) and the primitives only it used. Adapted from
gattaca-com/leanVM's keccak-opt branch, without their bus rewrite,
which was slower on the M4.

Proving time and peak memory vs main
(aggregate --xmss 900 / recursion --n 2 --xmss-per-leaf 900):
  M4 Max        -1.6% / -4.0%   6.31 -> 5.78 GiB
  Zen 4         -6.2% / -5.1%   5.00 -> 4.51 GiB
  Zen 5         -4.8% / -3.2%   5.07 -> 4.60 GiB
  Zen 4, AVX2   -2.6% / -2.8%   4.92 -> 4.51 GiB

Co-Authored-By: alexX512 <alexey@gattaca.com>
Co-Authored-By: vladimir-ea <85992906+vladimir-ea@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TomWambsgans
TomWambsgans merged commit 1acdff1 into main Nov 1, 2026
8 checks passed
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.

1 participant