Skip to content

fix: preserve arrays on false conditional stores - #249

Draft
NullWitnessZK wants to merge 1 commit into
circify:masterfrom
NullWitnessZK:fix/linear-scan-conditional-store
Draft

fix: preserve arrays on false conditional stores#249
NullWitnessZK wants to merge 1 commit into
circify:masterfrom
NullWitnessZK:fix/linear-scan-conditional-store

Conversation

@NullWitnessZK

Copy link
Copy Markdown

Fixes #246.

Minimal reproducer

Save as main.zok:

def main(private field i, private field x, private bool c) -> field:
    field[2] values = [1, 2]
    cond_store(values, i, x, c)
    return values[0]

Use this input:

i = 1
x = 0
c = false

The stage comparison at CirC 271f911 is:

Stage return = 1 return = 0
Raw source IR accepted rejected
After LinearScan rejected accepted
Final R1CS relation rejected accepted

Expected

A false conditional store is a no-op. The array remains [1, 2], so the function returns 1.

Actual

The rewritten relation stores 0 into slot zero and returns 0.

Why it happens

The dynamic-index lowering initializes its fold with an unconditional Update(0, ...), then guards only candidate indices 1..N. If c is false, all guarded arms fall through to that slot-zero update.

Impact: an unsound verifier relation for a custom witness, plus disagreement with the bundled witness computation. The stock CLI does not directly produce a false proof here: its source-correct precompute conflicts with the malformed constraints.

Proposed fix

fix/linear-scan-conditional-store at 62bbb92 starts the fold with the untouched tuple and guards every candidate update—including index zero—with index == candidate && condition.

Self-contained regression:

cargo test false_dynamic_conditional_store_preserves_array

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False dynamic conditional store overwrites slot zero

1 participant