Raw File
Counter.eca
require import Int Real Distr StdOrder.
(*---*) import RealOrder.

type from, to.

module type System = {
  proc init(): unit
  proc oracle(_ : from): to
}.

module type Oracle = {
  proc oracle(_ : from): to
}.

module type Distinguisher(O : Oracle) = {
  proc distinguish(): unit
}.

module Counter(S : System) = {
  var c : int

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

  proc oracle(x : from): to = {
    var r;

    r <@ S.oracle(x);
    c <- c + 1;
    return r;
  }
}.

section.
  declare module S <: System.
  declare module D <: Distinguisher { -S }.


  lemma ind_counting (E : (glob S) -> bool) &m:
      Pr[D(S).distinguish() @ &m: E (glob S)]
    = Pr[D(Counter(S)).distinguish() @ &m: E (glob S)].
  proof.
  byequiv=> //=; proc *.
  by call (_: ={glob S}); first by proc *; inline *; sim.
  qed.

  equiv eq_counting:
    S.oracle ~ Counter(S).oracle: ={glob S, arg} ==> ={glob S, res}.
  proof. by proc *; inline *; sim. qed.
end section.

op q : { int | 0 <= q } as ge0_q.

section.
  declare module D <: Distinguisher { -Counter }.

  declare axiom D_bounded (S <: System { -Counter, -D }) c0 &m:
    islossless S.oracle =>
    Counter.c{m} = c0 =>
    Pr[D(Counter(S)).distinguish() @ &m : Counter.c <= c0 + q] = 1%r.

  lemma D_ll (S <: System { -Counter, -D }):
    islossless S.oracle => islossless D(Counter(S)).distinguish.
  proof.
  move=> S_ll.
  exists* Counter.c; elim*=> c0.
  bypr=> &m0 /= /eq_sym /(D_bounded S c0 &m0 S_ll) pr_E1.
  apply/ler_anti; split=> [|_]; first by smt w=mu_bounded.
  by rewrite -pr_E1 Pr [mu_sub].
  qed.

  lemma D_bounded_hoare (S <: System { -Counter, -D }) c0:
    islossless S.oracle =>
    hoare [D(Counter(S)).distinguish: Counter.c = c0 ==> Counter.c <= c0 + q].
  proof.
  move=> S_ll; hoare.
  bypr=> &m0 /(D_bounded S c0 &m0 S_ll).
  rewrite Pr [mu_not] (_: Pr[D(Counter(S)).distinguish() @ &m0 : true] = 1%r)=> [|<-//].
  by byphoare (D_ll S S_ll).
  qed.
end section.
back to top