Theory Anonymity

(*  Title:       The Relational Method with Message Anonymity for the Verification of Cryptographic Protocols
    Author:      Pasquale Noce
                 Software Engineer at HID Global, Italy
                 pasquale dot noce dot lavoro at gmail dot com
                 pasquale dot noce at hidglobal dot com
*)

section "Anonymity properties"

theory Anonymity
  imports Authentication
begin

text ‹
\label{Anonymity}
›


proposition crypts_empty [simp]:
 "crypts {} = {}"
by (rule equalityI, rule subsetI, erule crypts.induct, simp_all)

proposition crypts_mono:
 "H ⊆ H' ⟹ crypts H ⊆ crypts H'"
by (rule subsetI, erule crypts.induct, auto)

lemma crypts_union_1:
 "crypts (H ∪ H') ⊆ crypts H ∪ crypts H'"
by (rule subsetI, erule crypts.induct, auto)

lemma crypts_union_2:
 "crypts H ∪ crypts H' ⊆ crypts (H ∪ H')"
by (rule subsetI, erule UnE, erule_tac [!] crypts.induct, auto)

proposition crypts_union:
 "crypts (H ∪ H') = crypts H ∪ crypts H'"
by (rule equalityI, rule crypts_union_1, rule crypts_union_2)

proposition crypts_insert:
 "crypts (insert X H) = crypts_msg X ∪ crypts H"
by (simp only: insert_def crypts_union, subst crypts_msg_def, simp)

proposition crypts_msg_num [simp]:
 "crypts_msg (Num n) = {Num n}"
by (subst crypts_msg_def, rule equalityI, rule subsetI, erule crypts.induct, simp,
 rotate_tac [1-3], erule_tac [1-3] rev_mp, rule_tac [1-3] list.induct, simp_all,
 blast)

proposition crypts_msg_agent [simp]:
 "crypts_msg (Agent n) = {Agent n}"
by (subst crypts_msg_def, rule equalityI, rule subsetI, erule crypts.induct, simp,
 rotate_tac [1-3], erule_tac [1-3] rev_mp, rule_tac [1-3] list.induct, simp_all,
 blast)

proposition crypts_msg_pwd [simp]:
 "crypts_msg (Pwd n) = {Pwd n}"
by (subst crypts_msg_def, rule equalityI, rule subsetI, erule crypts.induct, simp,
 rotate_tac [1-3], erule_tac [1-3] rev_mp, rule_tac [1-3] list.induct, simp_all,
 blast)

proposition crypts_msg_key [simp]:
 "crypts_msg (Key K) = {Key K}"
by (subst crypts_msg_def, rule equalityI, rule subsetI, erule crypts.induct, simp,
 rotate_tac [1-3], erule_tac [1-3] rev_mp, rule_tac [1-3] list.induct, simp_all,
 blast)

proposition crypts_msg_mult [simp]:
 "crypts_msg (A ⊗ B) = {A ⊗ B}"
by (subst crypts_msg_def, rule equalityI, rule subsetI, erule crypts.induct, simp,
 rotate_tac [1-3], erule_tac [1-3] rev_mp, rule_tac [1-3] list.induct, simp_all,
 blast)

lemma crypts_hash_1:
 "crypts {Hash X} ⊆ insert (Hash X) (crypts {X})"
by (rule subsetI, erule crypts.induct, simp_all, (erule disjE, rotate_tac, erule rev_mp,
 rule list.induct, simp_all, blast, (drule crypts_hash, simp)?)+)

lemma crypts_hash_2:
 "insert (Hash X) (crypts {X}) ⊆ crypts {Hash X}"
by (rule subsetI, simp, erule disjE, blast, erule crypts.induct, simp,
 subst id_apply [symmetric], subst foldr_Nil [symmetric], rule crypts_hash, simp,
 blast+)

proposition crypts_msg_hash [simp]:
 "crypts_msg (Hash X) = insert (Hash X) (crypts_msg X)"
by (simp add: crypts_msg_def, rule equalityI, rule crypts_hash_1, rule crypts_hash_2)

proposition crypts_comp:
 "X ∈ crypts H ⟹ Crypt K X ∈ crypts (Crypt K ` H)"
by (erule crypts.induct, blast, (simp only: comp_apply
 [symmetric, where f = "Crypt K"] foldr_Cons [symmetric],
 (erule crypts_hash | erule crypts_fst | erule crypts_snd))+)

lemma crypts_crypt_1:
 "crypts {Crypt K X} ⊆ Crypt K ` crypts {X}"
by (rule subsetI, erule crypts.induct, fastforce, rotate_tac [!], erule_tac [!] rev_mp,
 rule_tac [!] list.induct, auto)

lemma crypts_crypt_2:
 "Crypt K ` crypts {X} ⊆ crypts {Crypt K X}"
by (rule subsetI, simp add: image_iff, erule bexE, drule crypts_comp, simp)

proposition crypts_msg_crypt [simp]:
 "crypts_msg (Crypt K X) = Crypt K ` crypts_msg X"
by (simp add: crypts_msg_def, rule equalityI, rule crypts_crypt_1, rule crypts_crypt_2)

lemma crypts_mpair_1:
 "crypts {⦃X, Y⦄} ⊆ insert ⦃X, Y⦄ (crypts {X} ∪ crypts {Y})"
by (rule subsetI, erule crypts.induct, simp_all, (erule disjE, rotate_tac, erule rev_mp,
 rule list.induct, (simp+, blast)+)+)

lemma crypts_mpair_2:
 "insert ⦃X, Y⦄ (crypts {X} ∪ crypts {Y}) ⊆ crypts {⦃X, Y⦄}"
by (rule subsetI, simp, erule disjE, blast, erule disjE, (erule crypts.induct, simp,
 subst id_apply [symmetric], subst foldr_Nil [symmetric], (rule crypts_fst [of _ X] |
 rule crypts_snd), rule crypts_used, simp, blast+)+)

proposition crypts_msg_mpair [simp]:
 "crypts_msg ⦃X, Y⦄ = insert ⦃X, Y⦄ (crypts_msg X ∪ crypts_msg Y)"
by (simp add: crypts_msg_def, rule equalityI, rule crypts_mpair_1, rule crypts_mpair_2)


proposition foldr_crypt_size:
 "size (foldr Crypt KS X) = size X + length KS"
by (induction KS, simp_all)

proposition key_sets_empty [simp]:
 "key_sets X {} = {}"
by (simp add: key_sets_def)

proposition key_sets_mono:
 "H ⊆ H' ⟹ key_sets X H ⊆ key_sets X H'"
by (auto simp add: key_sets_def)

proposition key_sets_union:
 "key_sets X (H ∪ H') = key_sets X H ∪ key_sets X H'"
by (auto simp add: key_sets_def)

proposition key_sets_insert:
 "key_sets X (insert Y H) = key_sets_msg X Y ∪ key_sets X H"
by (simp only: insert_def key_sets_union, subst key_sets_msg_def, simp)

proposition key_sets_msg_eq:
 "key_sets_msg X X = {{}}"
by (simp add: key_sets_msg_def key_sets_def, rule equalityI, rule subsetI, simp,
 erule exE, erule rev_mp, rule list.induct, simp, rule impI, erule conjE,
 drule arg_cong [of _ X size], simp_all add: foldr_crypt_size)

proposition key_sets_msg_num [simp]:
 "key_sets_msg X (Num n) = (if X = Num n then {{}} else {})"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def key_sets_def, rule impI,
 rule allI, rule list.induct, simp_all)

proposition key_sets_msg_agent [simp]:
 "key_sets_msg X (Agent n) = (if X = Agent n then {{}} else {})"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def key_sets_def, rule impI,
 rule allI, rule list.induct, simp_all)

proposition key_sets_msg_pwd [simp]:
 "key_sets_msg X (Pwd n) = (if X = Pwd n then {{}} else {})"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def key_sets_def, rule impI,
 rule allI, rule list.induct, simp_all)

proposition key_sets_msg_key [simp]:
 "key_sets_msg X (Key K) = (if X = Key K then {{}} else {})"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def key_sets_def, rule impI,
 rule allI, rule list.induct, simp_all)

proposition key_sets_msg_mult [simp]:
 "key_sets_msg X (A ⊗ B) = (if X = A ⊗ B then {{}} else {})"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def key_sets_def, rule impI,
 rule allI, rule list.induct, simp_all)

proposition key_sets_msg_hash [simp]:
 "key_sets_msg X (Hash Y) = (if X = Hash Y then {{}} else {})"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def key_sets_def, rule impI,
 rule allI, rule list.induct, simp_all)

lemma key_sets_crypt_1:
 "X ≠ Crypt K Y ⟹
    key_sets X {Crypt K Y} ⊆ insert (InvKey K) ` key_sets X {Y}"
by (rule subsetI, simp add: key_sets_def, erule exE, rotate_tac, erule rev_mp,
 rule list.induct, auto)

lemma key_sets_crypt_2:
 "insert (InvKey K) ` key_sets X {Y} ⊆ key_sets X {Crypt K Y}"
by (rule subsetI, simp add: key_sets_def image_iff, (erule exE, erule conjE)+,
 drule arg_cong [where f = "Crypt K"], simp only: comp_apply
 [symmetric, of "Crypt K"] foldr_Cons [symmetric], subst conj_commute,
 rule exI, rule conjI, assumption, simp)

proposition key_sets_msg_crypt [simp]:
 "key_sets_msg X (Crypt K Y) = (if X = Crypt K Y then {{}} else
    insert (InvKey K) ` key_sets_msg X Y)"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def, rule impI,
 rule equalityI, erule key_sets_crypt_1 [simplified],
 rule key_sets_crypt_2 [simplified])

proposition key_sets_msg_mpair [simp]:
 "key_sets_msg X ⦃Y, Z⦄ = (if X = ⦃Y, Z⦄ then {{}} else {})"
by (simp add: key_sets_msg_eq, simp add: key_sets_msg_def key_sets_def, rule impI,
 rule allI, rule list.induct, simp_all)

proposition key_sets_range:
 "U ∈ key_sets X H ⟹ U ⊆ range Key"
by (simp add: key_sets_def, blast)

proposition key_sets_crypts_hash:
 "key_sets (Hash X) (crypts H) ⊆ key_sets X (crypts H)"
by (simp add: key_sets_def, blast)

proposition key_sets_crypts_fst:
 "key_sets ⦃X, Y⦄ (crypts H) ⊆ key_sets X (crypts H)"
by (simp add: key_sets_def, blast)

proposition key_sets_crypts_snd:
 "key_sets ⦃X, Y⦄ (crypts H) ⊆ key_sets Y (crypts H)"
by (simp add: key_sets_def, blast)


lemma log_spied_1:
 "⟦s ⊢ s';
    Log X ∈ parts (used s) ⟶ Log X ∈ spied s;
    Log X ∈ parts (used s')⟧ ⟹
  Log X ∈ spied s'"
by (simp add: rel_def, ((erule disjE)?, ((erule exE)+)?, simp add: parts_insert,
 ((subst (asm) disj_assoc [symmetric])?, erule disjE, (drule parts_dec |
 drule parts_enc | drule parts_sep | drule parts_con), simp+)?)+)

proposition log_spied [rule_format]:
 "s0 ⊨ s ⟹
    Log X ∈ parts (used s) ⟶
  Log X ∈ spied s"
by (erule rtrancl_induct, subst parts_init, simp add: Range_iff image_def, rule impI,
 rule log_spied_1)


proposition log_dec:
 "⟦s0 ⊨ s; s' = insert (Spy, X) s ∧ (Spy, Crypt K X) ∈ s ∧
    (Spy, Key (InvK K)) ∈ s⟧ ⟹
  key_sets Y (crypts {Y. Log Y = X}) ⊆ key_sets Y (crypts (Log -` spied s))"
by (rule key_sets_mono, rule crypts_mono, rule subsetI, simp, drule parts_dec
 [where Y = X], drule_tac [!] sym, simp_all, rule log_spied [simplified])

proposition log_sep:
 "⟦s0 ⊨ s; s' = insert (Spy, X) (insert (Spy, Y) s) ∧ (Spy, ⦃X, Y⦄) ∈ s⟧ ⟹
    key_sets Z (crypts {Z. Log Z = X}) ⊆ key_sets Z (crypts (Log -` spied s)) ∧
    key_sets Z (crypts {Z. Log Z = Y}) ⊆ key_sets Z (crypts (Log -` spied s))"
by (rule conjI, (rule key_sets_mono, rule crypts_mono, rule subsetI, simp,
 frule parts_sep [where Z = X], drule_tac [2] parts_sep [where Z = Y],
 simp_all add: parts_msg_def, blast+, drule sym, simp,
 rule log_spied [simplified], assumption+)+)


lemma idinfo_spied_1:
 "⟦s ⊢ s';
    ⟨n, X⟩ ∈ parts (used s) ⟶ ⟨n, X⟩ ∈ spied s;
    ⟨n, X⟩ ∈ parts (used s')⟧ ⟹
  ⟨n, X⟩ ∈ spied s'"
by (simp add: rel_def, (erule disjE, (erule exE)+, simp add: parts_insert,
 ((subst (asm) disj_assoc [symmetric])?, erule disjE, (drule parts_dec |
 drule parts_enc | drule parts_sep | drule parts_con), simp+)?)+,
 auto simp add: parts_insert)

proposition idinfo_spied [rule_format]:
 "s0 ⊨ s ⟹
    ⟨n, X⟩ ∈ parts (used s) ⟶
  ⟨n, X⟩ ∈ spied s"
by (erule rtrancl_induct, subst parts_init, simp add: Range_iff image_def, rule impI,
 rule idinfo_spied_1)


proposition idinfo_dec:
 "⟦s0 ⊨ s; s' = insert (Spy, X) s ∧ (Spy, Crypt K X) ∈ s ∧
    (Spy, Key (InvK K)) ∈ s; ⟨n, Y⟩ = X⟧ ⟹
  ⟨n, Y⟩ ∈ spied s"
by (drule parts_dec [where Y = "⟨n, Y⟩"], drule sym, simp, rule idinfo_spied)

proposition idinfo_sep:
 "⟦s0 ⊨ s; s' = insert (Spy, X) (insert (Spy, Y) s) ∧ (Spy, ⦃X, Y⦄) ∈ s;
    ⟨n, Z⟩ = X ∨ ⟨n, Z⟩ = Y⟧ ⟹
  ⟨n, Z⟩ ∈ spied s"
by (drule parts_sep [where Z = "⟨n, Z⟩"], erule disjE, (drule sym, simp)+,
 rule idinfo_spied)


lemma idinfo_msg_1:
  assumes A: "s0 ⊨ s"
  shows "⟦s ⊢ s'; ⟨n, X⟩ ∈ spied s ⟶ X ∈ spied s; ⟨n, X⟩ ∈ spied s'⟧ ⟹
    X ∈ spied s'"
by (simp add: rel_def, (erule disjE, (erule exE)+, simp, ((subst (asm) disj_assoc
 [symmetric])?, erule disjE, (drule idinfo_dec [OF A] | drule idinfo_sep [OF A]),
 simp+ | erule disjE, (simp add: image_iff)+, blast?)?)+)

proposition idinfo_msg [rule_format]:
 "s0 ⊨ s ⟹
    ⟨n, X⟩ ∈ spied s ⟶
  X ∈ spied s"
by (erule rtrancl_induct, simp, blast, rule impI, rule idinfo_msg_1)


proposition parts_agent_start:
 "⟦s ⊢ s'; Agent n ∈ parts (used s'); Agent n ∉ parts (used s)⟧ ⟹ False"
by (simp add: rel_def, (((erule disjE)?, ((erule exE)+)?, simp add: parts_insert
 image_iff)+, ((drule parts_dec | drule parts_enc | drule parts_sep | drule parts_con),
 simp+)?)+)

proposition parts_agent [rotated]:
  assumes A: "n ∉ bad_agent"
  shows "s0 ⊨ s ⟹ Agent n ∉ parts (used s)"
by (rule notI, drule rtrancl_start, assumption, subst parts_init, simp add:
 Range_iff image_def A, (erule exE)+, (erule conjE)+, drule parts_agent_start)


lemma idinfo_init_1 [rule_format]:
  assumes A: "s0 ⊨ s"
  shows "⟦s ⊢ s'; n ∉ bad_id_password ∪ bad_id_pubkey ∪ bad_id_shakey;
    ∀X. ⟨n, X⟩ ∉ spied s⟧ ⟹
  ⟨n, X⟩ ∉ spied s'"
by (rule notI, simp add: rel_def, ((erule disjE)?, (erule exE)+, (blast | simp,
 ((drule idinfo_dec [OF A] | drule idinfo_sep [OF A]), simp, blast |
 (erule conjE)+, drule parts_agent [OF A], blast))?)+)

proposition idinfo_init:
 "⟦s0 ⊨ s; n ∉ bad_id_password ∪ bad_id_pubkey ∪ bad_id_shakey⟧ ⟹
  ⟨n, X⟩ ∉ spied s"
by (induction arbitrary: X rule: rtrancl_induct, simp add: image_def, blast,
 rule idinfo_init_1)


lemma idinfo_mpair_1 [rule_format]:
 "⟦(s, s') ∈ rel_id_hash ∪ rel_id_crypt ∪ rel_id_sep ∪ rel_id_con;
    ∀X Y. ⟨n, ⦃X, Y⦄⟩ ∈ spied s ⟶
      key_sets ⦃X, Y⦄ (crypts (Log -` spied s)) ≠ {};
    ⟨n, ⦃X, Y⦄⟩ ∈ spied s'⟧ ⟹
  key_sets ⦃X, Y⦄ (crypts (Log -` spied s')) ≠ {}"
by ((erule disjE)?, clarify?, simp add: image_iff Image_def, (drule subsetD
 [OF key_sets_crypts_hash] | drule key_sets_range, blast | (drule spec)+,
 drule mp, simp, simp add: ex_in_conv [symmetric], erule exE, frule subsetD
 [OF key_sets_crypts_fst], drule subsetD [OF key_sets_crypts_snd])?)+

lemma idinfo_mpair_2 [rule_format]:
  assumes A: "s0 ⊨ s"
  shows "⟦s ⊢ s'; (s, s') ∉ rel_id_hash ∪ rel_id_crypt ∪ rel_id_sep ∪ rel_id_con;
    ∀X Y. ⟨n, ⦃X, Y⦄⟩ ∈ spied s ⟶
      key_sets ⦃X, Y⦄ (crypts (Log -` spied s)) ≠ {};
    ⟨n, ⦃X, Y⦄⟩ ∈ spied s'⟧ ⟹
  key_sets ⦃X, Y⦄ (crypts (Log -` spied s')) ≠ {}"
by (simp only: rel_def Un_iff de_Morgan_disj, simp, ((erule disjE)?, (erule exE)+,
 simp add: Image_def, (simp only: Collect_disj_eq crypts_union key_sets_union, simp)?,
 ((subst (asm) disj_assoc [symmetric])?, erule disjE, (drule idinfo_dec [OF A] |
 drule idinfo_sep [OF A]), simp+)?)+)

proposition idinfo_mpair [rule_format]:
 "s0 ⊨ s ⟹
    ⟨n, ⦃X, Y⦄⟩ ∈ spied s ⟶
  key_sets ⦃X, Y⦄ (crypts (Log -` spied s)) ≠ {}"
proof (induction arbitrary: X Y rule: rtrancl_induct, simp add: image_def,
 rule impI)
  fix s s' X Y
  assume
   "s0 ⊨ s" and
   "s ⊢ s'" and
   "⋀X Y. ⟨n, ⦃X, Y⦄⟩ ∈ spied s ⟶
      key_sets ⦃X, Y⦄ (crypts (Log -` spied s)) ≠ {}" and
   "⟨n, ⦃X, Y⦄⟩ ∈ spied s'"
  thus "key_sets ⦃X, Y⦄ (crypts (Log -` spied s')) ≠ {}"
    by (cases "(s, s') ∈ rel_id_hash ∪ rel_id_crypt ∪ rel_id_sep ∪ rel_id_con",
     erule_tac [2] idinfo_mpair_2, erule_tac idinfo_mpair_1, simp_all)
qed


proposition key_sets_pwd_empty:
 "s0 ⊨ s ⟹
    key_sets (Hash (Pwd n)) (crypts (Log -` spied s)) = {} ∧
    key_sets ⦃Pwd n, X⦄ (crypts (Log -` spied s)) = {} ∧
    key_sets ⦃X, Pwd n⦄ (crypts (Log -` spied s)) = {}"
  (is "_ ⟹ key_sets ?X (?H s) = _ ∧ key_sets ?Y _ = _ ∧ key_sets ?Z _ = _")
proof (erule rtrancl_induct, simp add: image_iff Image_def)
  fix s s'
  assume
    A: "s0 ⊨ s" and
    B: "s ⊢ s'" and
    C: "key_sets (Hash (Pwd n)) (?H s) = {} ∧
      key_sets ⦃Pwd n, X⦄ (?H s) = {} ∧
      key_sets ⦃X, Pwd n⦄ (?H s) = {}"
  show "key_sets (Hash (Pwd n)) (?H s') = {} ∧
    key_sets ⦃Pwd n, X⦄ (?H s') = {} ∧
    key_sets ⦃X, Pwd n⦄ (?H s') = {}"
    by (insert B C, simp add: rel_def, ((erule disjE)?, ((erule exE)+)?, simp add:
     image_iff Image_def, (simp only: Collect_disj_eq crypts_union
     key_sets_union, simp add: crypts_insert key_sets_insert)?,
     (frule log_dec [OF A, where Y = "?X"],
     frule log_dec [OF A, where Y = "?Y"], drule log_dec [OF A, where Y = "?Z"] |
     frule log_sep [OF A, where Z = "?X"], frule log_sep [OF A, where Z = "?Y"],
     drule log_sep [OF A, where Z = "?Z"])?)+)
qed

proposition key_sets_pwd_seskey [rule_format]:
 "s0 ⊨ s ⟹
    U ∈ key_sets (Pwd n) (crypts (Log -` spied s)) ⟶
  (∃SK. U = {SesKey SK} ∧
    ((Owner n, Crypt (SesK SK) (Pwd n)) ∈ s ∨
     (Asset n, Crypt (SesK SK) (Num 0)) ∈ s))"
  (is "_ ⟹ _ ⟶ ?P s")
proof (erule rtrancl_induct, simp add: image_iff Image_def, rule impI)
  fix s s'
  assume
    A: "s0 ⊨ s" and
    B: "s ⊢ s'" and
    C: "U ∈ key_sets (Pwd n) (crypts (Log -` spied s)) ⟶ ?P s" and
    D: "U ∈ key_sets (Pwd n) (crypts (Log -` spied s'))"
  show "?P s'"
    by (insert B C D, simp add: rel_def, ((erule disjE)?, ((erule exE)+)?, simp
     add: image_iff Image_def, (simp only: Collect_disj_eq crypts_union
     key_sets_union, simp add: crypts_insert key_sets_insert split: if_split_asm,
     blast?)?, (erule disjE, (drule log_dec [OF A] | drule log_sep [OF A]),
     (erule conjE)?, drule subsetD, simp)?)+)
qed


lemma pwd_anonymous_1 [rule_format]:
 "⟦s0 ⊨ s; n ∉ bad_id_password⟧ ⟹
    ⟨n, Pwd n⟩ ∈ spied s ⟶
  (∃SK. SesKey SK ∈ spied s ∧
    ((Owner n, Crypt (SesK SK) (Pwd n)) ∈ s ∨
     (Asset n, Crypt (SesK SK) (Num 0)) ∈ s))"
  (is "⟦_; _⟧ ⟹ _ ⟶ ?P s")
proof (erule rtrancl_induct, simp add: image_def, rule impI)
  fix s s'
  assume
    A: "s0 ⊨ s" and
    B: "s ⊢ s'" and
    C: "⟨n, Pwd n⟩ ∈ spied s ⟶ ?P s" and
    D: "⟨n, Pwd n⟩ ∈ spied s'"
  show "?P s'"
    by (insert B C D, simp add: rel_def, ((erule disjE)?, (erule exE)+, simp add:
     image_iff, blast?, ((subst (asm) disj_assoc [symmetric])?, erule disjE,
     (drule idinfo_dec [OF A] | drule idinfo_sep [OF A]), simp, blast+ |
     insert key_sets_pwd_empty [OF A], clarsimp)?, (((erule disjE)?, erule
     conjE, drule sym, simp, (drule key_sets_pwd_seskey [OF A] | drule
     idinfo_mpair [OF A, simplified]), simp)+ | drule key_sets_range, blast)?)+)
qed

theorem pwd_anonymous:
  assumes
    A: "s0 ⊨ s" and
    B: "n ∉ bad_id_password" and
    C: "n ∉ bad_shakey ∩ (bad_pwd ∪ bad_prikey) ∩ (bad_id_pubkey ∪ bad_id_shak)"
  shows "⟨n, Pwd n⟩ ∉ spied s"
proof
  assume D: "⟨n, Pwd n⟩ ∈ spied s"
  hence "n ∈ bad_id_password ∪ bad_id_pubkey ∪ bad_id_shakey"
    by (rule contrapos_pp, rule_tac idinfo_init [OF A])
  moreover have "∃SK. SesKey SK ∈ spied s ∧
    ((Owner n, Crypt (SesK SK) (Pwd n)) ∈ s ∨
     (Asset n, Crypt (SesK SK) (Num 0)) ∈ s)"
    (is "∃SK. ?P SK ∧ (?Q SK ∨ ?R SK)")
    by (rule pwd_anonymous_1 [OF A B D])
  then obtain SK where "?P SK" and "?Q SK ∨ ?R SK" by blast
  moreover {
    assume "?Q SK"
    hence "n ∈ bad_shakey ∩ bad_prikey"
      by (rule_tac contrapos_pp [OF ‹?P SK›], rule_tac owner_seskey_secret [OF A])
  }
  moreover {
    assume "?R SK"
    hence "n ∈ bad_shakey ∩ (bad_pwd ∪ bad_prikey)"
      by (rule_tac contrapos_pp [OF ‹?P SK›], rule_tac asset_seskey_secret [OF A])
  }
  ultimately show False
    using B and C by blast
qed


proposition idinfo_pwd_start:
  assumes
    A: "s0 ⊨ s" and
    B: "n ∉ bad_agent"
  shows "⟦s ⊢ s'; ∃X. ⟨n, X⟩ ∈ spied s' ∧ X ≠ Pwd n;
    ¬ (∃X. ⟨n, X⟩ ∈ spied s ∧ X ≠ Pwd n)⟧ ⟹
      ∃SK. SesKey SK ∈ spied s ∧
        ((Owner n, Crypt (SesK SK) (Pwd n)) ∈ s ∨
         (Asset n, Crypt (SesK SK) (Num 0)) ∈ s)"
proof (simp add: rel_def, insert parts_agent [OF A B], insert key_sets_pwd_empty
 [OF A], (erule disjE, (erule exE)+, simp, erule conjE, (subst (asm) disj_assoc
 [symmetric])?, (erule disjE)?, (drule idinfo_dec [OF A] | drule idinfo_sep
 [OF A] | drule spec, drule mp), simp+)+, auto, rule FalseE, rule_tac [3] FalseE)
  fix X U K
  assume "∀X. (Spy, ⟨n, X⟩) ∈ s ⟶ X = Pwd n" and "(Spy, ⟨n, K⟩) ∈ s"
  hence "K = Pwd n" by simp
  moreover assume "U ∈ key_sets X (crypts (Log -` spied s))"
  hence "U ⊆ range Key"
    by (rule key_sets_range)
  moreover assume "K ∈ U"
  ultimately show False by blast
next
  fix X U
  assume "∀X. (Spy, ⟨n, X⟩) ∈ s ⟶ X = Pwd n" and "(Spy, ⟨n, X⟩) ∈ s"
  hence C: "X = Pwd n" by simp
  moreover assume "U ∈ key_sets X (crypts (Log -` spied s))"
  ultimately have "U ∈ key_sets (Pwd n) (crypts (Log -` spied s))" by simp
  hence "∃SK. U = {SesKey SK} ∧
    ((Owner n, Crypt (SesK SK) (Pwd n)) ∈ s ∨
     (Asset n, Crypt (SesK SK) (Num 0)) ∈ s)"
    by (rule key_sets_pwd_seskey [OF A])
  moreover assume "U ⊆ spied s"
  ultimately show "∃x U V. (Spy, Key (SesK (x, U, V))) ∈ s ∧
    ((Owner n, Crypt (SesK (x, U, V)) X) ∈ s ∨
     (Asset n, Crypt (SesK (x, U, V)) (Num 0)) ∈ s)"
    using C by auto
next
  fix X U K
  assume "∀X. (Spy, ⟨n, X⟩) ∈ s ⟶ X = Pwd n" and "(Spy, ⟨n, K⟩) ∈ s"
  hence "K = Pwd n" by simp
  moreover assume "U ∈ key_sets X (crypts (Log -` spied s))"
  hence "U ⊆ range Key"
    by (rule key_sets_range)
  moreover assume "K ∈ U"
  ultimately show False by blast
qed

proposition idinfo_pwd:
 "⟦s0 ⊨ s; ∃X. ⟨n, X⟩ ∈ spied s ∧ X ≠ Pwd n;
    n ∉ bad_id_pubkey ∪ bad_id_shakey⟧ ⟹
  ∃SK. SesKey SK ∈ spied s ∧
    ((Owner n, Crypt (SesK SK) (Pwd n)) ∈ s ∨
     (Asset n, Crypt (SesK SK) (Num 0)) ∈ s)"
by (drule rtrancl_start, assumption, simp, blast, (erule exE)+, (erule conjE)+,
 frule idinfo_pwd_start [of _ n], simp+, drule r_into_rtrancl, drule rtrancl_trans,
 assumption, (drule state_subset)+, blast)


theorem auth_prikey_anonymous:
  assumes
    A: "s0 ⊨ s" and
    B: "n ∉ bad_id_prikey" and
    C: "n ∉ bad_shakey ∩ bad_prikey ∩ (bad_id_password ∪ bad_id_shak)"
  shows "⟨n, Auth_PriKey n⟩ ∉ spied s"
proof
  assume D: "⟨n, Auth_PriKey n⟩ ∈ spied s"
  hence "n ∈ bad_id_password ∪ bad_id_pubkey ∪ bad_id_shakey"
    by (rule contrapos_pp, rule_tac idinfo_init [OF A])
  moreover have "Auth_PriKey n ∈ spied s"
    by (rule idinfo_msg [OF A D])
  hence "n ∈ bad_prikey"
    by (rule contrapos_pp, rule_tac auth_prikey_secret [OF A])
  moreover from this have E: "n ∉ bad_id_pubkey"
    using B by simp
  moreover have "n ∈ bad_shakey"
  proof (cases "n ∈ bad_id_shakey", simp)
    case False
    with D and E have "∃SK. SesKey SK ∈ spied s ∧
      ((Owner n, Crypt (SesK SK) (Pwd n)) ∈ s ∨
       (Asset n, Crypt (SesK SK) (Num 0)) ∈ s)"
      (is "∃SK. ?P SK ∧ (?Q SK ∨ ?R SK)")
      by (rule_tac idinfo_pwd [OF A], rule_tac exI [of _ "Auth_PriKey n"], simp_all)
    then obtain SK where "?P SK" and "?Q SK ∨ ?R SK" by blast
    moreover {
      assume "?Q SK"
      hence "n ∈ bad_shakey ∩ bad_prikey"
        by (rule_tac contrapos_pp [OF ‹?P SK›], rule_tac owner_seskey_secret
         [OF A])
    }
    moreover {
      assume "?R SK"
      hence "n ∈ bad_shakey ∩ (bad_pwd ∪ bad_prikey)"
        by (rule_tac contrapos_pp [OF ‹?P SK›], rule_tac asset_seskey_secret
         [OF A])
    }
    ultimately show ?thesis by blast
  qed
  ultimately show False
    using C by blast
qed


theorem auth_shakey_anonymous:
  assumes
    A: "s0 ⊨ s" and
    B: "n ∉ bad_id_shakey" and
    C: "n ∉ bad_shakey ∩ (bad_id_password ∪ bad_id_pubkey)"
  shows "⟨n, Key (Auth_ShaKey n)⟩ ∉ spied s"
proof
  assume D: "⟨n, Key (Auth_ShaKey n)⟩ ∈ spied s"
  hence "n ∈ bad_id_password ∪ bad_id_pubkey ∪ bad_id_shakey"
    by (rule contrapos_pp, rule_tac idinfo_init [OF A])
  moreover have "Key (Auth_ShaKey n) ∈ spied s"
    by (rule idinfo_msg [OF A D])
  hence "n ∈ bad_shakey"
    by (rule contrapos_pp, rule_tac auth_shakey_secret [OF A])
  ultimately show False
    using B and C by blast
qed

end