Theory Degeneracy
section "Degeneracy to stateless level-based information flow control"
theory Degeneracy
imports Correctness "HOL-IMP.Sec_TypingT"
begin
text ‹
\null
The goal of this concluding section is to prove the degeneracy of the information flow correctness
notion and the static type system defined in this paper to the classical counterparts addressed in
\<^cite>‹"Nipkow23-1"›, section 9.2.6, and formalized in \<^cite>‹"Nipkow23-2"› and \<^cite>‹"Nipkow23-3"›, in
case of a stateless level-based information flow correctness policy.
First of all, locale @{locale noninterf} is interpreted within the context of the class @{class sec}
defined in \<^cite>‹"Nipkow23-2"›, as follows.
▪ Parameter @{text dom} is instantiated as function @{text sec}, which also sets the type variable
standing for the type of the domains to @{typ nat}.
▪ Parameter @{text interf} is instantiated as the predicate such that for any program state, the
output is @{const True} just in case the former input level may interfere with, namely is not larger
than, the latter one.
▪ Parameter @{text state} is instantiated as the empty set, consistently with the fact that the
policy is represented by a single, stateless interference predicate.
Next, the information flow security notion implied by theorem @{thm [source] noninterference} in
\<^cite>‹"Nipkow23-3"› is formalized as a predicate @{text secure} taking a program as input. This
notion is then proven to be implied, in the degenerate interpretation described above, by the
information flow correctness notion formalized as predicate @{const [names_short] noninterf.correct}
(theorem @{text correct_secure}). Particularly:
▪ This theorem demands the additional assumption that the @{typ "state set"} @{term A} input to
@{const [names_short] noninterf.correct} is nonempty, since @{const [names_short] noninterf.correct}
is vacuously true for @{prop "A = {}"}.
▪ In order for this theorem to hold, predicate @{text secure} needs to slight differ from the
information flow security notion implied by theorem @{thm [source] noninterference}, in that it
requires state @{term t'} to exist if there also exists some variable with a level not larger than
@{term l}, namely if condition @{prop "s = t (≤ l)"} is satisfied \emph{nontrivially} -- actually,
no leakage may arise from two initial states disagreeing on the value of \emph{every} variable. In
fact, predicate @{const [names_short] noninterf.correct} requires a nontrivial configuration
@{term "(c⇩2', t⇩2)"} to exist in case condition @{prop "s⇩1 = t⇩1 (⊆ sources cs s⇩1 x)"} is satisfied
\emph{for some variable} \lstinline{x}.
Finally, the static type system @{const [names_short] noninterf.ctyping2} is proven to be equivalent
to the @{const sec_type} one defined in \<^cite>‹"Nipkow23-3"› in the above degenerate interpretation
(theorems @{text ctyping2_sec_type} and @{text sec_type_ctyping2}). The former theorem, which proves
that a \emph{pass} verdict from @{const [names_short] noninterf.ctyping2} implies the issuance of a
\emph{pass} verdict from @{const sec_type} as well, demands the additional assumptions that (a) the
@{typ "state set"} input to @{const [names_short] noninterf.ctyping2} is nonempty, (b) the input
program does not contain any loop with @{term "Bc True"} as boolean condition, and (c) the input
program has undergone \emph{constant folding}, as addressed in \<^cite>‹"Nipkow23-1"›, section 3.1.3
for arithmetic expressions and in \<^cite>‹"Nipkow23-1"›, section 3.2.1 for boolean expressions. Why?
This need arises from the different ways in which the two type systems handle ``dead'' conditional
branches. Type system @{const sec_type} does not try to detect ``dead'' branches; it simply applies
its full range of information flow security checks to any conditional branch contained in the input
program, even if it actually is a ``dead'' one. On the contrary, type system @{const [names_short]
noninterf.ctyping2} detects ``dead'' branches whenever boolean conditions can be evaluated at
compile time, and applies only a subset of its information flow correctness checks to such branches.
As parameter @{text state} is instantiated as the empty set, boolean conditions containing variables
cannot be evaluated at compile time, yet they can if they only contain constants. Thus, assumption
(a) prevents @{const [names_short] noninterf.ctyping2} from handling the entire input program as a
``dead'' branch, while assumptions (b) and (c) ensure that @{const [names_short] noninterf.ctyping2}
will not detect any ``dead'' conditional branch within the program. On the whole, those assumptions
guarantee that @{const [names_short] noninterf.ctyping2}, like @{const sec_type}, applies its full
range of checks to \emph{any} conditional branch contained in the input program, as required for
theorem @{text ctyping2_sec_type} to hold.
›
subsection "Global context definitions and proofs"
fun cgood :: "com ⇒ bool" where
"cgood (c⇩1;; c⇩2) = (cgood c⇩1 ∧ cgood c⇩2)" |
"cgood (IF _ THEN c⇩1 ELSE c⇩2) = (cgood c⇩1 ∧ cgood c⇩2)" |
"cgood (WHILE b DO c) = (b ≠ Bc True ∧ cgood c)" |
"cgood _ = True"
fun seq :: "com ⇒ com ⇒ com" where
"seq SKIP c = c" |
"seq c SKIP = c" |
"seq c⇩1 c⇩2 = c⇩1;; c⇩2"
fun ifc :: "bexp ⇒ com ⇒ com ⇒ com" where
"ifc (Bc True) c _ = c" |
"ifc (Bc False) _ c = c" |
"ifc b c⇩1 c⇩2 = (if c⇩1 = c⇩2 then c⇩1 else IF b THEN c⇩1 ELSE c⇩2)"
fun while :: "bexp ⇒ com ⇒ com" where
"while (Bc False) _ = SKIP" |
"while b c = WHILE b DO c"
primrec csimp :: "com ⇒ com" where
"csimp SKIP = SKIP" |
"csimp (x ::= a) = x ::= asimp a" |
"csimp (c⇩1;; c⇩2) = seq (csimp c⇩1) (csimp c⇩2)" |
"csimp (IF b THEN c⇩1 ELSE c⇩2) = ifc (bsimp b) (csimp c⇩1) (csimp c⇩2)" |
"csimp (WHILE b DO c) = while (bsimp b) (csimp c)"
lemma not_size:
"size (not b) ≤ Suc (size b)"
by (induction b rule: not.induct, simp_all)
lemma and_size:
"size (and b⇩1 b⇩2) ≤ Suc (size b⇩1 + size b⇩2)"
by (induction b⇩1 b⇩2 rule: and.induct, simp_all)
lemma less_size:
"size (less a⇩1 a⇩2) = 0"
by (induction a⇩1 a⇩2 rule: less.induct, simp_all)
lemma bsimp_size:
"size (bsimp b) ≤ size b"
by (induction b, auto intro: le_trans not_size and_size simp: less_size)
lemma seq_size:
"size (seq c⇩1 c⇩2) ≤ Suc (size c⇩1 + size c⇩2)"
by (induction c⇩1 c⇩2 rule: seq.induct, simp_all)
lemma ifc_size:
"size (ifc b c⇩1 c⇩2) ≤ Suc (size c⇩1 + size c⇩2)"
by (induction b c⇩1 c⇩2 rule: ifc.induct, simp_all)
lemma while_size:
"size (while b c) ≤ Suc (size c)"
by (induction b c rule: while.induct, simp_all)
lemma csimp_size:
"size (csimp c) ≤ size c"
by (induction c, auto intro: le_trans seq_size ifc_size while_size)
lemma avars_asimp:
"avars a = {} ⟹ ∃i. asimp a = N i"
by (induction a, auto)
lemma seq_match [dest!]:
"seq (csimp c⇩1) (csimp c⇩2) = c⇩1;; c⇩2 ⟹ csimp c⇩1 = c⇩1 ∧ csimp c⇩2 = c⇩2"
by (rule seq.cases [of "(csimp c⇩1, csimp c⇩2)"],
insert csimp_size [of c⇩1], insert csimp_size [of c⇩2], simp_all)
lemma ifc_match [dest!]:
"ifc (bsimp b) (csimp c⇩1) (csimp c⇩2) = IF b THEN c⇩1 ELSE c⇩2 ⟹
bsimp b = b ∧ (∀v. b ≠ Bc v) ∧ csimp c⇩1 = c⇩1 ∧ csimp c⇩2 = c⇩2"
by (insert csimp_size [of c⇩1], insert csimp_size [of c⇩2],
subgoal_tac "csimp c⇩1 ≠ IF b THEN c⇩1 ELSE c⇩2", auto intro: ifc.cases
[of "(bsimp b, csimp c⇩1, csimp c⇩2)"] split: if_split_asm)
lemma while_match [dest!]:
"while (bsimp b) (csimp c) = WHILE b DO c ⟹
bsimp b = b ∧ b ≠ Bc False ∧ csimp c = c"
by (rule while.cases [of "(bsimp b, csimp c)"], auto)
subsection "Local context definitions and proofs"
context sec
begin
interpretation noninterf "λs. (≤)" sec "{}"
by (unfold_locales, simp)
notation interf_set (‹(_: _ ↝ _)› [51, 51, 51] 50)
notation univ_states_if (‹(Univ? _ _)› [51, 75] 75)
notation atyping (‹(_ ⊨ _ '(⊆ _'))› [51, 51] 50)
notation btyping2_aux (‹(⊫ _ '(⊆ _, _'))› [51] 55)
notation btyping2 (‹(⊨ _ '(⊆ _, _'))› [51] 55)
notation ctyping1 (‹(⊢ _ '(⊆ _, _'))› [51] 55)
notation ctyping2 (‹(_ ⊨ _ '(⊆ _, _'))› [51, 51] 55)
abbreviation eq_le_ext :: "state ⇒ state ⇒ level ⇒ bool"
(‹(_ = _ '(❙≤ _'))› [51, 51, 0] 50) where
"s = t (❙≤ l) ≡ s = t (≤ l) ∧ (∃x :: vname. sec x ≤ l)"
definition secure :: "com ⇒ bool" where
"secure c ≡ ∀s s' t l. (c, s) ⇒ s' ∧ s = t (❙≤ l) ⟶
(∃t'. (c, t) ⇒ t' ∧ s' = t' (≤ l))"
definition levels :: "config set ⇒ level set" where
"levels U ≡ insert 0 (sec ` ⋃ (snd ` {(B, Y) ∈ U. B ≠ {}}))"
lemma avars_finite:
"finite (avars a)"
by (induction a, simp_all)
lemma avars_in:
"n < sec a ⟹ sec a ∈ sec ` avars a"
by (induction a, auto simp: max_def)
lemma avars_sec:
"x ∈ avars a ⟹ sec x ≤ sec a"
by (induction a, auto)
lemma avars_ub:
"sec a ≤ l = (∀x ∈ avars a. sec x ≤ l)"
by (induction a, auto)
lemma bvars_finite:
"finite (bvars b)"
by (induction b, simp_all add: avars_finite)
lemma bvars_in:
"n < sec b ⟹ sec b ∈ sec ` bvars b"
by (induction b, auto dest!: avars_in simp: max_def)
lemma bvars_sec:
"x ∈ bvars b ⟹ sec x ≤ sec b"
by (induction b, auto dest: avars_sec)
lemma bvars_ub:
"sec b ≤ l = (∀x ∈ bvars b. sec x ≤ l)"
by (induction b, auto simp: avars_ub)
lemma levels_insert:
assumes
A: "A ≠ {}" and
B: "finite (levels U)"
shows "finite (levels (insert (A, bvars b) U)) ∧
Max (levels (insert (A, bvars b) U)) = max (sec b) (Max (levels U))"
(is "finite (levels ?U') ∧ ?P")
proof -
have C: "levels ?U' = sec ` bvars b ∪ levels U"
using A by (auto simp: image_def levels_def univ_states_if_def)
hence D: "finite (levels ?U')"
using B by (simp add: bvars_finite)
moreover have ?P
proof (rule Max_eqI [OF D])
fix l
assume "l ∈ levels (insert (A, bvars b) U)"
thus "l ≤ max (sec b) (Max (levels U))"
using C by (auto dest: Max_ge [OF B] bvars_sec)
next
show "max (sec b) (Max (levels U)) ∈ levels (insert (A, bvars b) U)"
using C by (insert Max_in [OF B],
fastforce dest: bvars_in simp: max_def not_le levels_def)
qed
ultimately show ?thesis ..
qed
lemma sources_le:
"y ∈ sources cs s x ⟹ sec y ≤ sec x"
and sources_aux_le:
"y ∈ sources_aux cs s x ⟹ sec y ≤ sec x"
by (induction cs s x and cs s x rule: sources_induct,
auto split: com_flow.split_asm if_split_asm, fastforce+)
lemma bsimp_btyping2_aux_not [intro]:
"⟦bsimp b = b ⟹ ∀v. b ≠ Bc v ⟹ ⊫ b (⊆ A, X) = None;
not (bsimp b) = Not b⟧ ⟹ ⊫ b (⊆ A, X) = None"
by (rule not.cases [of "bsimp b"], auto)
lemma bsimp_btyping2_aux_and [intro]:
assumes
A: "⟦bsimp b⇩1 = b⇩1; ∀v. b⇩1 ≠ Bc v⟧ ⟹ ⊫ b⇩1 (⊆ A, X) = None" and
B: "and (bsimp b⇩1) (bsimp b⇩2) = And b⇩1 b⇩2"
shows "⊫ b⇩1 (⊆ A, X) = None"
proof -
{
assume "bsimp b⇩2 = And b⇩1 b⇩2"
hence "Bc True = b⇩1"
by (insert bsimp_size [of b⇩2], simp)
}
moreover {
assume "bsimp b⇩2 = And (Bc True) b⇩2"
hence False
by (insert bsimp_size [of b⇩2], simp)
}
moreover {
assume "bsimp b⇩1 = And b⇩1 b⇩2"
hence False
by (insert bsimp_size [of b⇩1], simp)
}
ultimately have "bsimp b⇩1 = b⇩1 ∧ (∀v. b⇩1 ≠ Bc v)"
using B by (auto intro: and.cases [of "(bsimp b⇩1, bsimp b⇩2)"])
thus ?thesis
using A by simp
qed
lemma bsimp_btyping2_aux_less [elim]:
"⟦less (asimp a⇩1) (asimp a⇩2) = Less a⇩1 a⇩2;
avars a⇩1 = {}; avars a⇩2 = {}⟧ ⟹ False"
by (fastforce dest: avars_asimp)
lemma bsimp_btyping2_aux:
"⟦bsimp b = b; ∀v. b ≠ Bc v⟧ ⟹ ⊫ b (⊆ A, X) = None"
by (induction b, auto split: option.split)
lemma bsimp_btyping2:
"⟦bsimp b = b; ∀v. b ≠ Bc v⟧ ⟹ ⊨ b (⊆ A, X) = (A, A)"
by (auto dest: bsimp_btyping2_aux [of _ A X] simp: btyping2_def)
lemma csimp_ctyping2_if:
"⟦⋀U' B B'. U' = U ⟹ B = B⇩1 ⟹ {} = B' ⟹ B⇩1 ≠ {} ⟹ False; s ∈ A;
⊨ b (⊆ A, X) = (B⇩1, B⇩2); bsimp b = b; ∀v. b ≠ Bc v⟧ ⟹
False"
by (drule bsimp_btyping2 [of _ A X], auto)
lemma csimp_ctyping2_while:
"⟦(if P then Some (B⇩2 ∪ B⇩2', Y) else None) = Some ({}, Z); s ∈ A;
⊨ b (⊆ A, X) = (B⇩1, B⇩2); bsimp b = b; b ≠ Bc True; b ≠ Bc False⟧ ⟹
False"
by (drule bsimp_btyping2 [of _ A X], auto split: if_split_asm)
lemma csimp_ctyping2:
"⟦(U, v) ⊨ c (⊆ A, X) = Some (B, Y); A ≠ {}; cgood c; csimp c = c⟧ ⟹
B ≠ {}"
proof (induction "(U, v)" c A X arbitrary: B Y U v rule: ctyping2.induct)
fix A X B Y U v c⇩1 c⇩2
show
"⟦⋀B Y. (U, v) ⊨ c⇩1 (⊆ A, X) = Some (B, Y) ⟹
A ≠ {} ⟹ cgood c⇩1 ⟹ csimp c⇩1 = c⇩1 ⟹
B ≠ {};
⋀p B Y C Z. (U, v) ⊨ c⇩1 (⊆ A, X) = Some p ⟹
(B, Y) = p ⟹ (U, v) ⊨ c⇩2 (⊆ B, Y) = Some (C, Z) ⟹
B ≠ {} ⟹ cgood c⇩2 ⟹ csimp c⇩2 = c⇩2 ⟹
C ≠ {};
(U, v) ⊨ c⇩1;; c⇩2 (⊆ A, X) = Some (B, Y);
A ≠ {}; cgood (c⇩1;; c⇩2);
csimp (c⇩1;; c⇩2) = c⇩1;; c⇩2⟧ ⟹
B ≠ {}"
by (fastforce split: option.split_asm)
next
fix A X C Y U v b c⇩1 c⇩2
show
"⟦⋀U' p B⇩1 B⇩2 C Y.
(U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
(B⇩1, B⇩2) = p ⟹ (U', v) ⊨ c⇩1 (⊆ B⇩1, X) = Some (C, Y) ⟹
B⇩1 ≠ {} ⟹ cgood c⇩1 ⟹ csimp c⇩1 = c⇩1 ⟹
C ≠ {};
⋀U' p B⇩1 B⇩2 C Y.
(U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
(B⇩1, B⇩2) = p ⟹ (U', v) ⊨ c⇩2 (⊆ B⇩2, X) = Some (C, Y) ⟹
B⇩2 ≠ {} ⟹ cgood c⇩2 ⟹ csimp c⇩2 = c⇩2 ⟹
C ≠ {};
(U, v) ⊨ IF b THEN c⇩1 ELSE c⇩2 (⊆ A, X) = Some (C, Y);
A ≠ {}; cgood (IF b THEN c⇩1 ELSE c⇩2);
csimp (IF b THEN c⇩1 ELSE c⇩2) = IF b THEN c⇩1 ELSE c⇩2⟧ ⟹
C ≠ {}"
by (auto split: option.split_asm prod.split_asm,
rule csimp_ctyping2_if)
next
fix A X B Z U v b c
show
"⟦⋀B⇩1 B⇩2 C Y B⇩1' B⇩2' B Z.
(B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹
(B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
B: sec ` W ↝ UNIV ⟹
({}, False) ⊨ c (⊆ B⇩1, X) = Some (B, Z) ⟹
B⇩1 ≠ {} ⟹ cgood c ⟹ csimp c = c ⟹
B ≠ {};
⋀B⇩1 B⇩2 C Y B⇩1' B⇩2' B Z.
(B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹
(B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
B: sec ` W ↝ UNIV ⟹
({}, False) ⊨ c (⊆ B⇩1', Y) = Some (B, Z) ⟹
B⇩1' ≠ {} ⟹ cgood c ⟹ csimp c = c ⟹
B ≠ {};
(U, v) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Z);
A ≠ {}; cgood (WHILE b DO c);
csimp (WHILE b DO c) = WHILE b DO c⟧ ⟹
B ≠ {}"
by (auto split: option.split_asm prod.split_asm,
rule csimp_ctyping2_while)
qed (simp_all split: if_split_asm)
theorem correct_secure:
assumes
A: "correct c A X" and
B: "A ≠ {}"
shows "secure c"
proof -
{
fix s s' t l and x :: vname
assume "(c, s) ⇒ s'"
then obtain cfs where C: "(c, s) →*{cfs} (SKIP, s')"
by (auto dest: small_steps_stepsl simp: big_iff_small)
assume D: "s = t (≤ l)"
have E: "∀x. sec x ≤ l ⟶ s = t (⊆ sources (flow cfs) s x)"
proof (rule allI, rule impI)
fix x :: vname
assume "sec x ≤ l"
moreover have "sources (flow cfs) s x ⊆ {y. sec y ≤ sec x}"
by (rule subsetI, simp, rule sources_le)
ultimately show "s = t (⊆ sources (flow cfs) s x)"
using D by auto
qed
assume "∀s c⇩1 c⇩2 s⇩1 s⇩2 cfs.
(c, s) →* (c⇩1, s⇩1) ∧ (c⇩1, s⇩1) →*{cfs} (c⇩2, s⇩2) ⟶
(∀t⇩1. ∃c⇩2' t⇩2. ∀x.
s⇩1 = t⇩1 (⊆ sources (flow cfs) s⇩1 x) ⟶
(c⇩1, t⇩1) →* (c⇩2', t⇩2) ∧ (c⇩2 = SKIP) = (c⇩2' = SKIP) ∧
s⇩2 x = t⇩2 x)"
note F = this [rule_format]
obtain t' where G: "∀x.
s = t (⊆ sources (flow cfs) s x) ⟶
(c, t) →* (SKIP, t') ∧ s' x = t' x"
using F [of s c s cfs SKIP s' t] and C by blast
assume H: "sec x ≤ l"
{
have "s = t (⊆ sources (flow cfs) s x)"
using E and H by simp
hence "(c, t) ⇒ t'"
using G by (simp add: big_iff_small)
}
moreover {
fix x :: vname
assume "sec x ≤ l"
hence "s = t (⊆ sources (flow cfs) s x)"
using E by simp
hence "s' x = t' x"
using G by simp
}
ultimately have "∃t'. (c, t) ⇒ t' ∧ s' = t' (≤ l)"
by auto
}
with A and B show ?thesis
by (auto simp: correct_def secure_def split: if_split_asm)
qed
lemma ctyping2_sec_type_assign [elim]:
assumes
A: "(if ((∃s. s ∈ Univ? A X) ⟶ (∀y ∈ avars a. sec y ≤ sec x)) ∧
(∀p ∈ U. ∀B Y. p = (B, Y) ⟶ B = {} ∨ (∀y ∈ Y. sec y ≤ sec x))
then Some (if x ∈ {} ∧ A ≠ {}
then if v ⊨ a (⊆ X)
then ({s(x := aval a s) |s. s ∈ A}, insert x X) else (A, X - {x})
else (A, Univ?? A X))
else None) = Some (B, Y)"
(is "(if (_ ⟶ ?P) ∧ ?Q then _ else _) = _") and
B: "s ∈ A" and
C: "finite (levels U)"
shows "Max (levels U) ⊢ x ::= a"
proof -
have "?P ∧ ?Q"
using A and B by (auto simp: univ_states_if_def split: if_split_asm)
moreover from this have "Max (levels U) ≤ sec x"
using C by (subst Max_le_iff, auto simp: levels_def, blast)
ultimately show "Max (levels U) ⊢ x ::= a"
by (auto intro: Assign simp: avars_ub)
qed
lemma ctyping2_sec_type_seq:
assumes
A: "⋀B' s. B = B' ⟹ s ∈ A ⟹ Max (levels U) ⊢ c⇩1" and
B: "⋀B' B'' C Z s'. B = B' ⟹ B'' = B' ⟹
(U, v) ⊨ c⇩2 (⊆ B', Y) = Some (C, Z) ⟹
s' ∈ B' ⟹ Max (levels U) ⊢ c⇩2" and
C: "(U, v) ⊨ c⇩1 (⊆ A, X) = Some (B, Y)" and
D: "(U, v) ⊨ c⇩2 (⊆ B, Y) = Some (C, Z)" and
E: "s ∈ A" and
F: "cgood c⇩1" and
G: "csimp c⇩1 = c⇩1"
shows "Max (levels U) ⊢ c⇩1;; c⇩2"
proof -
have "Max (levels U) ⊢ c⇩1"
using A and E by simp
moreover from C and E and F and G have "B ≠ {}"
by (erule_tac csimp_ctyping2, blast)
hence "Max (levels U) ⊢ c⇩2"
using B and D by blast
ultimately show ?thesis ..
qed
lemma ctyping2_sec_type_if:
assumes
A: "⋀U' B C s. U' = insert (Univ? A X, bvars b) U ⟹
B = B⇩1 ⟹ C⇩1 = C ⟹ s ∈ B⇩1 ⟹
finite (levels (insert (Univ? A X, bvars b) U)) ⟹
Max (levels (insert (Univ? A X, bvars b) U)) ⊢ c⇩1"
(is "⋀_ _ _ _. _ = ?U' ⟹ _ ⟹ _ ⟹ _ ⟹ _ ⟹ _")
assumes
B: "⋀U' B C s. U' = ?U' ⟹ B = B⇩1 ⟹ C⇩2 = C ⟹ s ∈ B⇩2 ⟹
finite (levels ?U') ⟹ Max (levels ?U') ⊢ c⇩2" and
C: "⊨ b (⊆ A, X) = (B⇩1, B⇩2)" and
D: "s ∈ A" and
E: "bsimp b = b" and
F: "∀v. b ≠ Bc v" and
G: "finite (levels U)"
shows "Max (levels U) ⊢ IF b THEN c⇩1 ELSE c⇩2"
proof -
from D and G have H: "finite (levels ?U') ∧
Max (levels ?U') = max (sec b) (Max (levels U))"
using levels_insert by (auto simp: univ_states_if_def)
moreover have I: "⊨ b (⊆ A, X) = (A, A)"
using E and F by (rule bsimp_btyping2)
hence "Max (levels ?U') ⊢ c⇩1"
using A and C and D and H by auto
moreover have "Max (levels ?U') ⊢ c⇩2"
using B and C and D and H and I by auto
ultimately show ?thesis
by (auto intro: If)
qed
lemma ctyping2_sec_type_while:
assumes
A: "⋀B C' B' D' s. B = B⇩1 ⟹ C' = C ⟹ B' = B⇩1' ⟹
((∃s. s ∈ Univ? A X ∨ s ∈ Univ? C Y) ⟶
(∀x ∈ bvars b. All ((≤) (sec x)))) ∧
(∀p ∈ U. case p of (B, W) ⇒ (∃s. s ∈ B) ⟶
(∀x ∈ W. All ((≤) (sec x)))) ⟹
D = D' ⟹ s ∈ B⇩1 ⟹ finite (levels {}) ⟹ Max (levels {}) ⊢ c"
(is "⋀_ _ _ _ _. _ ⟹ _ ⟹ _ ⟹
?P ∧ (∀p ∈ _. case p of (_, W) ⇒ _ ⟶ ?Q W) ⟹
_ ⟹ _ ⟹ _ ⟹ _")
assumes
B: "(if ?P ∧ (∀p ∈ U. ∀B W. p = (B, W) ⟶ B = {} ∨ ?Q W)
then Some (B⇩2 ∪ B⇩2', Univ?? B⇩2 X ∩ Y) else None) = Some (B, Z)"
(is "(if ?R then _ else _) = _") and
C: "⊨ b (⊆ A, X) = (B⇩1, B⇩2)" and
D: "s ∈ A" and
E: "bsimp b = b" and
F: "b ≠ Bc False" and
G: "b ≠ Bc True" and
H: "finite (levels U)"
shows "Max (levels U) ⊢ WHILE b DO c"
proof -
have ?R
using B by (simp split: if_split_asm)
hence "sec b ≤ 0"
using D by (subst bvars_ub, auto simp: univ_states_if_def, fastforce)
moreover have "⊨ b (⊆ A, X) = (A, A)"
using E and F and G by (blast intro: bsimp_btyping2)
hence "0 ⊢ c"
using A and C and D and `?R` by (fastforce simp: levels_def)
moreover have "Max (levels U) = 0"
proof (rule Max_eqI [OF H])
fix l
assume "l ∈ levels U"
thus "l ≤ 0"
using `?R` by (fastforce simp: levels_def)
next
show "0 ∈ levels U"
by (simp add: levels_def)
qed
ultimately show ?thesis
by (auto intro: While)
qed
theorem ctyping2_sec_type:
"⟦(U, v) ⊨ c (⊆ A, X) = Some (B, Y);
s ∈ A; cgood c; csimp c = c; finite (levels U)⟧ ⟹
Max (levels U) ⊢ c"
proof (induction "(U, v)" c A X arbitrary: B Y U v s rule: ctyping2.induct)
fix U
show "Max (levels U) ⊢ SKIP"
by (rule Skip)
next
fix A X C Z U v c⇩1 c⇩2 s
show
"⟦⋀B Y s. (U, v) ⊨ c⇩1 (⊆ A, X) = Some (B, Y) ⟹
s ∈ A ⟹ cgood c⇩1 ⟹ csimp c⇩1 = c⇩1 ⟹ finite (levels U) ⟹
Max (levels U) ⊢ c⇩1;
⋀p B Y C Z s. (U, v) ⊨ c⇩1 (⊆ A, X) = Some p ⟹
(B, Y) = p ⟹ (U, v) ⊨ c⇩2 (⊆ B, Y) = Some (C, Z) ⟹
s ∈ B ⟹ cgood c⇩2 ⟹ csimp c⇩2 = c⇩2 ⟹ finite (levels U) ⟹
Max (levels U) ⊢ c⇩2;
(U, v) ⊨ c⇩1;; c⇩2 (⊆ A, X) = Some (C, Z);
s ∈ A; cgood (c⇩1;; c⇩2);
csimp (c⇩1;; c⇩2) = c⇩1;; c⇩2;
finite (levels U)⟧ ⟹
Max (levels U) ⊢ c⇩1;; c⇩2"
by (auto split: option.split_asm, rule ctyping2_sec_type_seq)
next
fix A X B Y U v b c⇩1 c⇩2 s
show
"⟦⋀U' p B⇩1 B⇩2 C Y s.
(U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
(B⇩1, B⇩2) = p ⟹ (U', v) ⊨ c⇩1 (⊆ B⇩1, X) = Some (C, Y) ⟹
s ∈ B⇩1 ⟹ cgood c⇩1 ⟹ csimp c⇩1 = c⇩1 ⟹ finite (levels U') ⟹
Max (levels U') ⊢ c⇩1;
⋀U' p B⇩1 B⇩2 C Y s.
(U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
(B⇩1, B⇩2) = p ⟹ (U', v) ⊨ c⇩2 (⊆ B⇩2, X) = Some (C, Y) ⟹
s ∈ B⇩2 ⟹ cgood c⇩2 ⟹ csimp c⇩2 = c⇩2 ⟹ finite (levels U') ⟹
Max (levels U') ⊢ c⇩2;
(U, v) ⊨ IF b THEN c⇩1 ELSE c⇩2 (⊆ A, X) = Some (B, Y);
s ∈ A; cgood (IF b THEN c⇩1 ELSE c⇩2);
csimp (IF b THEN c⇩1 ELSE c⇩2) = IF b THEN c⇩1 ELSE c⇩2;
finite (levels U)⟧ ⟹
Max (levels U) ⊢ IF b THEN c⇩1 ELSE c⇩2"
by (auto split: option.split_asm prod.split_asm,
rule ctyping2_sec_type_if)
next
fix A X B Z U v b c s
show
"⟦⋀B⇩1 B⇩2 C Y B⇩1' B⇩2' D Z s.
(B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹
(B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
B: sec ` W ↝ UNIV ⟹
({}, False) ⊨ c (⊆ B⇩1, X) = Some (D, Z) ⟹
s ∈ B⇩1 ⟹ cgood c ⟹ csimp c = c ⟹ finite (levels {}) ⟹
Max (levels {}) ⊢ c;
⋀B⇩1 B⇩2 C Y B⇩1' B⇩2' D' Z' s.
(B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹
(B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
B: sec ` W ↝ UNIV ⟹
({}, False) ⊨ c (⊆ B⇩1', Y) = Some (D', Z') ⟹
s ∈ B⇩1' ⟹ cgood c ⟹ csimp c = c ⟹ finite (levels {}) ⟹
Max (levels {}) ⊢ c;
(U, v) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Z);
s ∈ A; cgood (WHILE b DO c);
csimp (WHILE b DO c) = WHILE b DO c;
finite (levels U)⟧ ⟹
Max (levels U) ⊢ WHILE b DO c"
by (auto split: option.split_asm prod.split_asm,
rule ctyping2_sec_type_while)
qed (auto split: prod.split_asm)
lemma sec_type_ctyping2_if:
assumes
A: "⋀U' B⇩1 B⇩2. U' = insert (Univ? A X, bvars b) U ⟹
(B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
Max (levels (insert (Univ? A X, bvars b) U)) ⊢ c⇩1 ⟹
finite (levels (insert (Univ? A X, bvars b) U)) ⟹
∃C Y. (insert (Univ? A X, bvars b) U, v) ⊨ c⇩1 (⊆ B⇩1, X) =
Some (C, Y)"
(is "⋀_ _ _. _ = ?U' ⟹ _ ⟹ _ ⟹ _ ⟹ _")
assumes
B: "⋀U' B⇩1 B⇩2. U' = ?U' ⟹ (B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
Max (levels ?U') ⊢ c⇩2 ⟹ finite (levels ?U') ⟹
∃C Y. (?U', v) ⊨ c⇩2 (⊆ B⇩2, X) = Some (C, Y)" and
C: "finite (levels U)" and
D: "max (sec b) (Max (levels U)) ⊢ c⇩1" and
E: "max (sec b) (Max (levels U)) ⊢ c⇩2"
shows "∃C Y. (U, v) ⊨ IF b THEN c⇩1 ELSE c⇩2 (⊆ A, X) = Some (C, Y)"
proof -
obtain B⇩1 B⇩2 where F: "(B⇩1, B⇩2) = ⊨ b (⊆ A, X)"
by (cases "⊨ b (⊆ A, X)", simp)
moreover have "∃C⇩1 C⇩2 Y⇩1 Y⇩2. (?U', v) ⊨ c⇩1 (⊆ B⇩1, X) = Some (C⇩1, Y⇩1) ∧
(?U', v) ⊨ c⇩2 (⊆ B⇩2, X) = Some (C⇩2, Y⇩2)"
proof (cases "A = {}")
case True
hence "levels ?U' = levels U"
by (auto simp: levels_def univ_states_if_def)
moreover have "Max (levels U) ⊢ c⇩1"
using D by (auto intro: anti_mono)
moreover have "Max (levels U) ⊢ c⇩2"
using E by (auto intro: anti_mono)
ultimately show ?thesis
using A and B and C and F by simp
next
case False
with C have "finite (levels ?U') ∧
Max (levels ?U') = max (sec b) (Max (levels U))"
by (simp add: levels_insert univ_states_if_def)
thus ?thesis
using A and B and D and E and F by simp
qed
ultimately show ?thesis
by (auto split: prod.split)
qed
lemma sec_type_ctyping2_while:
assumes
A: "⋀B⇩1 B⇩2 C Y B⇩1' B⇩2'. (B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹ (B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
((∃s. s ∈ Univ? A X ∨ s ∈ Univ? C Y) ⟶
(∀x ∈ bvars b. All ((≤) (sec x)))) ∧
(∀p ∈ U. case p of (B, W) ⇒ (∃s. s ∈ B) ⟶
(∀x ∈ W. All ((≤) (sec x)))) ⟹
Max (levels {}) ⊢ c ⟹ finite (levels {}) ⟹
∃D Z. ({}, False) ⊨ c (⊆ B⇩1, X) = Some (D, Z)"
(is "⋀_ _ C Y _ _. _ ⟹ _ ⟹ _ ⟹ ?P C Y ⟹ _ ⟹ _ ⟹ _")
assumes
B: "⋀B⇩1 B⇩2 C Y B⇩1' B⇩2'. (B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹ (B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
?P C Y ⟹ Max (levels {}) ⊢ c ⟹ finite (levels {}) ⟹
∃D Z. ({}, False) ⊨ c (⊆ B⇩1', Y) = Some (D, Z)" and
C: "finite (levels U)" and
D: "Max (levels U) = 0" and
E: "sec b = 0" and
F: "0 ⊢ c"
shows "∃B Y. (U, v) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Y)"
proof -
obtain B⇩1 B⇩2 where G: "(B⇩1, B⇩2) = ⊨ b (⊆ A, X)"
by (cases "⊨ b (⊆ A, X)", simp)
moreover obtain C Y where H: "(C, Y) = ⊢ c (⊆ B⇩1, X)"
by (cases "⊢ c (⊆ B⇩1, X)", simp)
moreover obtain B⇩1' B⇩2' where I: "(B⇩1', B⇩2') = ⊨ b (⊆ C, Y)"
by (cases "⊨ b (⊆ C, Y)", simp)
moreover {
fix l x s B W
assume J: "(B, W) ∈ U" and K: "x ∈ W" and L: "s ∈ B"
have "sec x ≤ l"
proof (rule le_trans, rule Max_ge [OF C])
show "sec x ∈ levels U"
using J and K and L by (fastforce simp: levels_def)
next
show "Max (levels U) ≤ l"
using D by simp
qed
}
hence J: "?P C Y"
using E by (auto dest: bvars_sec)
ultimately have "∃D D' Z Z'. ({}, False) ⊨ c (⊆ B⇩1, X) = Some (D, Z) ∧
({}, False) ⊨ c (⊆ B⇩1', Y) = Some (D', Z')"
using A and B and F by (force simp: levels_def)
thus ?thesis
using G and H and I and J by (auto split: prod.split)
qed
theorem sec_type_ctyping2:
"⟦Max (levels U) ⊢ c; finite (levels U)⟧ ⟹
∃B Y. (U, v) ⊨ c (⊆ A, X) = Some (B, Y)"
proof (induction "(U, v)" c A X arbitrary: U v rule: ctyping2.induct)
fix A X U v x a
show "Max (levels U) ⊢ x ::= a ⟹ finite (levels U) ⟹
∃B Y. (U, v) ⊨ x ::= a (⊆ A, X) = Some (B, Y)"
by (fastforce dest: avars_sec simp: levels_def)
next
fix A X U v b c⇩1 c⇩2
show
"⟦⋀U' p B⇩1 B⇩2.
(U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
(B⇩1, B⇩2) = p ⟹ Max (levels U') ⊢ c⇩1 ⟹ finite (levels U') ⟹
∃B Y. (U', v) ⊨ c⇩1 (⊆ B⇩1, X) = Some (B, Y);
⋀U' p B⇩1 B⇩2.
(U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
(B⇩1, B⇩2) = p ⟹ Max (levels U') ⊢ c⇩2 ⟹ finite (levels U') ⟹
∃B Y. (U', v) ⊨ c⇩2 (⊆ B⇩2, X) = Some (B, Y);
Max (levels U) ⊢ IF b THEN c⇩1 ELSE c⇩2; finite (levels U)⟧ ⟹
∃B Y. (U, v) ⊨ IF b THEN c⇩1 ELSE c⇩2 (⊆ A, X) = Some (B, Y)"
by (auto simp del: ctyping2.simps(4), rule sec_type_ctyping2_if)
next
fix A X U v b c
show
"⟦⋀B⇩1 B⇩2 C Y B⇩1' B⇩2'.
(B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹
(B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
B: sec ` W ↝ UNIV ⟹
Max (levels {}) ⊢ c ⟹ finite (levels {}) ⟹
∃B Z. ({}, False) ⊨ c (⊆ B⇩1, X) = Some (B, Z);
⋀B⇩1 B⇩2 C Y B⇩1' B⇩2'.
(B⇩1, B⇩2) = ⊨ b (⊆ A, X) ⟹
(C, Y) = ⊢ c (⊆ B⇩1, X) ⟹
(B⇩1', B⇩2') = ⊨ b (⊆ C, Y) ⟹
∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
B: sec ` W ↝ UNIV ⟹
Max (levels {}) ⊢ c ⟹ finite (levels {}) ⟹
∃B Z. ({}, False) ⊨ c (⊆ B⇩1', Y) = Some (B, Z);
Max (levels U) ⊢ WHILE b DO c; finite (levels U)⟧ ⟹
∃B Z. (U, v) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Z)"
by (auto simp del: ctyping2.simps(5), rule sec_type_ctyping2_while)
qed auto
end
end