feat(prover): Memory-mapped private input for guest programs#512
Conversation
Codex Code Review
|
|
Benchmark Results for modified programs 🚀
|
|
Benchmark Results for unmodified programs 🚀
|
|
/bench |
Codex Code Review
No other concrete security/bug/perf issues stood out in this diff. |
Benchmark — fib_iterative_8M (median of 3)Table parallelism: 32 (auto = cores / 3)
Commit: 7adb2d9 · Baseline: built from main · Runner: self-hosted bench |
PR Review: Memory-mapped private inputOverall the architecture is sound — replacing the ecall with a memory-mapped region at [High] CLI
|
…a_vm into feat/private-input-v2
…a_vm into feat/private-input-v2
Codex Code Review
No other clear security/correctness/perf issues stood out in this diff. |
Code Review — feat(prover): Memory-mapped private inputThe core design (pre-loading private input at HighAttacker-controlled allocation in verifier ( MediumNo bounds check on Global page size bump from 4 KB → 256 KB ( LowPR description is stale ( Not issues (noted for clarity)
|
…a_vm into feat/private-input-v2
Verify the verifier rejects proofs with tampered num_private_input_pages (zeroed, inflated, exceeds max) and tampered public_output when private input is present. Also confirm the proof struct does not carry raw private input bytes.
22a81c9 to
b3cdaa5
Compare
Summary
Replace the
GetPrivateInputsecall with a memory-mapped approach: private input is pre-loaded at address0xFF000000as part of the initial memory image. The guest reads it via normalRISC-V loads — no ecall, no invisible writes, no bus imbalance.
Problem
The old
GetPrivateInputsecall (syscall #4) copied input bytes into a guest buffer inside the executor without emitting anyLogentries. The prover never saw those writes, so whenthe guest later read the buffer, the MEMW table had
old_value = actual_bytebut the PAGE table hadinit = 0(zero-init page). This caused a Memory bus imbalance and made verificationfail for any program reading private input.
How it works now
Host side:
Executor::new(elf, private_input)pre-loads input at0xFF000000with a 4-byte LE length prefix followed by the raw data bytes. This happens before execution starts.Prover side:
MemoryState::add_private_input()mirrors the same layout at timestamp 0. A shared helperbuild_init_page_data(elf, private_input)produces the PAGE init valuesfor both the prover (trace generation) and verifier (page config reconstruction), ensuring they agree exactly.
Guest side:
get_private_input()does aread_volatileof the length at0xFF000000, thenslice::from_raw_partsfor the data bytes. No ecall — just normal RISC-V loads thatthe prover tracks through the standard MEMW → PAGE chain.
Proof artifact:
VmProofincludesprivate_input: Vec<u8>so the verifier can reconstruct the matching PAGE preprocessed commitments at0xFF000000.API