Theory Noninterference
section ‹Noninterference \`{a} la Goguen and Meseguer›
theory Noninterference
imports Shallow
begin
subsection‹Goguen-Meseguer noninterference›
text‹Definition›
locale GM_sec_model =
fixes st0 :: 'St
and do :: "'St ⇒ 'U ⇒ 'C ⇒ 'St"
and out :: "'St ⇒ 'U ⇒ 'Out"
and GH :: "'U set"
and GL :: "'U set"
begin
text‹Extension of ``do'' to sequences of pairs (user, command):›
fun doo :: "'St ⇒ ('U × 'C) list ⇒ 'St" where
"doo st [] = st"
|"doo st ((u,c) # ucl) = (doo (do st u c ) ucl)"
definition purge :: "'U set ⇒ ('U × 'C) list ⇒ ('U × 'C) list" where
"purge G ucl ≡ filter (λ (u,c). u ∉ G) ucl"
lemma purge_Nil[simp]: "purge G [] = []"
and purge_Cons_in[simp]: "u ∉ G ⟹ purge G ((u,c) # ucl) = (u,c) # purge G ucl"
and purge_Cons_notIn[simp]: "u ∈ G ⟹ purge G ((u,c) # ucl) = purge G ucl"
unfolding purge_def by auto
lemma purge_append:
"purge G (ucl1 @ ucl2) = purge G ucl1 @ purge G ucl2"
unfolding purge_def by (metis filter_append)
definition nonint :: bool where
"nonint ≡ ∀ ucl. ∀ u ∈ GL. out (doo st0 ucl) u = out (doo st0 (purge GH ucl)) u"
end
text‹end-of-context GM-sec-model›
subsection‹Specialized Kripke structures›
text‹As a preparation for representing noninterference in HyperCTL*,
we define a specialized notion of Kripke structure. It is enriched
with the following date:
two binary state predicates f and g, intuitively capturing high-input
and low-output equivalence, respectively;
a set Sink of
states immediately accessible from any state and such that, for the states in Sink,
there exist self-transitions and f holds.
This specialized structure, represented by the locale Shallow-Idle, is an auxiliary that streamlines our proofs,
easing the connection
between finite paths (specific to Goguen-Meseguer noninterference) and
infinite paths (specific to the HyperCTL* semantics).
The desired Kripke structure produced from a Goguen-Meseguer model
will actually be such a specialized structure.
›
locale Shallow_Idle = Shallow S "s0" δ AP
for S :: "'state set" and s0 :: 'state and δ :: "'state ⇒ 'state set"
and AP :: "'aprop set"
and f :: "'state ⇒ 'state ⇒ bool" and g :: "'state ⇒ 'state ⇒ bool"
and Sink :: "'state set"
+
assumes Sink_S: "Sink ⊆ S"
and Sink: "⋀ s. s ∈ S ⟹ ∃ s'. s' ∈ δ s ∩ Sink"
and Sink_idle: "⋀ s. s ∈ Sink ⟹ s ∈ δ s"
and Sink_f: "⋀ s1 s2. {s1,s2} ⊆ Sink ⟹ f s1 s2"
begin
definition "toSink s ≡ SOME s'. s' ∈ δ s ∩ Sink"
lemma toSink: "s ∈ S ⟹ toSink s ∈ δ s ∩ Sink"
unfolding toSink_def by (metis Sink someI)
lemma fall2_imp_alw:
"fall2 (λ π' π πl. imp (alw (φ πl)) (alw (ψ πl)) (πl @ [π,π'])) []
⟷
(∀ π π'. wfp AP' π ∧ wfp AP' π' ∧ stateOf π = s0 ∧ stateOf π' = s0
⟶ imp (alw (φ [])) (alw (ψ [])) [π,π']
)"
by (auto intro!: fall2_intro imp_intro elim!: fall2_elim imp_elim) (metis imp_elim)+
lemma wfp_stateOf_shift_stake_sconst:
fixes π i
defines "π1 ≡ shift (stake (Suc i) π) (sconst (toSink (fst (π !! i)), L (toSink (fst (π !! i)))))"
assumes π: "wfp AP' π"
shows "wfp AP' π1 ∧ stateOf π1 = stateOf π"
proof
have π1_less[simp]: "⋀ k. k < Suc i ⟹ π1 !! k = π !! k"
and π1_geq[simp]: "⋀ k. k > i ⟹ π1 !! k = (toSink (fst (π !! i)) , L (toSink (fst (π !! i))))"
unfolding π1_def by (auto simp del: stake.simps)
{fix k have "fst (π1 !! Suc k) ∈ δ (fst (π1 !! k))"
proof(cases "k < Suc i")
case True
hence 0: "π1 !! k = π !! k" by simp
show ?thesis
proof(cases "k < i")
case True hence 1: "Suc k < Suc i" by simp
show ?thesis using π unfolding π1_less[OF 1] 0 wfp by auto
next
case False hence 1: "Suc k > i" and k: "k = i" using True by simp_all
show ?thesis using π unfolding π1_geq[OF 1] 0 wfp unfolding k by (metis IntD1 fstI toSink)
qed
next
case False
hence k: "k > i" and sk: "Suc k > i" by auto
show ?thesis unfolding π1_geq[OF k] π1_geq[OF sk] using π wfp Sink_idle toSink by auto
qed
}
moreover
{fix k have "fst (π1 !! k) ∈ S ∧ snd (π1 !! k) ⊆ AP' ∧ snd (π1 !! k) ∩ AP = L (fst (π1 !! k))"
apply(cases "k < Suc i",simp_all)
by (metis (lifting, no_types) π wfp AP_AP' IntD1 L δ inf.orderE order_trans rev_subsetD toSink)+
}
ultimately show "wfp AP' π1" unfolding wfp by auto
show "stateOf π1 = stateOf π"
by (metis π1_def shift.simps(2) stake.simps(2) stream.sel(1))
qed
lemma fall2_imp_alw_index:
assumes 0: "⋀ π π'. wfp AP' π ∧ wfp AP' π' ⟶
φ [] [π,π'] = f (stateOf π) (stateOf π') ∧
ψ [] [π,π'] = g (stateOf π) (stateOf π')"
shows
"fall2 (λ π' π πl. imp (alw (φ πl)) (alw (ψ πl)) (πl @ [π,π'])) []
⟷
(∀ π π'. wfp AP' π ∧ wfp AP' π' ∧ stateOf π = s0 ∧ stateOf π' = s0
⟶
(∀ i. (∀ j ≤ i. f (fst (π !! j)) (fst (π' !! j))) ⟶ g (fst (π !! i)) (fst (π' !! i)))
)"
(is "?L ⟷ ?R")
proof-
have 1: "⋀ i π π'. wfp AP' π ∧ wfp AP' π' ⟶
f (fst (π !! i)) (fst (π' !! i)) = φ [] [sdrop i π, sdrop i π'] ∧
g (fst (π !! i)) (fst (π' !! i)) = ψ [] [sdrop i π, sdrop i π']"
using 0 by auto
show ?thesis unfolding fall2_imp_alw proof(intro iffI allI impI, elim conjE)
fix π π' i
assume L: "∀ π π'. wfp AP' π ∧ wfp AP' π' ∧ stateOf π = s0 ∧ stateOf π' = s0
⟶ imp (alw (φ [])) (alw (ψ [])) [π,π']"
and ππ'[simp]: "wfp AP' π" "wfp AP' π'" "stateOf π = s0" "stateOf π' = s0"
and φ: "∀j≤i. f (fst (π !! j)) (fst (π' !! j))"
have ππ'i[simp]: "⋀ i. wfp AP' (sdrop i π) ∧ wfp AP' (sdrop i π')" by (metis ππ' wfp_sdrop)
define π1 where "π1 = shift (stake (Suc i) π) (sconst (toSink (fst (π !! i)), L (toSink (fst (π !! i)))))"
define π1' where "π1' = shift (stake (Suc i) π') (sconst (toSink (fst (π' !! i)), L (toSink (fst (π' !! i)))))"
have π1π1': "wfp AP' π1 ∧ stateOf π1 = s0 ∧ wfp AP' π1' ∧ stateOf π1' = s0"
using wfp_stateOf_shift_stake_sconst unfolding π1_def π1'_def by auto
hence π1π1'i: "⋀ i. wfp AP' (sdrop i π1) ∧ wfp AP' (sdrop i π1')" by (metis ππ' wfp_sdrop)
have imp: "imp (alw (φ [])) (alw (ψ [])) [π1,π1']" using L π1π1' by auto
moreover have "alw (φ []) [π1,π1']" unfolding alw proof
fix k
have a: "fst (π !! i) ∈ S" and b: "fst (π' !! i) ∈ S" using ππ' unfolding wfp by auto
thus "φ [] (map (sdrop k) [π1, π1'])"
using φ 0 π1π1'i unfolding π1_def π1'_def
apply(cases "k < Suc i", simp_all del: stake.simps)
using toSink[OF a] toSink[OF b] Sink_f by auto
qed
ultimately have "alw (ψ []) [π1,π1']" by auto
hence "ψ [] [sdrop i π1, sdrop i π1']" unfolding alw by simp
hence "g (fst (π1 !! i)) (fst (π1' !! i))" using 0 π1π1'i by simp
thus "g (fst (π !! i)) (fst (π' !! i))"
unfolding π1_def π1'_def by (auto simp del: stake.simps)
qed(auto simp: sdrop_imp_alw 1)
qed
end
text‹end-of-context Shallow-Idle›
subsection‹Faithful representation as a HyperCTL* property›
text‹Starting with a Goguen-Meseguer model, we will produce a specialized
Kripke structure and a shallow HyperCTL* formula.
Then we we will prove that the structure satisfies the formula iff the
Goguen-Meseguer model satisfies noninterference.›
text‹
The Kripke structure has two kinds of states: ``idle'' states storing Goguen-Meseguer states,
and normal states storing Goguen-Meseguer states, users and commands: the former
will be used for synchronization and the latter for Goguen-Meseguer steps.
The Kripke labels store user-command actions and user-output observations.
›