scyther-proof-0.3.0: data/isabelle/src/ESPLogic/InferenceRules.thy
(*****************************************************************************
* ESPL --- an embedded security protocol logic
* http://people.inf.ethz.ch/meiersi/espl/
*
* Copyright (c) 2009-2011, Simon Meier, ETH Zurich, Switzerland
*
* Extension to compromising adversaries:
*
* Copyright (c) 2010-2011, Martin Schaub, ETH Zurich, Switzerland
*
* All rights reserved. See file LICENCE for more information.
******************************************************************************)
theory InferenceRules
imports
HOL_ext
Hints
ExplicitModel
begin
section{* Inference Rules *}
subsection{* Role Order *}
definition roleMap :: "threadpool \<Rightarrow> tid \<rightharpoonup> role"
where "roleMap pool \<equiv> (\<lambda>(done,todo,skipped). Some (done @ todo)) \<circ>\<^sub>m pool"
lemma roleMap_empty [simp]: "roleMap empty = empty"
by(simp add: roleMap_def)
lemma dom_roleMap [simp]: "dom (roleMap r) = dom r"
by(auto simp: dom_def roleMap_def map_comp_def
split: option.splits)
lemma roleMap_upd [simp]:
"roleMap (pool(i \<mapsto> (done,todo,skipped))) =
(roleMap pool)(i \<mapsto> (done@todo))"
by(rule ext, simp add: roleMap_def map_comp_def)
lemma roleMap_SomeD:
"roleMap r i = Some R \<Longrightarrow>
\<exists> todo done skipped. r i = Some (done, todo, skipped) \<and> R = done@todo"
by(auto simp: roleMap_def map_comp_def split: option.splits)
lemma roleMap_SomeI:
"\<lbrakk> r i = Some (done, todo, skipped); R = done @ todo \<rbrakk> \<Longrightarrow>
roleMap r i = Some R"
by(auto simp: roleMap_def map_comp_def split: option.splits)
lemma roleMap_SomeE:
assumes role_exists: "roleMap r i = Some R"
obtains "done" todo skipped
where "r i = Some (done, todo, skipped)" and "R = done @ todo"
using role_exists
by (auto simp: roleMap_def map_comp_def split: option.splits)
lemma roleMap_le_roleMapI [intro!]:
assumes roleMap_leD:
"\<And> i done todo skipped. r i = Some (done, todo, skipped) \<Longrightarrow>
\<exists> done' todo' skipped'. r' i = Some (done', todo', skipped') \<and> done@todo = done'@todo'"
shows "roleMap r \<subseteq>\<^sub>m roleMap r'"
by(auto simp: roleMap_def map_comp_def split: option.splits
intro!: map_leI dest!: roleMap_leD)
lemma (in reachable_thread) roleMap:
"roleMap r i = Some (done@todo)"
by(fast intro!: thread_exists roleMap_SomeI)
subsection{* Prefix Close *}
definition prefixClose :: "store \<Rightarrow> explicit_trace \<Rightarrow> role \<Rightarrow> rolestep \<Rightarrow> tid \<Rightarrow> bool"
where
"prefixClose s t R step i =
(\<forall> st st'.
(nextRel (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R) @ [step]) st st') \<longrightarrow>
((recvStep st \<longrightarrow> (\<exists> m. Some m = inst s i (stepPat st) \<and> predOrd t (Ln m) (St (i, st)))) \<and>
predOrd t (St (i, st)) (St (i, st')))
)"
context reachable_state begin
lemma note_filtered_done[iff]:
"Note l ty pt \<notin> set (filter (\<lambda> x. \<not> (noteStep x)) done)"
by auto
lemma take_while_is_done:
assumes facts:
"r i = Some(done, step # todo, skipped)"
"roleMap r i = Some R"
shows isDone:
"(takeWhile (\<lambda> x. x \<noteq> step) R) = done"
using facts
proof -
interpret reachable_thread P t r s i "done" "step#todo" skipped
using facts by unfold_locales auto
hence "step \<in> set (step # todo)" by auto
hence "step \<notin> set done" using facts by (fastsimp dest!: todo_notin_doneD)
hence "(takeWhile (\<lambda> x. x \<noteq> step) done) = done" by auto
hence "(takeWhile (\<lambda> x. x \<noteq> step) (done @ (step # todo))) = done" by auto
moreover
have "R = (done @ (step # todo))" using facts by (fastsimp dest: roleMap_SomeD)
ultimately show ?thesis by auto
qed
lemma note_filtered_role:
"Note l ty pt \<in> set (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R) @ [step]) \<Longrightarrow> step = (Note l ty pt)"
by auto
lemma note_filtered_revRole:
"Note l ty pt \<in> set (step# rev (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R))) \<Longrightarrow> step = (Note l ty pt)"
by auto
lemma filtered_role_conv:
assumes filtered:
"st \<in> set (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R) @ [step])"
shows "(st \<in> set R \<and> st \<noteq> (Note l ty pt)) \<or> (st = step)"
proof -
have "st \<in> set (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R)) \<or> (st = step)" using filtered by auto
moreover {
assume inFilter: "st \<in> set (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R)) \<and> (st \<noteq> step)"
hence "st \<in> set (takeWhile (\<lambda> x. x \<noteq> step) R) \<and> (st \<noteq> step)" by auto
hence "st \<in> set R \<and> (st \<noteq> step)" by (auto dest: set_takeWhileD)
hence "st \<in> set R" by auto
moreover
have "st \<noteq> (Note l ty pt)" using inFilter by (auto dest: note_filtered_role)
ultimately have ?thesis by auto
}
ultimately show ?thesis by auto
qed
lemma filtered_done_conv:
assumes isThread:
"r i = Some(done, step # todo, skipped)"
"roleMap r i = Some R"
and filtered:
"st \<in> set (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R) @ [step])"
shows
"(st \<in> set done \<and> st \<noteq> (Note l ty pt)) \<or> (st = step)"
proof -
have "(st \<in> set R \<and> st \<noteq> (Note l ty pt)) \<or> (st = step)" using filtered by (fastsimp dest: filtered_role_conv)
moreover
have "(takeWhile (\<lambda> x. x \<noteq> step) R) = done" using isThread by (fastsimp dest: take_while_is_done)
ultimately show ?thesis using isThread and filtered by fastsimp
qed
lemma filtered_in_done:
assumes step: "(i, step) \<in> steps t"
and role_exists: "roleMap r i = Some R \<and> r i = Some(done, todo, skipped)"
and inFiltered: "st \<in> set (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R) @ [step])"
shows "st \<in> set done"
proof -
interpret this_thread:
reachable_thread P t r s i "done" todo skipped
using role_exists by unfold_locales auto
hence "step \<in> set done"
using step by (auto dest: this_thread.in_steps_in_done)
moreover
then obtain prefix suffix
where done_split: "done = prefix @ step # suffix \<and> step \<notin> set prefix"
by (auto dest!: split_list_first)
hence "takeWhile (\<lambda>x. x \<noteq> step) (prefix@step#suffix@todo) = prefix"
by (subst takeWhile_append2) auto
hence "takeWhile (\<lambda>x. x \<noteq> step) R = prefix"
using role_exists done_split by (auto elim!: roleMap_SomeE)
moreover {
assume "st \<noteq> step \<and> takeWhile (\<lambda>x. x \<noteq> step) R = prefix"
hence "st \<in> set prefix" using inFiltered
by auto
hence ?thesis using done_split by fastsimp
}
moreover {
assume "st = step \<and> step \<in> set done"
hence ?thesis by auto
}
ultimately show ?thesis by auto
qed
lemma recv_roleOrd_imp_predOrd:
assumes step: "(i, step) \<in> steps t"
and role_exists: "roleMap r i = Some R"
and role_ord: "listOrd R (Recv l pt) step"
shows "St (i, (Recv l pt)) \<prec> St (i, step)"
proof -
from role_exists
obtain "done" todo skipped
where "R = done @ todo"
and "r i = Some (done, todo, skipped)"
by (auto elim!: roleMap_SomeE)
then interpret this_thread:
reachable_thread P t r s i "done" todo skipped
by unfold_locales auto
show ?thesis using step role_ord `R = done @ todo`
by (fast intro!: listOrd_imp_predOrd
this_thread.listOrd_recv_role_imp_listOrd_trace)
qed
lemma send_roleOrd_imp_predOrd:
assumes step: "(i, step) \<in> steps t"
and role_exists: "roleMap r i = Some R"
and role_ord: "listOrd R (Send l pt) step"
shows "St (i, (Send l pt)) \<prec> St (i, step)"
proof -
from role_exists
obtain "done" todo skipped
where "R = done @ todo"
and "r i = Some (done, todo, skipped)"
by (auto elim!: roleMap_SomeE)
then interpret this_thread:
reachable_thread P t r s i "done" todo skipped
by unfold_locales auto
show ?thesis using step role_ord `R = done @ todo`
by (fast intro!: listOrd_imp_predOrd
this_thread.listOrd_send_role_imp_listOrd_trace)
qed
lemmas roleOrd_imp_predOrd' =
send_roleOrd_imp_predOrd[OF in_steps_predOrd1, rule_format]
recv_roleOrd_imp_predOrd[OF in_steps_predOrd1, rule_format]
lemmas roleOrd_imp_step =
in_steps_predOrd1[OF send_roleOrd_imp_predOrd, rule_format]
in_steps_predOrd1[OF recv_roleOrd_imp_predOrd, rule_format]
lemmas roleOrd_imp_step' =
roleOrd_imp_step[OF in_steps_predOrd1, rule_format]
lemma prefixClose_rawI:
assumes "\<And> st st'.
\<lbrakk> nextRel (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R) @ [step]) st st';
recvStep st
\<rbrakk> \<Longrightarrow> \<exists> m. Some m = inst s i (stepPat st) \<and> Ln m \<prec> St (i, st)"
and "\<And> st st'.
\<lbrakk> nextRel (filter (\<lambda> x. \<not> (noteStep x)) (takeWhile (\<lambda> x. x \<noteq> step) R) @ [step]) st st'
\<rbrakk> \<Longrightarrow> St (i, st) \<prec> St (i, st')"
shows "prefixClose s t R step i"
using prems by (auto simp: prefixClose_def)
lemma prefixCloseI:
assumes step: "(i, step) \<in> steps t"
and role_exists: "roleMap r i = Some R"
shows "prefixClose s t R step i"
proof -
from role_exists
obtain "done" todo skipped
where R_split: "R = done @ todo"
and "r i = Some (done, todo,skipped)"
by (auto elim!: roleMap_SomeE)
moreover
then interpret this_thread:
reachable_thread P t r s i "done" todo skipped
by unfold_locales auto
from step have "step \<in> set done"
by (rule this_thread.in_steps_in_done)
then obtain prefix suffix
where done_split: "done = prefix @ step # suffix \<and> step \<notin> set prefix"
by (auto dest!: split_list_first)
moreover
hence "takeWhile (\<lambda>x. x \<noteq> step) (prefix@step#suffix@todo) = prefix"
by (subst takeWhile_append2) auto
moreover
{ fix st st'
assume nextRel: "nextRel (step#rev (filter (\<lambda> x. \<not> (noteStep x)) prefix)) st' st"
hence in_nextRel: "st' \<in> set (step#rev (filter (\<lambda> x. \<not> (noteStep x)) prefix)) \<and>
st \<in> set (step#rev (filter (\<lambda> x. \<not> (noteStep x)) prefix))"
by(auto dest: in_set_nextRel1 in_set_nextRel2)
hence "st \<in> set done" and "st' \<in> set done"
using done_split step role_exists nextRel
by (auto dest: in_set_nextRel1 in_set_nextRel2 filtered_in_done)
hence "st \<in> set done \<and> st \<notin> skipped" and "st' \<in> set done \<and> st' \<notin> skipped"
using step in_nextRel
apply -
apply(rule conjI, assumption)
apply(case_tac "st = step")
apply(fastsimp dest: this_thread.in_steps_conv_done_skipped[THEN iffD1])
apply(fastsimp dest!: this_thread.note_in_skipped note_filtered_revRole)
apply(rule conjI, assumption)
apply(case_tac "st' = step")
apply(fastsimp dest: this_thread.in_steps_conv_done_skipped[THEN iffD1])
by(fastsimp dest!: this_thread.note_in_skipped note_filtered_revRole)
hence steps: "(i, st) \<in> steps t" "(i, st') \<in> steps t"
by(auto dest: this_thread.in_steps_conv_done_skipped[THEN iffD1])
{ assume "recvStep st" then
obtain l pt where "st = Recv l pt" by (cases st) auto
hence "\<exists> m. Some m = inst s i (stepPat st) \<and> Ln m \<prec> St (i, st)"
using steps by(auto intro!: Ln_before_inp)
}
note input = this
have "listOrd R st st'"
using nextRel and R_split and done_split
by(fastsimp dest: nextRel_imp_listOrd listOrd_rev[THEN iffD1] listOrd_filter)
hence "St (i, st) \<prec> St (i, st')"
using role_exists steps R_split
apply -
apply(drule this_thread.in_steps_conv_done_skipped[THEN iffD1])
by(fastsimp dest!: this_thread.roleOrd_notSkipped_imp_listOrd_trace dest:listOrd_imp_predOrd)+
note input and this
}
ultimately show ?thesis
by (auto simp: prefixClose_def)
qed
text{* Support for the "prefix\_close" command. *}
lemma ext_prefixClose:
"\<lbrakk> (i, step) \<in> steps t; roleMap r i = Some R \<rbrakk> \<Longrightarrow>
prefixClose s t R step i \<and>
(recvStep step \<longrightarrow> (\<exists> m. Some m = inst s i (stepPat step) \<and> Ln m \<prec> St (i, step)))"
by (cases step) (fastsimp intro!: prefixCloseI Ln_before_inp)+
text{*
Used for prefix closing assumptions corresponding to a case of
an annotation completeness induction proof.
*}
lemma thread_prefixClose:
assumes thread_exists: "r i = Some (step#done, todo, skipped)"
and not_skipped: "step \<notin> skipped"
shows
"(\<forall> st st'. nextRel (step # (filter (\<lambda> x. \<not> (noteStep x)) done)) st st' \<longrightarrow>
((recvStep st \<longrightarrow>
(\<exists> m. Some m = inst s i (stepPat st) \<and> predOrd t (Ln m) (St (i, st)))
) \<and>
predOrd t (St (i, st)) (St (i, st')))
) \<and>
(recvStep (last (step#done)) \<longrightarrow>
(\<exists> m. Some m = inst s i (stepPat (last (step#done))) \<and>
predOrd t (Ln m) (St (i, (last (step#done))))
)
)"
(is "?prefix \<and> ?inp_last")
proof -
interpret this_thread: reachable_thread P t r s i "step#done" todo skipped
using thread_exists by unfold_locales auto
{
assume recv: "recvStep (last (step#done))"
hence last_step: "(i, last (step#done)) \<in> steps t"
proof
obtain l pt
where recv_eq: "(Recv l pt) = (last (step # done))"
using recv by (fastsimp dest!: recvStepD)
hence "Recv l pt \<in> set (step # done)" by auto
thus ?thesis
using thread_exists recv_eq
by(fastsimp dest!: this_thread.in_steps_recv[THEN iffD1])
qed
hence "?inp_last"
by (cases "last (step # done)") (fastsimp dest!: Ln_before_inp)+
}
moreover
{
fix st st'
assume "nextRel (step # (filter (\<lambda> x. \<not> (noteStep x)) done)) st st'"
hence listOrd: "listOrd (step # [x\<leftarrow>done . \<not> noteStep x]) st st'"
by (auto dest: nextRel_imp_listOrd)
hence skipped: "st \<notin> skipped \<and> st' \<notin> skipped"
proof(cases "st = step \<and> st' \<in> set done \<and> \<not> noteStep st'")
case True
thus "?thesis" using listOrd not_skipped by (fastsimp dest: this_thread.note_in_skipped)
next
case False
note falseAsms = this
thus ?thesis using falseAsms listOrd
by (cases "listOrd [x\<leftarrow>done . \<not> noteStep x] st st'")
(auto simp add: dest: this_thread.note_in_skipped in_set_listOrd1 in_set_listOrd2 )
qed
hence "st \<notin> skipped" "st' \<notin> skipped" by auto
hence step_ord: "predOrd t (St (i, st)) (St (i, st'))"
proof(cases "st = step \<and> st' \<in> set [x\<leftarrow>done . \<not> noteStep x]")
case True
hence "st' \<in> set done" by auto
thus ?thesis using listOrd skipped True
apply -
apply(drule conjunct1,
drule_tac ?P = "st = step" and ?Q = "st' \<in> set done" in conjI,
assumption)
apply(drule_tac ?Q = "listOrd done st st'" and ?P = "st = step \<and> st' \<in> set done" in disjI1)
apply(drule listOrd.simps(2)[THEN iffD2])
by(fastsimp dest: listOrd_imp_predOrd this_thread.listOrd_done_imp_listOrd_trace)
next
case False
note assms = this
thus ?thesis
proof(cases "listOrd [x\<leftarrow>done . \<not> noteStep x] st st'")
case False
thus ?thesis using assms listOrd by auto
next
case True
thus ?thesis using assms listOrd skipped
apply -
apply(drule listOrd_filter)
apply(drule_tac ?Q = "listOrd done st st'" and ?P = "st = step \<and> st' \<in> set done" in disjI2)
apply(drule listOrd.simps(2)[THEN iffD2])
by (fastsimp dest: listOrd_imp_predOrd this_thread.listOrd_done_imp_listOrd_trace)
qed
qed
hence recv: "recvStep st \<Longrightarrow>
\<exists> m. Some m = inst s i (stepPat st) \<and> predOrd t (Ln m) (St (i, st))"
using this_thread.roleMap
by (cases st) (auto intro!: Ln_before_inp dest: in_steps_predOrd1)
note step_ord recv
}
ultimately
show ?thesis by fast
qed
end
text{*
TODO: Find the right place for this lemma. It is used only in
the "prefix\_close" command.
*}
lemma steps_in_steps: "(i,step) \<in> steps t \<Longrightarrow> (i,step) \<in> steps t"
by auto
subsection{* Additional Lemmas on Learning Messages *}
context reachable_state
begin
(* TODO: Move *)
lemma nothing_before_IK0: "m \<in> IK0 \<Longrightarrow> \<not> y \<prec> Ln m"
proof(induct arbitrary: y rule: reachable_induct)
case (send t r s i "done" l pt todo m y)
then interpret this_state: reachable_state P t r s by unfold_locales
show ?case using send
by(fastsimp dest: this_state.knows_IK0)
next
case (decr t r s m k y)
then interpret this_state: reachable_state P t r s by unfold_locales
show ?case using decr
by(fastsimp dest: this_state.knows_IK0)
next
case (lkr t r s a)
then interpret this_state: reachable_state P t r s by unfold_locales
show ?case using lkr
by(fastsimp dest: this_state.knows_IK0)
next
case (compr t r s "done" l ty pt todo skipped m y)
then interpret this_state: reachable_state P t r s by unfold_locales
show ?case using compr
by(fastsimp dest: this_state.knows_IK0)
qed auto
lemmas nothing_before_IK0_iffs [iff] = in_IK0_simps[THEN nothing_before_IK0]
end (* rechable_state *)
subsubsection{* Resoning about Variable Contents *}
context reachable_state
begin
lemma inst_AVar_ineqs [iff]:
"s (AVar v, i) \<noteq> Tup x y"
"s (AVar v, i) \<noteq> Enc m k"
"s (AVar v, i) \<noteq> Hash m"
"s (AVar v, i) \<noteq> PK a"
"s (AVar v, i) \<noteq> SK a"
"s (AVar v, i) \<noteq> K a b"
"s (AVar v, i) \<noteq> KShr A"
"s (AVar v, i) \<noteq> Lit (ENonce n i')"
"s (AVar v, i) \<noteq> Lit (EConst c)"
"s (AVar v, i) \<noteq> Lit (EveNonce n)"
by (insert inst_AVar_cases[of v i])
(auto simp: Agent_def)
declare inst_AVar_cases[iff]
declare inst_AVar_ineqs[symmetric, iff]
end
end