(*
 * Copyright 2014, General Dynamics C4 Systems
 *
 * This software may be distributed and modified according to the terms of
 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
 * See "LICENSE_GPLv2.txt" for details.
 *
 * @TAG(GD_GPL)
 *)

(* Wellformedness of caps, kernel objects, states on the C level
*)

theory Wellformed_C
imports
  "../../lib/CTranslationNICTA"
  CLevityCatch
  "../../spec/cspec/Substitute"
begin

context begin interpretation Arch . (*FIXME: arch_split*)

abbreviation
  cte_Ptr :: "word32 \<Rightarrow> cte_C ptr" where "cte_Ptr == Ptr"
abbreviation
  mdb_Ptr :: "word32 \<Rightarrow> mdb_node_C ptr" where "mdb_Ptr == Ptr"
abbreviation
  cap_Ptr :: "word32 \<Rightarrow> cap_C ptr" where "cap_Ptr == Ptr"
abbreviation
  tcb_Ptr :: "word32 \<Rightarrow> tcb_C ptr" where "tcb_Ptr == Ptr"
abbreviation
  ep_Ptr :: "word32 \<Rightarrow> endpoint_C ptr" where "ep_Ptr == Ptr"
abbreviation
  ntfn_Ptr :: "word32 \<Rightarrow> notification_C ptr" where "ntfn_Ptr == Ptr"
abbreviation
  ap_Ptr :: "word32 \<Rightarrow> asid_pool_C ptr" where "ap_Ptr == Ptr"
abbreviation
  pte_Ptr :: "word32 \<Rightarrow> pte_C ptr" where "pte_Ptr == Ptr"
abbreviation
  pde_Ptr :: "word32 \<Rightarrow> pde_C ptr" where "pde_Ptr == Ptr"

lemma halt_spec:
  "Gamma \<turnstile> {} Call halt_'proc {}"
  apply (rule hoare_complete)
  apply (simp add: HoarePartialDef.valid_def)
  done

definition
  isUntypedCap_C :: "cap_CL \<Rightarrow> bool" where
  "isUntypedCap_C c \<equiv>
   case c of
   Cap_untyped_cap q \<Rightarrow> True
   | _ \<Rightarrow> False"

definition
  isNullCap_C :: "cap_CL \<Rightarrow> bool" where
  "isNullCap_C c \<equiv>
  case c of
   Cap_null_cap \<Rightarrow> True
   | _ \<Rightarrow> False"

definition
  isEndpointCap_C :: "cap_CL \<Rightarrow> bool" where
 "isEndpointCap_C v \<equiv> case v of
  Cap_endpoint_cap ec \<Rightarrow> True
  | _ \<Rightarrow> False"

definition
  isCNodeCap_C :: "cap_CL \<Rightarrow> bool" where
  "isCNodeCap_C c \<equiv> case c of
   Cap_cnode_cap a \<Rightarrow> True
   | _ \<Rightarrow> False"

definition
  isThreadCap_C :: "cap_CL \<Rightarrow> bool" where
  "isThreadCap_C c \<equiv> case c of
   Cap_thread_cap a \<Rightarrow> True
   | _ \<Rightarrow> False"

definition
  isIRQControlCap_C :: "cap_CL \<Rightarrow> bool" where
  "isIRQControlCap_C c \<equiv> case c of
   Cap_irq_control_cap \<Rightarrow> True
   | _ \<Rightarrow> False"

definition
  isIRQHandlerCap_C :: "cap_CL \<Rightarrow> bool" where
  "isIRQHandlerCap_C c \<equiv> case c of
   Cap_irq_handler_cap a \<Rightarrow> True
   | _ \<Rightarrow> False"

definition
  isNotificationCap_C :: "cap_CL \<Rightarrow> bool" where
 "isNotificationCap_C v \<equiv> case v of
  Cap_notification_cap aec \<Rightarrow> True
  | _ \<Rightarrow> False"

definition
  ep_at_C' :: "word32 \<Rightarrow> heap_raw_state \<Rightarrow> bool"
where
  "ep_at_C' p h \<equiv> Ptr p \<in> dom (clift h :: endpoint_C typ_heap)" -- "endpoint_lift is total"

definition
  ntfn_at_C' :: "word32 \<Rightarrow> heap_raw_state \<Rightarrow> bool"
  where -- "notification_lift is total"
  "ntfn_at_C' p h \<equiv> Ptr p \<in> dom (clift h :: notification_C typ_heap)"

definition
  tcb_at_C' :: "word32 \<Rightarrow> heap_raw_state \<Rightarrow> bool"
  where
  "tcb_at_C' p h \<equiv> Ptr p \<in> dom (clift h :: tcb_C typ_heap)"

definition
  cte_at_C' :: "word32 \<Rightarrow> heap_raw_state \<Rightarrow> bool"
  where
  "cte_at_C' p h \<equiv> Ptr p \<in> dom (clift h :: cte_C typ_heap)"

definition
  ctcb_offset :: word32
  where
  "ctcb_offset \<equiv> 2 ^ 8"

definition
  ctcb_ptr_to_tcb_ptr :: "tcb_C ptr \<Rightarrow> word32"
  where
  "ctcb_ptr_to_tcb_ptr p \<equiv> ptr_val p - ctcb_offset"

definition
  tcb_ptr_to_ctcb_ptr :: "word32 \<Rightarrow> tcb_C ptr"
  where
  "tcb_ptr_to_ctcb_ptr p \<equiv> Ptr (p + ctcb_offset)"

primrec
  tcb_queue_relation :: "(tcb_C \<Rightarrow> tcb_C ptr) \<Rightarrow> (tcb_C \<Rightarrow> tcb_C ptr) \<Rightarrow>
                         (tcb_C ptr \<Rightarrow> tcb_C option) \<Rightarrow> word32 list \<Rightarrow>
                         tcb_C ptr \<Rightarrow> tcb_C ptr \<Rightarrow> bool"
where
  "tcb_queue_relation getNext getPrev hp [] qprev qhead = (qhead = NULL)"
| "tcb_queue_relation getNext getPrev hp (x#xs) qprev qhead =
     (qhead = tcb_ptr_to_ctcb_ptr x \<and>
      (\<exists>tcb. (hp qhead = Some tcb \<and> getPrev tcb = qprev \<and> tcb_queue_relation getNext getPrev hp xs qhead (getNext tcb))))"

abbreviation
  "ep_queue_relation \<equiv> tcb_queue_relation tcbEPNext_C tcbEPPrev_C"

abbreviation
  "sched_queue_relation \<equiv> tcb_queue_relation tcbSchedNext_C tcbSchedPrev_C"

definition
wordSizeCase :: "'a \<Rightarrow> 'a \<Rightarrow> 'a" where
"wordSizeCase a b \<equiv> (if bitSize (undefined::word32) = 32
        then  a
        else if bitSize (undefined::word32) = 64
        then  b
        else  error []
        )"

primrec
  capBits_C :: "cap_CL \<Rightarrow> nat"
where
  "capBits_C Cap_null_cap = 0"
| "capBits_C (Cap_untyped_cap uc) = unat (capBlockSize_CL uc)"
| "capBits_C (Cap_endpoint_cap ec) = wordSizeCase 4 5"
| "capBits_C (Cap_notification_cap aec) = wordSizeCase 4 5"
| "capBits_C (Cap_cnode_cap cnc) =  wordSizeCase 4 5"
| "capBits_C (Cap_thread_cap tc) = 10"
| "capBits_C (Cap_zombie_cap zc) =  (wordSizeCase 4 5)"

definition
capUntypedPtr_C :: "cap_CL \<Rightarrow> word32" where
  "capUntypedPtr_C cap \<equiv> case cap of
 (Cap_untyped_cap uc) \<Rightarrow> (capBlockSize_CL uc)
 |  Cap_endpoint_cap ep \<Rightarrow> (capEPPtr_CL ep)
 |  Cap_notification_cap ntfn \<Rightarrow> (capNtfnPtr_CL ntfn)
 |  Cap_cnode_cap ccap \<Rightarrow> (capCNodePtr_CL ccap)
 |  Cap_reply_cap rc \<Rightarrow>  (cap_reply_cap_CL.capTCBPtr_CL rc)
 |  Cap_thread_cap tc \<Rightarrow>  (cap_thread_cap_CL.capTCBPtr_CL tc)
 |  Cap_small_frame_cap sfc \<Rightarrow>  (cap_small_frame_cap_CL.capFBasePtr_CL sfc)
 |  Cap_frame_cap fc \<Rightarrow>  (cap_frame_cap_CL.capFBasePtr_CL fc)
 |  Cap_page_table_cap ptc \<Rightarrow>  (capPTBasePtr_CL ptc)
 |  Cap_page_directory_cap pdc \<Rightarrow>  (capPDBasePtr_CL pdc)
 | _ \<Rightarrow> error []"

definition ZombieTCB_C_def:
"ZombieTCB_C \<equiv> bit 5"

definition
  isZombieTCB_C :: "word32 \<Rightarrow> bool" where
 "isZombieTCB_C v \<equiv> v = ZombieTCB_C"

definition
vmrights_to_H :: "word32 \<Rightarrow> vmrights" where
"vmrights_to_H c \<equiv>
  if c = scast Kernel_C.VMNoAccess then VMNoAccess
  else if c = scast Kernel_C.VMKernelOnly then VMKernelOnly
  else if c = scast Kernel_C.VMReadOnly then VMReadOnly
  else VMReadWrite"

(* Force clarity over name collisions *)
abbreviation
  ARMSmallPage :: "vmpage_size" where
 "ARMSmallPage == ARM.ARMSmallPage"
abbreviation
  ARMLargePage :: "vmpage_size" where
 "ARMLargePage == ARM.ARMLargePage"
abbreviation
  ARMSection :: "vmpage_size" where
 "ARMSection == ARM.ARMSection"
abbreviation
  ARMSuperSection :: "vmpage_size" where
 "ARMSuperSection == ARM.ARMSuperSection"

-- "ARMSmallFrame is treated in a separate cap in C,
    so needs special treatment in ccap_relation"
definition
framesize_to_H:: "word32 \<Rightarrow> vmpage_size" where
"framesize_to_H c \<equiv>
  if c = scast Kernel_C.ARMLargePage then ARMLargePage
  else if c = scast Kernel_C.ARMSection then ARMSection
  else ARMSuperSection"

-- "Use this for results of generic_frame_cap_get_capFSize"
definition
gen_framesize_to_H:: "word32 \<Rightarrow> vmpage_size" where
"gen_framesize_to_H c \<equiv>
  if c = scast Kernel_C.ARMSmallPage then ARMSmallPage
  else if c = scast Kernel_C.ARMLargePage then ARMLargePage
  else if c = scast Kernel_C.ARMSection then ARMSection
  else ARMSuperSection"

end

record cte_CL =
  cap_CL :: cap_CL
  cteMDBNode_CL :: mdb_node_CL

context begin interpretation Arch . (*FIXME: arch_split*)

definition
  cte_lift :: "cte_C \<rightharpoonup> cte_CL"
  where
  "cte_lift c \<equiv> case cap_lift (cte_C.cap_C c) of
                     None \<Rightarrow> None
                   | Some cap \<Rightarrow> Some \<lparr> cap_CL = cap,
                                       cteMDBNode_CL = mdb_node_lift (cteMDBNode_C c) \<rparr>"

lemma to_bool_false [simp]: "\<not> to_bool false"
  by (simp add: to_bool_def false_def)

(* this is slightly weird, but the bitfield generator
   masks everything with the expected bit length.
   So we do that here too. *)
definition
  to_bool_bf :: "'a::len word \<Rightarrow> bool" where
  "to_bool_bf w \<equiv> (w && mask 1) = 1"

lemma to_bool_bf_mask1 [simp]:
  "to_bool_bf (mask (Suc 0))"
  by (simp add: mask_def to_bool_bf_def)

lemma to_bool_bf_0 [simp]: "\<not>to_bool_bf 0"
  by (simp add: to_bool_bf_def)

lemma to_bool_bf_1 [simp]: "to_bool_bf 1"
  by (simp add: to_bool_bf_def mask_def)

lemma to_bool_bf_false [simp]:
  "\<not>to_bool_bf false"
  by (simp add: false_def)

lemma to_bool_bf_true [simp]:
  "to_bool_bf true"
  by (simp add: true_def)

lemma to_bool_to_bool_bf:
  "w = false \<or> w = true \<Longrightarrow> to_bool_bf w = to_bool w"
  by (auto simp: false_def true_def to_bool_def to_bool_bf_def mask_def)

lemma to_bool_bf_mask_1 [simp]:
  "to_bool_bf (w && mask (Suc 0)) = to_bool_bf w"
  by (simp add: to_bool_bf_def)

lemma to_bool_bf_and [simp]:
  "to_bool_bf (a && b) = (to_bool_bf a \<and> to_bool_bf (b::word32))"
  apply (clarsimp simp: to_bool_bf_def)
  apply (rule iffI)
   apply (subst (asm) bang_eq)
   apply (simp add: word_size)
   apply (rule conjI)
    apply (rule word_eqI)
    apply (auto simp add: word_size)[1]
   apply (rule word_eqI)
   apply (auto simp add: word_size)[1]
  apply clarsimp
  apply (rule word_eqI)
  apply (subst (asm) bang_eq)+
  apply (auto simp add: word_size)[1]
  done

lemma to_bool_bf_to_bool_mask:
  "w && mask (Suc 0) = w \<Longrightarrow> to_bool_bf w = to_bool (w::word32)"
  apply (auto simp add: to_bool_bf_def to_bool_def mask_eq_iff_w2p word_size)
  apply (auto simp add: mask_def dest: word_less_cases)
  done

definition
  mdb_node_to_H :: "mdb_node_CL \<Rightarrow> mdbnode"
  where
  "mdb_node_to_H n \<equiv> MDB (mdbNext_CL n)
                         (mdbPrev_CL n)
                         (to_bool (mdbRevocable_CL n))
                         (to_bool (mdbFirstBadged_CL n))"

definition
cap_to_H :: "cap_CL \<Rightarrow> capability"
where
"cap_to_H c \<equiv>  case c of
 Cap_null_cap \<Rightarrow> NullCap
 | Cap_zombie_cap zc \<Rightarrow>  (if isZombieTCB_C(capZombieType_CL zc)
                         then
                               (Zombie ((capZombieID_CL zc) && ~~(mask(5)))
                                       (ZombieTCB)
                                       (unat ((capZombieID_CL zc) && mask(5))))
                         else let radix = unat (capZombieType_CL zc) in
                               (Zombie ((capZombieID_CL zc) && ~~(mask (radix+1)))
                                       (ZombieCNode radix)
                                       (unat ((capZombieID_CL zc) && mask(radix+1)))))
 | Cap_cnode_cap ccap \<Rightarrow>
    CNodeCap (capCNodePtr_CL ccap) (unat (capCNodeRadix_CL ccap))
             (capCNodeGuard_CL ccap)
             (unat (capCNodeGuardSize_CL ccap))
 | Cap_untyped_cap uc \<Rightarrow> UntypedCap (to_bool(capIsDevice_CL uc)) (capPtr_CL uc) (unat (capBlockSize_CL uc)) (unat (capFreeIndex_CL uc << 4))
 | Cap_endpoint_cap ec \<Rightarrow>
    EndpointCap (capEPPtr_CL ec) (capEPBadge_CL ec) (to_bool(capCanSend_CL ec)) (to_bool(capCanReceive_CL ec))
                (to_bool(capCanGrant_CL ec))
 | Cap_notification_cap ntfn \<Rightarrow>
    NotificationCap (capNtfnPtr_CL ntfn)(capNtfnBadge_CL ntfn)(to_bool(capNtfnCanSend_CL ntfn))
                     (to_bool(capNtfnCanReceive_CL ntfn))
 | Cap_reply_cap rc \<Rightarrow> ReplyCap (ctcb_ptr_to_tcb_ptr (Ptr (cap_reply_cap_CL.capTCBPtr_CL rc))) (to_bool (capReplyMaster_CL rc))
 | Cap_thread_cap tc \<Rightarrow>  ThreadCap(ctcb_ptr_to_tcb_ptr (Ptr (cap_thread_cap_CL.capTCBPtr_CL tc)))
 | Cap_irq_handler_cap ihc \<Rightarrow> IRQHandlerCap (ucast(capIRQ_CL ihc))
 | Cap_irq_control_cap \<Rightarrow> IRQControlCap
 | Cap_asid_control_cap \<Rightarrow> ArchObjectCap ASIDControlCap
 | Cap_asid_pool_cap apc \<Rightarrow> ArchObjectCap (ASIDPoolCap (capASIDPool_CL apc) (capASIDBase_CL apc))
 | Cap_small_frame_cap sfc \<Rightarrow> ArchObjectCap (PageCap (to_bool(cap_small_frame_cap_CL.capFIsDevice_CL sfc)) (cap_small_frame_cap_CL.capFBasePtr_CL sfc)
                                            (vmrights_to_H(cap_small_frame_cap_CL.capFVMRights_CL sfc)) (ARMSmallPage)
                                            (if cap_small_frame_cap_CL.capFMappedASIDHigh_CL sfc = 0
                                                \<and> cap_small_frame_cap_CL.capFMappedASIDLow_CL sfc = 0
                                             then None else
                                             Some( (((cap_small_frame_cap_CL.capFMappedASIDHigh_CL sfc)<<asidLowBits) +
                                             (cap_small_frame_cap_CL.capFMappedASIDLow_CL sfc)) ,
                                             cap_small_frame_cap_CL.capFMappedAddress_CL sfc)))
 | Cap_frame_cap fc \<Rightarrow> ArchObjectCap (PageCap (to_bool(capFIsDevice_CL fc)) (capFBasePtr_CL fc)
                                            (vmrights_to_H(capFVMRights_CL fc)) (framesize_to_H(capFSize_CL fc))
                                            (if capFMappedASIDHigh_CL fc = 0
                                               \<and> capFMappedASIDLow_CL fc = 0
                                             then None else
                                             Some( (((capFMappedASIDHigh_CL fc)<<asidLowBits) +
                                             (capFMappedASIDLow_CL fc)),capFMappedAddress_CL fc)))
 | Cap_page_table_cap ptc \<Rightarrow> ArchObjectCap (PageTableCap (capPTBasePtr_CL ptc)
                                          (if to_bool (capPTIsMapped_CL ptc)
                                           then Some( ((capPTMappedASID_CL ptc)),(capPTMappedAddress_CL ptc))
                                           else None))
 | Cap_page_directory_cap pdf \<Rightarrow> ArchObjectCap (PageDirectoryCap (capPDBasePtr_CL pdf)
                                          (if to_bool (capPDIsMapped_CL pdf)
                                           then Some (capPDMappedASID_CL pdf)
                                           else None))
 | Cap_domain_cap \<Rightarrow> DomainCap"

lemmas cap_to_H_simps = cap_to_H_def[split_simps cap_CL.split]

definition
  cte_to_H :: "cte_CL \<Rightarrow> cte"
  where
  "cte_to_H cte \<equiv> CTE (cap_to_H (cap_CL cte)) (mdb_node_to_H (cteMDBNode_CL cte))"

definition
cl_valid_cap :: "cap_CL \<Rightarrow> bool"
where
"cl_valid_cap c \<equiv>
   case c of
     Cap_frame_cap fc \<Rightarrow> ((capFSize_CL fc) \<noteq>  scast Kernel_C.ARMSmallPage)
     | Cap_irq_handler_cap fc \<Rightarrow> ((capIRQ_CL fc) && mask 10 = capIRQ_CL fc)
     | x \<Rightarrow> True"

definition
c_valid_cap :: "cap_C \<Rightarrow> bool"
where
"c_valid_cap c \<equiv> case_option True cl_valid_cap (cap_lift c)"

definition
cl_valid_cte :: "cte_CL \<Rightarrow> bool"
where
"cl_valid_cte c \<equiv>  cl_valid_cap (cap_CL c)"

definition
c_valid_cte :: "cte_C \<Rightarrow> bool"
where
"c_valid_cte c \<equiv>  c_valid_cap (cte_C.cap_C c)"

lemma  c_valid_cap_simps [simp]:
  "cap_get_tag c = scast cap_small_frame_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_thread_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_notification_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_endpoint_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_cnode_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_page_directory_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_asid_control_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_irq_control_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_page_table_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_asid_pool_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_untyped_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_zombie_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_reply_cap \<Longrightarrow> c_valid_cap c"
  "cap_get_tag c = scast cap_null_cap \<Longrightarrow> c_valid_cap c"
  unfolding c_valid_cap_def  cap_lift_def cap_tag_defs
  by (simp add: cl_valid_cap_def)+

lemma ptr_val_tcb_ptr_mask2:
  "is_aligned thread 9
      \<Longrightarrow> ptr_val (tcb_ptr_to_ctcb_ptr thread) && (~~ mask 9)
                  = thread"
  apply (clarsimp simp: tcb_ptr_to_ctcb_ptr_def projectKOs)
  apply (simp add: is_aligned_add_helper ctcb_offset_def objBits_simps)
  done

lemma maxDom_to_H:
  "ucast maxDom = maxDomain"
  by (simp add: maxDomain_def maxDom_def numDomains_def)

lemma maxPrio_to_H:
  "ucast seL4_MaxPrio = maxPriority"
  by (simp add: maxPriority_def seL4_MaxPrio_def numPriorities_def)

abbreviation(input)
  NotificationObject :: sword32
where
  "NotificationObject == seL4_NotificationObject"

abbreviation(input)
  CapTableObject :: sword32
where
  "CapTableObject == seL4_CapTableObject"

abbreviation(input)
  EndpointObject :: sword32
where
  "EndpointObject == seL4_EndpointObject"

abbreviation(input)
  LargePageObject :: sword32
where
  "LargePageObject == seL4_ARM_LargePageObject"

abbreviation(input)
  PageDirectoryObject :: sword32
where
  "PageDirectoryObject == seL4_ARM_PageDirectoryObject"

abbreviation(input)
  PageTableObject :: sword32
where
  "PageTableObject == seL4_ARM_PageTableObject"

abbreviation(input)
  SectionObject :: sword32
where
  "SectionObject == seL4_ARM_SectionObject"

abbreviation(input)
  SmallPageObject :: sword32
where
  "SmallPageObject == seL4_ARM_SmallPageObject"

abbreviation(input)
  SuperSectionObject :: sword32
where
  "SuperSectionObject == seL4_ARM_SuperSectionObject"

abbreviation(input)
  TCBObject :: sword32
where
  "TCBObject == seL4_TCBObject"

abbreviation(input)
  UntypedObject :: sword32
where
  "UntypedObject == seL4_UntypedObject"

abbreviation(input)
  maxPrio :: sword32
where
  "maxPrio == seL4_MaxPrio"

abbreviation(input)
  minPrio :: sword32
where
  "minPrio == seL4_MinPrio"

abbreviation(input)
  nAPIObjects :: sword32
where
  "nAPIObjects == seL4_NonArchObjectTypeCount"

abbreviation(input)
  nObjects :: sword32
where
  "nObjects == seL4_ObjectTypeCount"

abbreviation(input)
  prioInvalid :: sword32
where
  "prioInvalid == seL4_InvalidPrio"

end

end


(*  Title:      HOL/Auth/n_g2kAbsAfter_lemma_inv__20_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_g2kAbsAfter Protocol Case Study*}

theory n_g2kAbsAfter_lemma_inv__20_on_rules imports n_g2kAbsAfter_lemma_on_inv__20
begin
section{*All lemmas on causal relation between inv__20*}
lemma lemma_inv__20_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(f=inv__20  )"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> d. d\<le>N\<and>r=n_n_Store_i1  d)\<or>
    (\<exists> d. d\<le>N\<and>r=n_n_AStore_i1  d)\<or>
    (r=n_n_SendReqS_j1  )\<or>
    (r=n_n_SendReqEI_i1  )\<or>
    (r=n_n_SendReqES_i1  )\<or>
    (r=n_n_RecvReq_i1  )\<or>
    (r=n_n_SendInvE_i1  )\<or>
    (r=n_n_SendInvS_i1  )\<or>
    (r=n_n_SendInvAck_i1  )\<or>
    (r=n_n_RecvInvAck_i1  )\<or>
    (r=n_n_SendGntS_i1  )\<or>
    (r=n_n_SendGntE_i1  )\<or>
    (r=n_n_RecvGntS_i1  )\<or>
    (r=n_n_RecvGntE_i1  )\<or>
    (r=n_n_ASendReqIS_j1  )\<or>
    (r=n_n_ASendReqSE_j1  )\<or>
    (r=n_n_ASendReqEI_i1  )\<or>
    (r=n_n_ASendReqES_i1  )\<or>
    (r=n_n_SendReqEE_i1  )\<or>
    (r=n_n_ARecvReq_i1  )\<or>
    (r=n_n_ASendInvE_i1  )\<or>
    (r=n_n_ASendInvS_i1  )\<or>
    (r=n_n_ASendInvAck_i1  )\<or>
    (r=n_n_ARecvInvAck_i1  )\<or>
    (r=n_n_ASendGntS_i1  )\<or>
    (r=n_n_ASendGntE_i1  )\<or>
    (r=n_n_ARecvGntS_i1  )\<or>
    (r=n_n_ARecvGntE_i1  )"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> d. d\<le>N\<and>r=n_n_Store_i1  d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_Store_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(\<exists> d. d\<le>N\<and>r=n_n_AStore_i1  d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_AStore_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqS_j1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqS_j1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqEI_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqEI_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqES_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqES_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_RecvReq_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvReq_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendInvE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendInvE_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendInvS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendInvS_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendInvAck_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_RecvInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvInvAck_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendGntS_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendGntE_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_RecvGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvGntS_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_RecvGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvGntE_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqIS_j1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqIS_j1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqSE_j1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqSE_j1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqEI_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqEI_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqES_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqES_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqEE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqEE_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvReq_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvReq_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendInvE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendInvE_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendInvS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendInvS_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendInvAck_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvInvAck_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendGntS_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ASendGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendGntE_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvGntS_i1Vsinv__20) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvGntE_i1Vsinv__20) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


(*  Title:      HOL/Auth/n_germanSymIndex_lemma_inv__21_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_germanSymIndex Protocol Case Study*}

theory n_germanSymIndex_lemma_inv__21_on_rules imports n_germanSymIndex_lemma_on_inv__21
begin
section{*All lemmas on causal relation between inv__21*}
lemma lemma_inv__21_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__21  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqE__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqE__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_StoreVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqSVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqE__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqE__part__0Vsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqE__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqE__part__1Vsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqSVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqEVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__0Vsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__1Vsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvAckVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvInvAckVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntSVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntEVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntSVsinv__21) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntEVsinv__21) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


(*
 * Copyright 2016, NICTA
 *
 * This software may be distributed and modified according to the terms of
 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
 * See "LICENSE_GPLv2.txt" for details.
 *
 * @TAG(NICTA_GPL)
 *)

theory OstoreInvS
imports
  "BilbyFsConsts.BilbyFs_Shallow_Desugar_Tuples"
  "BilbyFsConsts.BilbyFs_ShallowConsts_Desugar_Tuples"
  "../spec/OstoreS"
  "../spec/SerialS"
  "../spec/UbiS"
  "../adt/BufferT"
  "../adt/RbtT"
  "HOL-Library.Sublist"
begin

definition
  \<alpha>_index :: "IndexState\<^sub>T \<Rightarrow> (ObjId \<rightharpoonup> ObjAddr\<^sub>T)"
where
 "\<alpha>_index index_st \<equiv> \<alpha>rbt (addrs\<^sub>f index_st)"

consts \<alpha>_fsm_gim :: "(ObjId,  GimNode\<^sub>T) Rbt \<Rightarrow> (ObjId \<rightharpoonup> GimNode\<^sub>T)"

definition
  nopad :: "U8 list \<Rightarrow> U8 list"
where
 "nopad xs \<equiv>
    dropWhile ((=) bilbyFsPadByte) xs"

lemma pTrans_termination[simp]:
 "is_valid_ObjHeader obj (d # data) \<Longrightarrow>
    Suc (length data) - unat (Obj.len\<^sub>f obj) < Suc (length data)"
 "is_valid_ObjHeader obj data \<Longrightarrow>
    (length data) - unat (Obj.len\<^sub>f obj) < (length data)"
  unfolding bilbyFsObjHeaderSize_def
  by (drule is_valid_ObjHeader_len_facts,
         clarsimp simp add: bilbyFsObjHeaderSize_def, unat_arith)+

type_synonym Trans = "Obj\<^sub>T list"
fun
  pTrans :: "U8 list \<Rightarrow> (U8 list \<times> Trans)"
where
 "pTrans [] = ([],[])"
|pTrans_Cons: "pTrans data =
    (let obj = pObj data 0
    \<comment> \<open> We stop at the first obviously invalid object. \<close>
     in if \<not>is_valid_ObjHeader obj data then
       (drop (max (unat bilbyFsObjHeaderSize) (unat (Obj.len\<^sub>f obj))) data, [])
     else if Obj.trans\<^sub>f obj = bilbyFsTransIn then
       (\<lambda>(d,os). (d, (obj#os))) (pTrans (drop (unat (Obj.len\<^sub>f obj)) data))
     else
       (drop (unat (Obj.len\<^sub>f obj)) data, [obj])
)"

lemma drop_0_eq[simp]:
  "\<exists>n. xs = drop n xs"
 by (rule_tac x=0 in exI, simp)

lemma pTrans_data_is_substring:
  "(\<exists>n. prod.fst (pTrans data) = drop n data)"
  by (induct data rule: pTrans.induct) (fastforce simp: Let_def prod.case_eq_if)+

lemma pTrans_length_helper:
assumes len: "is_valid_ObjHeader (pObj (d # data) 0) (d # data)"
shows
  "length (prod.fst (pTrans (drop (unat (Obj.len\<^sub>f (pObj (d # data) 0))) (d # data)))) < length (d # data)"
  using pTrans_data_is_substring apply clarsimp
  apply (drule_tac x="(drop (unat (Obj.len\<^sub>f (pObj (d # data) 0))) (d # data))" in meta_spec)
  using is_valid_ObjHeader_len[OF len]  apply (clarsimp simp: bilbyFsObjHeaderSize_def)
  apply unat_arith
 done

text {*
The termination proof above does not look at the shape of the returned
values of pTrans, it only shows that the size of the input
data list decreases.
To prove termination of \<alpha>_updates_fun we need to know that the returned data
list is smaller than the one received as argument.
I could not figure a way to reuse the termination proof above to show
that \<alpha>_updates_fun terminates. I wouldn't be surprise to see that there's
a simpler way to achieve my goal. If you find one, please educate me.
*}
lemma pTrans_termination_argument:
 "(nd#nds, o'#os) = pTrans (d#data) \<Longrightarrow> length (nd#nds) < length (d#data)"
  apply (clarsimp simp del: list.size split: if_splits
         simp : bilbyFsObjHeaderSize_def Let_def prod.case_eq_if)
  apply (fastforce dest: pTrans_length_helper simp: prod.case_eq_if)
  done

definition
  is_valid_addr :: "MountState\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> ObjAddr\<^sub>T \<Rightarrow> bool"
where
 "is_valid_addr mount_st ostore_st addr \<equiv>
    ebnum\<^sub>f addr < nb_eb\<^sub>f (super\<^sub>f mount_st) \<and>
    bilbyFsFirstLogEbNum \<le> ebnum\<^sub>f addr \<and>
    bilbyFsMinObjSize \<le> ObjAddr.len\<^sub>f addr \<and>
    offs\<^sub>f addr < offs\<^sub>f addr + ObjAddr.len\<^sub>f addr \<and>
    offs\<^sub>f addr + ObjAddr.len\<^sub>f addr \<le> eb_size\<^sub>f (super\<^sub>f mount_st) \<and>
    (ebnum\<^sub>f addr = wbuf_eb\<^sub>f ostore_st \<longrightarrow>
        (offs\<^sub>f addr + ObjAddr.len\<^sub>f addr \<le> used\<^sub>f ostore_st))"

text {* It turns out that transactions can be separated by few bilbyFsPadByte bytes.
This happens when there isn't enough room for a padding object to fill up a
hardware page. Thus there cannot be such padding area at an offset corresponding
to the beginning of a page.
*}
function
  list_trans :: "U8 list \<Rightarrow> (U8 list \<times> Trans list)"
where
"list_trans data =
    (case pTrans data of
      (_, []) \<Rightarrow> (data, []) \<comment> \<open> We return the beginning of an invalid transaction as it's obviously non-empty \<close>
    | ([],objs) \<Rightarrow> ([], [objs])
    | (newdata, objs) \<Rightarrow>
      \<comment> \<open> let objs = if length objs = 1 \<and>
                    otype<^sub>f (objs!0) = bilbyFsObjTypePad then [] else objs
       in \<close> (\<lambda>(d,txs). (d,objs#txs)) (list_trans (nopad newdata)))"
  by pat_completeness auto
  termination
  apply (relation "measure length")
  apply (clarsimp simp del: pTrans.simps split:prod.splits)
  apply (case_tac "data")
   apply clarsimp
  apply (fastforce dest:pTrans_termination_argument
          simp: nopad_def dropWhile_eq_drop)
 done

definition
  list_trans_no_pad :: "U8 list \<Rightarrow> (U8 list \<times> Trans list)"
where
  "list_trans_no_pad data \<equiv>
    (case list_trans data of
     (rem, txs) \<Rightarrow>
     (rem, filter (\<lambda>tx. \<not> (length tx = 1 \<and> otype\<^sub>f (tx!0) = bilbyFsObjTypePad)) txs))"

lemma list_trans_no_pad_Cons[simp]:
 "list_trans_no_pad (x#xs) =
 (prod.fst (list_trans (x # xs)),
  [tx\<leftarrow>prod.snd (list_trans (x # xs)).  \<not> (length tx = 1 \<and> otype\<^sub>f (tx!0) = bilbyFsObjTypePad)])"
  by (simp add: list_trans_no_pad_def prod.case_eq_if del: list_trans.simps)

lemma list_trans_no_pad_Nil[simp]:
 "list_trans_no_pad [] = ([], [])"
  by (simp add: list_trans_no_pad_def)

type_synonym EbLog = "Trans list"

definition
 list_eb_log :: "ubi_leb list \<Rightarrow> EbLog list"
where
 "list_eb_log wubi \<equiv>
   map (prod.snd o list_trans_no_pad) (drop (unat bilbyFsFirstLogEbNum) wubi)"

definition
  prune_ostore :: "Obj\<^sub>T \<Rightarrow> ostore_map \<Rightarrow> ostore_map"
where
 "prune_ostore del omap \<equiv>
  (\<lambda>oid. case omap oid of
         option.Some obj \<Rightarrow>
           if obj_is_deleted_by obj del then
             option.None
           else
             option.Some obj
        | option.None \<Rightarrow> option.None)"

definition
  trans_order :: "Obj\<^sub>T list \<Rightarrow> U64"
where
 "trans_order objs \<equiv> Obj.sqnum\<^sub>f ((sort_key Obj.sqnum\<^sub>f objs)!0)"

definition
  abstract_mount_\<alpha>_ostore :: "ubi_leb list \<Rightarrow> ostore_map"
where
 "abstract_mount_\<alpha>_ostore wubi \<equiv>
  let alltrans = (concat $ list_eb_log wubi);
      alltrans' = sort_key trans_order alltrans
  in fold id (map ostore_update alltrans') Map.empty"

text {* @{term mount_\<alpha>_ostore} returns the logical representation of the object
store curently stored (synchronised) on medium. *}
definition
  mount_\<alpha>_ostore :: "ubi_leb list \<Rightarrow> ostore_map"
where
 "mount_\<alpha>_ostore wubi \<equiv>
   let lel = list_eb_log wubi ;
       delobjs = concat $ concat $ map (map (filter obj_is_del)) lel;
       delfree_lel = map (map (filter (Not o obj_is_del))) lel;
       ostore_map = fold id (map (\<lambda>ltx. fold id (map ostore_update ltx)) delfree_lel) Map.empty
  in fold prune_ostore delobjs ostore_map"

definition
  ostore_get_obj :: "OstoreState\<^sub>T \<Rightarrow> ObjAddr\<^sub>T \<Rightarrow> Obj\<^sub>T"
where
 "ostore_get_obj ostore_st addr \<equiv>
  let buf = (if ebnum\<^sub>f addr = wbuf_eb\<^sub>f ostore_st then
               (\<alpha>wa $ data\<^sub>f $ wbuf\<^sub>f ostore_st)
             else
               \<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st)!(unat $ ebnum\<^sub>f addr))
  in pObj (take (unat (ObjAddr.offs\<^sub>f addr) + unat (ObjAddr.len\<^sub>f addr)) buf) (offs\<^sub>f addr)"

definition
 \<alpha>_ostore_medium :: "OstoreState\<^sub>T \<Rightarrow> ostore_map"
where
 "\<alpha>_ostore_medium ostore_st \<equiv> abstract_mount_\<alpha>_ostore (\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st))"

text {* \<alpha>_updates: returns updates not synchronised to medium yet *}
definition
  \<alpha>_updates :: "OstoreState\<^sub>T \<Rightarrow> (ostore_map \<Rightarrow> ostore_map) list"
where
 "\<alpha>_updates ostore_st \<equiv>
  (map ostore_update $ prod.snd $ list_trans_no_pad
    (buf_slice (wbuf\<^sub>f ostore_st) (sync_offs\<^sub>f ostore_st) (used\<^sub>f ostore_st)))"

text {* \<alpha>_ostore_uptodate: returns the logical view of the object store when all
 updates are applied.
*}

definition
  \<alpha>_ostore_uptodate ::  "OstoreState\<^sub>T \<Rightarrow> ostore_map"
where
 "\<alpha>_ostore_uptodate ostore_st \<equiv>
    fold id (\<alpha>_updates ostore_st) (\<alpha>_ostore_medium ostore_st)"

definition
  \<alpha>_ostore_runtime :: "OstoreState\<^sub>T \<Rightarrow> ostore_map"
where
 "\<alpha>_ostore_runtime ostore_st oid \<equiv>
  (case (\<alpha>_index $ index_st\<^sub>f ostore_st) oid of
   option.None \<Rightarrow> option.None
   | option.Some addr \<Rightarrow>
       option.Some $ ostore_get_obj ostore_st addr)"

definition
 is_valid_ObjIn :: "Obj\<^sub>T \<Rightarrow> U8 list \<Rightarrow> bool"
where
 "is_valid_ObjIn obj buf \<equiv>
   is_valid_ObjHeader obj buf \<and> Obj.trans\<^sub>f (pObj buf 0) = bilbyFsTransIn"

definition
 is_valid_ObjCommit :: "Obj\<^sub>T \<Rightarrow> U8 list \<Rightarrow> bool"
where
 "is_valid_ObjCommit obj buf \<equiv>
   is_valid_ObjHeader obj buf \<and> Obj.trans\<^sub>f (pObj buf 0) = bilbyFsTransCommit"

lemma bilbyFsTrans_diff[simp]:
  "bilbyFsTransIn \<noteq> bilbyFsTransCommit"
  "bilbyFsTransCommit \<noteq> bilbyFsTransIn"
   unfolding bilbyFsTransIn_def bilbyFsTransCommit_def
   by simp+

lemmas is_valid_ObjTrans = is_valid_ObjIn_def is_valid_ObjCommit_def

lemma drop_n_ge_0:
  "0<n \<Longrightarrow> drop n (v # va) = drop (n - 1) va"
 by (case_tac n, simp+)

lemma is_valid_ObjHeader_drop_non_zero:
 "is_valid_ObjHeader (pObj (v # va) 0) (v # va) \<Longrightarrow>
  drop (unat (Obj.len\<^sub>f (pObj (v # va) 0))) (v # va) = drop (unat (Obj.len\<^sub>f (pObj (v # va) 0)) - 1) (va)
 "
  apply (frule is_valid_ObjHeader_len_facts)
  apply (clarsimp simp:  bilbyFsObjHeaderSize_def unat_arith_simps)
  apply (simp add: drop_n_ge_0)
 done

fun
  valid_trans :: "U8 list \<Rightarrow> bool"
where
"valid_trans [] = False"
|valid_trans_Cons: "valid_trans buf =
   (if is_valid_ObjIn (pObj buf 0) buf then
     valid_trans (drop (unat $ Obj.len\<^sub>f $ pObj buf 0) buf)
   else is_valid_ObjCommit (pObj buf 0) buf)"

declare valid_trans.simps[simp del]

lemma valid_trans_simps[simp]:
  "valid_trans [] = False"
  "is_valid_ObjIn (pObj xs 0) xs \<Longrightarrow>
    valid_trans xs = valid_trans (drop (unat $ Obj.len\<^sub>f $ pObj xs 0) xs)"
  "is_valid_ObjCommit (pObj xs 0) xs \<Longrightarrow>
    valid_trans xs = True"
    apply (simp add: valid_trans.simps)
   apply (case_tac xs, (clarsimp simp: is_valid_ObjHeader_len_facts valid_trans.simps is_valid_ObjTrans is_valid_ObjHeader_def bilbyFsObjHeaderSize_def )+)
  apply (case_tac xs, simp)
   apply (frule is_len_and_type_ok_hdr_szD)
   apply (simp add: bilbyFsObjHeaderSize_def, unat_arith)
  apply (simp add: valid_trans.simps is_valid_ObjTrans is_valid_ObjHeader_def)
 done

lemma is_valid_Obj_diff:
  "is_valid_ObjCommit (pObj buf n) buf \<longrightarrow> \<not>is_valid_ObjIn (pObj buf n) buf"
  "is_valid_ObjIn (pObj buf n) buf \<longrightarrow> \<not>is_valid_ObjCommit (pObj buf n) buf"
  by (simp add: is_valid_ObjTrans)+

lemma Nil_not_valid_Obj[simp]:
  "is_valid_ObjHeader (pObj [] n) [] = False"
  "is_valid_ObjIn (pObj [] n) [] = False"
  "is_valid_ObjCommit (pObj [] n) [] = False"
  by (clarsimp simp add: is_valid_ObjTrans,
      frule is_valid_ObjHeader_len_facts,
      simp add: bilbyFsObjHeaderSize_def)+

fun
 trans_len :: "U8 list \<Rightarrow> nat"
where
trans_len_Nil: "trans_len [] = max (unat bilbyFsObjHeaderSize) (unat $ Obj.len\<^sub>f $ pObj [] 0)"
|trans_len_Cons: "trans_len buf =
   (if \<not>is_valid_ObjHeader (pObj buf 0) buf then
        max (unat bilbyFsObjHeaderSize) (unat $ Obj.len\<^sub>f $ pObj buf 0)
    else if is_valid_ObjIn (pObj buf 0) buf then
     (unat $ Obj.len\<^sub>f $ pObj buf 0) + trans_len (drop (unat $ Obj.len\<^sub>f $ pObj buf 0) buf)
    else
     unat $ Obj.len\<^sub>f $ pObj buf 0)"

declare trans_len.simps [simp del]
lemma trans_len_simps[simp]:
  "trans_len [] = max (unat bilbyFsObjHeaderSize) (unat $ Obj.len\<^sub>f $ pObj [] 0)"
  "is_valid_ObjIn (pObj xs 0) xs \<Longrightarrow>
    trans_len xs = (unat $ Obj.len\<^sub>f $ pObj xs 0) + trans_len (drop (unat $ Obj.len\<^sub>f $ pObj xs 0) xs)"
  "is_valid_ObjCommit (pObj xs 0) xs \<Longrightarrow>
    trans_len xs = unat (Obj.len\<^sub>f $ pObj xs 0)"
  apply (case_tac xs, (clarsimp simp: is_valid_ObjTrans is_valid_ObjHeader_def bilbyFsObjHeaderSize_def trans_len.simps)+)
  apply (case_tac xs, (clarsimp simp: is_valid_ObjTrans is_valid_ObjHeader_def bilbyFsObjHeaderSize_def trans_len.simps)+)
  apply (case_tac xs, (clarsimp simp: is_valid_ObjTrans, frule is_len_and_type_ok_hdr_szD, simp add: bilbyFsObjHeaderSize_def, unat_arith))
  apply (clarsimp simp: is_valid_ObjTrans, frule is_len_and_type_ok_hdr_szD,
         clarsimp simp add: bilbyFsObjHeaderSize_def trans_len.simps is_valid_ObjTrans, unat_arith)
 done

lemma trans_len_min_header[simp]:
  "unat bilbyFsObjHeaderSize - 1 < trans_len xs"
  apply (rule_tac x=xs in trans_len.cases)
   apply (fastforce simp: bilbyFsObjHeaderSize_def)
  apply (simp only: trans_len_Cons)
  apply (case_tac "is_valid_ObjIn (pObj (v # va) 0) (v # va)")
   apply (clarsimp simp: is_valid_Obj_diff is_valid_ObjTrans)
   apply (drule is_valid_ObjHeader_len, simp add: bilbyFsObjHeaderSize_def, unat_arith)
  apply (clarsimp simp: is_valid_ObjTrans)
  apply (auto dest!:  is_valid_ObjHeader_len[simplified bilbyFsObjHeaderSize_def], (simp add: bilbyFsObjHeaderSize_def | unat_arith)+)
 done

lemma hdr_sz_le_trans_len:
  "unat bilbyFsObjHeaderSize \<le> trans_len xs"
 using trans_len_min_header[where xs=xs] by simp

lemma trans_len_non_zero:
 "0 < trans_len xs"
 using trans_len_min_header
 by (drule_tac x=xs in meta_spec) fastforce

lemma take_non0:
 "xs \<noteq> [] \<Longrightarrow> 0 < n \<Longrightarrow>
   take n xs = hd xs#(take (n- 1) (tl xs))"
by (case_tac n, auto simp: take_Suc)

lemma prefix_length_le_Cons:
 "prefix xs (y#ys) \<Longrightarrow> length xs \<le> Suc (length ys)"
  using prefix_length_le by fastforce

function
  valid_list_trans :: "U8 list \<Rightarrow> bool"
where
"valid_list_trans [] = False"
|"valid_list_trans (b#buf) =
   (valid_trans (b#buf) \<and>
    (if nopad (drop (trans_len (b#buf)) (b#buf)) = [] then True
     else valid_list_trans (nopad (drop (trans_len (b#buf)) (b#buf)))))"

by pat_completeness simp+
termination
  apply (relation "measure (Suc o length)")
   apply simp
  apply (simp add: dropWhile_eq_drop nopad_def)
  apply (cut_tac xs="b # buf" in trans_len_non_zero)
  apply unat_arith
 done

definition
  valid_list_trans_no_pad :: "U8 list \<Rightarrow> bool"
where
  "valid_list_trans_no_pad buf \<equiv>
    valid_list_trans buf \<and> prod.snd (list_trans_no_pad buf) \<noteq> []"

lemma valid_list_trans_to_valid_trans:
 "valid_list_trans buf \<Longrightarrow> valid_trans buf"
by (erule valid_list_trans.elims, simp)

text {* \<alpha>_summary_updates: returns all the updates included in the summary.
This includes the updates already synchronised to medium i.e. wbuf[0:used] and
updates only applied in memory i.e. wbuf[used:sync_offs]. (Where wbuf[x:y] is the
slice of the WordArray U8 maching the medium contents for the erase-block in
question.)
*}
definition
  \<alpha>_summary_updates :: "OstoreState\<^sub>T \<Rightarrow> (ostore_map \<Rightarrow> ostore_map) list"
where
 "\<alpha>_summary_updates ostore_st \<equiv>
   let offs = unat $ (used\<^sub>f ostore_st);
       buf = take offs (\<alpha>wa $ data\<^sub>f $ wbuf\<^sub>f ostore_st)
    in (map ostore_update $ prod.snd $ list_trans_no_pad buf)"

text {* inv_\<alpha>_step_updates: asserts inv is true no matter how many updates we apply. *}
definition
  inv_\<alpha>_step_updates :: "OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_\<alpha>_step_updates ostore_st \<equiv>
   (let updates = \<alpha>_updates ostore_st
    in \<forall>n\<le>length updates.
     inv_\<alpha>_ostore (apply_n_updates n (\<alpha>_ostore_medium ostore_st) updates))"

definition
  sum_from_wbuf :: "Buffer\<^sub>T \<Rightarrow> Obj\<^sub>T"
where
 "sum_from_wbuf buf \<equiv>
   let  data = \<alpha>wa $ data\<^sub>f buf ;
        offs = ple32 data (buf_length buf - 4)
   in pObj data offs"

text {*
 summary_map: builds a ostore_map from a summary.
 The resulting map should be the same as applying all updates returned by \<alpha>_summary_updates to an empty
 map. (see inv_sum_consistent)
*}

definition
 summary_map :: "ObjSummary\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> ostore_map"
where
 "summary_map summary ostore_st \<equiv>
  let nb_entry = unat $ nb_sum_entry\<^sub>f summary;
      entries = take nb_entry $ \<alpha>wa $ entries\<^sub>f summary;
      nodel = filter (Not o obj_sum_entry_is_del) entries;
      maps = map (\<lambda>entry. Map.empty(ObjSumEntry.id\<^sub>f entry \<mapsto> pObj (\<alpha>wa $ data\<^sub>f $ wbuf\<^sub>f ostore_st) (obj_sum_entry_offs entry))) nodel;
      omap = fold (++) maps Map.empty;
      dels = filter (obj_sum_entry_is_del) entries
  in fold (\<lambda>entry gos.
    (\<lambda>oid. if oid_is_deleted_by oid (ObjSumEntry.id\<^sub>f entry) then
              option.None
           else gos oid)) dels omap"

definition
  inv_sum_consistent :: "Obj\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_sum_consistent sumobj ostore_st \<equiv>
   True
   \<comment> \<open> ignore summary consistency for now:
   otype<^sub>f sumobj = bilbyFsObjTypeSum \<and>
   let sum = obj_osummary sumobj
   in summary_map sum ostore_st = fold id (\<alpha>_summary_updates ostore_st) Map.empty \<close>"

definition
  room_for_summary :: "MountState\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> bool"
where
 "room_for_summary mount_st ostore_st \<equiv>
   (\<not>no_summary\<^sub>f mount_st \<and> used\<^sub>f ostore_st \<noteq> (eb_size\<^sub>f $ super\<^sub>f mount_st)) \<longrightarrow>
     (unat (eb_size\<^sub>f $ super\<^sub>f mount_st) - unat (used\<^sub>f ostore_st) \<le> unat (serialise_size_summary_Obj (summary\<^sub>f ostore_st)))
    "

text {*
Unless "used" equals "eb_size", there must be enough room for the summary
to be serialised. If "used" is equal to "eb_size", the summary's been
serialised already and can be read from the buffer.

nb_sum_entry constrain says that the maximum number of objects in
an erase-block has to be less than the number of min-size object that fit
in that buffer (this is an over-approximation because at least one of these
objects must be a summary).
*}
definition
  inv_ostore_summary :: "MountState\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_ostore_summary mount_st ostore_st \<equiv>
 True
  "
(* No summary invariant for now.
   let eb_size = eb_size\<^sub>f (super\<^sub>f mount_st)
   in nb_sum_entry\<^sub>f (summary\<^sub>f ostore_st) < (eb_size div bilbyFsMinObjSize) \<and>
   room_for_summary mount_st ostore_st \<and>
   (if used\<^sub>f ostore_st = eb_size then
    inv_sum_consistent (sum_from_wbuf (wbuf\<^sub>f ostore_st)) ostore_st
   else
     used\<^sub>f ostore_st < used\<^sub>f ostore_st + os_sum_sz ostore_st \<and>
     used\<^sub>f ostore_st + os_sum_sz ostore_st \<le> eb_size \<and>
     inv_sum_consistent ((sum_obj\<^sub>f ostore_st)\<lparr> ounion\<^sub>f:= TObjSummary (summary\<^sub>f ostore_st) \<rparr>) ostore_st)
*)

text {*
 inv_ostore_obj_meta: is the invariant of object meta data in
 relation to the object store state.
*}
definition
  inv_mem_ostore_obj :: "OstoreState\<^sub>T \<Rightarrow> Obj\<^sub>T \<Rightarrow> bool"
where
 "inv_mem_ostore_obj ostore_st obj \<equiv>
  Obj.sqnum\<^sub>f obj < OstoreState.next_sqnum\<^sub>f ostore_st \<and>
  ucast (otype\<^sub>f obj) = bilbyFsObjInode \<longrightarrow>
    (inum_from_obj_id $ get_obj_oid obj) < OstoreState.next_inum\<^sub>f ostore_st"

text {* @{term pollute_buf} ensures that the buffer does not contain a valid transaction
at offset @{term offs}. It does not matter what the value is as long as it's not
a valid transaction or padding, mount will stop at this offset.
Note that we could allow invalid to be prefixed by padding bytes but it's this is Ok for now.
We don't use pollute_buf at the moment because we do not care about crash-tolerance.
*}
definition
 pollute_buf :: "nat \<Rightarrow> U8 list \<Rightarrow> U8 list"
where
 "pollute_buf offs xs = xs[offs:=0xff]"

text {* list_eb_log_wbuf: returns the logical view of the log on-flash with the current
state of the buffer wbuf instead of the content of the corresponding erase-block.
*}
definition
 list_eb_log_wbuf :: "OstoreState\<^sub>T \<Rightarrow> EbLog list"
where
 "list_eb_log_wbuf ostore_st \<equiv>
  let eblogs = list_eb_log (\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st));
      wbuflog = prod.snd (list_trans_no_pad (\<comment> \<open> pollute_buf \<close> buf_slice (wbuf\<^sub>f ostore_st) 0 (used\<^sub>f ostore_st)))
  in eblogs[unat (wbuf_eb\<^sub>f ostore_st) - unat bilbyFsFirstLogEbNum:=wbuflog]"

text {* Attempt at on-flash invariant.

It's composed of 3 level of invariant, the top-level being the on that talks
about the entire log and relation between objects: inv_flash
The next level talks about individual erase-blocks: inv_eb_log
Erase-blocks log are made of multiple transactions: inv_trans
Transactions are made of objects: inv_obj

*}

definition
  ostore_log_objects :: "EbLog list \<Rightarrow> Obj\<^sub>T list"
where
 "ostore_log_objects \<equiv> concat o concat "

definition
 inv_trans :: "Obj\<^sub>T list \<Rightarrow> bool"
where
 "inv_trans olist \<equiv> (\<forall>obj\<in>set olist. \<not>obj_is_del obj \<longrightarrow> inv_read_obj obj)"

definition
  inv_eb_log :: "EbLog \<Rightarrow> Obj\<^sub>T set \<Rightarrow> bool"
where
 "inv_eb_log tlist allobjs \<equiv>
     (let sumtrans = tlist!(length tlist - 1);
         sumobj = hd sumtrans ;
         sum = obj_osummary sumobj
     in length sumtrans = 1 \<and> otype\<^sub>f sumobj = bilbyFsObjTypeSum \<and>
        (\<forall>entry\<in>(set $ \<alpha>wa $ ObjSummary.entries\<^sub>f sum).
          let objs = set $ concat $ tlist
          in \<exists>obj. Obj.offs\<^sub>f obj = obj_sum_entry_offs entry \<and>
          get_obj_oid obj = ObjSumEntry.id\<^sub>f entry \<and>
          (obj_sum_entry_is_del entry \<longrightarrow>
            (otype\<^sub>f obj = bilbyFsObjTypeDel \<and>
             card {x. x \<in> allobjs \<and>
                      oid_is_deleted_by (get_obj_oid x) (ObjSumEntry.id\<^sub>f entry) \<and>
                      Obj.sqnum\<^sub>f obj < ObjSumEntry.sqnum\<^sub>f entry
                  } = unat (ObjSumEntry.count\<^sub>f entry))) \<and>
          Obj.len\<^sub>f obj = ObjSumEntry.len\<^sub>f entry) \<and>
          (\<forall>trans \<in> set(butlast tlist). inv_trans trans))"

definition
  obj_is_alive :: "Obj\<^sub>T \<Rightarrow> Obj\<^sub>T set \<Rightarrow> bool"
where
 "obj_is_alive obj all \<equiv>
  (\<forall>delobj \<in>{x. x\<in> all \<and> obj_is_del x}. \<not>obj_is_deleted_by obj delobj)"

definition
  inv_flash :: "EbLog list \<Rightarrow> bool"
  where
 "inv_flash flash \<equiv> True
"
(*
  let all = ostore_log_objects flash in \<close>
  \<comment> \<open> The root inode exists, we don't really need to know that for the object store \<close>
  \<comment> \<open> (\<exists>obj\<in>set all. get_obj_oid obj = obj_id_inode_mk bilbyFsRootIno \<and> obj_is_alive obj (set all)) \<and> \<close>
  \<comment> \<open> all sqnums are uniq \<close>
  (card (Obj.sqnum\<^sub>f ` set all) = length (map Obj.sqnum\<^sub>f all)) \<and>
  (\<forall>eblog\<in>set flash. inv_eb_log eblog (set all)) \<and>
  \<comment> \<open> There is maximum 1 erase-block with garbage, (stripping out unmapped erase-blocks) \<close>
  length ((filter (op \<noteq> []) $ map (prod.fst o the) $ filter (op \<noteq> option.None) flash)) \<le> 1
  \<comment> \<open>rel dentarr inode and inode data blocks? no cyclic dependencies in graph? \<close>
  *)

definition
 is_obj_addr_consistent :: "Obj\<^sub>T \<Rightarrow> ObjAddr\<^sub>T \<Rightarrow> bool"
where
 "is_obj_addr_consistent obj addr \<equiv>
  Obj.sqnum\<^sub>f obj = ObjAddr.sqnum\<^sub>f addr \<and>
  Obj.offs\<^sub>f obj = ObjAddr.offs\<^sub>f addr \<and>
  Obj.len\<^sub>f obj = ObjAddr.len\<^sub>f addr"

definition
 inv_ostore_index :: "MountState\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_ostore_index mount_st ostore_st \<equiv>
  (\<forall>oid\<in>dom(\<alpha>_index $ index_st\<^sub>f ostore_st).
    let addr = the $ (\<alpha>_index $ index_st\<^sub>f ostore_st) oid;
        obj = ostore_get_obj ostore_st addr
     in is_valid_addr mount_st ostore_st addr \<and>
        is_obj_addr_consistent obj addr \<and>
        get_obj_oid obj = oid)"

definition
  inv_ostore_index_gim_disjoint :: "OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_ostore_index_gim_disjoint ostore_st \<equiv>
   dom (\<alpha>_index $ index_st\<^sub>f ostore_st) \<inter> dom (\<alpha>_fsm_gim $ gim\<^sub>f $ fsm_st\<^sub>f ostore_st) = {}"

definition
 inv_fsm_st :: "MountState\<^sub>T \<Rightarrow> FsmState\<^sub>T \<Rightarrow> bool"
where
 "inv_fsm_st mount_st fsm_st \<equiv>
 length (\<alpha>wa $ dirty_space\<^sub>f $ fsm_st) = unat (nb_eb\<^sub>f $ super\<^sub>f mount_st) \<and>
 length (\<alpha>wa $ used_eb\<^sub>f $ fsm_st) = unat (nb_eb\<^sub>f $ super\<^sub>f mount_st)"

definition
 inv_ostore_fsm :: "MountState\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_ostore_fsm mount_st ostore_st \<equiv>
 (\<alpha>wa $ used_eb\<^sub>f $ fsm_st\<^sub>f ostore_st) ! unat (wbuf_eb\<^sub>f ostore_st) \<noteq> 0 \<and>
\<comment> \<open> Count on each gimnode is equal to the number of objects with the same oid
   in the log \<close>
  (\<forall>oid \<in> dom(\<alpha>_fsm_gim $ gim\<^sub>f $ fsm_st\<^sub>f ostore_st).
   let gimnode = the $ (\<alpha>_fsm_gim $ gim\<^sub>f $ fsm_st\<^sub>f ostore_st) oid
   in unat (GimNode.count\<^sub>f gimnode) =
     card {x. x \<in> (set $ ostore_log_objects $ list_eb_log_wbuf ostore_st)  \<and>
              oid_is_deleted_by (get_obj_oid x) oid}) \<and>

\<comment> \<open> All Ubi erase-block with data are marked as used in the FSM used_eb<^sub>f bit map \<close>
  (\<forall>ebnum\<in> {bilbyFsFirstLogEbNum..<nb_eb\<^sub>f (super\<^sub>f mount_st)}.
     (unat ebnum \<noteq> unat (wbuf_eb\<^sub>f ostore_st) \<longrightarrow>
     ((\<alpha>wubi $ OstoreState.ubi_vol\<^sub>f ostore_st)  ! (unat ebnum) = [] \<longleftrightarrow>
     ((\<alpha>wa $ used_eb\<^sub>f $ fsm_st\<^sub>f ostore_st) ! (unat ebnum) \<noteq> 0))))

\<comment> \<open> Dirty space book-keeping (commented out for now) \<close>
"
  (* let ebnum = wbuf_eb\<^sub>f ostore_st in
  ((\<alpha>wa $ used_eb\<^sub>f $ fsm_st\<^sub>f ostore_st) ! (unat ebnum) \<noteq> 0)  \<longrightarrow>
   (let eb_log = list_eb_log_wbuf ostore_st ! (unat ebnum);
       eb_size =  unat (eb_size\<^sub>f (super\<^sub>f mount_st));
       nondirt = listsum (map (unat o Obj.len\<^sub>f) (concat eb_log)) ;
       nonused = (if ebnum = wbuf_eb\<^sub>f ostore_st then eb_size - unat (used\<^sub>f ostore_st) else 0) in
  (unat ((\<alpha>wa $ dirty_space\<^sub>f $ fsm_st\<^sub>f ostore_st) ! unat ebnum) = eb_size - nondirt - nonused)) *)

definition
 inv_bufs :: "MountState\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_bufs mount_st ostore_st \<equiv>
   inv_ubi_vol mount_st (OstoreState.ubi_vol\<^sub>f ostore_st) \<and>
   (\<forall>ebnum\<in>{unat bilbyFsFirstLogEbNum.. length ((\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st)))}.
    unat (wbuf_eb\<^sub>f ostore_st) \<noteq> ebnum \<longrightarrow>
    length ((\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st))!ebnum) = unat (eb_size\<^sub>f (super\<^sub>f mount_st) )) \<and>
  (let synced = buf_take (wbuf\<^sub>f ostore_st) (sync_offs\<^sub>f ostore_st);
       sync_to_used = buf_slice (wbuf\<^sub>f ostore_st) (sync_offs\<^sub>f ostore_st) (used\<^sub>f ostore_st) in
   \<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st) ! unat (wbuf_eb\<^sub>f ostore_st) = synced \<and>
   (sync_offs\<^sub>f ostore_st < used\<^sub>f ostore_st \<longrightarrow> valid_list_trans_no_pad sync_to_used) \<and>
   (used\<^sub>f ostore_st > 0 \<longrightarrow> valid_list_trans_no_pad synced) \<and>
   sort_key trans_order (prod.snd (list_trans_no_pad sync_to_used)) =
     prod.snd (list_trans_no_pad sync_to_used))
"
(*
  (let nb_eb = nb_eb\<^sub>f (super\<^sub>f mount_st) in
   (\<forall>ebnum\<in>{bilbyFsFirstLogEbNum..nb_eb}.
      (case ubi_to_buf (OstoreState.ubi_vol\<^sub>f ostore_st) ebnum of
         option.None \<Rightarrow> True |
         option.Some buf \<Rightarrow> valid_list_trans buf)))
*)

definition
  inv_log :: "Trans list list \<Rightarrow> Trans list \<Rightarrow> bool"
where
 "inv_log eb_log wbuf_log \<equiv>
  (\<forall>x\<in>set (concat eb_log).
   \<forall>y\<in>set (wbuf_log). trans_order x < trans_order y) \<and>
   inj_on trans_order (set $ concat $ eb_log @ [wbuf_log])"

definition
  inv_opad :: "Obj\<^sub>T \<Rightarrow> bool"
where
 "inv_opad opad \<equiv>
   magic\<^sub>f opad = bilbyFsMagic \<and>
   otype\<^sub>f opad = bilbyFsObjTypePad \<and>
   trans\<^sub>f opad = bilbyFsTransCommit \<and>
   bilbyFsObjHeaderSize \<le> Obj.len\<^sub>f opad \<and>
   ounion\<^sub>f (opad) = ObjUnion.TObjPad () \<and>
   Obj.offs\<^sub>f opad = 0"

(*
From inv_ostore, we know that  used\<^sub>f ostore_st \<le> eb_size,
see lemma inv_ostore_used below.
*)

definition
  inv_ostore :: "MountState\<^sub>T \<Rightarrow> OstoreState\<^sub>T \<Rightarrow> bool"
where
 "inv_ostore mount_st ostore_st \<equiv>
  sync_offs\<^sub>f ostore_st \<le> used\<^sub>f ostore_st \<and>
  io_size\<^sub>f (super\<^sub>f mount_st) udvd sync_offs\<^sub>f ostore_st \<and>
  used\<^sub>f ostore_st \<le> eb_size\<^sub>f (super\<^sub>f mount_st) \<and>
  used\<^sub>f ostore_st < used\<^sub>f ostore_st + io_size\<^sub>f (super\<^sub>f mount_st) \<and>
  buf_length (rbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st) \<and>
  buf_length (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st) \<and>
  buf_bound (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st) \<and>
  wbuf_eb\<^sub>f ostore_st \<ge> bilbyFsFirstLogEbNum \<and>
  wbuf_eb\<^sub>f ostore_st < nb_eb\<^sub>f (super\<^sub>f mount_st) \<and>
  inv_opad (opad\<^sub>f ostore_st) \<and>
  \<alpha>_ostore_runtime ostore_st = \<alpha>_ostore_uptodate ostore_st \<and>
  inv_ostore_summary mount_st ostore_st \<and>
  inv_ostore_index mount_st ostore_st \<and>
  inv_ostore_index_gim_disjoint ostore_st \<and>
  inv_bufs mount_st ostore_st \<and>
  inv_fsm_st mount_st (fsm_st\<^sub>f ostore_st) \<and>
  inv_ostore_fsm mount_st ostore_st \<and>
  inv_flash (list_eb_log_wbuf ostore_st) \<and>
  inv_log (list_eb_log (\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st)))
    (prod.snd $ list_trans_no_pad (buf_slice (wbuf\<^sub>f ostore_st) (sync_offs\<^sub>f ostore_st) (used\<^sub>f ostore_st)))"

lemmas inv_ostore_simps =
  inv_ostore_def
  inv_ostore_summary_def
  inv_ostore_index_def
  inv_ostore_index_gim_disjoint_def
  inv_bufs_def
  inv_ostore_fsm_def
  inv_flash_def
  inv_eb_log_def

lemma inv_summaryD: "inv_ostore mount_st ostore_st \<Longrightarrow> inv_ostore_summary mount_st ostore_st"
by (simp add: inv_ostore_def)

lemma inv_ostore_wbuf_lengthD: "inv_ostore mount_st ostore_st \<Longrightarrow> buf_length (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st)"
by (simp add: inv_ostore_def)

lemma inv_ostore_wbuf_boundD: "inv_ostore mount_st ostore_st \<Longrightarrow> buf_bound (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st)"
by (simp add: inv_ostore_def)

lemma inv_ostore_usedD:
  "inv_ostore mount_st ostore_st \<Longrightarrow>
  used\<^sub>f ostore_st \<le> eb_size\<^sub>f (super\<^sub>f mount_st)"
by (clarsimp simp:inv_ostore_def)

lemma inv_ostore_used_len_wbufD:
  "inv_ostore mount_st ostore_st \<Longrightarrow> inv_mount_st mount_st \<Longrightarrow> unat (used\<^sub>f ostore_st) \<le> length (\<alpha>wa $ data\<^sub>f $ wbuf\<^sub>f ostore_st)"
  apply (frule inv_ostore_wbuf_lengthD[THEN sym])
  apply (frule inv_ostore_usedD)
  apply (clarsimp simp: word_unat.Rep_inject[symmetric] word_le_nat_alt buf_simps inv_mount_st_def Let_def wordarray_length_ret)
 done

lemma inv_ostore_sync_offsD:
  "inv_ostore mount_st ostore_st \<Longrightarrow>  sync_offs\<^sub>f ostore_st \<le>  used\<^sub>f ostore_st"
by (clarsimp simp:inv_ostore_def)

lemma inv_ostore_fsmD:
  "inv_ostore mount_st ostore_st \<Longrightarrow> inv_ostore_fsm mount_st ostore_st"
by (clarsimp simp:inv_ostore_def)

lemma used_eq_sync_offs_means_no_update:
 "sync_offs\<^sub>f ostore_st = used\<^sub>f ostore_st \<Longrightarrow>
  \<alpha>_updates ostore_st = []"
 unfolding \<alpha>_updates_def by (simp add:  buf_simps)

lemma inv_bufsD[simplified inv_bufs_def Let_def]:
 "inv_ostore mount_st ostore_st \<Longrightarrow> inv_bufs mount_st ostore_st"
  by (simp add: inv_ostore_def)

lemma length_ubi_buf_eq_sync_offsD:
  "inv_ostore mount_st ostore_st \<Longrightarrow>
   inv_mount_st mount_st \<Longrightarrow>
  length (\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st) ! unat (wbuf_eb\<^sub>f ostore_st)) =
    unat (sync_offs\<^sub>f ostore_st)"
   apply (frule inv_bufsD)
   apply (subgoal_tac "unat (sync_offs\<^sub>f ostore_st) \<le> unat (buf_length (wbuf\<^sub>f ostore_st))")
   using wordarray_length_ret[where arr="data\<^sub>f (wbuf\<^sub>f ostore_st)"]
   apply (clarsimp simp:  inv_bufs_def buf_simps min_absorb1 Let_def)
   apply unat_arith
 apply (frule inv_ostore_usedD)
 apply (clarsimp simp: inv_ostore_def buf_simps inv_mount_st_def Let_def, unat_arith+)
done

lemma inv_ubi_volD:
 "inv_ostore mount_st ostore_st \<Longrightarrow> inv_ubi_vol mount_st (OstoreState.ubi_vol\<^sub>f ostore_st)"
 by (drule inv_bufsD, clarsimp simp: inv_bufs_def)

lemma inv_ostore_indexD:
 "inv_ostore mount_st ostore_st \<Longrightarrow> inv_ostore_index mount_st ostore_st"
 by (clarsimp simp: inv_ostore_def)

lemma inv_ostore_eb_size_wbuf_eqD:
  "inv_ostore mount_st ostore_st  \<Longrightarrow>
   unat (eb_size\<^sub>f (super\<^sub>f mount_st)) = length (\<alpha>wa (data\<^sub>f (wbuf\<^sub>f ostore_st)))"
using wordarray_length_ret[where arr="(data\<^sub>f (wbuf\<^sub>f ostore_st))"]
by (clarsimp simp: inv_ostore_def Let_def buf_simps wordarray_length_ret)

lemma inv_ostore_eb_size_rbuf_eqD:
  "inv_ostore mount_st ostore_st  \<Longrightarrow>
   unat (eb_size\<^sub>f (super\<^sub>f mount_st)) = length (\<alpha>wa (data\<^sub>f (rbuf\<^sub>f ostore_st)))"
using wordarray_length_ret[where arr="(data\<^sub>f (rbuf\<^sub>f ostore_st))"]
by (clarsimp simp: inv_ostore_def Let_def buf_simps wordarray_length_ret)

lemma inv_ostore_buf_boundD:
  "inv_ostore mount_st ostore_st \<Longrightarrow>
   unat (buf_bound (wbuf\<^sub>f ostore_st)) \<le> length (\<alpha>wa (data\<^sub>f (wbuf\<^sub>f ostore_st)))"
using wordarray_length_ret[where arr="(data\<^sub>f (wbuf\<^sub>f ostore_st))",symmetric]
by (clarsimp simp: inv_ostore_def buf_simps)

lemma inv_ostore_buf_bound_eqD:
  "inv_ostore mount_st ostore_st \<Longrightarrow>
   unat (buf_bound (wbuf\<^sub>f ostore_st)) = length (\<alpha>wa (data\<^sub>f (wbuf\<^sub>f ostore_st)))"
using wordarray_length_ret[where arr="(data\<^sub>f (wbuf\<^sub>f ostore_st))",symmetric]
by (clarsimp simp: inv_ostore_def buf_simps)

lemma inv_mount_st_no_summaryD:
  "inv_mount_st mount_st \<Longrightarrow> \<not> no_summary\<^sub>f mount_st"
 by (simp add: inv_mount_st_def Let_def)

lemma inv_logD[simplified inv_log_def]:
  "inv_ostore mount_st ostore_st \<Longrightarrow>
   inv_log (list_eb_log (\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st))) (prod.snd $ list_trans_no_pad (buf_slice (wbuf\<^sub>f ostore_st) (sync_offs\<^sub>f ostore_st) (used\<^sub>f ostore_st)))"
 by (clarsimp simp add: inv_ostore_def Let_def)

lemma inv_ostore_used_no_overflowD:
 "inv_ostore mount_st ostore_st \<Longrightarrow> used\<^sub>f ostore_st < used\<^sub>f ostore_st + io_size\<^sub>f (super\<^sub>f mount_st)"
 by (clarsimp simp: inv_ostore_def)

lemma used_neq_sync_offs_means_updates_not_Nil:
assumes inv_ostore: "inv_ostore mount_st ostore_st"
shows
 "sync_offs\<^sub>f ostore_st \<noteq> used\<^sub>f ostore_st \<Longrightarrow>
  \<alpha>_updates ostore_st \<noteq> []"
 unfolding \<alpha>_updates_def
using inv_bufsD[OF inv_ostore]  inv_ostore_sync_offsD[OF inv_ostore]
 by (fastforce simp add: valid_list_trans_no_pad_def)

lemma inv_mount_st_eb_size_boundD:
  "inv_mount_st mount_st \<Longrightarrow> eb_size\<^sub>f (super\<^sub>f mount_st) \<le> bilbyFsMaxEbSize"
 by (simp add: inv_mount_st_def Let_def)

lemma inv_fsm_stD[simplified inv_fsm_st_def]:
 "inv_ostore mount_st ostore_st \<Longrightarrow> inv_fsm_st mount_st (fsm_st\<^sub>f ostore_st)"
 by (clarsimp simp: inv_ostore_def)

lemma inv_ostore_wbuf_eb_rangeD:
 "inv_ostore mount_st ostore_st \<Longrightarrow>   wbuf_eb\<^sub>f ostore_st \<ge> bilbyFsFirstLogEbNum \<and>
  wbuf_eb\<^sub>f ostore_st < nb_eb\<^sub>f (super\<^sub>f mount_st)"
 by (clarsimp simp: inv_ostore_def)

lemma inv_opadD[simplified inv_opad_def]:
 "inv_ostore mount_st ostore_st \<Longrightarrow> inv_opad (opad\<^sub>f ostore_st)"
 by (simp add: inv_ostore_def)

definition
 valid_pad_obj :: "Obj\<^sub>T \<Rightarrow> bool"
where
 "valid_pad_obj obj \<equiv> otype\<^sub>f obj = bilbyFsObjTypePad \<and> is_valid_Obj obj \<and> Obj.offs\<^sub>f obj = 0"

lemma is_valid_ObjCommit_trans_len:
 "valid_pad_obj obj \<Longrightarrow> is_valid_ObjCommit obj (sObj obj) \<Longrightarrow> unat (Obj.len\<^sub>f obj) = length (sObj obj) \<Longrightarrow>  trans_len (sObj obj) = length (sObj obj)"
  apply (clarsimp simp add: is_valid_ObjTrans)
  apply (frule is_valid_ObjHeader_len_facts, clarsimp)
  apply (case_tac "sObj obj")
   apply (simp add: bilbyFsObjHeaderSize_def is_valid_ObjHeader_def)
  apply (simp add: trans_len_Cons)
  apply (rename_tac x xs)
  apply (clarsimp simp add: valid_pad_obj_def is_valid_ObjHeader_def)
  apply (drule_tac t="x#xs" in sym, simp add: Obj_inverse[where xs=Nil, simplified] is_valid_ObjTrans)
 done

lemma is_valid_ObjHeader_length_sObj:
 "valid_pad_obj obj \<Longrightarrow> is_valid_ObjHeader obj (sObj obj)  \<Longrightarrow> length (sObj obj) = unat (Obj.len\<^sub>f obj)"
  by (frule is_valid_ObjHeader_len_facts)
     (clarsimp simp: is_valid_ObjHeader_def length_sObj valid_pad_obj_def)

lemma inv_ostore_valid_pad_objD:
 "inv_ostore mount_st ostore_st \<Longrightarrow> valid_pad_obj (opad\<^sub>f ostore_st)"
 by (drule inv_opadD)  (clarsimp simp: inv_ostore_def valid_pad_obj_def is_valid_Obj_def)

lemma inv_ostoreI:
  assumes
    "sync_offs\<^sub>f ostore_st \<le> used\<^sub>f ostore_st"
    "io_size\<^sub>f (super\<^sub>f mount_st) udvd sync_offs\<^sub>f ostore_st"
    "used\<^sub>f ostore_st \<le> eb_size\<^sub>f (super\<^sub>f mount_st)"
    "used\<^sub>f ostore_st < used\<^sub>f ostore_st + io_size\<^sub>f (super\<^sub>f mount_st)"
    "buf_length (rbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st)"
    "buf_length (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st)"
    "buf_bound (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st)"
    "wbuf_eb\<^sub>f ostore_st \<ge> bilbyFsFirstLogEbNum"
    "wbuf_eb\<^sub>f ostore_st < nb_eb\<^sub>f (super\<^sub>f mount_st)"
    "inv_opad (opad\<^sub>f ostore_st)"
    "\<alpha>_ostore_runtime ostore_st = \<alpha>_ostore_uptodate ostore_st"
    "inv_ostore_summary mount_st ostore_st"
    "inv_ostore_index mount_st ostore_st"
    "inv_ostore_index_gim_disjoint ostore_st"
    "inv_bufs mount_st ostore_st"
    "inv_fsm_st mount_st (fsm_st\<^sub>f ostore_st)"
    "inv_ostore_fsm mount_st ostore_st"
    "inv_flash (list_eb_log_wbuf ostore_st)"
    "inv_log (list_eb_log (\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st)))
    (prod.snd $ list_trans_no_pad (buf_slice (wbuf\<^sub>f ostore_st) (sync_offs\<^sub>f ostore_st) (used\<^sub>f ostore_st)))"
  shows
    "inv_ostore mount_st ostore_st"
  using assms
  unfolding inv_ostore_def
  by fastforce

lemma inv_ostoreE:
  assumes
    "inv_ostore mount_st ostore_st"
    "sync_offs\<^sub>f ostore_st \<le> used\<^sub>f ostore_st \<Longrightarrow>
     io_size\<^sub>f (super\<^sub>f mount_st) udvd sync_offs\<^sub>f ostore_st \<Longrightarrow>
     used\<^sub>f ostore_st \<le> eb_size\<^sub>f (super\<^sub>f mount_st)\<Longrightarrow>
     used\<^sub>f ostore_st < used\<^sub>f ostore_st + io_size\<^sub>f (super\<^sub>f mount_st) \<Longrightarrow>
     buf_length (rbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st) \<Longrightarrow>
     buf_length (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st) \<Longrightarrow>
     buf_bound (wbuf\<^sub>f ostore_st) = eb_size\<^sub>f (super\<^sub>f mount_st) \<Longrightarrow>
     wbuf_eb\<^sub>f ostore_st \<ge> bilbyFsFirstLogEbNum \<Longrightarrow>
     wbuf_eb\<^sub>f ostore_st < nb_eb\<^sub>f (super\<^sub>f mount_st) \<Longrightarrow>
     inv_opad (opad\<^sub>f ostore_st) \<Longrightarrow>
     \<alpha>_ostore_runtime ostore_st = \<alpha>_ostore_uptodate ostore_st \<Longrightarrow>
     inv_ostore_summary mount_st ostore_st \<Longrightarrow>
     inv_ostore_index mount_st ostore_st \<Longrightarrow>
     inv_ostore_index_gim_disjoint ostore_st \<Longrightarrow>
     inv_bufs mount_st ostore_st \<Longrightarrow>
     inv_fsm_st mount_st (fsm_st\<^sub>f ostore_st) \<Longrightarrow>
     inv_ostore_fsm mount_st ostore_st \<Longrightarrow>
     inv_flash (list_eb_log_wbuf ostore_st) \<Longrightarrow>
     inv_log (list_eb_log (\<alpha>wubi (OstoreState.ubi_vol\<^sub>f ostore_st)))
       (prod.snd $ list_trans_no_pad (buf_slice (wbuf\<^sub>f ostore_st) (sync_offs\<^sub>f ostore_st) (used\<^sub>f ostore_st))) \<Longrightarrow>
     thesis"
  shows "thesis"
  using assms
  unfolding inv_ostore_def
  by fastforce

end


(*  Title:      HOL/Auth/n_germanSymIndex_lemma_inv__24_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_germanSymIndex Protocol Case Study*}

theory n_germanSymIndex_lemma_inv__24_on_rules imports n_germanSymIndex_lemma_on_inv__24
begin
section{*All lemmas on causal relation between inv__24*}
lemma lemma_inv__24_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__24  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqE__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqE__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_StoreVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqSVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqE__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqE__part__0Vsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqE__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqE__part__1Vsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqSVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqEVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__0Vsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__1Vsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvAckVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvInvAckVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntSVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntEVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntSVsinv__24) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntEVsinv__24) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


(*  Title:      HOL/Auth/n_germanSimp_lemma_inv__12_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_germanSimp Protocol Case Study*}

theory n_germanSimp_lemma_inv__12_on_rules imports n_germanSimp_lemma_on_inv__12
begin
section{*All lemmas on causal relation between inv__12*}
lemma lemma_inv__12_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(\<exists> p__Inv3 p__Inv4. p__Inv3\<le>N\<and>p__Inv4\<le>N\<and>p__Inv3~=p__Inv4\<and>f=inv__12  p__Inv3 p__Inv4)"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_StoreVsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqSVsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__0Vsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__1Vsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__0Vsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__1Vsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvAckVsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvInvAckVsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntSVsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntEVsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntSVsinv__12) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntEVsinv__12) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


(*  Title:      HOL/Auth/n_germanSimp_lemma_inv__32_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_germanSimp Protocol Case Study*}

theory n_germanSimp_lemma_inv__32_on_rules imports n_germanSimp_lemma_on_inv__32
begin
section{*All lemmas on causal relation between inv__32*}
lemma lemma_inv__32_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(\<exists> p__Inv3 p__Inv4. p__Inv3\<le>N\<and>p__Inv4\<le>N\<and>p__Inv3~=p__Inv4\<and>f=inv__32  p__Inv3 p__Inv4)"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_StoreVsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqSVsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__0Vsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__1Vsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__0Vsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__1Vsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvAckVsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvInvAckVsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntSVsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntEVsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntSVsinv__32) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntEVsinv__32) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


theory Friend_Network
  imports
    "../API_Network"
    "Friend"
    "BD_Security_Compositional.Composing_Security_Network"
begin

subsection \<open>Confidentiality for the N-ary composition\<close>

locale FriendNetwork = Network + FriendNetworkObservationSetup +
fixes
  AID :: apiID
and
  UID1 :: userID
and
  UID2 :: userID
assumes
  UID1_UID2_UIDs: "{UID1,UID2} \<inter> (UIDs AID) = {}"
and
  UID1_UID2: "UID1 \<noteq> UID2"
and
  AID_AIDs: "AID \<in> AIDs"
begin

sublocale Issuer: Friend "UIDs AID" UID1 UID2 using UID1_UID2_UIDs UID1_UID2 by unfold_locales

abbreviation \<phi> :: "apiID \<Rightarrow> (state, act, out) trans \<Rightarrow> bool"
where "\<phi> aid trn \<equiv> (Issuer.\<phi> trn \<and> aid = AID)"

abbreviation f :: "apiID \<Rightarrow> (state, act, out) trans \<Rightarrow> Friend.value"
where "f aid trn \<equiv> Friend.f UID1 UID2 trn"

abbreviation T :: "apiID \<Rightarrow> (state, act, out) trans \<Rightarrow> bool"
where "T aid trn \<equiv> False"

abbreviation B :: "apiID \<Rightarrow> Friend.value list \<Rightarrow> Friend.value list \<Rightarrow> bool"
where "B aid vl vl1 \<equiv> (if aid = AID then Issuer.B vl vl1 else (vl = [] \<and> vl1 = []))"

abbreviation "comOfV aid vl \<equiv> Internal"
abbreviation "tgtNodeOfV aid vl \<equiv> undefined"
abbreviation "syncV aid1 vl1 aid2 vl2 \<equiv> False"

sublocale Net: BD_Security_TS_Network_getTgtV
where istate = "\<lambda>_. istate" and validTrans = validTrans and srcOf = "\<lambda>_. srcOf" and tgtOf = "\<lambda>_. tgtOf"
  and nodes = AIDs and comOf = comOf and tgtNodeOf = tgtNodeOf
  and sync = sync and \<phi> = \<phi> and f = f and \<gamma> = \<gamma> and g = g and T = T and B = B
  and comOfV = comOfV and tgtNodeOfV = tgtNodeOfV and syncV = syncV
  and comOfO = comOfO and tgtNodeOfO = tgtNodeOfO and syncO = syncO (*and cmpO = cmpO*)
  and source = AID and getTgtV = id
proof (unfold_locales, goal_cases)
  case (1 aid trn) then show ?case by auto next
  case (2 aid trn) then show ?case by auto next
  case (3 aid trn) then show ?case by (cases trn) auto next
  case (4 aid trn) then show ?case by (cases "(aid,trn)" rule: tgtNodeOf.cases) auto next
  case (5 aid1 trn1 aid2 trn2) then show ?case by auto next
  case (6 aid1 trn1 aid2 trn2) then show ?case by (cases trn1; cases trn2; auto) next
  case (7 aid1 trn1 aid2 trn2) then show ?case by auto next
  case (8 aid1 trn1 aid2 trn2) then show ?case by (cases trn1; cases trn2; auto) next
  case (9 aid trn) then show ?case by (cases "(aid,trn)" rule: tgtNodeOf.cases) (auto simp: FriendObservationSetup.\<gamma>.simps) next
  case (10 aid trn) then show ?case by auto
qed auto

sublocale BD_Security_TS_Network_Preserve_Source_Security_getTgtV
where istate = "\<lambda>_. istate" and validTrans = validTrans and srcOf = "\<lambda>_. srcOf" and tgtOf = "\<lambda>_. tgtOf"
  and nodes = AIDs and comOf = comOf and tgtNodeOf = tgtNodeOf
  and sync = sync and \<phi> = \<phi> and f = f and \<gamma> = \<gamma> and g = g and T = T and B = B
  and comOfV = comOfV and tgtNodeOfV = tgtNodeOfV and syncV = syncV
  and comOfO = comOfO and tgtNodeOfO = tgtNodeOfO and syncO = syncO (*and cmpO = cmpO*)
  and source = AID and getTgtV = id
using AID_AIDs Issuer.secure
by unfold_locales auto

theorem secure: "secure"
proof (intro preserve_source_secure ballI)
  fix aid
  assume "aid \<in> AIDs - {AID}"
  then show "Net.lsecure aid" by (intro Abstract_BD_Security.B_id_secure) (auto simp: B_id_def)
qed

end

end


(*  Title:      HOL/Auth/n_g2kAbsAfter_lemma_inv__88_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_g2kAbsAfter Protocol Case Study*}

theory n_g2kAbsAfter_lemma_inv__88_on_rules imports n_g2kAbsAfter_lemma_on_inv__88
begin
section{*All lemmas on causal relation between inv__88*}
lemma lemma_inv__88_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(f=inv__88  )"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> d. d\<le>N\<and>r=n_n_Store_i1  d)\<or>
    (\<exists> d. d\<le>N\<and>r=n_n_AStore_i1  d)\<or>
    (r=n_n_SendReqS_j1  )\<or>
    (r=n_n_SendReqEI_i1  )\<or>
    (r=n_n_SendReqES_i1  )\<or>
    (r=n_n_RecvReq_i1  )\<or>
    (r=n_n_SendInvE_i1  )\<or>
    (r=n_n_SendInvS_i1  )\<or>
    (r=n_n_SendInvAck_i1  )\<or>
    (r=n_n_RecvInvAck_i1  )\<or>
    (r=n_n_SendGntS_i1  )\<or>
    (r=n_n_SendGntE_i1  )\<or>
    (r=n_n_RecvGntS_i1  )\<or>
    (r=n_n_RecvGntE_i1  )\<or>
    (r=n_n_ASendReqIS_j1  )\<or>
    (r=n_n_ASendReqSE_j1  )\<or>
    (r=n_n_ASendReqEI_i1  )\<or>
    (r=n_n_ASendReqES_i1  )\<or>
    (r=n_n_SendReqEE_i1  )\<or>
    (r=n_n_ARecvReq_i1  )\<or>
    (r=n_n_ASendInvE_i1  )\<or>
    (r=n_n_ASendInvS_i1  )\<or>
    (r=n_n_ASendInvAck_i1  )\<or>
    (r=n_n_ARecvInvAck_i1  )\<or>
    (r=n_n_ASendGntS_i1  )\<or>
    (r=n_n_ASendGntE_i1  )\<or>
    (r=n_n_ARecvGntS_i1  )\<or>
    (r=n_n_ARecvGntE_i1  )"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> d. d\<le>N\<and>r=n_n_Store_i1  d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_Store_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(\<exists> d. d\<le>N\<and>r=n_n_AStore_i1  d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_AStore_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqS_j1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqS_j1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqEI_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqEI_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqES_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqES_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_RecvReq_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvReq_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendInvE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendInvE_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendInvS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendInvS_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendInvAck_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_RecvInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvInvAck_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendGntS_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendGntE_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_RecvGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvGntS_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_RecvGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_RecvGntE_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqIS_j1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqIS_j1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqSE_j1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqSE_j1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqEI_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqEI_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendReqES_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendReqES_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_SendReqEE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_SendReqEE_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvReq_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvReq_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendInvE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendInvE_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendInvS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendInvS_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendInvAck_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvInvAck_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvInvAck_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendGntS_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ASendGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ASendGntE_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvGntS_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvGntS_i1Vsinv__88) done
    }

    moreover {
      assume d1: "(r=n_n_ARecvGntE_i1  )"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_n_ARecvGntE_i1Vsinv__88) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


(*  Title:      HOL/Auth/n_germanSimp_lemma_inv__50_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_germanSimp Protocol Case Study*}

theory n_germanSimp_lemma_inv__50_on_rules imports n_germanSimp_lemma_on_inv__50
begin
section{*All lemmas on causal relation between inv__50*}
lemma lemma_inv__50_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(\<exists> p__Inv3 p__Inv4. p__Inv3\<le>N\<and>p__Inv4\<le>N\<and>p__Inv3~=p__Inv4\<and>f=inv__50  p__Inv3 p__Inv4)"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_StoreVsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqSVsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__0Vsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__1Vsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__0Vsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__1Vsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvAckVsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvInvAckVsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntSVsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntEVsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntSVsinv__50) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntEVsinv__50) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end