Proof-State Object Unification and Indexed-Binding Discipline
- Name: proof-state object unification and indexed-binding discipline
- Category: proof-system reference / split-statement prevention note / indexed-state-transition checklist / public-input-witness unification discipline
- Summary: Healthy proof systems do not let one security-critical state object appear as two separately satisfiable stories, or let per-item witness objects float free from the indexed public semantics the application claims. They force one canonical state commitment to mean the same thing everywhere it matters, and they force each command, note, or message to operate on the exact state object its public semantics name before any invalidity branching, skipping logic, or settlement logic can weaken that relation. This note exists to keep the positive-design target explicit for witness-public-input-binding-failure, spanning both the
public root says one thing, witness root says anotherAztec 2.0 shape and themessage says stateIndex k, witness swaps in a different leaf firstMACI shape. - Why this note exists:
- witness-public-input-binding-failure preserves the exploit family where the proof system verifies a weaker relation than the application thinks it is verifying.
- The exploit note is useful for classification, but the healthy-side design question is different:
how do we keep one live state object and one indexed-object mapping fused tightly enough that the prover cannot satisfy public truth and witness truth independently? - In practice, teams often inventory verifier keys and review settlement consumers more carefully than they review the semantic binding between
this root,this index,this leaf, andthis transitioninside the proof statement itself. - This note keeps the positive design target explicit instead of making readers reconstruct it only by inverting Aztec 2.0 or MACI.
Three proof-state promotions healthy systems should keep separate
-
Some proof-shaped state object exists
- A public root, witness-side root, indexed leaf list, intermediate root, or verifier relation exists and some proof can be made to verify over it.
- This is only the weakest fact:
some proof-adjacent state story exists.
-
That object deserves to count as canonical live-state truth for this exact state object and index mapping
- The public root, witness-side root, indexed object identity, and intermediate-root continuity have to stay fused tightly enough that the system is still talking about one non-fungible state object rather than two separately satisfiable stories.
- This is the semantic-binding question:
the accepted proof really authenticated the same canonical state object and per-item mapping the application promise names.
-
That accepted proof-state truth deserves downstream withdrawal, release, or tally authority
- Even a proof-valid object should not automatically mean
release assets,honor this escape, orpublish this tally resultunless downstream consumers are still honoring the same canonical state object and indexed-object relation the proof actually bound. - This is the authority question:
why does this accepted proof-state object still get to matter this much here?
- Even a proof-valid object should not automatically mean
Healthy review gets materially better once teams stop collapsing those three promotions into one vague the proof verified against the root moment.
Fast classifier: what kind of proof-state binding are you trying to protect?
one root matters publicly and privately— the contract checks a public root while witness-side membership, note ownership, or nullifier validity also depends on a root that must be the same object. [[../incidents/proofs-verifiers/aztec-2-escapehatch-old-data-root-decoupling-unsound-proof-withdrawal-2026-06-17|Aztec 2.0escapeHatch()]] is the clean exemplar.each command names one indexed object— messages, notes, or updates carry an index or identity that is supposed to bind them to one exact state leaf, but the witness can still substitute another object before invalidity or transition logic runs. [[../incidents/proofs-verifiers/maci-1-0-processmessages-under-constrained-message-state-binding-coordinator-censorship-near-miss-2021-12-01|MACI 1.0ProcessMessages]] is the clean exemplar.the repository was patched, but the live verifier still proves the old relation— the source code now expresses the right statement, but a deployed verification key or legacy proof path still accepts the underbound one. Pair this note with verification-key-statement-inventory-and-asset-reachability-discipline.- Use this note when the sharper design question is
what exact constraints, witness structure, and key inventory make one public state story and one witness state story impossible to split apart?
What this note means by state-object unification
- State-object unification means every security-critical commitment, root, accumulator, or indexed state object has one meaning across public inputs, witness-side membership checks, intermediate-root transitions, and downstream contract assumptions.
- The useful positive-design claim is not merely
the proof verifiesorthe contract checked the root. It isthe proof verified one unified claim about the same canonical object the contract and the user-facing semantics both mean. - For indexed batch systems, the claim is stronger still:
message i was processed against the exact object named by its public index or identity, not merely against some witness object that later produced a plausible next root.
The six joints a healthy proof-state binding should keep fused
1. One semantic commitment per security-critical object
- If a root, accumulator, epoch commitment, or note set matters to both witness-side logic and public settlement checks, the design should treat it as one security object.
- Parallel plumbing paths that merely intend to carry the same value are already a red flag.
- Reviewers should be able to point to one constrained object, not two variables that humans believe are equal.
2. Public-input and witness-side equality as circuit truth
- If the same semantic state object appears in both public and private roles, equality must be enforced by the circuit or verification relation, not by convention.
The prover will pass the same root to both placesis not a control.- This is the joint Aztec 2.0 broke: one root summarized the live ledger the contract checked, while another root could still anchor fabricated witness-side ownership.
3. Indexed-object membership before effect application
- If a message, command, or note update claims to act on object
k, the proof should first establish that the witness object is the canonical object atkunder the current or previous authenticated root. - The proof should not be allowed to decide validity, invalidity, or next-state effects before that identity binding is established.
- This is the joint MACI broke: the coordinator could pick
currentStateLeaves[i]first and only encounterstateIndexconsistency too late to matter.
4. Intermediate-root continuity
- Batch systems should make each step prove
this exact witness object belonged to the prior authenticated root, then this exact transition produced the next root. - The useful positive property is a chain of non-fungible state transitions, not a batch of loosely associated witness objects that happen to roll up into a plausible final root.
- Intermediate roots matter because they prevent
apply command to some other leaf now, hope the later root still looks acceptabletricks.
5. Branching only after identity is fixed
- Invalidity branches, skip logic, pruning, no-op transitions, or alternate handlers should never be allowed to weaken the
this command belongs to this objectrelation. - The safe order is: bind object identity and membership first, then decide whether the command is valid, invalid, or no-op relative to that exact object.
- If the circuit can mark a command invalid before proving it referenced the correct object, the invalid branch itself becomes an evasion route.
6. Live-statement inventory and residual reachability
- Even a well-designed replacement circuit does not help if an older onchain verification key still proves the weaker statement against funded contracts or governance-critical outcomes.
- Healthy systems keep an inventory of which verifier keys prove which exact relation and what balances, exits, or tally rights remain reachable through each one.
- This is where the design companion meets lifecycle reality; pair with verification-key-statement-inventory-and-asset-reachability-discipline when the sharper question is
which live keys still matter?
What sound design looks like
-
One root means one thing everywhere
- The root the contract trusts publicly should be the same constrained root the witness-side membership logic uses privately.
- Reviewers should be able to answer
which exact live state commitment did this proof establish ownership or authority against?with one object, not a sentence about how two equivalent-looking variables are supposed to line up.
-
Each command acts on one proved object before any branch can hide the mismatch
- If a message says
stateIndex = 7, the proof should first show membership of leaf7under the authenticated root, then evaluate validity and apply updates to that exact leaf. - The proof should not let a witness-supplied sibling leaf, zero leaf, or alternate note stand in temporarily just because an invalid branch later suppresses the inconsistency.
- If a message says
-
Intermediate roots should certify exact object continuity
- The state transition story should be
bind exact object -> apply exact update -> commit exact next root, repeated step by step. - This is the healthiest shape for both private-ledger withdrawals and proof-backed tally systems.
- The state transition story should be
-
Legacy verifiers should be treated as live policy artifacts
- A patched repository does not retire a stale statement.
- Deployed verification keys, escape hatches, migration circuits, and proof-backed tally processors need owners, reachability reviews, and economic shutdown plans.
-
Downstream consumers should not rescue split proof state into real authority
- If a proof is supposed to establish ownership, spend validity, or tally legitimacy against one canonical object, downstream settlement or outcome code should not infer that relation from partial signals.
- Pair with proof-effect-truth-security-object when the next question is how that same-object proof should stay fused to the final economically or politically honored effect set.
Useful positive design shapes
1. Literal variable reuse for shared state commitments
- Where the same root or accumulator plays multiple roles, prefer designs where those roles consume the same constrained variable rather than separate variables connected only by developer intent.
- The more plumbing layers a semantic value crosses, the more valuable literal unification becomes.
2. Membership-first indexed transition circuits
- Model batch processing as
prove membership of target object under authenticated root, then apply operation to that object, then expose the next root. - This is the direct positive-design answer to MACI-style witness substitution.
3. Intermediate-root handoff objects
- Make each batch step inherit the prior authenticated root and produce the next one, rather than letting the prover assemble an overall batch from per-step objects whose identity is only loosely implied.
- A good circuit makes it painful, not convenient, to swap in an unrelated witness object mid-batch.
4. Invalidity that stays object-specific
- Invalid commands should be proven invalid with respect to the correct indexed object, not invalid with respect to whatever witness object the prover preferred.
- This preserves censorship resistance, fair ordering claims, and user-facing batch semantics.
5. Per-key statement ownership
- Keep one artifact that states, for each live verifier key: what exact relation it proves, what public inputs it expects, what witness-side objects it binds, and what contracts or tally outcomes still trust it.
- This is the operations-side control that keeps patched source and live policy from drifting apart.
Design questions worth asking first
- Where exactly is the equality constraint that forces the public root and the witness-side root to be the same security object?
- If a command names an index, what exact constraint proves the witness object belongs to that index before any validity or invalidity branch executes?
- Can a prover keep the contract-facing public root canonical while mutating the witness-side tree, note set, or state leaf and still generate a valid proof?
- Do intermediate roots prove continuity of the exact object being updated, or only continuity of a larger batch after witness-side substitutions have already happened?
- If the repository patched the circuit later, which deployed keys still prove the old relation against reachable assets or outcome-critical state?
- What downstream contract or tally consumer assumes a stronger object-binding story than the proof actually establishes?
- If a reviewer asked
which exact object did message k or withdrawal note k operate on?, what single chain of constraints would you point to?
Red flags that usually mean proof-state truth is still split
the contract checks the root anywayused as if that proved witness-side membership referenced the same rootstateIndex is checked laterwhen earlier invalidity logic can already route the command away from the intended object- witness arrays like
currentStateLeaves[]or note lists treated as transport details rather than as the actual security object deciding what gets proven - batch circuits that prove a final root transition but never force per-step membership of the exact object each command names
- repository patches cited as mitigation without an inventory of still-live onchain verifier keys or residual proof rails
the invalid branch is harmlesseven though it is exactly where incorrect object binding stops being checked- downstream settlement or tally code assuming proof success implies one exact provenance story that the proof relation never actually bound
Failure-prevention checklist
- Treat
proof-shaped object exists,object counts as canonical live-state truth, andthat accepted truth deserves downstream withdrawal / release / tally authorityas separate promotions in circuit design, verifier review, and consumer review. Do not let bare verifier success silently stand in for all three. - Represent each security-critical root, accumulator, epoch commitment, or ledger fingerprint once as a semantic security object. If it appears in both public inputs and witness logic, make the proof relation enforce equality rather than relying on plumbing discipline.
- For indexed message or command systems, prove target-object membership before any validity check, invalidity branch, or state transition.
We reject mismatches lateris not safe if earlier branches can already consume the wrong object. - Make intermediate-root transitions object-specific. Each step should prove
this exact object was in the previous authenticated rootandthis exact update produced the next root. - Treat witness-side arrays of leaves, notes, or objects as custody- or outcome-critical inputs, not helper data. Their ordering and identity semantics deserve explicit constraints and tests.
- Ensure invalid commands remain bound to the correct indexed object. The system should prove
message was invalid for its real target, not merelymessage was invalid for some witness object. - Inventory deployed verification keys and legacy proof paths. If an old key still proves the weaker split statement against reachable value or governance outcomes, the bug is still live regardless of repository history.
- Version proof-facing schemas as one object: public inputs, witness objects, intermediate roots, and downstream consumer expectations should change together or not at all.
- Add negative tests that hold the public root constant while mutating the witness-side root, and that hold
stateIndexconstant while substituting the witness leaf. The required result is proof generation or verification failure. - Add path-level tests for batch processing that try zero leaves, sibling leaves, reordered witness arrays, stale intermediate roots, and mismatched path elements before and after invalidity branches.
- Keep downstream settlement or tally consumers provenance-aware. Proof success should only authorize effects that were bound to the same canonical state object the application promise names.
- Require an owner for every live proof statement and decommission it economically, not just socially. Deprecated escape hatches, migration verifiers, and tally processors should have reachability reviews and residual-surface reduction.
Audit prompts
- Which proof-state promotion is happening at each step here: proof-shaped object existence, accepted canonical live-state truth, or downstream authority to withdraw / release / finalize against that accepted truth?
- What exact constraint makes the public state commitment and the witness-side membership commitment the same object rather than parallel assumptions?
- If a message or note carries an index or identity, where is membership of that exact indexed object proven before any validity branching happens?
- Can a prover substitute a zero leaf, sibling leaf, or fabricated note set and still produce a valid proof because the later branch that should have caught it never becomes binding?
- Do intermediate roots prove per-step continuity of the exact object being updated, or only a looser batch-level plausibility condition?
- Which deployed verification keys still prove this relation today, and what balances, exits, or outcome-critical actions remain reachable through them?
- Does downstream settlement or tally code rely on a stronger provenance story than the proof statement actually enforces?
- Are witness arrays, Merkle path elements, or note lists treated as audited security inputs, or are they still implicitly trusted transport between offchain components?
- During upgrades, where is the assertion that old and new circuits bind the same public state object, the same per-item identity relation, and the same downstream authorization semantics?
- If one proof succeeded today, what artifact would prove that the relevant withdrawal, tally update, or note spend was evaluated against the same canonical object users think it referenced?
- What test demonstrates that invalid commands are invalid relative to their real target objects rather than invalid only after witness substitution?
Lessons that should already be standard
A proof-shaped object exists,that object counts as canonical live-state truth, andthat accepted truth may now move assets or decide outcomesare three different claims.The proof verifiedis not enough. The real question is whether it verified one unified statement about the exact canonical object the application and contract both trust.- Public-input roots and witness-side roots are one security object whenever the contract assumes they describe the same ledger. If equality is not circuit truth, the system is already depending on folklore.
- Indexed commands need object binding before branching. A later index check does not rescue a system that already let the wrong object determine validity.
- Witness arrays are not harmless plumbing. In many proof systems they are the real authority surface deciding which objects the proof is about.
- Intermediate roots should prove object continuity, not just batch plausibility. Otherwise many different hidden per-step stories can lead to one acceptable-looking final root.
- Repository patches do not revoke old proof statements. Verification keys and residual proof rails keep the old relation alive until someone inventories and economically retires them.
- Proof-driven governance, tallies, and censorship-resistance claims deserve the same semantic-binding rigor as proof-driven withdrawals. Outcome integrity can fail for the same reason solvency does: the proof proves the wrong object.
- The clean mantra is simple: one canonical state object, one indexed target object per command, one authenticated chain of transitions, and no branch that can weaken identity after the fact.
Negative exemplar cluster: what split proof-state truth looks like
- [[../incidents/proofs-verifiers/aztec-2-escapehatch-old-data-root-decoupling-unsound-proof-withdrawal-2026-06-17|Aztec 2.0
escapeHatch()]] preserves the dual-root decoupling shape: witness-side ownership could be proven against fabricated state while the contract still checked the genuine live root publicly. - [[../incidents/proofs-verifiers/maci-1-0-processmessages-under-constrained-message-state-binding-coordinator-censorship-near-miss-2021-12-01|MACI 1.0
ProcessMessages]] preserves the indexed-object substitution shape: coordinator-chosen witness leaves could decide invalidity before the circuit ever forced each message onto its realstateIndextarget. - public-input binding failure preserves the broader exploit family: one supposedly shared semantic object gets split into separately satisfiable proof components and downstream code turns the weaker statement into real authority.
- The preserved common lesson is not merely
some zk circuit had a bug. It is that the protocol never forcedthis public state storyandthis witness state storyto remain one non-fungible security object.
How this note complements the exploit corpus
- Start with witness-public-input-binding-failure when the exploit-side question is
did the proof authenticate a weaker state-binding relation than the application promise required? - Use this note when the sharper design question becomes
what exact root-unification, indexed-object binding, intermediate-root continuity, and live-key inventory rules should have made that split impossible? - Pair with verification-key-statement-inventory-and-asset-reachability-discipline when the semantic binding is conceptually clear in source but stale deployed keys or legacy proof rails may still keep the old statement live.
- Pair with proof-effect-truth-security-object when the object-binding story inside the proof is sound, but the next question is whether the economically or politically honored effect set still matches the authenticated one.
- Pair with exit-only-residual-surface-discipline when the split statement lives on a legacy escape hatch, migration rail, or deprecated proof route that should already have been economically narrowed.
Internal linkages
- Core exploit family: witness-public-input-binding-failure.
- Best current negative exemplars: aztec-2-escapehatch-old-data-root-decoupling-unsound-proof-withdrawal-2026-06-17, maci-1-0-processmessages-under-constrained-message-state-binding-coordinator-censorship-near-miss-2021-12-01.
- Adjacent live-key lifecycle companion: verification-key-statement-inventory-and-asset-reachability-discipline.
- Adjacent proof-consumer companion: proof-effect-truth-security-object.
- Adjacent residual-service companion: exit-only-residual-surface-discipline.
Control surface
-
The decisive control surface is not only the verifier arithmetic.
-
It is the full semantic-binding path where the protocol decides which proof-shaped state object even exists, which root is live, which witness object corresponds to which public index, which intermediate root each step inherits, which verification key still proves that relation, and which downstream contract or tally consumer treats the resulting proof as real authority.
-
The recurring mistake is to blur three different promotions —
proof-shaped state object exists,object counts as canonical live-state truth, andthat accepted truth may now cash out or finalize— into one implementation event. -
Protocols get materially safer when that whole path shares one explicit rule: one canonical state object, one exact per-command target object, and one proof statement that cannot be satisfied by splitting the two apart.
-
Sources:
- witness-public-input-binding-failure
- aztec-2-escapehatch-old-data-root-decoupling-unsound-proof-withdrawal-2026-06-17
- maci-1-0-processmessages-under-constrained-message-state-binding-coordinator-censorship-near-miss-2021-12-01
- https://www.aztec-labs.com/blog/aztec-2-incident.html
- https://github.com/privacy-ethereum/maci/issues/320
-
Last reviewed: 2026-07-29 UTC