Proved basic properties of Blanchet protocol
Lean Action CI / build (push) Has been cancelled

This commit is contained in:
Your Name
2026-03-11 17:11:44 +01:00
parent c705c80f23
commit e41142896f
5 changed files with 490 additions and 122 deletions
+147 -42
View File
@@ -21,9 +21,30 @@ inductive KeyMode
| Signature
| Encryption
axiom publicKey : KeyMode Agent Key
axiom injective_publicKey : {b c : KeyMode} {A A' : Agent},
publicKey b A = publicKey c A' b = c A = A'
-- TODO replace axioms with classes
-- Also make sure that there are infinite key supplies
class AgentKeys where
publicKey : KeyMode Agent Key
injective_publicKey : {b c : KeyMode} {A A' : Agent},
publicKey b A = publicKey c A' b = c A = A'
privateKey_neq_publicKey : invKey (publicKey b A) publicKey c A'
not_surjective_publicKey_asymK : (¬all_symmetric)
( K : Key, K' > K,
K' symKeys
( b : KeyMode, A : Agent,
publicKey b A K' invKey (publicKey b A) K'))
-- Symmetric Keys
-- For some protocols, it is convenient to equip agents with symmetric as
-- well as asymmetric keys. The theory Shared assumes that all keys
-- are symmetric.
shrK : Agent Key
inj_shrK : Function.Injective shrK
sym_shrK : {A : Agent}, shrK A symKeys
not_surjective_shrK_symK : K : Key, K' > K,
K' symKeys ( A : Agent, shrK A K')
open AgentKeys
variable [AgentKeys]
noncomputable abbrev pubEK (A : Agent) : Key := publicKey KeyMode.Encryption A
noncomputable abbrev pubSK (A : Agent) : Key := publicKey KeyMode.Signature A
@@ -33,28 +54,27 @@ noncomputable abbrev priSK (A : Agent) : Key := privateKey KeyMode.Signature A
noncomputable abbrev pubK (A : Agent) : Key := pubEK A
noncomputable abbrev priK (A : Agent) : Key := invKey (pubEK A)
abbrev Sign (K : Key) (M : Msg) := Msg.Crypt K M, M
attribute [simp] pubEK
attribute [simp] pubSK
-- attribute [simp] priEK
-- attribute [simp] priSK
attribute [simp] privateKey_neq_publicKey
-- Axioms for private and public keys
@[simp]
axiom privateKey_neq_publicKey {b c : KeyMode} {A A' : Agent} :
privateKey b A publicKey c A'
@[simp]
lemma publicKey_neq_privateKey {b c : KeyMode} {A A' : Agent} :
publicKey b A privateKey c A' := by
exact privateKey_neq_publicKey.symm
-- Basic properties of pubK and priK
omit [InvKey] in
@[simp]
lemma publicKey_inject {b c : KeyMode} {A A' : Agent} :
(publicKey b A = publicKey c A') (b = c A = A') := by
grind[injective_publicKey]
omit [AgentKeys] in
lemma invKey_injective: Function.Injective invKey := by
intro _ _ _
simp_all[invKey_eq]
@@ -67,23 +87,42 @@ by
lemma not_symKeys_priK {b : KeyMode} {A : Agent} :
privateKey b A symKeys := by
simp [symKeys, privateKey, invKey_eq, privateKey_neq_publicKey]
@[simp]
lemma pubK_neq_symK {b : KeyMode} {A : Agent} {h : K symKeys} :
publicKey b A K
:= by
intro h₁; have h₂ := not_symKeys_pubK (b := b) (A := A); simp_all
lemma syKey_neq_priEK :
K symKeys K priEK A := by
intro _ _
have _ := not_symKeys_pubK (b := KeyMode.Encryption) (A := A)
simp_all[symKeys, invKey_eq]
@[simp]
lemma priK_neq_symK {b : KeyMode} {A : Agent} {h : K symKeys} :
privateKey b A K
:= by
intro h₁; have h₂ := not_symKeys_priK (b := b) (A := A); simp_all
@[simp]
lemma symK_neq_pubK {b : KeyMode} {A : Agent} {h : K symKeys} :
K publicKey b A
:= by intro h₁; aapply pubK_neq_symK; simp_all
@[simp]
lemma symK_neq_priK {b : KeyMode} {A : Agent} {h : K symKeys} :
K privateKey b A
:= by intro h₁; aapply priK_neq_symK; simp_all
omit [AgentKeys] in
lemma symKeys_neq_imp_neq :
((K symKeys) (K' symKeys)) K K' := by
intro h eq
rw[eq] at h
contradiction
omit [AgentKeys] in
@[simp]
lemma symKeys_invKey_iff : (invKey K symKeys) = (K symKeys) := by
simp [symKeys, invKey_eq]
omit [AgentKeys] in
lemma analz_symKeys_Decrypt :
Msg.Crypt K X analz H K symKeys Msg.Key K analz H X analz H := by
simp [symKeys]
@@ -92,11 +131,11 @@ lemma analz_symKeys_Decrypt :
-- "Image" equations that hold for injective functions
omit [AgentKeys] in
@[simp]
lemma invKey_image_eq : (invKey x invKey '' A) (x A) := by
simp [Set.mem_image]
omit [InvKey] in
@[simp]
lemma publicKey_image_eq :
(publicKey b x publicKey c '' AA) (b = c x AA) := by
@@ -117,17 +156,6 @@ lemma publicKey_notin_image_privateKey :
publicKey b A invKey '' ( publicKey c '' AS ) := by
simp [privateKey_neq_publicKey]
-- Symmetric Keys
-- For some protocols, it is convenient to equip agents with symmetric as
-- well as asymmetric keys. The theory Shared assumes that all keys
-- are symmetric.
axiom shrK : Agent Key
axiom inj_shrK : Function.Injective shrK
-- All shared keys are symmetric
axiom sym_shrK : {A : Agent}, shrK A symKeys
-- Injectiveness: Agents' long-term keys are distinct.
@[simp]
lemma invKey_shrK :
@@ -139,8 +167,8 @@ lemma analz_shrK_Decrypt :
by
intro _ _
aapply analz.decrypt; rw[invKey_shrK]; assumption
omit [AgentKeys] in
lemma analz_Decrypt' :
Msg.Crypt K X analz H K symKeys Msg.Key K analz H X analz H := by
intro _ _ _
@@ -189,7 +217,6 @@ lemma shrK_notin_image_privateKey :
shrK x (invKey '' ((publicKey b) '' AA )) := by
simp
omit [InvKey] in
@[simp]
lemma shrK_image_eq : (shrK x shrK '' AA) (x AA) := by
grind[inj_shrK]
@@ -199,7 +226,6 @@ attribute [simp] invKey_K
variable [Bad]
open Bad
-- Fill in definition for Initial States of Agents
@[simp]
instance : HasInitState Agent where
initState
| Agent.Server =>
@@ -226,7 +252,7 @@ lemma used_parts_subset_parts :
simp[used]; intro A h₁ X h₂; simp; exists A
cases A
all_goals (
simp_all[-parts_union]
simp_all[-parts_union, initState]
apply_rules [parts_trans, h₂, Set.singleton_subset_iff.mpr]
)
| cons e evs ih =>
@@ -260,6 +286,12 @@ lemma keysFor_parts_initState {C : Agent} :
keysFor (parts (initState C)) = := by
cases C <;>
simp[initState, keysFor]
@[simp]
lemma keysFor_used_empty :
keysFor (used []) =
:= by
rw[used, keysFor_iunion]; simp;
lemma Crypt_notin_initState {B : Agent} :
Msg.Crypt K X parts ( initState B ) := by
@@ -268,7 +300,7 @@ lemma Crypt_notin_initState {B : Agent} :
@[simp]
lemma Crypt_notin_used_empty :
Msg.Crypt K X used [] := by
simp[used]; intro A; cases A <;> simp
simp[used]; intro A; cases A <;> simp[initState]
-- Basic properties of shrK
@@ -339,7 +371,7 @@ lemma publicKey_in_initState {b : KeyMode} {A : Agent} {B : Agent} :
@[simp]
lemma spies_pubK : Msg.Key (publicKey b A) spies evs := by
induction evs with
| nil => simp [spies, knows]
| nil => simp [spies, knows, initState]
cases b <;> tauto
| cons e evs ih =>
cases e <;> rw [spies] <;> apply knows_subset_knows_Cons <;> assumption
@@ -352,14 +384,14 @@ lemma analz_spies_pubK : Msg.Key (publicKey b A) ∈ analz (spies evs) := by
@[grind .]
lemma Spy_spies_bad_privateKey { h : A bad } : Msg.Key (privateKey b A) spies evs := by
induction evs with
| nil => simp_all [spies, knows, pubSK, pubEK]; cases b <;> tauto
| nil => simp_all [spies, knows, initState]; cases b <;> tauto
| cons e evs ih =>
cases e <;> rw[spies] <;> aapply knows_subset_knows_Cons
-- Spy sees long-term shared keys of bad agents
lemma Spy_spies_bad_shrK {h : A bad} : Msg.Key (shrK A) spies evs := by
induction evs with
| nil => simp [spies, knows]; exists A
| nil => simp [spies, knows, initState]; exists A
| cons e evs ih =>
cases e <;> rw [spies] <;> aapply knows_subset_knows_Cons
@@ -374,6 +406,19 @@ lemma privateKey_into_used : Msg.Key (privateKey b A) ∈ used evs := by
aapply initState_into_used
apply parts_increasing
exact priK_in_initState
@[simp]
lemma shrK_into_used: Msg.Key (shrK A) used evs := by
aapply initState_into_used
apply parts_increasing
exact shrK_in_initState
@[grind .]
lemma analz_priK_Decrypt :
Msg.Crypt (priSK A) X analz (spies evs) X analz (spies evs) :=
by
intro h; aapply analz.decrypt
simp[priSK, privateKey, invKey_spec]
-- For case analysis on whether or not an agent is compromised
lemma Crypt_Spy_analz_bad :
@@ -396,6 +441,35 @@ lemma Crypt_synth_analz_pubK :
(Msg.Crypt (pubEK A) X (analz (spies evs)) ( X synth (analz (spies evs)))) :=
by simp[Crypt_synth_EK];
@[simp]
lemma Crypt_synth_priK :
(Msg.Crypt (priSK A) X synth (spies evs))
(Msg.Crypt (priSK A) X spies evs
(Msg.Key (priSK A) spies evs X synth (spies evs))) :=
by simp[Crypt_synth_EK]
@[simp]
lemma Crypt_synth_analz_priK :
(Msg.Crypt (priSK A) X synth (analz (spies evs)))
(Msg.Crypt (priSK A) X analz (spies evs)
(Msg.Key (priSK A) analz (spies evs) X synth (analz (spies evs)))) :=
by simp[Crypt_synth_EK];
@[grind .]
lemma Crypt_synth_analz_priK_decrypt :
(Msg.Crypt (priSK A) X synth (analz (spies evs)))
(X analz (spies evs)
(Msg.Key (priSK A) analz (spies evs) X synth (analz (spies evs)))) :=
by simp[Crypt_synth_EK]; grind
@[simp]
lemma Sign_synth_priK :
(Sign (priSK A) X synth (analz (spies evs)))
(Msg.Crypt (priSK A) X analz (spies evs) Msg.Key (priSK A) analz (spies evs))
X synth (analz (spies evs))
:= by
simp[Sign, Crypt_synth_EK]; grind
@[simp]
lemma Nonce_notin_initState {B : Agent} : Msg.Nonce N parts (initState B) := by
cases B <;>
@@ -403,7 +477,7 @@ lemma Nonce_notin_initState {B : Agent} : Msg.Nonce N ∉ parts (initState B) :=
@[simp]
lemma Nonce_notin_used_empty : Msg.Nonce N used [] := by
simp [used]; intro A; cases A <;> simp
simp [used, initState]; intro A; cases A <;> simp
-- Supply fresh nonces for possibility theorems
lemma Nonce_supply_lemma : N, n, N n Msg.Nonce n used evs := by
@@ -429,11 +503,42 @@ lemma Nonce_supply_lemma : ∃ N, ∀ n, N ≤ n → Msg.Nonce n ∉ used evs :=
lemma Nonce_supply1 : N, Msg.Nonce N used evs := by
obtain N, h := Nonce_supply_lemma
exact N, h N (le_refl N)
-- TODO is this really needed?
-- lemma Nonce_supply : Msg.Nonce (Classical.some (Nonce_supply_lemma.some_spec)) ∉ used evs := by
-- obtain ⟨N, h⟩ := Nonce_supply_lemma
-- exact h (Classical.some (Nonce_supply_lemma.some_spec)) (le_refl _)
lemma symK_supply_lemma : K, K' > K,
K' symKeys Msg.Key K' used evs Msg.Key '' keysFor (used evs) :=
by
induction evs with
| nil =>
intro K
have exK := not_surjective_shrK_symK (K := K);
rcases exK with K' , _, symK, exK;
exists K';
apply And.intro
· assumption
· apply And.intro
· assumption
· simp_all[used]; intro A; cases A <;>
simp_all[initState, pubK_neq_symK, priK_neq_symK, symK_neq_priK]
rw[Eq.comm]; apply exK
| cons e evs ih =>
intro K
cases e with
| Says _ _ m =>
simp[used];
obtain K₁, ks := msg_Key_supply (msg := m);
obtain K', _, _, _ := ih ( K := Nat.max K₁ K); exists K'; simp_all; grind
| Notes A m =>
simp[used];
obtain K₁, ks := msg_Key_supply (msg := m);
obtain K', _, _, _ := ih ( K := Nat.max K₁ K); exists K';
apply ks at K'; by_cases h : A bad <;> simp_all <;> grind
| Gets => exact ih (K := K)
lemma symK_supply : K symKeys,
Msg.Key K used evs Msg.Key '' keysFor (used evs) :=
by
obtain K, _, _, _ := symK_supply_lemma (K := 0) (evs := evs)
exists K
-- Specialized Rewriting for Theorems About `analz` and Image
omit [InvKey] [Bad] in
@@ -445,7 +550,7 @@ omit [InvKey] [Bad] in
lemma insert_Key_image : insert (Msg.Key K) (Msg.Key '' KK C) = Msg.Key '' (insert K KK) C := by
rw[insert_Key_singleton, Set.image_insert_eq, Set.insert_eq, Set.union_assoc, Set.image_singleton]
omit [Bad] in
omit [Bad] [AgentKeys] in
lemma Crypt_imp_keysFor :
Msg.Crypt K X H K symKeys K keysFor H := by
intro h₁ h₂
@@ -455,7 +560,7 @@ lemma Crypt_imp_keysFor :
-- Lemma for the trivial direction of the if-and-only-if of the
-- Session Key Compromise Theorem
omit [Bad] in
omit [Bad] [AgentKeys] in
@[simp]
lemma analz_image_freshK_lemma :
((Msg.Key K analz (Msg.Key '' nE H))