Problem
Today ceno_rt::commit compares a guest value against preloaded public IO memory (pubio_read_slice) and asserts equality in guest runtime. This ties commit semantics to a public memory region and a dedicated public-io circuit path.
Current behavior is centered around:
ceno_rt/src/mmio.rs (commit<T>, pubio_read_slice)
- Public IO initialization in host/e2e paths (
ceno_host, ceno_zkvm/src/e2e.rs)
PublicValues.public_io: Vec<u32> in ceno_zkvm/src/scheme.rs
We want to move to digest-based commit semantics handled by syscall + precompile, and remove the old public IO memory/circuit flow.
Proposal
1) Rewrite guest API: ceno_rt::commit
- Change
ceno_rt::commit signature to accept raw bytes:
pub fn commit(data: &[u8])
- Internally:
- Compute Keccak digest (via
tiny_keccak)
- Convert digest into
[u32; 16], where each element stores one u16 limb in the low 16 bits
- Send digest limbs through a new syscall (
PUB_IO_COMMIT-style syscall)
2) Add syscall + precompile path
- Introduce new syscall for public-io commit digest submission
- Implement new precompile:
pubio_commit
- Assume syscall payload is always Keccak digest limbs (
[u32; 16] with 16-bit limbs)
3) Extend public values
- Update
PublicValues to include extra digest field:
- e.g.
pubio_digest: [u32; 16]
- Wire this through proving/verification/public input queries as needed
4) Update host/CLI/e2e input preparation
- In
ceno_zkvm/src/e2e.rs and ceno_cli, prepare public io from args by:
- serializing bytes (same format as guest input expectation)
- computing Keccak digest
- converting to
[u32; 16] limbs
- Pass digest limbs into
PublicValues instead of raw public IO memory vector semantics
5) Remove old public IO circuit/memory path
- Remove original public-io-memory-related circuit plumbing now replaced by precompile
- Remove dependencies on loading/verifying public IO via dedicated memory range where no longer required
Scope / Affected Areas
- Runtime guest API:
ceno_rt/src/mmio.rs
ceno_rt/src/lib.rs exports
- Syscall/ecall handling:
- new syscall opcode/plumbing
- instruction wiring near existing ecall paths (see
ceno_zkvm/src/instructions/riscv/ecall/halt.rs for style/context)
- Precompile:
- add
pubio_commit module and registration
- Public values and PI query:
ceno_zkvm/src/scheme.rs (PublicValues, constructor, index/query, MLE usage if needed)
- Execution pipeline:
ceno_zkvm/src/e2e.rs
ceno_cli public io arg handling (ceno_cli/src/commands/common_args/ceno.rs)
- Cleanup:
- remove/deprecate old public-io-specific circuit/memory plumbing
Implementation Checklist
Acceptance Criteria
- Guest programs can call
ceno_rt::commit(&[u8]) without reading from public-io memory
- Prover/verifier agree on public commitment via digest limbs (
[u32;16], low-16-bit populated)
PublicValues includes commitment digest and verification uses it
- CLI/e2e public input path produces identical digest/limbs to runtime rules
- Old public io memory circuit path is removed and no longer required
- Existing e2e flows pass with updated commitment mechanism
Problem
Today
ceno_rt::commitcompares a guest value against preloaded public IO memory (pubio_read_slice) and asserts equality in guest runtime. This ties commit semantics to a public memory region and a dedicated public-io circuit path.Current behavior is centered around:
ceno_rt/src/mmio.rs(commit<T>,pubio_read_slice)ceno_host,ceno_zkvm/src/e2e.rs)PublicValues.public_io: Vec<u32>inceno_zkvm/src/scheme.rsWe want to move to digest-based commit semantics handled by syscall + precompile, and remove the old public IO memory/circuit flow.
Proposal
1) Rewrite guest API:
ceno_rt::commitceno_rt::commitsignature to accept raw bytes:pub fn commit(data: &[u8])tiny_keccak)[u32; 16], where each element stores oneu16limb in the low 16 bitsPUB_IO_COMMIT-style syscall)2) Add syscall + precompile path
pubio_commit[u32; 16]with 16-bit limbs)3) Extend public values
PublicValuesto include extra digest field:pubio_digest: [u32; 16]4) Update host/CLI/e2e input preparation
ceno_zkvm/src/e2e.rsandceno_cli, prepare public io from args by:[u32; 16]limbsPublicValuesinstead of raw public IO memory vector semantics5) Remove old public IO circuit/memory path
Scope / Affected Areas
ceno_rt/src/mmio.rsceno_rt/src/lib.rsexportsceno_zkvm/src/instructions/riscv/ecall/halt.rsfor style/context)pubio_commitmodule and registrationceno_zkvm/src/scheme.rs(PublicValues, constructor, index/query, MLE usage if needed)ceno_zkvm/src/e2e.rsceno_clipublic io arg handling (ceno_cli/src/commands/common_args/ceno.rs)Implementation Checklist
ceno_rt::commitAPI tocommit(&[u8])[u32;16]limb conversion in runtimePUB_IO_COMMITsyscallpubio_commitprecompilePublicValuesand update constructors/consumerse2e.rsto compute and pass digest limbsceno-clito hash public io args and produce digest limbsexamples/examples/fibonacci.rs) to newcommitusageAcceptance Criteria
ceno_rt::commit(&[u8])without reading from public-io memory[u32;16], low-16-bit populated)PublicValuesincludes commitment digest and verification uses it