Theory Fun1_insecure

subsection "Proof"
theory Fun1_insecure
imports Fun1
begin


subsubsection "Concrete leak"

definition "PC ≡ {0..6}"

definition "same_xx cfg3 cfgs3 cfg4 cfgs4 ≡ 
 vstore (getVstore (stateOf cfg3)) xx = vstore (getVstore (stateOf cfg4)) xx ∧
 (∀cfg3'∈set cfgs3. vstore (getVstore (stateOf cfg3')) xx = vstore (getVstore (stateOf cfg3)) xx) ∧ 
 (∀cfg4'∈set cfgs4. vstore (getVstore (stateOf cfg4')) xx = vstore (getVstore (stateOf cfg4)) xx)"

(* two possible program traces for normal execution*)
definition "trueProg = {2,3,4,5,6}"
definition "falseProg = {2,3,5,6}"


(*pstate *)
definition "pstate1 ≡ update pstate0 [3]"
definition "pstate2 ≡ update pstate1 [5,5]"

lemmas pstate_def = pstate1_def pstate2_def

(*heap*)
(*provide different memories*)
fun hh3:: "nat ⇒ int" where 
"hh3 x =  (if x = (nat NN + 1) then 5 else 0)"

definition "h3 ≡(Heap hh3)"

fun hh4:: "nat ⇒ int" where 
"hh4 x = (if x = (nat NN + 1) then 6 else 0)"

definition "h4 ≡(Heap hh4)"

lemmas h_def = h3_def h4_def hh3.simps hh4.simps

(*used to show difference in heap vals*)
lemma ss_neq_aux1:"nat(5 * 512) ≠ nat (6 * 512)" by auto
lemma ss_neq_aux2:"nat(3 * 512) ≠ nat (5 * 512)" by auto
lemmas ss_neq = ss_neq_aux1 ss_neq_aux2
(*pointer*)
definition "p ≡ nat size_aa1 + nat size_aa2"

(*vstore and reads*)

definition "vs1 ≡ (vs0(xx := NN + 1))"


definition "vs2 ≡ (vs1(tt := 0))"

definition "aa1i ≡ array_loc aa1 (nat (vs2 xx)) avst'"

(*divergence between 3 and 4*)

definition "aa2vs3 ≡ array_loc aa2 (nat (hh3 aa1i * 512)) avst'"

definition "vs33 = vs2(tt := hh3 aa2vs3)"

(**)
definition "aa2vs4 ≡ array_loc aa2 (nat (hh4 aa1i * 512)) avst'"

definition "vs34 = vs2(tt := hh4 aa2vs4)"

lemmas readsm_def = aa1i_def aa2vs3_def aa2vs4_def
lemmas vs_def = vs0.simps vs1_def vs2_def vs33_def vs34_def


(*states*)
definition "s03 ≡ (State (Vstore vs0) avst' h3 p)"
definition "s13 ≡ (State (Vstore vs1) avst' h3 p)"
definition "s23 ≡ (State (Vstore vs2) avst' h3 p)"
definition "s33 ≡ (State (Vstore vs33) avst' h3 p)"

definition "s04 ≡ (State (Vstore vs0) avst' h4 p)"
definition "s14 ≡ (State (Vstore vs1) avst' h4 p)"
definition "s24 ≡ (State (Vstore vs2) avst' h4 p)"
definition "s34 ≡ (State (Vstore vs34) avst' h4 p)"

lemmas s_def = s03_def s13_def s23_def s33_def 
               s04_def s14_def s24_def s34_def

(*s3 stateA's*)
definition "(s30:: stateO) ≡ (pstate0, (Config 0 s03), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s31:: stateO) ≡ (pstate0, (Config 1 s03), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s32:: stateO) ≡ (pstate0, (Config 2 s13), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s33:: stateO) ≡ (pstate0, (Config 3 s23), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s34:: stateO) ≡ (pstate1, (Config 5 s23), [Config 4 s23], repeat (NN+1), repeat (NN+1), {})"
definition "(s35:: stateO) ≡ (pstate1, (Config 5 s23), [Config 5 s33], repeat (NN+1), repeat (NN+1), {aa2vs3, aa1i})"
definition "(s36:: stateO) ≡ (pstate2, (Config 5 s23), [], repeat (NN+1), repeat (NN+1), {aa2vs3, aa1i})"
definition "(s37:: stateO) ≡ (pstate2, (Config 6 s23), [], repeat (NN+1), repeat (NN+1), {aa2vs3, aa1i})"

lemmas s3_def = s30_def s31_def s32_def s33_def s34_def s35_def s36_def s37_def

lemmas state_def = s_def h_def vs_def readsm_def pstate_def avst_defs


(*s3 transition list*)
definition "s3_trans ≡ [s30, s31, s32, s33, s34, s35, s36, s37]"
lemmas s3_trans_defs = s3_trans_def s3_def 

lemma hd_s3_trans[simp]: "hd s3_trans = s30" by (simp add: s3_trans_def)
lemma s3_trans_nemp[simp]: "s3_trans ≠ []" by (simp add: s3_trans_def)


(*transitions*)
lemma s301[simp]:"s30 →S s31"
  unfolding s3_def
  using nonspec_normal
  by simp

lemma s312[simp]:"s31 →S s32"
  unfolding s3_def state_def
  using nonspec_normal
  by simp

lemma s323[simp]:"s32 →S s33"
  unfolding s3_def state_def
  by (simp add: finalM_iff)

lemma s334[simp]:"s33 →S s34"
  unfolding s3_def state_def
  using nonspec_mispred
  by (simp add: finalM_iff)

lemma s345[simp]:"s34 →S s35"
  unfolding s3_def state_def
  using spec_normal
  by (simp_all add: finalM_iff, blast) 

lemma s356[simp]:"s35 →S s36"
  unfolding s3_def state_def
  using spec_resolve
  by simp

lemma s367[simp]:"s36 →S s37"
  unfolding s3_def state_def
  using nonspec_normal
  by simp

lemma finalS_s37[simp]:"finalS s37"
  unfolding finalS_def final_def s3_def
  by (simp add: stepS_endPC)

lemmas s3_trans_simps = s301 s312 s323 s334 s345 s356 s367

(*s4 stateA's*)
definition "(s40:: stateO) ≡ (pstate0, (Config 0 s04), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s41:: stateO) ≡ (pstate0, (Config 1 s04), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s42:: stateO) ≡ (pstate0, (Config 2 s14), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s43:: stateO) ≡ (pstate0, (Config 3 s24), [], repeat (NN+1), repeat (NN+1), {})"
definition "(s44:: stateO) ≡ (pstate1, (Config 5 s24), [Config 4 s24], repeat (NN+1), repeat (NN+1), {})"
definition "(s45:: stateO) ≡ (pstate1, (Config 5 s24), [Config 5 s34], repeat (NN+1), repeat (NN+1), {aa2vs4, aa1i})"
definition "(s46:: stateO) ≡ (pstate2, (Config 5 s24), [], repeat (NN+1), repeat (NN+1), {aa2vs4, aa1i})"
definition "(s47:: stateO) ≡ (pstate2, (Config 6 s24), [], repeat (NN+1), repeat (NN+1), {aa2vs4, aa1i})"

lemmas s4_def = s40_def s41_def s42_def s43_def s44_def s45_def s46_def s47_def


(*s4 transition list*)
definition "s4_trans ≡ [s40, s41, s42, s43, s44, s45, s46, s47]"
lemmas s4_trans_defs = s4_trans_def s4_def

lemma hd_s4_trans[simp]: "hd s4_trans = s40" by (simp add: s4_trans_def)
lemma s4_trans_nemp[simp]: "s4_trans ≠ []" by (simp add: s4_trans_def)


(*transitions*)
lemma s401[simp]:"s40 →S s41"
  unfolding s4_def
  using nonspec_normal
  by simp

lemma s412[simp]:"s41 →S s42"
  unfolding s4_def state_def
  using nonspec_normal
  by simp

lemma s424[simp]:"s42 →S s43"
  unfolding s4_def state_def
  using nonspec_normal
  by (simp add: finalM_iff)

lemma s434[simp]:"s43 →S s44"
  unfolding s4_def state_def
  using nonspec_mispred
  by (simp add: finalM_iff)

lemma s445[simp]:"s44 →S s45"
  unfolding s4_def state_def
  using spec_normal 
  by (simp add: finalM_iff, blast)

lemma s456[simp]:"s45 →S s46"
  unfolding s4_def state_def
  using spec_resolve
  by simp

lemma s467[simp]:"s46 →S s47"
  unfolding s4_def state_def
  using nonspec_normal
  by simp

lemma finalS_s47[simp]:"finalS s47"
  unfolding finalS_def final_def s4_def
  by (simp add: stepS_endPC)


lemmas s4_trans_simps = s401 s412 s424 s434 s445 s456 s467



subsubsection "Auxillary lemmas for disproof"
lemma validS_s3_trans[simp]:"Opt.validS s3_trans"
  unfolding Opt.validS_def validTransO.simps s3_trans_def
  apply safe  
  subgoal for i using cases_5[of i] 
    by(elim disjE, simp_all) .


lemma validS_s4_trans[simp]:"Opt.validS s4_trans"
  unfolding Opt.validS_def validTransO.simps s4_trans_def
  apply safe
  subgoal for i using cases_5[of i] 
  by(elim disjE, simp_all) .


lemma finalS_s3[simp]:"finalS (last s3_trans)" by (simp add: s3_trans_def)
lemma finalS_s4[simp]:"finalS (last s4_trans)" by (simp add: s4_trans_def)

lemma filter_s3[simp]:"(filter isIntO (butlast s3_trans)) = (butlast s3_trans)"
  unfolding s3_trans_def finalS_def final_def
  using s3_trans_simps validTransO.simps validTransO_iff_nextS 
  by (smt (verit) butlast.simps(2) filter.simps(1,2) isIntO.elims(3))

lemma filter_s4[simp]:"(filter isIntO (butlast s4_trans)) = (butlast s4_trans)"
  unfolding s4_trans_def finalS_def final_def
  using s4_trans_simps validTransO.simps validTransO_iff_nextS 
  by (smt (verit) butlast.simps(2) filter.simps(1,2) isIntO.elims(3))

lemma S_s3_trans[simp]:"Opt.S s3_trans = [s03]"
  apply (simp add: Opt.S_def filtermap_def)
  unfolding s3_trans_defs by simp

lemma S_s4_trans[simp]:"Opt.S s4_trans = [s04]"
  apply (simp add: Opt.S_def filtermap_def)
  unfolding s4_trans_defs by simp


lemma finalB_noStep[simp]:"⋀s1'. finalB (cfg1, ibT1, ibUT1) ⟹ (cfg1, ibT1, ibUT1, ls1) →N s1' ⟹ False"
  unfolding finalN_def final_def finalB_eq_finalN by auto

subsubsection "Disproof of fun1"
(*DISPROOF*)
fun common_memory::"config ⇒ config ⇒ bool" where 
"common_memory cfg1 cfg2 =
 (let h1 = (getHheap (stateOf cfg1)); 
      h2 = (getHheap (stateOf cfg2)) in
 ((∀x∈read_add. h1 x = h2 x ∧ h1 x = 0) ∧
  (getAvstore (stateOf cfg1)) = avst' ∧
  (getAvstore (stateOf cfg2)) = avst'))"
(*for proof ease*)
lemma heap_eq0[simp]: "∀x. x ≠ Suc NN ⟶ hh1' x = hh2' x ∧ hh1' x = 0 ⟹ hh2' NN = 0" 
  by (metis n_not_Suc_n)
lemma heap1_eq0[simp]:"∀x. x ≠ Suc NN ⟶ hh1' x = hh2' x ∧ hh1' x = 0 ⟹
               vs2 xx < NN ⟹
               hh2' (nat (vs2 xx)) = 0"
  using le_less_Suc_eq nat_le_eq_zle nat_less_eq_zless 
  by (metis lessI nat_int order.asym)

fun Γ_inv::"stateV ⇒ state list ⇒ stateV ⇒ state list ⇒ bool" where
"Γ_inv (cfg1,ibT1,ibUT1,ls1) sl1 (cfg2,ibT2,ibUT2,ls2) sl2 = 
(
 (pcOf cfg1 = pcOf cfg2) ∧ 

 (pcOf cfg1 < 2 ⟶ ibUT1 ≠ LNil ∧ ibUT2 ≠ LNil) ∧ 

 (pcOf cfg1 > 2 ⟶ same_var_val tt 0 cfg1 cfg2) ∧

 (pcOf cfg1 > 1 ⟶ (same_var xx cfg1 cfg2) ∧

                    (vsi_t cfg1 ⟶ pcOf cfg1 ∈ trueProg) ∧

                    (vsi_f cfg1 ⟶ pcOf cfg1 ∈ falseProg))
 ∧
 ls1 = ls2 ∧

 pcOf cfg1 ∈ PC ∧
 common_memory cfg1 cfg2
)"

declare Γ_inv.simps[simp del]
lemmas Γ_def = Γ_inv.simps
lemmas Γ_defs = Γ_def common_memory.simps PC_def aa1i_def
                trueProg_def falseProg_def same_var_val_def same_var_def

lemma Γ_implies:"Γ_inv (cfg1,ibT1, ibUT1,ls1) sl1 (cfg2,ibT2,ibUT2,ls2) sl2 ⟹ 
  pcOf cfg1 ≤ 6 ∧ pcOf cfg2 ≤ 6 ∧ 

  (pcOf cfg1 = 4 ⟶ vsi_t cfg1) ∧
  (pcOf cfg2 = 4 ⟶ vsi_t cfg2) ∧
  (pcOf cfg1 > 1 ⟶ vsi_t cfg1 ⟷ vsi_t cfg2) ∧

  (finalB (cfg1,ibT1,ibUT1) ⟷ pcOf cfg1 = 6) ∧
  (finalB (cfg2,ibT2,ibUT2) ⟷ pcOf cfg2 = 6)
"
  unfolding Γ_defs
  apply(elim conjE, intro conjI)
  subgoal using atLeastAtMost_iff by blast
  subgoal using vs_xx_cases[of cfg2] by (elim disjE, simp_all) 
  subgoal apply (rule impI,simp) using vs_xx_cases[of cfg1] by (elim disjE, simp_all)
  subgoal apply (rule impI,simp) using vs_xx_cases[of cfg2] vsi_defs by (elim disjE, simp_all)
  subgoal by (simp add: vsi_defs)
  using finalB_pcOf_iff 
   apply (metis atLeastAtMost_iff one_less_numeral_iff semiring_norm(76))
  using finalB_pcOf_iff
  by (metis atLeastAtMost_iff numeral_One numeral_less_iff semiring_norm(76))

(*istate*)
lemma istateO_s3[simp]:"istateO s30" unfolding s3_def state_def by simp
lemma istateO_s4[simp]:"istateO s40" unfolding s4_def state_def by simp

(*validFromS*)
lemma validFromS_s3[simp]:"Opt.validFromS s30 s3_trans"
  unfolding Opt.validFromS_def by simp

lemma validFromS_s4[simp]:"Opt.validFromS s40 s4_trans"
  unfolding Opt.validFromS_def by simp

(*completedFromO*)

lemma completedFromO_s3[simp]:"completedFromO s30 s3_trans"
  unfolding Opt.completedFrom_def by simp

lemma completedFromO_s4[simp]:"completedFromO s40 s4_trans"
  unfolding Opt.completedFrom_def by simp

(*Act eq*)
lemma Act_eq[simp]:"Opt.A s3_trans = Opt.A s4_trans"
  apply (simp add: Opt.A_def filtermap_def)
  unfolding s3_trans_defs s4_trans_defs
  by simp

lemma aa2_neq:"aa2vs3 ≠ aa2vs4"
  unfolding vs_def readsm_def avst_defs h_def array_loc_def  
  by (simp add: avst_defs array_base_def split: if_splits)

lemma aa1_neq:"aa2vs3 ≠ aa1i"
  apply(rule notI)
  unfolding vs_def readsm_def avst_defs h_def array_loc_def  
  by (simp add: avst_defs array_base_def split: if_splits)

lemma aa1_neq2:"aa2vs4 ≠ aa1i"
  apply(rule notI)
  unfolding vs_def readsm_def avst_defs h_def array_loc_def  
  by (simp add: avst_defs array_base_def split: if_splits)

(*Obs neq*)
lemma Obs_neq[simp]:"Opt.O s3_trans ≠ Opt.O s4_trans"
  apply (simp add: Opt.O_def filtermap_def)
  unfolding s3_trans_def s4_trans_def apply clarsimp
  unfolding s3_trans_defs s4_trans_defs apply simp
  using aa2_neq aa1_neq aa1_neq2 by blast
   
  

lemma Γ_init[simp]:"⋀s1 s2. istateV s1 ⟹ corrState s1 s30 ⟹ istateV s2 ⟹ corrState s2 s40 ⟹ Γ_inv s1 [s03] s2 [s04]"
  subgoal for s1 s2 apply(cases s1, cases s2, simp) 
    unfolding s3_def s4_def s_def h_def by (auto simp: Γ_defs) .

lemma val_neq_1:"nat (hh2' (nat (vs2 xx)) * 512) ≠ 1" 
  by (smt (z3) nat_less_eq_zless nat_one_as_int)


(*unwindSD*)
lemma unwindSD[simp]:"Rel_Sec.unwindSDCond validTransV istateV isSecV getSecV isIntV getIntV Γ_inv"
unfolding unwindSDCond_def
proof(intro allI, rule impI, elim conjE,intro conjI)
      fix ss1 ss2 sl1 sl2
      assume "reachV ss1" "reachV ss2" 
       and Γ:"Γ_inv ss1 sl1 ss2 sl2"

      obtain cfg1 ibT1 ibUT1 ls1 where ss1: "ss1 = (cfg1, ibT1, ibUT1, ls1)"
        by (cases ss1, auto) 
      obtain cfg2 ibT2 ibUT2 ls2 where ss2: "ss2 = (cfg2, ibT2, ibUT2, ls2)"
        by (cases ss2, auto) 
      note ss = ss1 ss2 

      obtain pc1 vs1 avst1 h1 p1 where 
        cfg1: "cfg1 = Config pc1 (State (Vstore vs1) avst1 h1 p1)"
        by (cases cfg1) (metis state.collapse vstore.collapse)
      obtain pc2 vs2 avst2 h2 p2 where 
        cfg2: "cfg2 = Config pc2 (State (Vstore vs2) avst2 h2 p2)"
        by (cases cfg2) (metis state.collapse vstore.collapse)
      note cfg = cfg1 cfg2

      obtain hh1 where h1: "h1 = Heap hh1" by(cases h1, auto)
      obtain hh2 where h2: "h2 = Heap hh2" by(cases h2, auto)
      note hh = h1 h2

      show "isIntV ss1 = isIntV ss2" 
        using  Γ unfolding isIntV.simps ss
        unfolding Γ_defs
        using vs_xx_cases[of cfg1]
        apply (elim disjE) by simp_all

      then have finalB:"finalB (cfg1, ibT1, ibUT1) = finalB (cfg2, ibT2, ibUT2)"
        unfolding isIntV.simps finalN_iff_finalB ss by blast

      show "¬ isIntV ss1 ⟶ move1 Γ_inv ss1 sl1 ss2 sl2 ∧ move2 Γ_inv ss1 sl1 ss2 sl2"
        apply(unfold ss, auto)
        subgoal unfolding move1_def finalB_defs by auto
        subgoal unfolding finalB 
                unfolding move2_def finalB_defs by auto . 

      show "isIntV ss1 ⟶ getActV ss1 = getActV ss2 ⟶ getObsV ss1 = getObsV ss2 ∧ move12 Γ_inv ss1 sl1 ss2 sl2"
      proof(unfold ss isIntV.simps finalN_iff_finalB, intro impI, rule conjI)
        assume final:"¬ finalB (cfg1, ibT1, ibUT1)" and
              getAct:"getActV (cfg1, ibT1, ibUT1, ls1) = getActV (cfg2, ibT2, ibUT2, ls2)"
        have not6:"pc1 = 6 ⟹ False"
          using cfg final Γ
          by simp

        show "getObsV (cfg1, ibT1, ibUT1, ls1) = getObsV (cfg2, ibT2, ibUT2, ls2)" 
          using Γ getAct unfolding ss 
          apply-apply(frule Γ_implies, elim conjE)
          using cases_5[of "pcOf cfg1"] cases_5[of "pcOf cfg2"] 
          by(elim disjE, simp_all add: Γ_defs final)

        show "move12 Γ_inv (cfg1, ibT1, ibUT1, ls1) sl1 (cfg2, ibT2, ibUT2, ls2) sl2" 
        unfolding move12_def validEtransO.simps 
      proof(intro allI, rule impI, elim conjE,unfold validTransV.simps isSecV_iff getSecV.simps fst_conv)
          fix ss1' ss2' sl1' sl2'

          assume v: "(cfg1, ibT1, ibUT1, ls1) →N ss1'" "(cfg2, ibT2, ibUT2, ls2) →N ss2'" and
               sec: "pcOf cfg1 ≠ 0 ∧ sl1 = sl1' ∨ pcOf cfg1 = 0 ∧ sl1 = stateOf cfg1 # sl1'"
                    "pcOf cfg2 ≠ 0 ∧ sl2 = sl2' ∨ pcOf cfg2 = 0 ∧ sl2 = stateOf cfg2 # sl2'"
          
          obtain cfg1' ibT1' ibUT1' ls1' where ss1': "ss1' = (cfg1', ibT1', ibUT1', ls1')"
            by (cases ss1', auto) 
          obtain cfg2' ibT2' ibUT2' ls2' where ss2': "ss2' = (cfg2', ibT2', ibUT2', ls2')"
            by (cases ss2', auto)

          obtain pc1' vs1' avst1' h1' p1' where 
            cfg1': "cfg1' = Config pc1' (State (Vstore vs1') avst1' h1' p1')"
            by (cases cfg1') (metis state.collapse vstore.collapse)
          obtain pc2' vs2' avst2' h2' p2' where 
            cfg2': "cfg2' = Config pc2' (State (Vstore vs2') avst2' h2' p2')"
            by (cases cfg2') (metis state.collapse vstore.collapse)
          note cfg = cfg cfg1' cfg2'

          obtain hh1' where h1': "h1' = Heap hh1'" by(cases h1', auto)
          obtain hh2' where h2': "h2' = Heap hh2'" by(cases h2', auto)
          note hh = hh h1' h2'

          note ss = ss1 ss2 ss1' ss2'
          have v':"(cfg1, ibT1, ibUT1) →B (cfg1', ibT1', ibUT1')" using v unfolding ss by simp
          then have v1:"nextB (cfg1, ibT1, ibUT1) = (cfg1', ibT1', ibUT1')" using stepB_nextB by auto

          have v'':"(cfg2, ibT2, ibUT2) →B (cfg2', ibT2', ibUT2')" using v unfolding ss by simp
          then have v2:"nextB (cfg2, ibT2, ibUT2) = (cfg2', ibT2', ibUT2')" using stepB_nextB by auto
          note valid = v' v1 v'' v2 

          have ls1':"ls1' = ls1 ∪ readLocs cfg1" using v unfolding ss by simp
          have ls2':"ls2' = ls2 ∪ readLocs cfg2" using v unfolding ss by simp
          note ls = ls1' ls2'


          note Γ_simps = cfg ls vsi_defs hh array_loc_def 
                          array_base_def state_def PC_def

          show "Γ_inv ss1' sl1' ss2' sl2'" 
            using Γ valid getAct
            unfolding ss apply-apply(frule Γ_implies)
            using cases_5[of "pc1"] not6 apply(elim disjE, simp_all)
            unfolding Γ_def ss
            prefer 4 subgoal using vs_xx_cases[of cfg1]
            by (elim disjE, unfold Γ_defs, auto simp add: Γ_simps) 
            subgoal by (unfold Γ_defs, auto simp add: Γ_simps) 
            subgoal by (unfold Γ_defs, auto simp add: Γ_simps) 
            subgoal by (unfold Γ_defs, auto simp add: Γ_simps)
            subgoal using val_neq_1 apply (unfold Γ_defs, auto simp add: Γ_simps) 
              using val_neq_1 by (metis NN_suc add_left_cancel nat_int) 
            subgoal by (unfold Γ_defs, auto simp add: Γ_simps) 
            subgoal by (unfold Γ_defs, auto simp add: Γ_simps) .
        qed
      qed
    qed


theorem "¬rsecure"
  apply(rule unwindSD_rsecure[of s30 s3_trans s40 s4_trans Γ_inv]) 
  by simp_all

end