Quotient matrix - #67
Merged
Merged
Conversation
Slice the quotient by COEFFICIENTS — Q(X) = sum_i X^(i*n) * c_i(X) with each c_i of degree < n — and commit all q slices of a circuit as a single q*D-column matrix on the trace domain, instead of one matrix per slice on the split sub-cosets. The opening phase pays several per-matrix, per-row costs that are independent of matrix width (barycentric evaluation, the (p(x) - y)/(x - z) FRI-input reduction, row extraction per query), so q matrices per circuit multiplied the dominant fri_open work by q. Measured on an IxVM-scale system, the per-matrix passes accounted for ~80% of fri_open and scaled directly with quotient matrix count. One matrix per circuit makes that cost independent of the quotient degree. The verifier gets simpler too: the sub-domain Lagrange recombination (the zps product over vanishing polynomials) becomes a plain power series, Q(zeta) = sum_i zeta^(i*n) * c_i(zeta) — also cheaper to port to the recursive verifier. Prover-side, slicing coefficients requires interpolating the quotient once (coset iDFT of the q*n evaluations, then a size-n DFT of the sliced matrix onto the trace domain) — transform work on q*D columns, negligible against the constraint-evaluation sweep. This adds a TwoAdicField bound on the prover's Val, which every FRI-based configuration satisfies. Breaking change: commitment layout, transcript, and proof shape (the quotient round carries one wide matrix per active circuit).
The repo is sometimes checked out inside another cargo workspace (e.g. the ix monorepo), whose manifest would otherwise absorb this package and break standalone builds. An empty [workspace] table keeps the package self-contained.
Member
Author
|
!benchmark |
arthurpaulino
approved these changes
Jul 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Commit quotient slices as one matrix per circuit
Changes how the quotient polynomial is committed: instead of one matrix per
degree-
nchunk on the split sub-cosets, each circuit's quotient is sliced bycoefficients —
Q(X) = Σᵢ X^{i·n}·cᵢ(X), eachcᵢof degree< n— andall
qslices are committed as a singleq·D-column matrix on the tracedomain, opened once at ζ.
Motivation
The opening phase's dominant costs are per-matrix and width-independent:
barycentric evaluation, the
(p(x) − y)/(x − ζ)reduction that feeds FRI, andper-query row extraction each walk the full LDE height once per matrix,
regardless of how many columns the matrix has. Under the old layout a circuit
contributed
qquotient matrices, so raising the quotient degree multipliedexactly the work these passes do. Profiling an Aiur-scale system (~500
circuits, quotient degree 4) showed the per-matrix passes were ~80% of
fri_open, scaling linearly with quotient matrix count — while the committedarea barely changed.
The same disease affected the commit side (one LDE/Merkle pipeline invocation
per tiny
D-column chunk) and even the proof size: every matrix in a query'sbatch opening carries its own length-prefixed vector, ~8 bytes × matrices ×
queries of pure framing.
The change
Prover (
prove_multiple_claims): after the constraint sweep produces thequotient's evaluations on the size-
q·ncoset, interpolate once (coset iDFT),slice the coefficient vector into
qdegree-< npolynomials, and evaluatethe sliced
n × q·Dmatrix back onto the trace domain (one size-nDFT).The evaluation sweep itself — the expensive part — is untouched; the added
transform work is on
q·Dcolumns and is negligible. Requires aTwoAdicFieldbound on the prover'sVal, which every FRI-basedconfiguration satisfies.
Opening round: the quotient round now has exactly one entry per active
circuit (same shape as stages 1 and 2), instead of
qchunk entries percircuit.
Verifier: the sub-domain Lagrange recombination — the
zpsproducts ofvanishing polynomials over the split cosets — collapses to a power series:
with each
cᵢ(ζ)read from column-slices of the one wide matrix. This isboth cheaper natively and substantially simpler to port to a recursive
verifier. Shape checks change accordingly (one opened row of
q·Dvalues percircuit at the single point ζ).
Soundness is unchanged: each slice is individually degree-bound
< nby FRI(same bound as before), the recombination identity is exact, and the layout
is bound into the transcript through the commitment.
Breaking changes
versions no longer verify. The quotient round of
Proof::quotient_opened_valuesnow carries one entry per active circuit (a
q·D-value row at ζ).recombination from the sub-domain
zpsformula to theζ^{i·n}powerseries.
Testing
The full test suite passes on top of the change (lookup systems, sparse
activation, high-degree circuits, adversarial/tamper tests, serialization
round-trip), and it is exercised end to end downstream by the Ix/Aiur proving
suites (70 prove/verify cases plus BLAKE3/SHA-256 circuits and IxVM kernel
checks).