https://github.com/EasyCrypt/easycrypt
Raw File
Tip revision: 9db28d59d65422c4ba10a109a3dc53d190f7d806 authored by Pierre-Yves Strub on 27 January 2020, 13:46:58 UTC
script for testing EasyCrypt on various external devs
Tip revision: 9db28d5
IterProc.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 -oldip.

require import Core List.

type t.

module type Orcl = {
  proc f (x : t) : unit
}.

module Iter (O:Orcl) = {

  proc iter(l : t list) = {
    while (l <> []) {
      O.f(head witness l);
      l <- drop 1 l;
    }
  }

  proc iters(l1 l2 : t list) = {
    iter(l1);
    iter(l2);
  }

  proc iter_1s(t:t, l:t list) = {
    O.f(t);
    iter(l);
  }

  proc iter_12(t1 t2 : t) = {
    O.f(t1);
    O.f(t2);
  }

  proc iter_21(t1 t2 : t) = {
    O.f(t2);
    O.f(t1);
  }

}.

lemma iter_ll (O <: Orcl): islossless O.f => islossless Iter(O).iter.
proof.
move=> O_ll; proc; inline Iter(O).iter.
while true (size l); auto=> /=.
+ call O_ll; skip=> /= ? [#] Hl <-.
  smt w=(size_eq0 size_ge0 size_drop).
smt w=(size_eq0 size_ge0).
qed.

lemma iters_ll (O <: Orcl): islossless O.f => islossless Iter(O).iters.
proof. by move=> f_ll;proc;do 2!call (iter_ll O f_ll). qed.

lemma iter_1s_ll (O <: Orcl): islossless O.f => islossless Iter(O).iter_1s.
proof. by move=> f_ll;proc;call (iter_ll O f_ll);call f_ll. qed.

equiv iter_cat (O <: Orcl):
  Iter(O).iter ~ Iter(O).iters:
  ={glob O} /\ l{1} = (l1++l2){2} ==> ={glob O}.
proof.
proc=> /=; inline Iter(O).iter.
exists* l2{2}; elim*=> _l2.
splitwhile{1} 1: l <> _l2.
while (={glob O} /\ l{1} = l0{2}).
+ by auto; call (_: true).
wp; while (={glob O} /\ l{1} = l{2}++_l2).
+ auto; call (_: true); auto.
  move=> ? &ml [#] 2!->; case: (l{ml})=> //= x l'.
  rewrite !drop0=> /= _ Ol Or ->> /= - {Or}; split=> [[] _|].
  + by apply/contraLR=> /= ->.
  rewrite -size_eq0=> size_l'.
  by split; rewrite -negP=> /(congr1 size); rewrite size_cat [smt(size_ge0)].
auto=> /> &2; split=> [_|].
+ by apply/contraLR=> /= ->.
rewrite -size_eq0=> size_l1.
by split; rewrite -negP=> /(congr1 size); rewrite size_cat [smt(size_ge0)].
qed.

equiv iter_cat_cat (O <: Orcl):
  Iter(O).iters ~ Iter(O).iters:
  ={glob O} /\ (l1++l2){1} = (l1++l2){2} ==> ={glob O}.
proof.
transitivity Iter(O).iter
  (={glob O} /\ (l1++l2){1} = l{2} ==> ={glob O})
  (={glob O} /\ l{1} = (l1++l2){2} ==> ={glob O})=> [/#|//||].
+ by symmetry; conseq (iter_cat O).
by apply (iter_cat O).
qed.

equiv iter_12_eq (O <: Orcl): Iter(O).iter_12 ~ Iter(O).iter:
  ={glob O} /\ l{2} = [t1;t2]{1} ==> ={glob O}.
proof.
proc=> /=.
rcondt{2} 1; 1: by auto.
rcondt{2} 3; 1: by auto; call (_: true); auto.
rcondf{2} 5; 1: by do !(auto; call (_: true)); auto.
by do !(auto; call (_: true)); auto.
qed.

lemma iter_21_eq (O <: Orcl):
  equiv [Iter(O).iter_21 ~ Iter(O).iter:
         ={glob O} /\ l{2} = [t2;t1]{1} ==> ={glob O}].
proof.
proc=> /=.
rcondt{2} 1; 1: by auto.
rcondt{2} 3; 1: by auto; call (_: true); auto.
rcondf{2} 5; 1: by do !(auto; call (_: true)); auto.
by do !(auto; call (_: true)); auto.
qed.

section.
  declare module O:Orcl.

  axiom iter2_eq:
    equiv [Iter(O).iter_12 ~ Iter(O).iter_21:
           ={glob O,t1,t2} ==> ={glob O}].

  lemma iter_swap s1 i s2:
    equiv [Iter(O).iter ~ Iter(O).iter :
           l{1} = i::s1++s2 /\ l{2} = s1++i::s2 /\ ={glob O} ==> ={glob O}].
  proof.
  elim: s1=> /= [|i' s1 Hrec]; 1:by sim.
  transitivity Iter(O).iters
    (={glob O} /\ l{1} = i::i'::(s1++s2) /\ l1{2} = [i;i'] /\ l2{2} = s1++s2 ==>
     ={glob O})
    (={glob O} /\ l1{1} = [i;i'] /\ l2{1} = s1 ++ s2 /\ l{2} = i'::(s1++i::s2) ==>
     ={glob O})=> //.
  + by move=> /> &2; exists ((glob O){2}) ([i;i'],s1++s2).
  + by conseq (iter_cat O)=> ? &ml [#] 4!->.
  transitivity Iter(O).iters
    (={glob O,l2} /\ l1{1} = [i;i'] /\ l1{2} = [i';i] /\ l2{1} = s1++s2 ==>
     ={glob O})
    (={glob O} /\ l1{1} = [i';i] /\ l2{1} = s1 ++ s2 /\ l{2} = i'::(s1++i::s2) ==>
     ={glob O})=> //.
  + by move=> /> &1 &2 _ ->; exists ((glob O){2}) ([i'; i],s1++s2).
  + proc; call (_: ={glob O}).
    * by while (={glob O,l}); auto; call (_: true).
    conseq (_: ={glob O} /\ l1{1} = [i;i'] /\ l1{2} = [i';i] ==> ={glob O})=> //.
    transitivity{1} {Iter(O).iter_12(i,i');}
      (l1{1} = [i;i'] /\ ={glob O,l1} ==> ={glob O})
      (l1{1} = [i;i'] /\ l1{2} = [i';i] /\ ={glob O} ==> ={glob O})=> [/#|//||].
    + by symmetry; call (iter_12_eq O).
    transitivity{1} {Iter(O).iter_21(i,i');}
      (l1{1} = [i;i'] /\ l1{2} =[i';i] /\ ={glob O} ==> ={glob O})
      (l1{1} = [i';i] /\ ={glob O,l1} ==> ={glob O})=> [/#|//||].
    + by wp; call iter2_eq.
    by call (iter_21_eq O).
  transitivity Iter(O).iters
    (={glob O} /\ l1{1} = [i';i] /\ l2{1} = s1++s2 /\ l1{2} = [i'] /\ l2{2} = i::(s1++s2) ==>
     ={glob O})
    (={glob O} /\ l1{1} = [i'] /\ l2{1} = i::s1++s2 /\ l{2} = i'::(s1++i::s2) ==>
     ={glob O})=> //.
  + by move=> /> &1 &2 _ _; exists ((glob O){2}) ([i'],i::(s1++s2)).
  + by conseq (iter_cat_cat O)=> ? &ml [#] 5!->.
  transitivity Iter(O).iters
    (={glob O,l1} /\ l1{1} = [i'] /\ l2{1} = i::s1++s2 /\ l2{2} = s1++i::s2 ==>
     ={glob O})
    (={glob O} /\ l1{1} = [i'] /\ l2{1} = s1++i::s2 /\ l{2} = i'::s1++i::s2 ==>
     ={glob O})=> //.
  + by move=> /> &1 &2 -> _; exists ((glob O){2}) ([i'],s1++i::s2).
  + proc; call Hrec; call (_: ={glob O})=> //.
    by while (={glob O, l}); auto; call (_: true).
  by symmetry; conseq (iter_cat O)=> // ? &ml [#] 4!->.
  qed.

  lemma iter_perm :
    equiv [Iter(O).iter ~ Iter(O).iter : perm_eq l{1} l{2} /\ ={glob O} ==> ={glob O}].
  proof.
  exists*l{1}, l{2}; elim*=>l1 l2; case (perm_eq l1 l2)=> Hp; last first.
  + conseq (_: false ==> _)=> // ?? [#] //.
  elim: l1 l2 Hp=> [|i s1 ih] s2 eq_s12 /=.
  + have ->: s2 = [] by apply/perm_eq_small/perm_eq_sym.
    by proc; rcondf{1} 1=> //; rcondf{2} 1=> //.
  have/perm_eq_mem /(_ i):= eq_s12; rewrite mem_head /=.
  move/splitPr => [s3 s4] ->>.
  transitivity Iter(O).iter
    (l{1}=i::s1 /\ l{2}=i::(s3++s4) /\ ={glob O} ==> ={glob O})
    (l{1}=i::(s3++s4) /\ l{2}=s3++i::s4 /\ ={glob O} ==> ={glob O})=>//.
  + by move=> ? &mr [#] 2!-> _ ->; exists (glob O){mr} (i :: (s3 ++ s4)).
  + proc; rcondt{1} 1=> //; rcondt{2}1=> //.
    seq  2  2: (s1 = l{1} /\ l{2}=s3++s4 /\ ={glob O}).
    + by wp; call (_: true); auto; progress; rewrite drop0.
    transitivity{1} {Iter(O).iter(l);}
      (={l,glob O} ==> ={glob O})
      (s1 = l{1} /\ l{2} = s3 ++ s4 /\ ={glob O} ==> ={glob O})=> //.
    + by move=> &1 &mr [#] 3!->; exists (glob O){mr} l{1}.
    + by inline Iter(O).iter; sim.
    transitivity{1} {Iter(O).iter(l);}
      (s1 = l{1} /\ l{2} = s3 ++ s4 /\ ={glob O} ==> ={glob O})
      (={l,glob O} ==> ={glob O})=> //.
    + by move=> ? &mr [#] 3!->; exists (glob O){mr} (s3++s4).
    + move: eq_s12; rewrite -(cat1s i s4) catA perm_eq_sym.
      rewrite perm_catCA /= perm_cons perm_eq_sym=> Hp.
      by call (ih (s3++s4) Hp).
    by inline Iter(O).iter; sim.
  by apply/(iter_swap s3 i s4). (* FIXME: apply iter_swap fail! *)
  qed.

  lemma iters_perm:
    equiv [Iter(O).iters ~ Iter(O).iter :
      perm_eq (l1{1}++l2{1}) l{2} /\ ={glob O} ==> ={glob O}].
  proof.
  transitivity Iter(O).iter
    (l{2} = l1{1}++l2{1} /\ ={glob O} ==> ={glob O})
    (perm_eq l{1} l{2} /\ ={glob O} ==> ={glob O})=>//.
  + by move=> &ml&mr[??]; exists (glob O){mr} (l1{ml} ++ l2{ml}).
  + by symmetry;conseq (iter_cat O).
  by apply iter_perm.
  qed.

  lemma iter1_perm:
    equiv [Iter(O).iter_1s ~ Iter(O).iter :
      perm_eq (t{1}::l{1}) l{2} /\ ={glob O} ==> ={glob O}].
  proof.
  transitivity Iter(O).iter
    (l{2} = t{1}::l{1} /\ ={glob O} ==> ={glob O})
    (perm_eq l{1} l{2} /\ ={glob O} ==> ={glob O})=>//.
  + by move=> &ml&mr[??]; exists (glob O){mr} (t{ml}::l{ml}).
  + proc;rcondt{2}1;1:by auto.
    by inline*;sim;wp;call (_:true);skip;progress;rewrite drop0.
  by apply iter_perm.
  qed.

end section.

lemma iter_inv (O<:Orcl) (P:t -> bool) (Inv: glob O -> glob O -> bool):
  equiv [ O.f ~ O.f:
          ={x} /\ P x{1} /\ Inv (glob O){1} (glob O){2} ==>
          Inv (glob O){1} (glob O){2} ] =>
  equiv [ Iter(O).iter ~ Iter(O).iter :
          ={l} /\ (forall x, mem l{1} x => P x) /\ Inv (glob O){1} (glob O){2} ==>
          Inv (glob O){1} (glob O){2} ].
proof.
move=> Hf;proc.
while (={l} /\ (forall x, mem l{1} x => P x) /\ Inv (glob O){1} (glob O){2});auto.
call Hf;auto=> ??[#]-> HP HI Hl _ /=;split.
+ by rewrite HI HP // <@ Hl=>/head_behead /(_ witness) {1}<-.
by move=>_ ??->/= x Hx;apply/HP/(mem_drop 1).
qed.
back to top