(* Title: HOL/Metis_Examples/Message.thy Author: Lawrence C. Paulson, Cambridge University Computer Laboratory Author: Jasmin Blanchette, TU Muenchen Metis example featuring message authentication. *)
section‹Metis Example Featuring Message Authentication›
theory Message imports Main begin
declare [[metis_new_skolem]]
lemma strange_Un_eq [simp]: "A ∪ (B ∪ A) = B ∪ A" by (metis Un_commute Un_left_absorb)
type_synonym key = nat
consts
all_symmetric :: bool 🍋‹true if all keys are symmetric›
invKey :: "key=>key"🍋‹inverse of a symmetric key›
text‹Concrete syntax: messages appear as ‹{A,B,NA}›, etc...› syntax "_MTuple" :: "['a, args] ==> 'a * 'b" (‹(‹indent=2 notation=‹mixfix message tuple›\›\{_,/ _})›)
syntax_consts "_MTuple"⇌ MPair translations "{x, y, z}"⇌"{x, {y, z}}" "{x, y}"⇌"CONST MPair x y"
definition HPair :: "[msg,msg] => msg" (‹(4Hash[_] /_)› [0, 1000]) where 🍋‹Message Y paired with a MAC computed with the help of X› "Hash[X] Y == { Hash{X,Y}, Y}"
definition keysFor :: "msg set => key set"where 🍋‹Keys useful to decrypt elements of a message set› "keysFor H == invKey ` {K. ∃X. Crypt K X ∈ H}"
subsubsection‹Inductive Definition of All Parts" of a Message›
inductive_set
parts :: "msg set => msg set" for H :: "msg set" where
Inj [intro]: "X ∈ H ==> X ∈ parts H"
| Fst: "{X,Y}∈ parts H ==> X ∈ parts H"
| Snd: "{X,Y}∈ parts H ==> Y ∈ parts H"
| Body: "Crypt K X ∈ parts H ==> X ∈ parts H"
lemma parts_mono: "G ⊆ H ==> parts(G) ⊆ parts(H)" apply auto apply (erule parts.induct) apply (metis parts.Inj rev_subsetD) apply (metis parts.Fst) apply (metis parts.Snd) by (metis parts.Body)
text‹Equations hold because constructors are injective.› lemma Friend_image_eq [simp]: "(Friend x ∈ Friend`A) = (x∈A)" by (metis agent.inject image_iff)
lemma Key_image_eq [simp]: "(Key x ∈ Key`A) = (x ∈ A)" by (metis image_iff msg.inject(4))
lemma Nonce_Key_image_eq [simp]: "Nonce x ∉ Key`A" by (metis image_iff msg.distinct(23))
subsubsection‹Inverse of keys›
lemma invKey_eq [simp]: "(invKey K = invKey K') = (K = K')" by (metis invKey)
lemma Crypt_imp_invKey_keysFor: "Crypt K X ∈ H ==> invKey K ∈ keysFor H" by (unfold keysFor_def, blast)
subsection‹Inductive relation "parts"›
lemma MPair_parts: "[| {X,Y}∈ parts H; [| X ∈ parts H; Y ∈ parts H |] ==> P |] ==> P" by (blast dest: parts.Fst parts.Snd)
declare MPair_parts [elim!] parts.Body [dest!] text‹NB These two rules are UNSAFE in the formal sense, as they discard the compound message. They work well on THIS FILE. ‹MPair_parts›is left as SAFE because it speeds up proofs. The Crypt rule is normally kept UNSAFE to avoid breaking up certificates.›
lemma parts_increasing: "H ⊆ parts(H)" by blast
lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD]
lemma parts_emptyE [elim!]: "X∈ parts{} ==> P" by simp
text‹WARNING: loops if H = {Y}, therefore must not be repeated!› lemma parts_singleton: "X∈ parts H ==> ∃Y∈H. X∈ parts {Y}" apply (erule parts.induct) apply fast+ done
lemma parts_insert: "parts (insert X H) = parts {X} ∪ parts H" apply (subst insert_is_Un [of _ H]) apply (simp only: parts_Un) done
lemma parts_insert2: "parts (insert X (insert Y H)) = parts {X} ∪ parts {Y} ∪ parts H" by (metis Un_commute Un_empty_left Un_empty_right Un_insert_left Un_insert_right parts_Un)
lemma parts_UN_subset1: "(∪x∈A. parts(H x)) ⊆ parts(∪x∈A. H x)" by (intro UN_least parts_mono UN_upper)
text‹Inductive definition of "analz" -- what can be broken down from a set of messages, including keys. A form of downward closure. Pairs can be taken apart; messages decrypted with known keys.›
inductive_set
analz :: "msg set => msg set" for H :: "msg set" where
Inj [intro,simp] : "X ∈ H ==> X ∈ analz H"
| Fst: "{X,Y}∈ analz H ==> X ∈ analz H"
| Snd: "{X,Y}∈ analz H ==> Y ∈ analz H"
| Decrypt [dest]: "[|Crypt K X ∈ analz H; Key(invKey K) ∈ analz H|] ==> X ∈ analz H"
text‹Making it safe speeds up proofs› lemma MPair_analz [elim!]: "[| {X,Y}∈ analz H; [| X ∈ analz H; Y ∈ analz H |] ==> P |] ==> P" by (blast dest: analz.Fst analz.Snd)
lemma analz_increasing: "H ⊆ analz(H)" by blast
lemma analz_subset_parts: "analz H ⊆ parts H" apply (rule subsetI) apply (erule analz.induct, blast+) done
text‹Converse fails: we can analz more from the union than from the separate parts, as a key in one might decrypt a message in the other› lemma analz_Un: "analz(G) ∪ analz(H) ⊆ analz(G ∪ H)" by (intro Un_least analz_mono Un_upper1 Un_upper2)
lemma analz_insert: "insert X (analz H) ⊆ analz(insert X H)" by (blast intro: analz_mono [THEN [2] rev_subsetD])
subsubsection‹Rewrite rules for pulling out atomic messages›
text‹Can pull out enCrypted message if the Key is not known› lemma analz_insert_Crypt: "Key (invKey K) ∉ analz H ==> analz (insert (Crypt K X) H) = insert (Crypt K X) (analz H)" apply (rule analz_insert_eq_I) apply (erule analz.induct, auto)
done
lemma lemma1: "Key (invKey K) ∈ analz H ==> analz (insert (Crypt K X) H) ⊆ insert (Crypt K X) (analz (insert X H))" apply (rule subsetI) apply (erule_tac x = x in analz.induct, auto) done
lemma lemma2: "Key (invKey K) ∈ analz H ==> insert (Crypt K X) (analz (insert X H)) ⊆ analz (insert (Crypt K X) H)" apply auto apply (erule_tac x = x in analz.induct, auto) apply (blast intro: analz_insertI analz.Decrypt) done
lemma analz_insert_Decrypt: "Key (invKey K) ∈ analz H ==> analz (insert (Crypt K X) H) = insert (Crypt K X) (analz (insert X H))" by (intro equalityI lemma1 lemma2)
text‹Case analysis: either the message is secure, or it is not! Effective, but can cause subgoals to blow up! Use with ‹if_split›; apparently ‹split_tac›does not cope with patterns such as 🍋‹analz (insert (Crypt K X) H)›\ lemma analz_Crypt_if [simp]: "analz (insert (Crypt K X) H) = (if (Key (invKey K) ∈ analz H) then insert (Crypt K X) (analz (insert X H)) else insert (Crypt K X) (analz H))" by (simp add: analz_insert_Crypt analz_insert_Decrypt) text‹This rule supposes "for the sake of argument" that we have the key.› lemma analz_insert_Crypt_subset: "analz (insert (Crypt K X) H) ⊆ insert (Crypt K X) (analz (insert X H))" apply (rule subsetI) apply (erule analz.induct, auto) done lemma analz_image_Key [simp]: "analz (Key`N) = Key`N" apply auto apply (erule analz.induct, auto) done subsubsection‹Idempotence and transitivity› lemma analz_analzD [dest!]: "X∈ analz (analz H) ==> X∈ analz H" by (erule analz.induct, blast+) lemma analz_idem [simp]: "analz (analz H) = analz H" by blast lemma analz_subset_iff [simp]: "(analz G ⊆ analz H) = (G ⊆ analz H)" apply (rule iffI) apply (iprover intro: subset_trans analz_increasing) apply (frule analz_mono, simp) done lemma analz_trans: "[| X∈ analz G; G ⊆ analz H |] ==> X∈ analz H" by (drule analz_mono, blast) declare analz_trans[intro] lemma analz_cut: "[| Y∈ analz (insert X H); X∈ analz H |] ==> Y∈ analz H" by (metis analz_idem analz_increasing analz_mono insert_absorb insert_mono insert_subset) text‹This rewrite rule helps in the simplification of messages that involve the forwarding of unknown components (X). Without it, removing occurrences of X can be very complicated.› lemma analz_insert_eq: "X∈ analz H ==> analz (insert X H) = analz H" by (blast intro: analz_cut analz_insertI) text‹A congruence rule for "analz"› lemma analz_subset_cong: "[| analz G ⊆ analz G'; analz H ⊆ analz H' |] ==> analz (G ∪ H) ⊆ analz (G' ∪ H')" apply simp apply (metis Un_absorb2 Un_commute Un_subset_iff Un_upper1 Un_upper2 analz_mono) done lemma analz_cong: "[| analz G = analz G'; analz H = analz H' |] ==> analz (G ∪ H) = analz (G' ∪ H')" by (intro equalityI analz_subset_cong, simp_all) lemma analz_insert_cong: "analz H = analz H' ==> analz(insert X H) = analz(insert X H')" by (force simp only: insert_def intro!: analz_cong) text‹If there are no pairs or encryptions then analz does nothing› lemma analz_trivial: "[| ∀X Y. {X,Y}∉ H; ∀X K. Crypt K X ∉ H |] ==> analz H = H" apply safe apply (erule analz.induct, blast+) done subsection‹Inductive relation "synth"› text‹Inductive definition of "synth" -- what can be built up from a set of messages. A form of upward closure. Pairs can be built, messages encrypted with known keys. Agent names are public domain. Numbers can be guessed, but Nonces cannot be.› inductive_set synth :: "msg set => msg set" for H :: "msg set" where Inj [intro]: "X ∈ H ==> X ∈ synth H" | Agent [intro]: "Agent agt ∈ synth H" | Number [intro]: "Number n ∈ synth H" | Hash [intro]: "X ∈ synth H ==> Hash X ∈ synth H" | MPair [intro]: "[|X ∈ synth H; Y ∈ synth H|] ==> {X,Y}∈ synth H" | Crypt [intro]: "[|X ∈ synth H; Key(K) ∈ H|] ==> Crypt K X ∈ synth H" text‹Monotonicity› lemma synth_mono: "G⊆H ==> synth(G) ⊆ synth(H)" by (auto, erule synth.induct, auto) text‹NO ‹Agent_synth›, as any Agent name can be synthesized. The same holds for 🍋‹Number›\› inductive_cases Nonce_synth [elim!]: "Nonce n ∈ synth H" inductive_cases Key_synth [elim!]: "Key K ∈ synth H" inductive_cases Hash_synth [elim!]: "Hash X ∈ synth H" inductive_cases MPair_synth [elim!]: "{X,Y}∈ synth H" inductive_cases Crypt_synth [elim!]: "Crypt K X ∈ synth H" lemma synth_increasing: "H ⊆ synth(H)" by blast subsubsection‹Unions› text‹Converse fails: we can synth more from the union than from the separate parts, building a compound message using elements of each.› lemma synth_Un: "synth(G) ∪ synth(H) ⊆ synth(G ∪ H)" by (intro Un_least synth_mono Un_upper1 Un_upper2) lemma synth_insert: "insert X (synth H) ⊆ synth(insert X H)" by (metis insert_iff insert_subset subset_insertI synth.Inj synth_mono) subsubsection‹Idempotence and transitivity› lemma synth_synthD [dest!]: "X∈ synth (synth H) ==> X∈ synth H" by (erule synth.induct, blast+) lemma synth_idem: "synth (synth H) = synth H" by blast lemma synth_subset_iff [simp]: "(synth G ⊆ synth H) = (G ⊆ synth H)" apply (rule iffI) apply (iprover intro: subset_trans synth_increasing) apply (frule synth_mono, simp add: synth_idem) done lemma synth_trans: "[| X∈ synth G; G ⊆ synth H |] ==> X∈ synth H" by (drule synth_mono, blast) lemma synth_cut: "[| Y∈ synth (insert X H); X∈ synth H |] ==> Y∈ synth H" by (metis insert_absorb insert_mono insert_subset synth_idem synth_increasing synth_mono) lemma Agent_synth [simp]: "Agent A ∈ synth H" by blast lemma Number_synth [simp]: "Number n ∈ synth H" by blast lemma Nonce_synth_eq [simp]: "(Nonce N ∈ synth H) = (Nonce N ∈ H)" by blast lemma Key_synth_eq [simp]: "(Key K ∈ synth H) = (Key K ∈ H)" by blast lemma Crypt_synth_eq [simp]: "Key K ∉ H ==> (Crypt K X ∈ synth H) = (Crypt K X ∈ H)" by blast lemma keysFor_synth [simp]: "keysFor (synth H) = keysFor H ∪ invKey`{K. Key K ∈ H}" by (unfold keysFor_def, blast) subsubsection‹Combinations of parts, analz and synth› lemma parts_synth [simp]: "parts (synth H) = parts H ∪ synth H" apply (rule equalityI) apply (rule subsetI) apply (erule parts.induct) apply (metis UnCI) apply (metis MPair_synth UnCI UnE insert_absorb insert_subset parts.Fst parts_increasing) apply (metis MPair_synth UnCI UnE insert_absorb insert_subset parts.Snd parts_increasing) apply (metis Body Crypt_synth UnCI UnE insert_absorb insert_subset parts_increasing) apply (metis Un_subset_iff parts_increasing parts_mono synth_increasing) done lemma analz_analz_Un [simp]: "analz (analz G ∪ H) = analz (G ∪ H)" apply (rule equalityI) apply (metis analz_idem analz_subset_cong order_eq_refl) apply (metis analz_increasing analz_subset_cong order_eq_refl) done declare analz_mono [intro] analz.Fst [intro] analz.Snd [intro] Un_least [intro] lemma analz_synth_Un [simp]: "analz (synth G ∪ H) = analz (G ∪ H) ∪ synth G" apply (rule equalityI) apply (rule subsetI) apply (erule analz.induct) apply (metis UnCI UnE Un_commute analz.Inj) apply (metis MPair_synth UnCI UnE Un_commute analz.Fst analz.Inj) apply (metis MPair_synth UnCI UnE Un_commute analz.Inj analz.Snd) apply (blast intro: analz.Decrypt) apply blast done lemma analz_synth [simp]: "analz (synth H) = analz H ∪ synth H" proof - have "∀x🪙2 x🪙1. synth x🪙1 ∪ analz (x🪙1 ∪ x🪙2) = analz (synth x🪙1 ∪ x🪙2)" by (metis Un_commute analz_synth_Un) hence "∀x🪙1. synth x🪙1 ∪ analz x🪙1 = analz (synth x🪙1 ∪ {})" by (metis Un_empty_right) hence "∀x🪙1. synth x🪙1 ∪ analz x🪙1 = analz (synth x🪙1)" by (metis Un_empty_right) hence "∀x🪙1. analz x🪙1 ∪ synth x🪙1 = analz (synth x🪙1)" by (metis Un_commute) thus "analz (synth H) = analz H ∪ synth H" by metis qed subsubsection‹For reasoning about the Fake rule in traces› lemma parts_insert_subset_Un: "X ∈ G ==> parts(insert X H) ⊆ parts G ∪ parts H" proof - assume "X ∈ G" hence "∀x🪙1. G ⊆ x🪙1 ⟶ X ∈ x🪙1 " by auto hence "∀x🪙1. X ∈ G ∪ x🪙1" by (metis Un_upper1) hence "insert X H ⊆ G ∪ H" by (metis Un_upper2 insert_subset) hence "parts (insert X H) ⊆ parts (G ∪ H)" by (metis parts_mono) thus "parts (insert X H) ⊆ parts G ∪ parts H" by (metis parts_Un) qed lemma Fake_parts_insert: "X ∈ synth (analz H) ==> parts (insert X H) ⊆ synth (analz H) ∪ parts H" proof - assume A1: "X ∈ synth (analz H)" have F1: "∀x🪙1. analz x🪙1 ∪ synth (analz x🪙1) = analz (synth (analz x🪙1))" by (metis analz_idem analz_synth) have F2: "∀x🪙1. parts x🪙1 ∪ synth (analz x🪙1) = parts (synth (analz x🪙1))" by (metis parts_analz parts_synth) have F3: "X ∈ synth (analz H)" using A1 by metis have "∀x🪙2 x🪙1::msg set. x🪙1 ≤ sup x🪙1 x🪙2" by (metis inf_sup_ord(3)) hence F4: "∀x🪙1. analz x🪙1 ⊆ analz (synth x🪙1)" by (metis analz_synth) have F5: "X ∈ synth (analz H)" using F3 by metis have "∀x🪙1. analz x🪙1 ⊆ synth (analz x🪙1) ⟶ analz (synth (analz x🪙1)) = synth (analz x🪙1)" using F1 by (metis subset_Un_eq) hence F6: "∀x🪙1. analz (synth (analz x🪙1)) = synth (analz x🪙1)" by (metis synth_increasing) have "∀x🪙1. x🪙1 ⊆ analz (synth x🪙1)" using F4 by (metis analz_subset_iff) hence "∀x🪙1. x🪙1 ⊆ analz (synth (analz x🪙1))" by (metis analz_subset_iff) hence "∀x🪙1. x🪙1 ⊆ synth (analz x🪙1)" using F6 by metis hence "H ⊆ synth (analz H)" by metis hence "H ⊆ synth (analz H) ∧ X ∈ synth (analz H)" using F5 by metis hence "insert X H ⊆ synth (analz H)" by (metis insert_subset) hence "parts (insert X H) ⊆ parts (synth (analz H))" by (metis parts_mono) hence "parts (insert X H) ⊆ parts H ∪ synth (analz H)" using F2 by metis thus "parts (insert X H) ⊆ synth (analz H) ∪ parts H" by (metis Un_commute) qed lemma Fake_parts_insert_in_Un: "[|Z ∈ parts (insert X H); X ∈ synth (analz H)|] ==> Z ∈ synth (analz H) ∪ parts H" by (blast dest: Fake_parts_insert [THEN subsetD, dest]) declare synth_mono [intro] lemma Fake_analz_insert: "X ∈ synth (analz G) ==> analz (insert X H) ⊆ synth (analz G) ∪ analz (G ∪ H)" by (metis Un_commute Un_insert_left Un_insert_right Un_upper1 analz_analz_Un analz_mono analz_synth_Un insert_absorb) lemma Fake_analz_insert_simpler: "X ∈ synth (analz G) ==> analz (insert X H) ⊆ synth (analz G) ∪ analz (G ∪ H)" apply (rule subsetI) apply (subgoal_tac "x ∈ analz (synth (analz G) ∪ H) ") apply (metis Un_commute analz_analz_Un analz_synth_Un) by (metis Un_upper1 Un_upper2 analz_mono insert_absorb insert_subset) end
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-05-03)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.