BINIUS-255: compose the AND-check and shift reduction into the M4 protocol#1771
Merged
jimpo merged 5 commits intoJul 11, 2026
Merged
Conversation
…tocol The batched AND-check and shift reduction existed as standalone building blocks, each driven only by its own test with hand-built inputs. Nothing ran them together on one transcript. Add the composition, for both sides. The prover runs the AND-check over all K * n_and rows, splits the resulting row point into a constraint part r_x (low) and an instance part r_rho (high), folds the witness over the instance axis at r_rho, and feeds the operand claims into the shift reduction at r_x. The verifier mirrors it: AND-check, split, shift verify, public-input check. The output is a single evaluation claim about the instance-folded witness. This is the batched shape of the single-instance protocol's bitand-then-shift threading, and it matches the wiring the shift round-trip test already validated; only the challenges now come from the shared transcript rather than being sampled by the test. The existing reductions are reused unchanged. Only AND constraints are handled; MUL is rejected. Binding the claim to the committed trace oracle (which binds r_rho and bridges the bit witness to the packed commitment via a batched ring-switch) is a later step, not done here. The CRC-64 test fixture moves from shift.rs to a crate-level test module so both the shift and reduction tests can share it without a cross-module reach. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The shared CRC fixture lived in a src file named `crc64.rs`, which reads like production source. CONTRIBUTING points shared test setup at a `test_utils` module, and the repo's convention (binius_math, arith-bench) is exactly a dedicated test-utility file under that name. Rename the module to `test_utils` so a reader sees at once that it is test-only support, matching that convention. No code change; the CRC helpers and their names are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The relocated fixture carried its original prose-style docs: sentences that ran across `///` lines and stacked several to a line. Split them one sentence per line, and turn the per-bit CRC step description into a bullet list. Documentation only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jimpo
reviewed
Jul 10, 2026
jimpo
left a comment
Collaborator
There was a problem hiding this comment.
Hell yeah! This looks super clean. A couple comments, and this'll need a rebase because of the ValueTable rename.
…lic arg Two review follow-ups on the reduction: - Build the shift key collection once in a setup phase rather than on every prove call. `prove_reduction` now takes a `&KeyCollection`, and the caller builds it after preparing the constraint system. The build is expensive, so it should be amortized across proofs of the same circuit. - Drop the `public_words` argument from `verify_reduction`. The shared constant words are already on the constraint system, so the public-input check reads `cs.constants` directly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ndcheck-shift-reduction # Conflicts: # crates/m4-prover/src/lib.rs # crates/m4-prover/src/shift.rs
Contributor
Author
Just fixed the comments and the conflicts with main :) |
jimpo
approved these changes
Jul 11, 2026
| let shift = shift::verify::<B128, _>(cs, &bitand, &intmul, channel)?; | ||
|
|
||
| // Tie in the shared constants through the public-input consistency check. | ||
| let domain = BinarySubspace::<B8>::with_dim(Word::LOG_BITS).isomorphic::<B128>(); |
Collaborator
There was a problem hiding this comment.
follow-up: It would be best to pass this domain into verify_bitand_reduction too (but the pre-isomorphism version). That would ensure it's consistent between andcheck and shift, by construction. On the prover side too.
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.
Part of BINIUS-255. One step toward the M4 protocol; does not close the issue (the trace-oracle tie remains).
Chains the two batched reductions into one reduction on a shared transcript, for prover and verifier. No new cryptography — just the glue.
The problem
The batched AND-check (
BatchAndCheckWitness::prove/verify_bitand_reduction) and the shift reduction (shift::provefeeding the single-instanceshift::{verify, check_eval}) existed as standalone building blocks, each exercised only by its own test with hand-built inputs. Nothing composed them on one Fiat-Shamir transcript.The idea
Run them back to back, the AND-check's output feeding the shift reduction:
The batch-specific step: the AND-check's row point is
(constraint, instance). Split it — the constraint partr_x(low) feeds the shift reduction; the instance partr_rho(high) says how to fold the K instances into one before the shift runs.Why this is correct given the codebase
crates/verifier/src/verify.rs), which already threadsbitand → shiftin this order — so the Fiat-Shamir ordering is unchanged.r_x/r_rho, fold atr_rho, feedr_xto the shift) is precisely the wiring the existingshift.rsround-trip test already validated; the only change is thatr_x,r_rho, and the operand claims now come from the shared transcript rather than being sampled by the test.Scope
m4-prover::prove_reduction,m4-verifier::verify_reduction, and their output structs.r_rhoand bridges the bit witness to the packed commitment via a batched ring-switch that does not exist yet — is a later step, flagged in both module docs.shift.rsto a crate-level#[cfg(test)] mod crc64, so the shift and reduction tests share it without one test module reaching into another's.Verification
cargo test -p binius-m4-prover(28) and-p binius-m4-verifier(3) — passclippy --all-targets,+nightly fmt -- --check— cleanreduction_round_trips: prover and verifier agree onr_rho, the challenge point, and the eval; and the reduced claim equals the true instance-folded witness evaluated at the shift point.tampered_transcript_is_rejected.Note
This branch is cut from
main, which still hasValueTable2(the rename in #1770 is open). When #1770 lands, this is a trivialValueTable2→ValueTablerename here.🤖 Generated with Claude Code