scroll-tech / scroll-tech/ceno
PublicValuesAir underconstrains tidx across AIR boundaries
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 153
- Forks
- 43
- Avg merge
- 3d 13h
- Merged PRs (30d)
- 4
Description
Summary
In ceno_recursion_v2, PublicValuesAir only anchors the first public-value row of each proof to public_values_start_tidx, and only enforces consecutive tidx values while adjacent rows belong to the same AIR. At AIR boundaries, the next row's tidx is not tied to the VK-derived public-value offset.
This leaves non-first AIR public-value transcript indices underconstrained.
Details
Current behavior in src/proof_shape/pvs/air.rs:
- The first public-value row is constrained with
local.tidx == public_values_start_tidx. - For rows in the same AIR,
next.tidx == local.tidx + 1andnext.pv_idx == local.pv_idx + 1. - At an AIR boundary, the AIR only constrains
next.is_first_in_air == 1; it does not constrain the new AIR'stidxto the expected start offset or prove the previous AIR had exactly the expected number of public-value rows.
The commented-out NumPublicValuesBus receive indicates this was likely intended to be checked structurally, but it is currently inactive.
Ceno-specific expected behavior
Unlike OpenVM, Ceno stores public values in one global public-value namespace. Each AIR's instance list stores absolute global public-value indices. The recursion circuit then projects those into (air_idx, pv_idx) rows for bus interactions.
A fix should restore a Ceno-adapted NumPublicValuesBus check:
- Proof-shape sends
(air_idx, start_tidx, num_pvs)using VK-derived public-value metadata. start_tidx = public_values_start_tidx + sum_{j < air_idx} per_air[j].num_public_values.num_pvs = per_air[air_idx].num_public_values.- The sender should be enabled for AIRs with public values in the global public-value block, not gated by trace presence.
PublicValuesAirreceives this message on each AIR's final PV row usingtidx = local.tidx - local.pv_idxandnum_pvs = local.pv_idx + 1.- Also constrain
is_first_in_air => pv_idx == 0.
This would bind each AIR's public-value row range to the VK-declared global public-value layout and close the AIR-boundary tidx gap.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/proof_shape/pvs/air.rs and inspect the active public-value constraints alongside the commented-out NumPublicValuesBus receive. Trace the VK-derived per-AIR public-value metadata used for proof-shape messages. Done means each AIR’s final public-value row is checked against its global start offset and count, including AIR-boundary rows and the first-row pv_idx condition.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cryptography
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100