fix(fel): require per-step weights non-negative over the counter range - #1096
fix(fel): require per-step weights non-negative over the counter range#1096namasikanam wants to merge 1 commit into
Conversation
The failure-event lemma tactic summed the per-step weights only over the counter values actually visited and never required `0%r <= ash i` on the whole range `0 <= i < q`. A counter that jumps (e.g. 0 -> 2) with a negative weight at a skipped index makes the full-range sum smaller than the visited sum, so `fel` "proves" `Pr[bad] <= 0` while the true probability is 1 (hence `false`). Emit the side-condition `forall i, 0 <= i < q => 0%r <= ash i` (as the last goal, so existing scripts keep their sub-goal positions). Existing library and `examples` uses of `fel` discharge it trivially (their weights are already non-negative). Regression: tests/fel-counter-jump.ec (asserts the buggy 0 -> 2 counter jump with a negative weight no longer closes, via the `fail` idiom). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ffffb12 to
bc3b89e
Compare
|
Jumps are only a special case of the real problem here, which is that for some counter values inside the specified range there might be no state satisfying the invariants, permitting negative integers on the right side of |
| + move=> c; proc; inline*; sp; rcondt 1; 1: auto=> />. | ||
| by wp -1=> />; conseq(:_==> true); auto; smt(). | ||
| + by move=> b c; proc; inline*; sp; rcondf 1; auto=> />. | ||
| + (* F003: non-negativity of the per-step weight over the whole range *) |
There was a problem hiding this comment.
The comments in the old easycrypt code refer to the LLM artifact "F003".
The comment in the regression test is mostly fine, though a bit verbose.
The comment in ecPhlFel is good.
|
The side-condition this PR adds, On the test: |
Summary
The failure-event lemma tactic (
fel) is unsound: it enforces neither that the counterincrements by exactly 1 per bad event, nor that each per-step weight is non-negative at the
indices it skips. A counter that jumps
0 -> 2with weights(1, -1)sums to0, sofel"proves"
Pr[bad] <= 0while the true probability is1— hencefalse.Root cause
t_failure_event_rsums the per-step weights only over the indices the counter actuallyvisits, and never requires
0%r <= ash ion the whole range0 <= i < q. Negative weightsat skipped indices are therefore uncounted.
Fix (
src/phl/ecPhlFel.ml)Add the side-condition
forall i, 0 <= i < q => 0%r <= ash i(emitted as the last goal).Existing library/
examplesuses offelare updated to discharge this trivially-trueobligation (all standard weights are already non-negative).
Test
tests/ko/fel-counter-jump.ec(must-fail): the0 -> 2counter jump with a negativeweight is now rejected.