Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8af3098
multi-stark proof deserializer
gabriel-barrett May 25, 2026
b0df14f
recursive verifier entrypoint
gabriel-barrett May 25, 2026
9e40ac2
keccak
gabriel-barrett May 25, 2026
e80ef01
recursive verifier keccak assertion
gabriel-barrett May 25, 2026
6ca79d5
`keccak_f` -> `keccak_f_fold`
gabriel-barrett May 25, 2026
6719422
`[U8; 8]` -> `&[U8; 8]`
gabriel-barrett May 25, 2026
db21198
keccak state defined
gabriel-barrett May 25, 2026
c242a84
recursive verifier stub
gabriel-barrett May 25, 2026
1f508d4
`Ext` redefinition
gabriel-barrett May 25, 2026
97000a5
Fiat-Shamir
gabriel-barrett May 26, 2026
91bfcfd
OOD check scaffold
gabriel-barrett May 26, 2026
db4ee07
Verifying key manual codec
gabriel-barrett May 26, 2026
76e4262
System deserialize in Aiur
gabriel-barrett May 28, 2026
5ad0062
OOD check
gabriel-barrett May 29, 2026
a4c6db5
Claims
gabriel-barrett May 29, 2026
af1552a
removed dead code
gabriel-barrett Jun 3, 2026
faca521
PCS MMCS hash (sponge + compress)
gabriel-barrett Jun 3, 2026
309b2cb
PCS Merkle verify_batch
gabriel-barrett Jun 3, 2026
2ac024f
PCS challenger sample_bits
gabriel-barrett Jun 3, 2026
a844c9d
PCS challenger continuation
gabriel-barrett Jun 5, 2026
9c2abb6
PCS FRI fold_row and reduced openings
gabriel-barrett Jun 5, 2026
dea3723
Goldilocks non-native arithmetic
gabriel-barrett Jun 8, 2026
2c50521
OOD check non-native arithmetic
gabriel-barrett Jun 8, 2026
99c61a0
PCS verifier finished
gabriel-barrett Jun 9, 2026
cbdbae3
Fully non-deterministic proof
gabriel-barrett Jun 10, 2026
3b0b7bc
Tests in a different toplevel
gabriel-barrett Jun 11, 2026
5995e1e
fixup
gabriel-barrett Jun 11, 2026
97ee6aa
clippy and fmt
gabriel-barrett Jun 11, 2026
201db04
manual codec, fixed Cargo.toml
gabriel-barrett Jun 19, 2026
f44f9e4
Replace recursive-verifier executable with LSpec tests
gabriel-barrett Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Test Ix CLI
run: lake test -- cli
- name: Aiur tests
run: lake test -- --ignored aiur aiur-hashes ixvm
run: lake test -- --ignored aiur aiur-hashes ixvm multi-stark recursive-verifier
- name: Check Lean versions match for Ix and compiler bench
run: diff lean-toolchain Benchmarks/Compile/lean-toolchain

Expand Down
4 changes: 4 additions & 0 deletions Ix/Aiur/Protocol.lean
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ namespace AiurSystem
@[extern "rs_aiur_system_build"]
opaque build : @&Bytecode.Toplevel → @&CommitmentParameters → AiurSystem

/-- Serialize the verifying key (`System<AiurCircuit>`) to bytes. -/
@[extern "rs_aiur_system_vk_bytes"]
opaque vkBytes : @& AiurSystem → ByteArray

@[extern "rs_aiur_system_prove"]
private opaque prove' : @& AiurSystem → @& FriParameters →
@& Bytecode.FunIdx → @& Array G →
Expand Down
98 changes: 98 additions & 0 deletions Ix/MultiStark.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
module
public import Ix.Aiur.Meta
public import Ix.IxVM.Core
public import Ix.IxVM.ByteStream
public import Ix.MultiStark.Goldilocks
public import Ix.MultiStark.Deserialize
public import Ix.MultiStark.Keccak
public import Ix.MultiStark.Pcs
public import Ix.MultiStark.SystemDeserialize
public import Ix.MultiStark.Verifier
public import Ix.MultiStark.Tests

/-!
# Multi-STARK proof verifier (Aiur)

The recursive verifier. Its public statement is purely existential: *"there
exists a valid multi-stark proof, under the FRI parameters given as public
input, for the constraint system with this keccak-256 digest and these public
claims."* The proof itself is **non-deterministic advice** (fed on IO channel 0,
never hashed or otherwise bound as a public input): the Fiat-Shamir transcript
replay plus the Merkle/OOD/FRI checks are exactly what make any accepted advice
a valid proof — a hash binding of the proof bytes would add nothing to the
statement, while costing one keccak-f per 136 bytes in-circuit.

The verifying key and claims, by contrast, ARE digest-bound (`system_digest`,
`claims_digest`): they determine *what was proven*.

Fixed protocol assumptions (our system): `queryProofOfWorkBits = 0`,
`capHeight = 0`, `maxLogArity = 1`, `logFinalPolyLen = 0`. The variable FRI
parameters (`num_queries`, `commit_pow_bits`, `log_blowup`) are public inputs.
-/

public section

namespace MultiStark

def entrypoints := ⟦
-- Public inputs: the keccak-256 digests of the verifying key and the claims
-- (4 little-endian u64 lanes each) plus the variable FRI parameters. The
-- proof is pure non-deterministic advice on IO channel 0 — see the module
-- docstring. One stream per channel (0 = proof, 1 = vk, 2 = claims), each
-- registered under key `[0]` on its channel.
pub fn verify_multi_stark_proof(system_digest: [[U8; 8]; 4], claims_digest: [[U8; 8]; 4], num_queries: G, commit_pow_bits: G, log_blowup: G) {
-- Proof advice from IO channel 0: deserialize, assert fully consumed.
let (idx, len) = io_get_info(0, [0]);
let bytes = #read_byte_stream(0, idx, len);
let (proof, rest) = read_proof(bytes);
assert_eq!(load(rest), ListNode.Nil);
-- Verifying key (`System<AiurCircuit>`) from IO channel 1: bind the bytes
-- to the public keccak-256 `system_digest`, then reconstruct the system.
let (sidx, slen) = io_get_info(1, [0]);
let sbytes = #read_byte_stream(1, sidx, slen);
assert_eq!(keccak256(sbytes), system_digest);
let (sys, srest) = read_system(sbytes);
assert_eq!(load(srest), ListNode.Nil);
-- Public claims (`&[&[Val]]`) from IO channel 2: bind the bytes to the
-- public keccak-256 `claims_digest`, then deserialize. Binding them as a
-- public input is what makes the lookup argument sound (a prover cannot
-- choose claims adaptively).
let (cidx, clen) = io_get_info(2, [0]);
let cbytes = #read_byte_stream(2, cidx, clen);
assert_eq!(keccak256(cbytes), claims_digest);
let (claims, crest) = read_claims(cbytes);
assert_eq!(load(crest), ListNode.Nil);
-- Structural + accumulator + PCS checks.
assert_eq!(verify(proof), 1);
-- Step 3 + 5: prover-faithful Fiat-Shamir replay and the out-of-domain
-- composition/quotient check, `composition(ζ)·inv_vanishing(ζ) == quotient(ζ)`.
assert_eq!(ood_verify(sys, proof, claims, num_queries, commit_pow_bits, log_blowup), 1);
()
}

/-- The standalone Multi-STARK verifier toplevel: `core` (lists/options) +
`byteStream` (`U64`, `flatten_u64`, `read_byte_stream`, …) + the deserializer,
the keccak-256 implementation, and the entrypoint. -/
def multiStark : Except Aiur.Global Aiur.Source.Toplevel := do
let t ← IxVM.core.merge IxVM.byteStream
let t ← t.merge MultiStark.goldilocks
let t ← t.merge deserialize
let t ← t.merge keccak
let t ← t.merge systemDeserialize
let t ← t.merge pcs
let t ← t.merge verifier
t.merge entrypoints

/-- The verifier toplevel PLUS its self-test entrypoints
(`Ix/MultiStark/Tests.lean`). Kept separate from `multiStark` because every
`pub fn` adds a circuit to the compiled system — the production verifier should
not carry test-only width. Use this toplevel only to run the `*_test`
entrypoints. -/
def multiStarkTests : Except Aiur.Global Aiur.Source.Toplevel := do
let t ← multiStark
t.merge tests

end MultiStark

end
Loading