https://github.com/EasyCrypt/easycrypt
Raw File
Tip revision: 374dae60b90d55b70e41805c88b33b26faaa455d authored by Pierre-Yves Strub on 12 October 2021, 13:09:21 UTC
parser: fix precedence issue
Tip revision: 374dae6
ROM.eca
(* --------------------------------------------------------------------
 * Copyright (c) - 2012--2016 - IMDEA Software Institute
 * Copyright (c) - 2012--2018 - Inria
 * Copyright (c) - 2012--2018 - Ecole Polytechnique
 *
 * Distributed under the terms of the CeCILL-B-V1 license
 * -------------------------------------------------------------------- *)

pragma +implicits.

require import AllCore Distr.

(* Input and output types for oracle *)
type in_t, out_t.
op dout: in_t -> out_t distr.

(* A signature for oracles from "in_t" to "out_t" *)
module type POracle = {
  proc o(x : in_t): out_t
}.

(* A Distinguisher (or distinguishing context) is a single algorithm
   that has access to an oracle, and has some input/output behaviour *)
type d_in_t, d_out_t.

module type Distinguisher (H : POracle) = {
  proc run(_ : d_in_t): d_out_t
}.

(* The oracle may be stateful, and its state might need initialized *)
module type Oracle = {
  proc init()      : unit
  proc o(x : in_t) : out_t
}.

module Exp (H : Oracle) (D : Distinguisher) = {
  proc main(x : d_in_t): d_out_t = {
    var r : d_out_t;

         H.init();
    r <@ D(H).run(x);
    return r;
  }
}.

(* -------------------------------------------------------------------- *)
theory Lazy.
require import SmtMap.

module LRO : Oracle = {
  var m : (in_t, out_t) fmap

  proc init() = {
    m <- empty;
  }

  proc o(x : in_t) = {
    var r;

    r <$ dout x;
    if (x \notin m) {
      m.[x] <- r;
    }
    return oget m.[x];
  }
}.

lemma LRO_init_ll : islossless LRO.init.
proof. by proc; auto. qed.

lemma LRO_o_ll : (forall x, is_lossless (dout x)) => islossless LRO.o.
proof. by move=> dout_ll; proc; auto; rewrite dout_ll. qed.

hoare LRO_initE : LRO.init : true ==> LRO.m = empty.
proof. by proc; auto. qed.

hoare LRO_oE (M : (in_t, out_t) fmap) x' :
  LRO.o :    LRO.m = M
          /\ x = x'
          ==>    LRO.m.[x'] = Some res
              /\ if   x' \in M
                 then LRO.m = M
                 else LRO.m = M.[x' <- res].
proof.
proc; auto=> /> r _; rewrite get_set_sameE domE /=.
by case: (M.[x']).
qed.

lemma LRO_o_notinE (M : (in_t, out_t) fmap) x' :
     x' \notin M
  => hoare [LRO.o : LRO.m = M /\ x = x' ==> LRO.m = M.[x' <- res]].
proof. by move=> x'_nin_M; conseq (LRO_oE M x'); rewrite x'_nin_M. qed.

lemma LRO_o_inE (M : (in_t, out_t) fmap) x' :
     x' \in M
  => hoare [LRO.o : LRO.m = M /\ x = x' ==> LRO.m = M /\ M.[x'] = Some res].
proof. by move=> x'_in_M; conseq (LRO_oE M x'); rewrite x'_in_M. qed.

end Lazy.

(* -------------------------------------------------------------------- *)
abstract theory FiniteEager.
require import List SmtMap.
require import FinType.

(** TODO: expose finiteness assumption **)
clone include FinType with
  type t <- in_t.

module ERO : Oracle = {
  var m : (in_t, out_t) fmap

  proc init(): unit = {
    var y, w, f;

    m <- empty;
    w <- enum;
    while (w <> []) {
      f     <- head witness w;
      y     <$ dout f;
      m.[f] <- y;
      w     <- behead w;
    }
  }

  proc o(x : in_t): out_t = {
    return oget m.[x];
  }
}.

hoare ERO_init_fu: ERO.init: true ==> forall x, x \in ERO.m.
proof.
proc.
while (forall x, x \in w \/ x \in ERO.m).
+ auto=> /> &m ih w_neq_nil y _ f.
  rewrite mem_set; case: (ih f)=> />.
  by move/(@mem_head_behead witness _ w_neq_nil); case=> />.
by auto=> /> x; rewrite enumP.
qed.

lemma ERO_init_ll:
  (forall x, is_lossless (dout x)) =>
  islossless ERO.init.
proof.
move=> dout_ll; proc; while (true) (size w).
+ by auto=> /> &m; rewrite dout_ll //=; case: (w{m})=> /#.
by auto=> /> w; rewrite -size_eq0 Int.eqz_leq size_ge0.
qed.

lemma ERO_o_ll: islossless ERO.o.
proof. by proc; wp. qed.

lemma ERO_oE (M : (in_t, out_t) fmap) x' :
     (forall x, x \in M)
  => hoare [ERO.o :     ERO.m = M /\ x = x'
                    ==> ERO.m = M /\ ERO.m.[x'] = Some res].
proof. by move=> m_fu; proc; auto=> />; rewrite -get_some 1:m_fu. qed.
end FiniteEager.

(* -------------------------------------------------------------------- *)
abstract theory LazyEager.
require import List SmtMap PROM.
require import FinType.

clone import FinType with
  type t <- in_t.

import Lazy.

clone include FiniteEager with
  op enum <- enum
proof * by exact/enum_spec.

section.
declare module D : Distinguisher { LRO, ERO }.

axiom dout_ll x : is_lossless (dout x).

local clone import PROM.FullRO as H with
  type in_t    <- in_t,
  type out_t   <- out_t,
  type d_in_t  <- d_in_t,
  type d_out_t <- d_out_t,
  op   dout    <- dout.

local module Wrap (O : RO) : Oracle = {
  proc init() = {
    var w, f;

         O.init();
    w <- enum;
    while (w <> []) {
      f <- head witness w;
           O.sample(f);
      w <- behead w;
    }
  }

  proc o = O.get
}.

local module D' (O : RO) = {
  proc distinguish(x : d_in_t) = {
    var r;

         Wrap(O).init();
    r <@ D(Wrap(O)).run(x);
    return r;
  }
}.

local module Exp' (O : RO) = {
  proc main(x : d_in_t) = {
    var r;

         O.init();
    r <@ D'(O).distinguish(x);
    return r;
  }
}.

local equiv eq_LRO_RO:
  Exp(LRO, D).main ~ Exp'(FullEager.LRO).main:
    ={glob D, arg} ==> ={res}.
proof.
proc; inline *; wp.
call (: LRO.m{1} = RO.m{2})=> />; first by sim.
while{2} true (size w{2}).
+ by auto=> &m />; case: (w{m})=> //#.
by auto=> /> w; rewrite -size_eq0 Int.eqz_leq size_ge0.
qed.

local equiv eq_ERO_RO_init:
  ERO.init ~ Wrap(RO).init:
    true
    ==>    ERO.m{1} = RO.m{2}
        /\ forall x, x \in ERO.m{1}.
proof.
proc; inline *.
while (   ={w}
       /\ ERO.m{1} = RO.m{2}
       /\ uniq w{1}
       /\ (forall x, x \in w <=> x \notin ERO.m){1}).
+ rcondt{2} 5.
  + auto=> /> _ ih w_neq_nil r _.
    exact/ih/(@mem_head_behead witness).
  auto=> |> &m uniq partition w_neq_nil r _.
  move: w_neq_nil uniq partition.
  case: (w{m})=> /> h t h_notin_t _ ih x.
  by rewrite mem_set negb_or -ih; case: (x = h).
auto=> />; rewrite enum_uniq=> /= x.
by rewrite enumP domE emptyE.
qed.

local equiv eq_ERO_RO:
  Exp(ERO, D).main ~ Exp'(RO).main:
    ={glob D, arg} ==> ={res}.
proof.
proc. inline D'(RO).distinguish; wp.
call (: ERO.m{1} = RO.m{2} /\ forall x, x \in ERO.m{1})=> //.
+ by proc; auto=> /> &m inv; rewrite dout_ll=> /= r _; rewrite inv.
by call eq_ERO_RO_init; inline *; auto.
qed.

equiv eq_eager_sampling:
  Exp(LRO, D).main ~ Exp(ERO, D).main: ={glob D, arg} ==> ={res}.
proof.
transitivity Exp'(FullEager.LRO).main
             (={glob D, arg} ==> ={res})
             (={glob D, arg} ==> ={res})=> />.
+ by move=> &2; exists (glob D){2} (x{2}).
+ exact/eq_LRO_RO.
transitivity Exp'(RO).main
             (={glob D, arg} ==> ={res})
             (={glob D, arg} ==> ={res})=> />.
+ by move=> &2; exists (glob D){2} (x{2}).
+ symmetry; proc; call (FullEager.RO_LRO_D D' dout_ll).
  by inline *; auto.
by symmetry; conseq eq_ERO_RO.
qed.

end section.
end LazyEager.

(* -------------------------------------------------------------------- *)
abstract theory BoundedCall.
require import Int.

op qH : { int | 0 <= qH } as ge0_qH.

module Bound (O : Oracle) = {
  var c : int

  proc init(): unit = {
         O.init();
    c <- 0;
  }

  proc o(x : in_t) : out_t = {
    var r <- witness;

    if (c < qH) {
      r <- O.o(x);
      c <- c + 1;
    }
    return r;
  }
}.

lemma Bound_init_ll (O <: Oracle): islossless O.init => islossless Bound(O).init.
proof. by move=> O_init_ll; proc; wp; call O_init_ll. qed.

lemma Bound_o_ll (O <: Oracle): islossless O.o => islossless Bound(O).o.
proof. by move=> O_o_ll; proc; sp; if=> //; wp; call O_o_ll. qed.
end BoundedCall.

(* -------------------------------------------------------------------- *)
abstract theory ListLog.
require import List.

op qH : int.

module Log (O : Oracle) = {
  var qs : in_t list

  proc init(): unit = {
          O.init();
    qs <- [];
  }

  proc o(x : in_t): out_t = {
    var r : out_t;

    qs <- x::qs;
    r  <@ O.o(x);
    return r;
  }
}.

lemma Log_init_ll (O <: Oracle): islossless O.init => islossless Log(O).init.
proof. by move=> O_init_ll; proc; wp; call O_init_ll. qed.

lemma Log_o_ll (O <: Oracle): islossless O.o => islossless Log(O).o.
proof. by move=> O_oL; proc; call O_oL; wp. qed.

lemma Log_o_stable (O <: Oracle {Log}) q:
  islossless O.o => phoare[Log(O).o: mem Log.qs q ==> mem Log.qs q] = 1%r.
proof. by move=> O_o_ll; proc; call O_o_ll; auto=> />. qed.

module Bound (O : Oracle) = {
  proc init = Log(O).init

  proc o (x : in_t): out_t = {
    var r <- witness;

    if (size Log.qs < qH) {
      r <@ O.o(x);
    }
    return r;
  }
}.
end ListLog.

(* -------------------------------------------------------------------- *)
abstract theory SetLog.
require import Int FSet.

op qH : int.

module Log (O : Oracle) = {
  var qs : in_t fset

  proc init(): unit = {
          O.init();
    qs <- fset0;
  }

  proc o(x : in_t): out_t = {
    var r;

    r  <@ O.o(x);
    qs <- qs `|` fset1 x;
    return r;
  }
}.

lemma Log_init_ll (O <: Oracle): islossless O.init => islossless Log(O).init.
proof. by move=> O_init_ll; proc; wp; call O_init_ll. qed.

lemma Log_o_ll (O <: Oracle): islossless O.o => islossless Log(O).o.
proof. by move=> O_o_ll; proc; wp; call O_o_ll; wp. qed.

hoare Log_o_stable (O <: Oracle {Log}) x: Log(O).o: x \in Log.qs ==> x \in Log.qs.
proof. by proc; wp; call (_: true); skip=> &m; rewrite in_fsetU in_fset1=> ->. qed.

module Bound (O : Oracle) = {
  proc init = Log(O).init

  proc o(x : in_t): out_t = {
    var r <- witness;

    if (card Log.qs < qH) {
      r <@ Log(O).o(x);
    }
    return r;
  }
}.

lemma Bound_init_ll (O <: Oracle): islossless O.init => islossless Bound(O).init.
proof. by move=> O_init_ll; proc; wp; call O_init_ll. qed.

lemma Bound_o_ll (O <: Oracle {Log}): islossless O.o => islossless Bound(O).o.
proof. by move=> O_o_ll; proc; sp; if=> //; wp; call (Log_o_ll O _). qed.

hoare Bound_o_stable (O <: Oracle {Log}) x: Bound(O).o: mem Log.qs x ==> mem Log.qs x.
proof. by proc; sp; if=> //; wp; call (Log_o_stable O x). qed.

equiv Log_Bound (O <: Oracle {Log}) (D <: Distinguisher { O, Log }):
  Exp(Bound(O),D).main ~ Exp(Log(Bound(O)),D).main: ={glob O, glob D, x} ==> ={res}.
proof.
proc.
call (_: ={glob O} /\ card Log.qs{1} <= card Log.qs{2} /\ (card Log.qs{1} < qH => ={glob Log})).
+ proc *; inline Log(Bound(O)).o Bound(O).o Log(O).o.
  sp; if=> />; first by smt().
  + wp; call (: true); auto=> /> &1 &2.
    move=> le_c1_c2 h ^ + /h <<-.
    have /#: Log.qs{1} `|` fset1 x{2} `|` fset1 x{2} = Log.qs{1} `|` fset1 x{2}.
    by rewrite fsetP=> x; rewrite !(in_fsetU, in_fset1)=> /#.
  auto=> /> &1 &2; rewrite fcardU fcard1; case: (x{2} \in Log.qs{2})=> [x_in_qs|x_notin_qs].
  + have ->: Log.qs{2} `&` fset1 x{2} = fset1 x{2}.
    + by rewrite fsetP=> x'; rewrite in_fsetI in_fset1 /#.
    by rewrite fcard1 addzK.
  have ->: Log.qs{2} `&` fset1 x{2} = fset0.
  + rewrite fsetP=> x'; rewrite in_fsetI in_fset1.
    case: (x' = x{2})=> [->>|].
    + by rewrite x_notin_qs in_fset0.
    by rewrite in_fset0.
  by rewrite fcards0 /#.
by inline *; wp; call (: true).
qed.
end SetLog.

(* -------------------------------------------------------------------- *)
abstract theory ROM_BadCall.
require import FSet SmtMap.

op qH : int.

clone export SetLog with
  op qH <- qH.

import Lazy.

module type Dist (H : POracle) = {
  proc a1(x : d_in_t): in_t
  proc a2(x : out_t) : d_out_t
}.

theory OnLog.
module G0 (D : Dist) (H : Oracle) = {
  proc main(i : d_in_t): d_out_t = {
    var x, y, r;

         Log(H).init();
    x <@ D(Log(H)).a1(i);
    y <@ H.o(x);
    r <@ D(Log(H)).a2(y);
    return r;
  }
}.

module G1 (D : Dist) (H : Oracle) = {
  proc main(i : d_in_t): d_out_t = {
    var x, y, r;

    Log(H).init();
    x <@ D(Log(H)).a1(i);
    y <$ dout x;
    r <@ D(Log(H)).a2(y);
    return r;
  }
}.

module G_bad (D : Dist) (H : Oracle) = {
  proc main(i : d_in_t): bool = {
    var x, y, r;

         Log(H).init();
    x <@ D(Log(H)).a1(i);
    y <$ dout x;
    r <@ D(Log(H)).a2(y);
    return x \in Log.qs;
  }
}.

section.
declare module D : Dist { Log, LRO }.
axiom D_a1_ll (H <: POracle { D }): islossless H.o => islossless D(H).a1.
axiom D_a2_ll (H <: POracle { D }): islossless H.o => islossless D(H).a2.

axiom dout_ll x : is_lossless (dout x).

local module G1' (D : Dist) (H : Oracle) = {
  var x : in_t

  proc main(i : d_in_t): d_out_t = {
    var y, r;

         Log(H).init();
    x <@ D(Log(H)).a1(i);
    y <$ dout x;
    r <@ D(Log(H)).a2(y);
    return r;
  }
}.

lemma ROM_BadCall &m i r:
     Pr[G0(D,LRO).main(i) @ &m: res = r]
  <=   Pr[G1(D,LRO).main(i) @ &m: res = r]
     + Pr[G_bad(D,LRO).main(i) @ &m: res].
proof.
have ->: Pr[G_bad(D,LRO).main(i) @ &m: res] = Pr[G1'(D,LRO).main(i) @ &m: G1'.x \in Log.qs].
+ byequiv (_: ={glob D, arg} ==> res{1} = (G1'.x \in Log.qs){2})=> //.
  proc.
  call (_: ={glob Log, glob LRO}); first by sim.
  rnd; call (_: ={glob Log, glob LRO}); first by sim.
  by inline *; wp.
have ->: Pr[G1(D,LRO).main(i) @ &m: res = r] = Pr[G1'(D,LRO).main(i) @ &m: res = r].
+ by byequiv (_: ={glob D, arg} ==> ={res}); first by sim.
have: Pr[G0(D,LRO).main(i) @ &m: res = r] <= Pr[G1'(D,LRO).main(i) @ &m: res = r \/ G1'.x \in Log.qs].
+ byequiv (_: ={glob D, arg} ==> !mem Log.qs{2} G1'.x{2} => ={res})=> //; last smt().
  proc.
  call (_: G1'.x \in Log.qs,
              ={glob Log}
           /\ (forall x, x \in Log.qs{2} <=> x \in LRO.m{2})
           /\ eq_except (pred1 G1'.x{2}) LRO.m{1} LRO.m{2}).
  + by apply D_a2_ll.
  + proc; inline LRO.o; auto=> /> //= &1 &2 x2_notin_qs eq_qs_m eqe y _.
    rewrite !inE !get_setE x2_notin_qs /= eq_except_set_eq //= eq_sym.
    split.
    + move=> x_notin_m2; split.
      + by move=> x_notin_m1 + x1; rewrite in_fsetU in_fset1 mem_set eq_qs_m.
      move: eqe; rewrite eq_exceptP /pred1=> /(_ x{2}) h + /h eq_mx.
      by rewrite domE eq_mx -domE.
    move=> x_in_m2; split.
    + move: eqe; rewrite eq_exceptP /pred1=> /(_ x{2}) h + /h eq_mx.
      by rewrite domE eq_mx -domE.
    move=> x_in_m1 x2_neq_G1'x. move: eqe; rewrite eq_exceptP=> -> //= x1.
    by rewrite in_fsetU in_fset1 eq_qs_m; case: (x1 = x{2})=> [->|] //=; rewrite x_in_m2.
  + by progress; apply (Log_o_ll LRO); apply (LRO_o_ll dout_ll).
  + progress; exists* G1'.x; elim* => x; conseq (Log_o_ll LRO _) (Log_o_stable LRO x)=> //.
    by apply (LRO_o_ll dout_ll).
  inline Log(LRO).o LRO.o; auto.
  call (_: ={glob Log, glob LRO} /\ (forall x, x \in Log.qs{2} = x \in LRO.m{2})).
  + proc; inline LRO.o; auto=> /> &2 eq_qs_m y _; split.
    + by move=> x_notin_m x1; rewrite in_fsetU in_fset1 mem_set eq_qs_m.
    move=> x_in_m x1; rewrite in_fsetU in_fset1 eq_qs_m; case: (x1 = x{2})=> //=.
    by move=> ->; rewrite x_in_m.          
  inline Log(LRO).init LRO.init; auto=> />; split=> [x1|_ a qs m eq_qs_m y _].
  + by rewrite in_fset0 mem_empty.
  by rewrite get_set_eqE //= eq_except_setl /= eq_qs_m /#.
by rewrite Pr [mu_or]; smt(mu_bounded).
qed.
end section.
end OnLog.

theory OnBound.
module G0 (D : Dist) (H : Oracle) = {
  proc main(i : d_in_t): d_out_t = {
    var x, y, r;

         Bound(H).init();
    x <@ D(Bound(H)).a1(i);
    y <@ H.o(x);
    r <@ D(Bound(H)).a2(y);
    return r;
  }
}.

module G1 (D : Dist) (H : Oracle) = {
  proc main(i : d_in_t): d_out_t = {
    var x, y, r;

         Bound(H).init();
    x <@ D(Bound(H)).a1(i);
    y <$ dout x;
    r <@ D(Bound(H)).a2(y);
    return r;
  }
}.

module G_bad (D : Dist) (H : Oracle) = {
  proc main(i : d_in_t): bool = {
    var x, y, r;

         Bound(H).init();
    x <@ D(Bound(H)).a1(i);
    y <$ dout x;
    r <@ D(Bound(H)).a2(y);
    return x \in Log.qs;
  }
}.

section.
declare module D : Dist { Log, LRO }.
axiom D_a1_ll (H <: POracle { D }): islossless H.o => islossless D(H).a1.
axiom D_a2_ll (H <: POracle { D }): islossless H.o => islossless D(H).a2.

axiom dout_ll x : is_lossless (dout x).

local module G1' (D : Dist) (H : Oracle) = {
  var x : in_t

  proc main(i) = {
    var y, r;

         Log(H).init();
    x <@ D(Bound(H)).a1(i);
    y <$ dout x;
    r <@ D(Bound(H)).a2(y);
    return r;
  }
}.

lemma ROM_BadCall &m i r:
     Pr[G0(D,LRO).main(i) @ &m: res = r]
  <=   Pr[G1(D,LRO).main(i) @ &m: res = r]
     + Pr[G_bad(D,LRO).main(i) @ &m: res].
proof.
have ->: Pr[G_bad(D,LRO).main(i) @ &m: res] = Pr[G1'(D,LRO).main(i) @ &m: G1'.x \in Log.qs].
+ byequiv (_: ={glob D, arg} ==> res{1} = (mem Log.qs G1'.x){2})=> //.
  proc.
  call (_: ={glob Log, glob LRO}); first by sim.
  rnd; call (_: ={glob Log, glob LRO}); first by sim.
  by inline *; wp.
have ->: Pr[G1(D,LRO).main(i) @ &m: res = r] = Pr[G1'(D,LRO).main(i) @ &m: res = r].
+ by byequiv (_: ={glob D, arg} ==> ={res}); first by sim.
have: Pr[G0(D,LRO).main(i) @ &m: res = r] <= Pr[G1'(D,LRO).main(i) @ &m: res = r \/ G1'.x \in Log.qs].
+ byequiv (_: ={glob D, arg} ==> (!G1'.x \in Log.qs){2} => ={res})=> //; last by smt().
  proc.
  call (_: G1'.x \in Log.qs,
              ={glob Log}
           /\ (forall x, x \in Log.qs{2} = x \in LRO.m{2})
           /\ eq_except (pred1 G1'.x{2}) LRO.m{1} LRO.m{2}).
  + by apply D_a2_ll.
  + proc; inline *; sp; if=> //=; auto=> /> //= &1 &2 x2_notin_qs eq_qs_m eqe _ y _.
    rewrite !inE !get_setE x2_notin_qs /= eq_except_set_eq //= eq_sym.
    split.
    + move=> x_notin_m2; split.
      + by move=> x_notin_m1 + x1; rewrite in_fsetU in_fset1 mem_set eq_qs_m.
      move: eqe; rewrite eq_exceptP /pred1=> /(_ x{2}) h + /h eq_mx.
      by rewrite domE eq_mx -domE.
    move=> x_in_m2; split.
    + move: eqe; rewrite eq_exceptP /pred1=> /(_ x{2}) h + /h eq_mx.
      by rewrite domE eq_mx -domE.
    move=> x_in_m1 x2_neq_G1'x. move: eqe; rewrite eq_exceptP=> -> //= x1.
    by rewrite in_fsetU in_fset1 eq_qs_m; case: (x1 = x{2})=> [->|] //=; rewrite x_in_m2.
  + by progress; apply (Bound_o_ll LRO); apply (LRO_o_ll dout_ll).
  + progress; exists* G1'.x; elim* => x; conseq (Bound_o_ll LRO _) (Bound_o_stable LRO x)=> //.
    by apply (LRO_o_ll dout_ll).
  + inline LRO.o; auto.
    call (_: ={glob Log, glob LRO} /\ (forall x, x \in Log.qs{2} = x \in LRO.m{2})).
    + proc; inline Log(LRO).o LRO.o; sp; if=> //; auto=> /> &2 eq_qs_m _ y _; split.
      + by move=> x_notin_m x1; rewrite in_fsetU in_fset1 mem_set eq_qs_m.
      move=> x_in_m x1; rewrite in_fsetU in_fset1 eq_qs_m; case: (x1 = x{2})=> //=.
      by move=> ->; rewrite x_in_m.          
    inline Log(LRO).init LRO.init; auto=> />; split=> [x1|_ a qs m eq_qs_m y _].
    + by rewrite in_fset0 mem_empty.
  by rewrite get_set_eqE //= eq_except_setl /= eq_qs_m /#.
by rewrite Pr [mu_or]; smt(mu_bounded).
qed.
end section.
end OnBound.
end ROM_BadCall.
back to top