Skip to content

Counted pulls in formal/: LT with byte μ and soundness by finishing order, on the Clean fork - #1031

Draft
jotabulacios wants to merge 6 commits into
formal/clean-modelfrom
formal/counted-pulls
Draft

jotabulacios wants to merge 6 commits into
formal/clean-modelfrom
formal/counted-pulls

Conversation

@jotabulacios

Copy link
Copy Markdown
Collaborator

Motivation

Lambda VM chips deduplicate: one LT row answers μ ≤ 255 identical queries, so it pulls its range
checks (IS_HALF, MSB16) with multiplicity μ. Clean main requires every pull to have
multiplicity 0 or 1, which is why the model kept LT's μ a bit and documented two deltas against
lt.rs. Two things are missing upstream:

  1. A balance check that matches a pull of multiplicity 1..N with a push. Field-sum balance alone
    doesn't: (p − 1)/2 pulls of 2 and one pull of 1 sum to p ≡ 0 with no push. It does when
    length · N < p.
  2. A finishing order that lets a table's requirements depend on channels finished earlier. LT's
    bound μ ≤ 255 comes from its own pull of ARE_BYTES[μ, 0], and DVRM pulls LT/MUL results and
    pushes DIVREM results on the same ALU bus, which a whole-channel order reads as a cycle.

Both live in the counted-pulls branch of the
yetanotherco/clean fork: Clean main
f3abad7c (the one #1030 moved to) plus three commits.

Description

  • lakefile.toml / lake-manifest.json: Clean from the fork at 1cf67e24. Mathlib and CompPoly
    are unchanged.
  • Tables/Lt.lean: μ is a byte, as in lt.rs. IS_HALF and MSB16 are pulled with
    multiplicity μ through Channel.counted 255, bounded by ARE_BYTES[μ, 0]. The export and
    lean_diff.rs now match LT exactly (6 constraints, 10 interactions), so the LT deltas are gone.
  • Ensembles/LtStaged.lean: the LT ensemble is sound under Balance.logUpUpTo 255, finishing
    ARE_BYTES before the counted IS_HALF and MSB16, and those before ALU.
  • MIN, a toy operation (PoC, not an RV64IM op). Tables/MinToy.lean and opselMIN := 7 in
    Buses/Alu.lean give an operation with DVRM's shape: it pulls an LT result on the ALU bus and
    pushes its own result on the same bus. LtStaged.lean finishes ALU in two stages (non-MIN
    messages, then MIN messages) and proves the ensemble sound; Ensembles/CountedSameBus.lean
    (CMIN) does it with the ALU bus itself counted. EQ, LT and SHIFT discharge the extra
    Alu.Guarantees clause by omega. MIN is meant to be replaced by DVRM once it is modelled.
  • Channels/Counted.lean: gains consistentUpTo, the positive counterpart of not_consistent
    under the fork's BalancedUpTo N. It is no longer used by any table; whether to keep only
    not_consistent or drop it is left for a follow-up.
  • README.md: the counted-pulls section describes what comes from the fork and the new ensembles.

Draft: opened to run formal.yml and to discuss the approach. The fork stays on f3abad7c until
something from newer Clean is needed.

How to Test

  1. cd formal && lake exe cache get && lake build
  2. lake env lean --run LambdaVM/Export.lean && git diff --exit-code -- export
  3. cargo test -p lambda-vm-prover --lib lean_diff

…ove the counted channel consistent there.

The lakefile points at the fork branch, which adds pulls of multiplicity up to N, a counted channel
and soundness by finishing order on top of Clean f3abad7c. For now it is a path dependency on the
build server (../../clean-fork-main); it becomes a git dependency on yetanotherco/clean once the
branch is pushed. Channels/Counted.lean gains consistentUpTo: under BalancedUpTo N, which the fork's
balance checks provide, the counted channel is consistent. It is the positive counterpart of
not_consistent, which still shows the gap under BalancedInteractions alone.
…oes.

mu is now a byte instead of a bit: the row pulls IS_HALF and MSB16 with multiplicity mu through
counted channels, and bounds mu by pulling ARE_BYTES[mu, 0]. The row spec holds for rows with
mu != 0, and the honest prover keeps mu below 2^8. With this the Lean LT chip matches the Rust one
exactly, so lean_diff.rs no longer expects the mu bit constraint on the Lean side and ARE_BYTES on
the Rust side; it asserts that no constraint or interaction appears on one side only.
…d pulls on one bus.

MIN is not an RV64IM operation. Its chip pulls an LT result from the ALU bus and pushes its own
result on the same bus, as the division chip pulls LT and MUL results and pushes DIVREM. The ALU
guarantee gets a MIN clause (opsel 7), so EQ, LT and SHIFT also prove that their pushes are not MIN
results.
… the ALU bus.

LtStaged builds the LT ensemble with counted IS_HALF and MSB16 and proves its table soundness with
tableSoundness_of_staged: ARE_BYTES is finished first, so LT's bound mu <= 255 on its counted pulls
follows from that guarantee. It then adds MIN, finishing the ALU bus in two stages, every message
that is not MIN before MIN. CountedSameBus does the same with CMIN, which pulls LT and pushes MIN
with a counted multiplicity on the ALU bus, the shape of a deduplicated division chip, and proves it
sound with tableSoundness_of_stagedOn.
…rk on GitHub instead of a

local path, so the branch builds anywhere and not only on the build server. The pinned revision,
1cf67e24, is the same Clean the model was built against (counted pulls and soundness by finishing
order on top of Clean main f3abad7c); Mathlib and CompPoly are unchanged.
…6 with multiplicity μ

through Channel.counted 255 and matches lt.rs exactly, so the LT deltas and the "LT keeps μ a bit"
notes are gone. The counted-pulls section says what the model takes from the yetanotherco/clean
fork (Balance.logUpUpTo, Channel.counted, soundness by finishing order) and describes the LtStaged
and CountedSameBus ensembles; the layout lists MinToy and flags MIN as a toy stand-in for DVRM on
the ALU bus.
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