Skip to content

Commit 059e8db

Browse files
TomWambsgansclaude
andcommitted
docs: merge doc.tex, pcs.tex and ring-switching.tex into one LaTeX project
`misc/` becomes `doc/`, a single project with one PDF output (39 pages): `doc/main.tex` inputs `preamble/`, the nine spec sections from `body/`, then ring switching and the PCS as annexes A and B. Section text is unchanged; only notation, redundant definitions and structure moved. Notation is now defined once, in `preamble/macros.tex`, and every named object has one meaning across the whole document: - multilinear extensions are `\widetilde` everywhere, freeing the hat for the additive NTT's normalized subspace polynomials; - annex B's symbols that collided with the spec are renamed through semantic macros, so changing a glyph is a one-line edit. Annex B opens with a table mapping all 31 renames back to the names WHIR/Ligerito/BCHKS25 and `crates/pcs` use; - genuine unifications rather than substitutions: `m_i` becomes the stack's `M_i`, the batching challenge is `\lambda` on both sides, claim counts join the pool's `J`, and a claim is `(W, c)` throughout; - bound and index variables stay short and shared, which the annex says. Redundant definitions collapsed: the fields were defined three times, `eq` and the weighted claim twice. Phi, its 64-term soundness argument and the weight-evaluation formula lived in both ring-switching.tex and doc.tex's appendix; they now appear once in annex A, and the flock instantiation (packing into q_pkd, the incoming claim, the coordinate transpose) is section 3.3, keeping the `sec:ringswitch` label. The `sec:state` label collided and annex B's copy is now `pcs:proof`; all other labels are preserved, so the `thm:rbr` and `thm:mca-johnson` references in `crates/pcs` still resolve. Three bibliographies become `doc/refs.bib` with `alphaurl`, folding the duplicate keys for Diamond-Posen, Ligerito and WHIR, and keeping the flock paper and the flock implementation as separate entries. CI: `pdf.yml`, `pcs.yml` and `ring-switching.yml` become one `doc.yml` that publishes `leanVM-b.pdf` to the existing `spec-latest` tag and fails a PR on any undefined reference. The `pcs-latest` and `ring-switching-latest` release tags now have nothing rebuilding them. Verified by a clean rebuild: no undefined references or citations, no multiply-defined labels, no overfull boxes. `cargo check --release` passes on the three crates whose comments moved from `misc/` to `doc/`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 6d29dfa commit 059e8db

35 files changed

Lines changed: 1632 additions & 1611 deletions
Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
name: Spec PDF
1+
name: Documentation PDF
22

33
on:
44
push:
55
branches: [ "main" ]
66
paths:
7-
- 'misc/doc.tex'
8-
- 'misc/images/**'
9-
- '.github/workflows/pdf.yml'
7+
- 'doc/**'
8+
- '.github/workflows/doc.yml'
109
pull_request:
1110
paths:
12-
- 'misc/doc.tex'
13-
- 'misc/images/**'
14-
- '.github/workflows/pdf.yml'
11+
- 'doc/**'
12+
- '.github/workflows/doc.yml'
1513
workflow_dispatch:
1614

1715
concurrency:
18-
group: pdf-${{ github.ref }}
16+
group: doc-${{ github.ref }}
1917
cancel-in-progress: true
2018

2119
jobs:
@@ -29,8 +27,11 @@ jobs:
2927
- name: Compile LaTeX
3028
uses: xu-cheng/latex-action@v3
3129
with:
32-
working_directory: misc
33-
root_file: doc.tex
30+
working_directory: doc
31+
root_file: main.tex
32+
- name: Fail on an undefined reference or citation
33+
run: |
34+
! grep -qE 'Reference .* undefined|Citation .* undefined|multiply defined' doc/.build/main.log
3435
3536
build-pdf:
3637
if: github.event_name != 'pull_request'
@@ -42,13 +43,17 @@ jobs:
4243
- name: Compile LaTeX
4344
uses: xu-cheng/latex-action@v3
4445
with:
45-
working_directory: misc
46-
root_file: doc.tex
46+
working_directory: doc
47+
root_file: main.tex
48+
- name: Name the artifact
49+
run: cp doc/.build/main.pdf leanVM-b.pdf
4750
- name: Publish PDF as release asset
4851
uses: softprops/action-gh-release@v2
4952
with:
5053
tag_name: spec-latest
51-
name: Latest spec PDF
52-
body: Auto-built from `misc/doc.tex` on every push to `main`.
54+
name: Latest leanVM-b PDF
55+
body: |
56+
Auto-built from `doc/main.tex` on every push to `main`.
57+
Contains the specification, Annex A (ring switching) and Annex B (the PCS).
5358
make_latest: false
54-
files: misc/doc.pdf
59+
files: leanVM-b.pdf

.github/workflows/pcs.yml

Lines changed: 0 additions & 52 deletions
This file was deleted.

.github/workflows/ring-switching.yml

Lines changed: 0 additions & 52 deletions
This file was deleted.

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
A minimal (zero-knowledge Virtual Machine, which is actually not ZK in the real sense, i.e. it's only a snark, not a zk-snark).
66

7-
- `misc/doc.tex` describes the machine ISA, the snark that proves it.
7+
- `doc/` is one LaTeX project (root `doc/main.tex`, build with `latexmk -pdf main.tex`, output in `doc/.build/`) describing the machine ISA and the snark that proves it. Sections live in `doc/body/`, ring switching and the PCS are annexes in `doc/annex/`, and every symbol is defined once in `doc/preamble/macros.tex`.
88
- `crates/lean_compiler/zkDSL.md` documents the (pythonic) zkDSL (that compiles to the ISA that our VM runs, and that our snark proves).
99

1010
Primary goal:
@@ -78,7 +78,7 @@ The same verification algorithm is written out three times, in three languages.
7878
The third is worth understanding before touching the verifier. `guests/recursion.py` is not Python that runs; it is the zkDSL, which `lean_compiler` lowers to the VM's seven-opcode ISA (`XOR`, `MUL`, `SET`, `DEREF`, `JUMP`, `BLAKE3`, `PACK64X2`) over write-once memory. So every verifier step, sponge absorption, sumcheck fold, Merkle path, field inverse, becomes VM instructions that the prover then proves the execution of, which is why the guest is ~500k instructions and why its opcode mix is what the recursion benchmark reports. Two consequences:
7979

8080
- The guest is **generic in the inner proof**: its placeholder map depends only on the inner bytecode size, so one compiled bytecode verifies inner proofs of different sizes and PCS rates (`recursion_2to1_mixed`, `recursion_generic_many`).
81-
- It does not verify *quite* everything in-circuit. Three claims on fixed polynomials (stacked bytecode, and flock's A0/B0) are deferred, bound to the guest's public input, and discharged natively by `RecursiveProof::verify`. Sumcheck is used to merge and further deref those 'postponed' claims in recursion, moving `n` such inner claims to a single outer one (explained in doc.tex).
81+
- It does not verify *quite* everything in-circuit. Three claims on fixed polynomials (stacked bytecode, and flock's A0/B0) are deferred, bound to the guest's public input, and discharged natively by `RecursiveProof::verify`. Sumcheck is used to merge and further deref those 'postponed' claims in recursion, moving `n` such inner claims to a single outer one (explained in `doc/`).
8282

8383
`recursion_2to1` is the fast end-to-end check; `recursion_soundness_binds` is the adversarial one, tampering each hint stream in turn and requiring rejection.
8484

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<h1 align="center">leanVM-b</h1>
22

33
<p align="center">
4-
<img src="./misc/images/banner-b.svg" alt="leanVM-b">
4+
<img src="./doc/images/banner-b.svg" alt="leanVM-b">
55
</p>
66

77
<p align="center">
8-
<a href="./misc/doc.tex"><img src="https://img.shields.io/badge/Specification-source-blue?style=for-the-badge&logo=latex&logoColor=white" alt="Specification source"></a>
8+
<a href="./doc/main.tex"><img src="https://img.shields.io/badge/Specification-source-blue?style=for-the-badge&logo=latex&logoColor=white" alt="Specification source"></a>
99
<a href="https://github.com/leanEthereum/leanVM-b/releases/download/spec-latest/doc.pdf"><img src="https://img.shields.io/badge/main-PDF-blue?style=for-the-badge&logo=latex&logoColor=white" alt="Latest main-branch PDF"></a>
1010
</p>
1111

crates/lean_compiler/zkDSL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ The zkDSL is a Python-syntax language that compiles to the leanVM-b ISA — seve
44
instructions (`XOR`, `MUL`, `SET`, `DEREF`, `JUMP`, `BLAKE3`, `PACK64X2`) over the binary
55
field GF(2^192), with write-once memory and all indices carried "in the
66
exponent" as powers of a fixed generator. For the underlying VM and proving
7-
system, see [`misc/doc.tex`](../../misc/doc.tex).
7+
system, see [`doc/main.tex`](../../doc/main.tex).
88

99
Source files use the `.py` extension and are **valid Python**: they import the
1010
[`snark_lib`](snark_lib.py) stub, which defines `GEN`, `log`, `mul_range`,

crates/lean_vm/src/constraints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
//! end, as the recursion guest does. That is what a recursive verifier needs.
3030
//!
3131
//! The eq point is the caller's, not a fresh one — the bus's GKR point `ζ` — which
32-
//! is what lets the forms' sums settle the bus. Batching derived in `misc/doc.tex`
32+
//! is what lets the forms' sums settle the bus. Batching derived in `doc/main.tex`
3333
//! §sec:air. Both sides take `n = max τ_t` from the announced heights; a recursive
3434
//! verifier certifies that maximum with one hinted `g`-power (§recursion), so there
3535
//! are no rounds in which no table has joined.

crates/lean_vm/src/cpu/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Whole-program assembly over GF(2^64) (`misc/doc.tex`): the instruction tables
1+
//! Whole-program assembly over GF(2^64) (`doc/main.tex`): the instruction tables
22
//! sharing the state / memory / bytecode buses, bound to one field-valued
33
//! commitment and verified oracle-free. Addresses, the program counter, and read
44
//! counts are g-powers, so every increment is a free ×g. Machine-word arithmetic
@@ -50,7 +50,7 @@ const MAX_LOG_MEM: usize = 32;
5050

5151
/// Each per-opcode table holds at most `2^MAX_LOG_ROWS` rows (executed
5252
/// instructions of that opcode). Together with `MAX_LOG_MEM` and the bytecode
53-
/// cap these are the instance caps from “Counts must not wrap” in `misc/doc.tex`: at `ord(g) = 2^64−1`
53+
/// cap these are the instance caps from “Counts must not wrap” in `doc/body/05-memory-and-bytecode-lookups.tex`: at `ord(g) = 2^64−1`
5454
/// the memory-soundness and count-non-wrap counting arguments are theorems only
5555
/// for instances whose total read-flush count stays far below `2^64`, so the
5656
/// verifier rejects any announcement exceeding them before running a reduction.

crates/lean_vm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! leanVM-b — arithmetization of a minimal zkVM (see `misc/doc.tex`).
1+
//! leanVM-b — arithmetization of a minimal zkVM (see `doc/main.tex`).
22
//!
33
//! Machine words are `c0 + c1*y + c2*y² ∈ E = K[y]/(y³ + y + 1)`.
44
//! Addresses, pc/fp, read counters, and logical indices live in

crates/lean_vm/src/tables.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Per-instruction tables (`misc/doc.tex`, “The instruction tables”). Each opcode is one [`Table`] impl that declares,
1+
//! Per-instruction tables (`doc/body/06-instruction-tables.tex`). Each opcode is one [`Table`] impl that declares,
22
//! in one place, its committed columns, how to fill them from the trace, its bus
33
//! interactions (flushes), the read-count columns that feed the count channel,
44
//! and its degree-2 constraint. Column indices here are *local* (`0..n_committed_columns`);
@@ -642,7 +642,7 @@ mod jump {
642642
pub const RBC: usize = 22;
643643
// Local witness columns (committed, never flushed): the inverse hint `w`
644644
// (192-bit: c⁻¹ in E) and the taken indicator `b = [c ≠ 0]` it certifies
645-
// (the `JUMP` table in `misc/doc.tex`). `b` is a single K-lane (0/1).
645+
// (the `JUMP` table in `doc/body/06-instruction-tables.tex`). `b` is a single K-lane (0/1).
646646
pub const W_LO: usize = 23;
647647
pub const W_HI: usize = 24;
648648
pub const W_TOP: usize = 25;
@@ -818,7 +818,7 @@ impl Table for Pack64x2Table {
818818

819819
// ---- BLAKE3 ------------------------------------------------------------------
820820

821-
/// `BLAKE3` (“BLAKE3” in `misc/doc.tex`): one standard compression. The four 128-bit message
821+
/// `BLAKE3` (“BLAKE3” in `doc/body/06-instruction-tables.tex`): one standard compression. The four 128-bit message
822822
/// chunks are addressed *independently* at `aa0, aa1, ab0, ab1`
823823
/// (`= fp·g^{ins[i]}`), each a single cell — no forced contiguity between
824824
/// chunks, so a caller hashing e.g. `(tweak, pp)` need not copy them into

0 commit comments

Comments
 (0)