fix(phl): emit the non-negativity of the bound as a separate goal in rnd (on #1105) - #1135
Yiping106283 wants to merge 1 commit into
Conversation
22f5ad0 to
b7fa0d8
Compare
rndrnd (on #1105)
b7fa0d8 to
20a2653
Compare
bb75dba to
df3b1a7
Compare
20a2653 to
cadadf5
Compare
|
Thanks, both done. The long comment is gone and each of the two |
cadadf5 to
f7a9ce7
Compare
26f2bfc to
c2fdd9b
Compare
c2fdd9b to
9e533cf
Compare
f7a9ce7 to
8b31253
Compare
8b31253 to
49987aa
Compare
|
The downstream script changes for this PR, on top of the #1105 ones now in the projects:
With them, the |
…yptobox on top of the EasyCrypt#1105 changes
|
@lyonel2017 can you please check the changes and mark them done if they are done (approving if you're happy). |
…`rnd` Summary: the pHL `rnd` tactic accepted `phoare[M.f : true ==> true] <= (-1)%r` for a procedure that diverges before its sampling (upstream EasyCrypt#1119), from which `false` follows with `Pr[mu_ge0]`. Root cause (src/phl/ecPhlRnd.ml, `Core.t_bdhoare_rnd_r`): for an upper bound, the rule lifts the bound check `mu d E <= bd` into the post-condition of a hoare judgment on the statements preceding the sampling. A hoare post-condition only has to hold on terminating runs, so a diverging prefix discharges it vacuously. The check is sound for the mass of the terminating runs, but the non-terminating runs contribute probability 0 to the conclusion, which is bounded by `bd` only if `0%r <= bd`: that premise was missing from the rule. Fix: the two `<=` branches that emit the hoare goal (explicit event, and event inferred from a post-condition depending on the sampled variable) now also emit `forall &hr, 0%r <= bd` as a last goal. Based on EasyCrypt#1105: under its semantics the bound must be non-negative in every memory, so the goal is unconditional (restricting it to memories satisfying `pre` would still let the rule prove a judgment whose bound is negative outside `pre`). The rule always emits it, and the rule closes the goal itself when it is trivial (`t_try t_trivial` on the last subgoal of the two `<=` arms, as `t_bdhoare_seq_r` does for its side-conditions), so trivially non-negative bounds stay effort-free; `auto` recurses only into the program-logic sub-goals of `rnd` (src/phl/ecPhlAuto.ml), so it keeps applying `rnd` when a non-trivial goal remains, and a genuinely negative bound is left as an unprovable goal. The documented rule in doc/tactics/rnd.rst is updated accordingly. Scripts that discharged the old post-condition with `rnd; skip`, `rnd; auto` or `rnd=> //` now reach the extra goal through `;`: theories/crypto/ {Birthday.eca, PROM.ec, RndExcept.eca, prp_prf/Strong_RP_RF.eca} and examples/{PRG.ec, ChaChaPoly/chacha_poly.ec, cramer-shoup/cramer_shoup.ec, global-hybrid/GlobalHybridExamp1.ec, prg-tutorial/PRGc.ec} close it with `smt` and the relevant non-negativity lemmas (since the goal no longer carries the pre-condition, facts such as `0 <= fsize m` come from the library lemmas instead). In examples/prg-tutorial/PRGc.ec the `fel` bound `(i + 1)%r * pr_dstate` is negative for `i < -1`, so under EasyCrypt#1105 the per-query judgment is false for such counter values; the bound becomes `(max 0 i + 1)%r * pr_dstate` (as EasyCrypt#1105 does in Strong_RP_RF.eca) and the sum is rewritten back with `eq_big_seq`. Test: tests/phoare-rnd-neg-bound.ec (explicit event, inferred event, and a loop-free variant). The remaining goal `forall &hr, 0%r <= -1%r` is introduced with `move=> &hr` (which fails when the goal is not emitted) and asserted unprovable with `fail (by smt())`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
49987aa to
8d3261d
Compare
|
Thanks, all three done: the old comment in |
|
I am currently struggling getting the eternal proofs' CI to play ball with this one, but will try merging by end of day today. (UK time.) Apologies for delaying this further, and thanks again to both of you for all your work. |
Fixes #1119. Based on
mainwith #1105 merged (the side goal is unconditional for the reason below).Summary
The pHL
rndtactic acceptedphoare[M.f : true ==> true] <= (-1)%rfor a procedure that diverges before its sampling, from whichfalsefollows withPr[mu_ge0]. #1105 does not reach this: the bound check stays inside the hoare post-condition and never passes throughconseq,byprorexfalso, so with bb75dba the reproducer is still accepted and still provesfalse. The rule now emits the missing premise as a separate goal quantified over all memories, and therndtactic triest_trivialon it.Under #1105's semantics a pHL judgement is false as soon as its bound is negative in some memory, whether or not that memory satisfies the pre-condition; the side goal is therefore unconditional (
forall &hr, 0%r <= bd) because a goal restricted topre, as in #1135, would still let the rule prove a judgement whose bound is negative outsidepre.Root cause (
src/phl/ecPhlRnd.ml,Core.t_bdhoare_rnd_r)For an upper bound, the rule lifts the bound check
mu d E <= bdinto the post-condition of a hoare judgment on the statementsspreceding the sampling. A hoare post-condition only has to hold on terminating runs, so a diverging prefix discharges it vacuously. The check is sound for the mass of the terminating runs (Pr[s; x <$ d : Q] = sum_m' Pr[s](m') * mu d(m') Q <= Pr[s : true] * bd), but the non-terminating runs contribute probability 0 to the conclusion, which is bounded bybdonly if0%r <= bd: that premise was missing from the rule.Fix
The two
<=branches that emit the hoare goal (explicit event, and event inferred from a post-condition depending on the sampled variable) now also emitforall &hr, 0%r <= bdas a last goal. The rule always emits it; therndtactic (process_rnd) triest_trivialon it, so trivially non-negative bounds stay effort-free and a genuinely negative bound is left as an unprovable goal.autonow only recurses into the program-logic sub-goals produced byrnd(src/phl/ecPhlAuto.ml,t_auto_phl_rnd_r), so it keeps applyingrndwhen the extra goal is present, and its own finalt_trivialcloses the goal when it is trivial. The documented rule indoc/tactics/rnd.rstis updated accordingly (its example proof already does not check onmain:by smt(dbool1E)does not prove the1%r/2%rbound with current provers; only the goal structure is updated here).Impact
rnd; skip,rnd; autoorrnd=> //now reach the extra goal through;and must close it when it is not trivial (a symbolic bound without0%r <= bdin context). Since the goal does not carry the pre-condition, non-negativity facts that used to come from it (0 <= fsize m,0 <= qF, ...) must come from the library lemmas.smtand the relevant non-negativity lemmas on that goal, on top of Change pHL to prevent negative probabilities #1105's own script changes to the same files:theories/crypto/Birthday.eca,theories/crypto/PROM.ec,theories/crypto/RndExcept.eca,theories/crypto/prp_prf/Strong_RP_RF.eca,examples/PRG.ec,examples/ChaChaPoly/chacha_poly.ec,examples/cramer-shoup/cramer_shoup.ec,examples/global-hybrid/GlobalHybridExamp1.ec,examples/prg-tutorial/PRGc.ec. None of them proves the same side condition twice: Change pHL to prevent negative probabilities #1105 adds0%r <= bdatconseq/bypr/exfalso, this PR at therndrule.Strong_RP_RF.eca: afelbound function must be non-negative for every counter value, not only for0 <= c < q. InPRGc.ecthe bound(i + 1)%r * pr_dstateis negative fori < -1, so the per-query judgement is false under the new semantics; the bound becomes(max 0 i + 1)%r * pr_dstateand the sum is rewritten back witheq_big_seq(one line). The same pattern is what the downstream sites will need.>=and=judgements, and<=with a post-condition independent of the sampled variable (which drops the sampling), are unchanged.Downstream
The extra goal reaches the CI external projects at symbolic-bound
rndsites: cryptobox (2), sha3 (16), xmss-security (3); sphincsplus and xsalsa20 are unaffected. Those sites need script changes on top of the ones #1105 already requires (the unconditional goal also drops the pre-condition facts the #1135 versions of those changes used); diffs to follow once the base is settled, as merge requests on each project.Test
tests/phoare-rnd-neg-bound.ec(explicit event, inferred event, and a loop-free varianty <$ dnull; x <$ dunit 0): the remaining goalforall &hr, 0%r <= -1%ris introduced withmove=> &hr(which fails with "all goals are closed" on the Change pHL to prevent negative probabilities #1105 head, where the lemma goes through) and asserted unprovable withfail (by smt()).make unit96/96,make stdlib128/128,make examples49/49 (ECJOBS=3, local prover set). Reproducers: pHL seq permits negative probabilities #1100 and pHL call permits negative probabilities #1101 are rejected by Change pHL to prevent negative probabilities #1105; both pHLrnd Esoundness #1119 variants (diverging prefix, loop-free) by this commit; pHL while permits negative probabilities #1102 is out of scope here (separate PR).