Theory LocallySoundModeUse

(*
Title: SIFUM-Type-Systems
Authors: Sylvia Grewe, Heiko Mantel, Daniel Schoepe
*)
section ‹Type System for Ensuring Locally Sound Use of Modes›

theory LocallySoundModeUse
imports Main Security Language
begin

subsection ‹Typing Rules›

locale sifum_modes = sifum_lang evA evB  +
  sifum_security dma Stop evalw
  for evA :: "('Var, 'Val) Mem  'AExp  'Val"
  and evB :: "('Var, 'Val) Mem  'BExp  bool"

context sifum_modes
begin

abbreviation eval_abv_modes :: "(_, 'Var, 'Val) LocalConf  (_, _, _) LocalConf  bool"
  (infixl "" 70)
  where
  "x  y  (x, y)  evalw"

fun update_annos :: "'Var Mds  'Var ModeUpd list  'Var Mds"
(infix "" 140)
  where
  "update_annos mds [] = mds" |
  "update_annos mds (a # as) = update_annos (update_modes a mds) as"

fun annotate :: "('Var, 'AExp, 'BExp) Stmt  'Var ModeUpd list  ('Var, 'AExp, 'BExp) Stmt"
(infix "" 140)
  where
  "annotate c [] = c" |
  "annotate c (a # as) = (annotate c as)@[a]"

inductive mode_type :: "'Var Mds 
  ('Var, 'AExp, 'BExp) Stmt 
  'Var Mds  bool" (" _ { _ } _")
  where
  skip: " mds { Skip  annos } (mds  annos)" |
  assign: " x  mds GuarNoWrite ; aexp_vars e  mds GuarNoRead = {}  
   mds { (x  e)  annos } (mds  annos)" |
  if_: "  (mds  annos) { c1 } mds'' ;
           (mds  annos) { c2 } mds'' ;
          bexp_vars e  mds GuarNoRead = {}  
         mds { If e c1 c2  annos } mds''" |
  while: " mds' = mds  annos ;  mds' { c } mds' ; bexp_vars e  mds' GuarNoRead = {}  
   mds { While e c  annos } mds'" |
  seq: "  mds { c1 } mds' ;  mds' { c2 } mds''    mds { c1 ;; c2 } mds''" |
  sub: "  mds2 { c } mds2' ; mds1  mds2 ; mds2'  mds1'  
   mds1 { c } mds1'"

subsection ‹Soundness of the Type System›

(* Special case for evaluation with an empty context *)
lemma cxt_eval:
  " cxt_to_stmt [] c, mds, mem  cxt_to_stmt [] c', mds', mem'  
  c, mds, mem  c', mds', mem'"
  by auto

lemma update_preserves_le:
  "mds1  mds2  (mds1  annos)  (mds2  annos)"
proof (induct annos arbitrary: mds1 mds2)
  case Nil
  thus ?case by simp
next
  case (Cons a annos mds1 mds2)
  hence "update_modes a mds1  update_modes a mds2"
    by (case_tac a, auto simp: le_fun_def)
  with Cons show ?case
    by auto
qed

(* Annotations do not affect doesnt_read and doesnt_modify: *)
lemma doesnt_read_annos:
  "doesnt_read c x  doesnt_read (c  annos) x"
  unfolding doesnt_read_def
  apply clarify
  apply (induct annos)
   apply simp
   apply (metis (lifting))
  apply auto
  apply (rule cxt_eval)
  apply (rule evalw.decl)
  by (metis cxt_eval evalw.decl upd_elim)

lemma doesnt_modify_annos:
  "doesnt_modify c x  doesnt_modify (c  annos) x"
  unfolding doesnt_modify_def
  apply auto
  apply (induct annos)
   apply simp
  apply auto
  by (metis (lifting) upd_elim)

(* The following part contains some lemmas about evaluation of
   commands annotated using ⊗ and characterisations of loc_reach for
   commands. *)

lemma stop_loc_reach:
  " c', mds', mem'  loc_reach Stop, mds, mem  
  c' = Stop  mds' = mds"
  apply (induct rule: loc_reach.induct)
  by (auto simp: stop_no_eval)

lemma stop_doesnt_access:
  "doesnt_modify Stop x  doesnt_read Stop x"
  unfolding doesnt_modify_def and doesnt_read_def
  using stop_no_eval
  by auto

lemma skip_eval_step:
  "Skip  annos, mds, mem  Stop, mds  annos, mem"
  apply (induct annos arbitrary: mds)
   apply simp
   apply (metis cxt_to_stmt.simps(1) evalw.unannotated evalw_simple.skip)
  apply simp
  apply (insert evalw.decl)
  apply (rule cxt_eval)
  apply (rule evalw.decl)
  by auto

lemma skip_eval_elim:
  " Skip  annos, mds, mem  c', mds', mem'   c' = Stop  mds' = mds  annos  mem' = mem"
  apply (rule ccontr)
  apply (insert skip_eval_step deterministic)
  apply clarify
  apply auto
    by metis+

lemma skip_doesnt_read:
  "doesnt_read (Skip  annos) x"
  apply (rule doesnt_read_annos)
  apply (auto simp: doesnt_read_def)
  by (metis annotate.simps(1) skip_elim skip_eval_step)

lemma skip_doesnt_write:
  "doesnt_modify (Skip  annos) x"
  apply (rule doesnt_modify_annos)
  apply (auto simp: doesnt_modify_def)
  by (metis skip_elim)

lemma skip_loc_reach:
  " c', mds', mem'  loc_reach Skip  annos, mds, mem  
  (c' = Stop  mds' = (mds  annos))  (c' = Skip  annos  mds' = mds)"
  apply (induct rule: loc_reach.induct)
    apply (metis fst_conv snd_conv)
   apply (metis skip_eval_elim stop_no_eval)
  by metis

lemma skip_doesnt_access:
  " lc  loc_reach Skip  annos, mds, mem ; lc = c', mds', mem'   doesnt_read c' x  doesnt_modify c' x"
  apply (subgoal_tac "(c' = Stop  mds' = (mds  annos))  (c' = Skip  annos  mds' = mds)")
   apply (rule conjI, erule disjE)
     apply (simp add: doesnt_read_def stop_no_eval)
    apply (metis (lifting) annotate.simps skip_doesnt_read)
   apply (erule disjE)
    apply (simp add: doesnt_modify_def stop_no_eval)
   apply (metis (lifting) annotate.simps skip_doesnt_write)
  by (metis skip_loc_reach)

lemma assign_doesnt_modify:
  " x  y   doesnt_modify ((x  e)  annos) y"
  apply (rule doesnt_modify_annos)
  apply (simp add: doesnt_modify_def)
  by (metis assign_elim fun_upd_apply)

lemma assign_annos_eval:
  "(x  e)  annos, mds, mem  Stop, mds  annos, mem (x := evA mem e)"
  apply (induct annos arbitrary: mds)
   apply (simp only: annotate.simps update_annos.simps)
   apply (rule cxt_eval)
   apply (rule evalw.unannotated)
   apply (rule evalw_simple.assign)
  apply (rule cxt_eval)
  apply (simp del: cxt_to_stmt.simps)
  apply (rule evalw.decl)
  by auto

lemma assign_annos_eval_elim:
  " (x  e)  annos, mds, mem  c', mds', mem'  
  c' = Stop  mds' = mds  annos"
  apply (rule ccontr)
  apply (insert deterministic assign_annos_eval)
  apply auto
   apply (metis (lifting))
  by metis

lemma mem_upd_commute:
  " x  y   mem (x := v1, y := v2) = mem (y := v2, x := v1)"
  by (metis fun_upd_twist)

lemma assign_doesnt_read:
  " y  aexp_vars e   doesnt_read ((x  e)  annos) y"
  apply (rule doesnt_read_annos)
proof (cases "x = y")
  assume "y  aexp_vars e"
    and [simp]: "x = y"
  show "doesnt_read (x  e) y"
    unfolding doesnt_read_def
    apply (rule allI)+
    apply (rename_tac mds mem c' mds' mem')
    apply (rule impI)
    apply (subgoal_tac "c' = Stop  mds' = mds  mem' = mem (x := evA mem e)")
     apply simp
     apply (rule disjI2)
     apply clarify
     apply (rule cxt_eval)
     apply (rule evalw.unannotated)
     apply simp
     apply (metis (opaque_lifting, no_types) x = y y  aexp_vars e evalw_simple.assign eval_vars_detA fun_upd_apply fun_upd_upd)
    by (metis assign_elim)
next
  assume asms: "y  aexp_vars e" "x  y"
  show "doesnt_read (x  e) y"
    unfolding doesnt_read_def
    apply (rule allI)+
    apply (rename_tac mds mem c' mds' mem')
    apply (rule impI)
    apply (subgoal_tac "c' = Stop  mds' = mds  mem' = mem (x := evA mem e)")
     apply simp
     apply (rule disjI1)
     apply (insert asms)
     apply clarify
     apply (subgoal_tac "mem (x := evA mem e, y := v) = mem (y := v, x := evA mem e)")
      apply simp
      apply (rule cxt_eval)
      apply (rule evalw.unannotated)
      apply (metis evalw_simple.assign eval_vars_detA fun_upd_apply)
     apply (metis mem_upd_commute)
    by (metis assign_elim)
qed

lemma assign_loc_reach:
  " c', mds', mem'  loc_reach (x  e)  annos, mds, mem  
  (c' = Stop  mds' = (mds  annos))  (c' = (x  e)  annos  mds' = mds)"
  apply (induct rule: loc_reach.induct)
    apply simp_all
  by (metis assign_annos_eval_elim stop_no_eval)

lemma if_doesnt_modify:
  "doesnt_modify (If e c1 c2  annos) x"
  apply (rule doesnt_modify_annos)
  by (auto simp: doesnt_modify_def)

lemma vars_evalB:
  "x  bexp_vars e  evB mem e = evB (mem (x := v)) e"
  by (metis (lifting) eval_vars_detB fun_upd_other)

lemma if_doesnt_read:
  "x  bexp_vars e  doesnt_read (If e c1 c2  annos) x"
  apply (rule doesnt_read_annos)
  apply (auto simp: doesnt_read_def)
  apply (rename_tac mds mem c' mds' mem' v va)
  apply (case_tac "evB mem e")
   apply (subgoal_tac "c' = c1  mds' = mds  mem' = mem")
    apply auto
   apply (rule cxt_eval)
   apply (rule evalw.unannotated)
   apply (rule evalw_simple.if_true)
   apply (metis (lifting) vars_evalB)
  apply (subgoal_tac "c' = c2  mds' = mds  mem' = mem")
   apply auto
  apply (rule cxt_eval)
  apply (rule evalw.unannotated)
  apply (rule evalw_simple.if_false)
  by (metis (lifting) vars_evalB)

lemma if_eval_true:
  " evB mem e  
  If e c1 c2  annos, mds, mem  c1, mds  annos, mem"
  apply (induct annos arbitrary: mds)
   apply simp
   apply (metis cxt_eval evalw.unannotated evalw_simple.if_true)
  by (metis annotate.simps(2) cxt_eval evalw.decl update_annos.simps(2))

lemma if_eval_false:
  " ¬ evB mem e  
  If e c1 c2  annos, mds, mem  c2, mds  annos, mem"
  apply (induct annos arbitrary: mds)
   apply simp
   apply (metis cxt_eval evalw.unannotated evalw_simple.if_false)
  by (metis annotate.simps(2) cxt_eval evalw.decl update_annos.simps(2))

lemma if_eval_elim:
  " If e c1 c2  annos, mds, mem  c', mds', mem'  
  ((c' = c1  evB mem e)  (c' = c2  ¬ evB mem e))  mds' = mds  annos  mem' = mem"
  apply (rule ccontr)
  apply (cases "evB mem e")
   apply (insert if_eval_true deterministic)
   apply (metis prod.inject)
  by (metis prod.inject if_eval_false deterministic)

lemma if_eval_elim':
  " If e c1 c2, mds, mem  c', mds', mem'  
  ((c' = c1  evB mem e)  (c' = c2  ¬ evB mem e))  mds' = mds  mem' = mem"
  using if_eval_elim [where annos = "[]"]
  by auto

lemma loc_reach_refl':
  "c, mds, mem  loc_reach c, mds, mem"
  apply (subgoal_tac " lc. lc  loc_reach lc  lc = c, mds, mem")
   apply blast
  by (metis loc_reach.refl fst_conv snd_conv)

lemma if_loc_reach:
  " c', mds', mem'  loc_reach If e c1 c2  annos, mds, mem  
  (c' = If e c1 c2  annos  mds' = mds) 
  ( mem''. c', mds', mem'  loc_reach c1, mds  annos, mem'') 
  ( mem''. c', mds', mem'  loc_reach c2, mds  annos, mem'')"
  apply (induct rule: loc_reach.induct)
    apply (metis fst_conv snd_conv)
   apply (erule disjE)
    apply (erule conjE)
    apply simp
    apply (drule if_eval_elim)
    apply (erule conjE)+
    apply (erule disjE)
     apply (erule conjE)
     apply simp
     apply (metis loc_reach_refl')
    apply (metis loc_reach_refl')
   apply (metis loc_reach.step)
  by (metis loc_reach.mem_diff)

lemma if_loc_reach':
  " c', mds', mem'  loc_reach If e c1 c2, mds, mem  
  (c' = If e c1 c2  mds' = mds) 
  ( mem''. c', mds', mem'  loc_reach c1, mds, mem'') 
  ( mem''. c', mds', mem'  loc_reach c2, mds, mem'')"
  using if_loc_reach [where annos = "[]"]
  by simp

lemma seq_loc_reach:
  " c', mds', mem'  loc_reach c1 ;; c2, mds, mem  
  ( c''. c' = c'' ;; c2  c'', mds', mem'  loc_reach c1, mds, mem) 
  ( c'' mds'' mem''. Stop, mds'', mem''  loc_reach c1, mds, mem  
                      c', mds', mem'  loc_reach c2, mds'', mem'')"
  apply (induct rule: loc_reach.induct)
    apply simp
    apply (metis  loc_reach_refl')
   apply simp
   apply (metis (no_types) loc_reach.step loc_reach_refl' seq_elim seq_stop_elim)
  by (metis (lifting) loc_reach.mem_diff)

lemma seq_doesnt_read:
  " doesnt_read c x   doesnt_read (c ;; c') x"
  apply (auto simp: doesnt_read_def)
  apply (rename_tac mds mem c'a mds' mem' v va)
  apply (case_tac "c = Stop")
   apply auto
   apply (subgoal_tac "c'a = c'  mds' = mds  mem' = mem")
    apply simp
    apply (metis cxt_eval evalw.unannotated evalw_simple.seq_stop)
   apply (metis (lifting) seq_stop_elim)
  by (metis (lifting, no_types) evalw.seq seq_elim)

lemma seq_doesnt_modify:
  " doesnt_modify c x   doesnt_modify (c ;; c') x"
  apply (auto simp: doesnt_modify_def)
  apply (case_tac "c = Stop")
   apply auto
   apply (metis (lifting) seq_stop_elim)
  by (metis (no_types) seq_elim)

inductive_cases seq_stop_elim': "Stop ;; c, mds, mem  c', mds', mem'"

lemma seq_stop_elim: "Stop ;; c, mds, mem  c', mds', mem' 
  c' = c  mds' = mds  mem' = mem"
  apply (erule seq_stop_elim')
    apply (metis evalw.unannotated seq_stop_elim)
   apply (metis evalw.seq seq_stop_elim)
  by (metis (lifting) Stmt.simps(28) Stmt.simps(34) cxt_seq_elim)

lemma seq_split:
  " Stop, mds', mem'  loc_reach c1 ;; c2, mds, mem  
   mds'' mem''. Stop, mds'', mem''  loc_reach c1, mds, mem 
                 Stop, mds', mem'  loc_reach c2, mds'', mem''"
  apply (drule seq_loc_reach)
  by (metis Stmt.simps(41))

lemma while_eval:
  "While e c  annos, mds, mem  (If e (c ;; While e c) Stop), mds  annos, mem"
  apply (induct annos arbitrary: mds)
   apply simp
   apply (rule cxt_eval)
   apply (rule evalw.unannotated)
   apply (metis (lifting) evalw_simple.while)
  apply simp
  by (metis cxt_eval evalw.decl)

lemma while_eval':
  "While e c, mds, mem  If e (c ;; While e c) Stop, mds, mem"
  using while_eval [where annos = "[]"]
  by auto

lemma while_eval_elim:
  " While e c  annos, mds, mem  c', mds', mem'  
   (c' = If e (c ;; While e c) Stop  mds' = mds  annos  mem' = mem)"
  apply (rule ccontr)
  apply (insert while_eval deterministic)
  by blast

lemma while_eval_elim':
  " While e c, mds, mem  c', mds', mem'  
   (c' = If e (c ;; While e c) Stop  mds' = mds  mem' = mem)"
  using while_eval_elim [where annos = "[]"]
  by auto

lemma while_doesnt_read:
  " x  bexp_vars e   doesnt_read (While e c  annos) x"
  unfolding doesnt_read_def
  using while_eval while_eval_elim
  by metis

lemma while_doesnt_modify:
  "doesnt_modify (While e c  annos) x"
  unfolding doesnt_modify_def
  using while_eval_elim
  by metis

(* TODO: try to find a better solution to this: *)
lemma disjE3:
  " A  B  C ; A  P ; B  P ; C  P   P"
  by auto

lemma disjE5:
  " A  B  C  D  E ; A  P ; B  P ; C  P ; D  P ; E  P   P"
  by auto

lemma if_doesnt_read':
  "x  bexp_vars e  doesnt_read (If e c1 c2) x"
  using if_doesnt_read [where annos = "[]"]
  by auto

theorem mode_type_sound:
  assumes typeable: " mds1 { c } mds1'"
  assumes mode_le: "mds2  mds1"
  shows " mem. (Stop, mds2', mem'  loc_reach c, mds2, mem  mds2'  mds1')  
                locally_sound_mode_use c, mds2, mem"
  using typeable mode_le
proof (induct arbitrary: mds2 mds2' mem' mem rule: mode_type.induct)
  case (skip mds annos)
  thus ?case
    apply auto
     apply (metis (lifting) skip_eval_step skip_loc_reach stop_no_eval update_preserves_le)
    apply (simp add: locally_sound_mode_use_def)
    by (metis annotate.simps skip_doesnt_access)
next
  case (assign x mds e annos)
  hence " mem. locally_sound_mode_use (x  e)  annos, mds2, mem"
    unfolding locally_sound_mode_use_def
  proof (clarify)
    fix mem c' mds' mem' y
    assume asm: "c', mds', mem'  loc_reach (x  e)  annos, mds2, mem"
    hence "c' = (x  e)  annos  mds' = mds2  c' = Stop  mds' = mds2  annos"
      using assign_loc_reach by blast
    thus "(y  mds' GuarNoRead  doesnt_read c' y) 
          (y  mds' GuarNoWrite  doesnt_modify c' y)"
    proof
      assume "c' = (x  e)  annos  mds' = mds2"
      thus ?thesis
      proof (auto)
        assume "y  mds2 GuarNoRead"
        hence "y  aexp_vars e"
          by (metis IntD2 IntI assign.hyps(2) assign.prems empty_iff inf_apply le_iff_inf)
        with assign_doesnt_read show "doesnt_read ((x  e)  annos) y"
          by blast
      next
        assume "y  mds2 GuarNoWrite"
        hence "x  y"
          by (metis assign.hyps(1) assign.prems in_mono le_fun_def)
        with assign_doesnt_modify show "doesnt_modify ((x  e)  annos) y"
          by blast
      qed
    next
      assume "c' = Stop  mds' = mds2  annos"
      with stop_doesnt_access show ?thesis by blast
    qed
  qed
  thus ?case
    apply auto
    by (metis assign.prems assign_annos_eval assign_loc_reach stop_no_eval update_preserves_le)
next
  case (if_ mds annos c1 mds'' c2 e)
    let ?c = "(If e c1 c2)  annos"
  from if_ have modes_le': "mds2  annos  mds  annos"
    by (metis (lifting) update_preserves_le)
  from if_ show ?case
    apply (simp add: locally_sound_mode_use_def)
    apply clarify
    apply (rule conjI)
     apply clarify
     prefer 2
     apply clarify
  proof -
    fix mem
    assume "Stop, mds2', mem'  loc_reach If e c1 c2  annos, mds2, mem"
    with modes_le' and if_ show "mds2'  mds''"
      by (metis if_eval_false if_eval_true if_loc_reach stop_no_eval)
  next
    fix mem c' mds' mem' x
    assume "c', mds', mem'  loc_reach If e c1 c2  annos, mds2, mem"
    hence "(c' = If e c1 c2  annos  mds' = mds2) 
           ( mem''. c', mds', mem'  loc_reach c1, mds2  annos, mem'') 
           ( mem''. c', mds', mem'  loc_reach c2, mds2  annos, mem'')"
      using if_loc_reach by blast
    thus "(x  mds' GuarNoRead  doesnt_read c' x) 
          (x  mds' GuarNoWrite  doesnt_modify c' x)"
    proof
      assume "c' = If e c1 c2  annos  mds' = mds2"
      thus ?thesis
      proof (auto)
        assume "x  mds2 GuarNoRead"
        with bexp_vars e  mds GuarNoRead = {} and mds2  mds have "x  bexp_vars e"
          by (metis IntD2 disjoint_iff_not_equal inf_fun_def le_iff_inf)
        thus "doesnt_read (If e c1 c2  annos) x"
          using if_doesnt_read by blast
      next
        assume "x  mds2 GuarNoWrite"
        thus "doesnt_modify (If e c1 c2  annos) x"
          using if_doesnt_modify by blast
      qed
    next
      assume "(mem''. c', mds', mem'  loc_reach c1, mds2  annos, mem'') 
              (mem''. c', mds', mem'  loc_reach c2, mds2  annos, mem'')"
      with if_ show ?thesis
        by (metis locally_sound_mode_use_def modes_le')
    qed
  qed
next
  case (while mdsa mds annos c e)
  hence "mds2  annos  mds  annos"
    by (metis (lifting) update_preserves_le)
  have while_loc_reach: " c' mds' mem' mem.
  c', mds', mem'  loc_reach While e c  annos, mds2, mem 
  c' = While e c  annos  mds' = mds2 
  c' = While e c  mds'  mdsa 
  c' = Stmt.If e (c ;; While e c) Stop  mds'  mdsa 
  c' = Stop  mds'  mdsa 
  (c'' mem'' mds3.
      c' = c'' ;; While e c 
      mds3  mdsa  c'', mds', mem'  loc_reach c, mds3, mem'')"
  proof -
    fix mem c' mds' mem'
    assume "c', mds', mem'  loc_reach While e c  annos, mds2, mem"
    thus "?thesis c' mds' mem' mem"
      apply (induct rule: loc_reach.induct)
        apply simp_all
       apply (erule disjE)
        apply simp
        apply (metis mds2  annos  mds  annos while.hyps(1) while_eval_elim)
       apply (erule disjE)
        apply (metis while_eval_elim')
       apply (erule disjE)
        apply simp
        apply (metis if_eval_elim' loc_reach_refl')
       apply (erule disjE)
        apply (metis stop_no_eval)
       apply (erule exE)
       apply (rename_tac c' mds' mem' c'' mds'' mem'' c''a)
       apply (case_tac "c''a = Stop")
        apply (insert while.hyps(3))
        apply (metis seq_stop_elim while.hyps(3))
       apply (metis loc_reach.step seq_elim)
      by (metis (full_types) loc_reach.mem_diff)
  qed
  from while show ?case
  proof (auto)
    fix mem
    assume "Stop, mds2', mem'  loc_reach While e c  annos, mds2, mem"
    thus "mds2'  mds  annos"
      by (metis Stmt.distinct(35) stop_no_eval while.hyps(1) while_eval while_loc_reach)
  next
    fix mem
    from while have "bexp_vars e  (mds2  annos) GuarNoRead = {}"
      by (metis (lifting, no_types) Int_empty_right Int_left_commute mds2  annos  mds  annos inf_fun_def le_iff_inf)
    show "locally_sound_mode_use While e c  annos, mds2, mem"
      unfolding locally_sound_mode_use_def
      apply (rule allI)+
      apply (rule impI)
    proof -
      fix c' mds' mem'
      define lc where "lc = While e c  annos, mds2, mem"
      assume "c', mds', mem'  loc_reach lc"
      thus " x. (x  mds' GuarNoRead  doesnt_read c' x) 
                 (x  mds' GuarNoWrite  doesnt_modify c' x)"
        apply (simp add: lc_def)
        apply (drule while_loc_reach)
        apply (erule disjE5)
      proof (auto del: conjI)
        fix x
        show "(x  mds2 GuarNoRead  doesnt_read (While e c  annos) x) 
              (x  mds2 GuarNoWrite  doesnt_modify (While e c  annos) x)"
          unfolding doesnt_read_def and doesnt_modify_def
          using while_eval and while_eval_elim
          by blast
      next
        fix x
        assume "mds'  mdsa"
        let ?c' = "If e (c ;; While e c) Stop"
        have "x  mds' GuarNoRead  doesnt_read ?c' x"
          apply clarify
          apply (rule if_doesnt_read')
          by (metis IntI mds'  mdsa empty_iff le_fun_def rev_subsetD while.hyps(1) while.hyps(4))
        moreover
        have "x  mds' GuarNoWrite  doesnt_modify ?c' x"
          by (metis annotate.simps(1) if_doesnt_modify)
        ultimately show "(x  mds' GuarNoRead  doesnt_read ?c' x) 
                         (x  mds' GuarNoWrite  doesnt_modify ?c' x)" ..
      next
        fix x
        assume "mds'  mdsa"
        show "(x  mds' GuarNoRead  doesnt_read Stop x) 
              (x  mds' GuarNoWrite  doesnt_modify Stop x)"
          by (metis stop_doesnt_access)
      next
        fix c'' x mem'' mds3
        assume "mds3  mdsa"
        assume "c'', mds', mem'  loc_reach c, mds3, mem''"
        thus "(x  mds' GuarNoRead  doesnt_read (c'' ;; While e c) x) 
              (x  mds' GuarNoWrite  doesnt_modify (c'' ;; While e c) x)"
          apply auto
           apply (rule seq_doesnt_read)
           apply (insert while(3))
           apply (metis mds3  mdsa locally_sound_mode_use_def while.hyps(1))
          apply (rule seq_doesnt_modify)
          by (metis mds3  mdsa locally_sound_mode_use_def while.hyps(1))
      next
        fix x
        assume "mds'  mdsa"
        show "(x  mds' GuarNoRead  doesnt_read (While e c) x) 
              (x  mds' GuarNoWrite  doesnt_modify (While e c) x)"
          unfolding doesnt_read_def and doesnt_modify_def
          using while_eval' and while_eval_elim'
          by blast
      qed
    qed
  qed
next
  case (seq mds c1 mds' c2 mds'')
  thus ?case
  proof (auto)
    fix mem
    assume "Stop, mds2', mem'  loc_reach c1 ;; c2, mds2, mem"
    then obtain mds2'' mem'' where "Stop, mds2'', mem''  loc_reach c1, mds2, mem" and
      "Stop, mds2', mem'  loc_reach c2, mds2'', mem''"
      using seq_split by blast
    thus "mds2'  mds''"
      using seq by blast
  next
    fix mem
    from seq show "locally_sound_mode_use c1 ;; c2, mds2, mem"
      apply (simp add: locally_sound_mode_use_def)
      apply clarify
      apply (drule seq_loc_reach)
      apply (erule disjE)
       apply (metis seq_doesnt_modify seq_doesnt_read)
      by metis
  qed
next
  case (sub mds2'' c mds2' mds1 mds1' c1)
  thus ?case
    apply auto
    by (metis (opaque_lifting, no_types) inf_absorb2 le_infI1)
qed

end

end