Translated library, started to prove NS_Public
Lean Action CI / build (push) Has been cancelled

This commit is contained in:
Your Name
2026-02-23 09:06:13 +01:00
parent 61616dc3b1
commit 31e638dd90
7 changed files with 1427 additions and 145 deletions
+237
View File
@@ -0,0 +1,237 @@
import InductiveVerification.Public
set_option diagnostics true
-- The Needham-Schroeder Public-Key Protocol
namespace NS_Public
variable [InvKey]
variable [Bad]
open Msg
open Event
open Bad
open HasInitState
open InvKey
-- Define the inductive set `ns_public`
inductive ns_public : List Event Prop
| Nil : ns_public []
| Fake : ns_public evsf
X synth (analz (spies evsf))
ns_public (Says Agent.Spy B X :: evsf)
| NS1 : ns_public evs1
Nonce NA used evs1
ns_public (Says A B (Crypt (pubEK B) Nonce NA, Agent A) :: evs1)
| NS2 : ns_public evs2
Nonce NB used evs2
Says A' B (Crypt (pubEK B) Nonce NA, Agent A) evs2
ns_public (Says B A (Crypt (pubEK A) Nonce NA, Nonce NB, Agent B) :: evs2)
| NS3 : ns_public evs3
Says A B (Crypt (pubEK B) Nonce NA, Agent A) evs3
Says B' A (Crypt (pubEK A) Nonce NA, Nonce NB, Agent B) evs3
ns_public (Says A B (Crypt (pubEK B) (Nonce NB)) :: evs3)
-- A "possibility property": there are traces that reach the end
theorem possibility_property :
NB, evs, ns_public evs Says A B (Crypt (pubEK B) (Nonce NB)) evs := by
exists 1
exists [ Says A B (Crypt (pubEK B) (Nonce 1)),
Says B A (Crypt (pubEK A) Nonce 0, Nonce 1, Agent B),
Says A B (Crypt (pubEK B) Nonce 0, Agent A),
]
constructor
· apply ns_public.NS3
· apply ns_public.NS2
· apply_rules [ns_public.NS1, ns_public.Nil, Nonce_notin_used_empty]
· simp
· left
all_goals tauto
· simp
-- Spy never sees another agent's private key unless it's bad at the start
set_option trace.aesop true
@[simp]
theorem Spy_see_priEK {h : ns_public evs} :
(Key (priEK A) parts (spies evs)) A bad := by
constructor
-- · induction h <;> aesop (add norm spies, norm knows, norm initState, norm pubEK, norm priEK, norm pubSK, norm priSK, norm injective_publicKey)
· induction h with
| Nil => simp[spies, knows, initState]; intro h; cases h with
| inl h => cases h with
| inl => aesop (add norm pubEK, norm pubSK, safe forward injective_publicKey)
| inr h => simp[pubEK, priEK] at h; cases h with
| intro _ h => apply publicKey_neq_privateKey at h; contradiction
| inr h => simp[pubSK, priEK] at h; cases h with
| intro _ h => apply publicKey_neq_privateKey at h; contradiction
| Fake _ h ih => apply Fake_parts_sing at h
simp[spies, knows]
intro h₁; apply ih;
cases h₁ with
| inl h₁ => apply h at h₁; cases h₁ with
| inl h₁ => cases h₁; aapply analz_subset_parts
| inr => assumption
| inr => assumption
| NS1 _ _ ih => aesop (add norm spies, norm knows)
| NS2 _ _ _ ih => aesop (add norm spies, norm knows)
| NS3 _ _ _ ih => rw[spies, knows]; simp; intro _; apply ih; grind
· intro h₁; apply parts_increasing; aapply Spy_spies_bad_privateKey
@[simp]
theorem Spy_analz_priEK {h : ns_public evs} :
Key (priEK A) analz (spies evs) A bad := by
constructor
· intro h₁; apply analz_subset_parts at h₁; aapply Spy_see_priEK.mp
· intro h₁; apply analz_increasing; aapply Spy_spies_bad_privateKey
-- Lammata for some very specific recurring cases in the following proof
lemma no_nonce_NS1_NS2_helper1
{h : synth (analz (spies evsf)) Nonce NA, Msg.Agent A}
: Nonce NA analz (knows Agent.Spy evsf) := by
cases h with
| inj => aapply analz.fst
| mpair n => cases n; assumption
lemma no_nonce_NS1_NS2_helper2
{ih : Crypt (pubEK C) NA', Nonce NA, Msg.Agent D parts (spies evsf)
Crypt (pubEK B) Nonce NA, Msg.Agent A parts (spies evsf)
Nonce NA analz (spies evsf)}
{h : parts {X} synth (analz (spies evsf)) parts (spies evsf)}
{h₁ : Crypt (pubEK C) NA', Nonce NA, Msg.Agent D parts (knows Agent.Spy evsf)}
{h₂ : Crypt (pubEK B) Nonce NA, Msg.Agent A parts {X}
Crypt (pubEK B) Nonce NA, Msg.Agent A parts (knows Agent.Spy evsf)}
: Nonce NA analz (knows Agent.Spy evsf) := by
apply ih at h₁; cases h₂ with
| inl h₂ => apply h at h₂; cases h₂ with
| inl h₂ => cases h₂ with
| inj => apply h₁; aapply analz_subset_parts
| crypt h₂ => aapply no_nonce_NS1_NS2_helper1
| inr => aapply h₁
| inr => aapply h₁
-- It is impossible to re-use a nonce in both NS1 and NS2, provided the nonce is secret
theorem no_nonce_NS1_NS2 { h : ns_public evs } :
(Crypt (pubEK C) NA', Nonce NA, Agent D parts (spies evs)
(Crypt (pubEK B) Nonce NA, Agent A parts (spies evs)
Nonce NA analz (spies evs))) := by
intro h₁ h₂
induction h with
| Nil => rw[spies, knows] at h₂; simp[initState] at h₂
| Fake _ h ih =>
apply Fake_parts_sing at h
simp[spies, knows] at h₁
apply analz_insert; right;
cases h₁ with
| inl h₁ => simp_all; apply h at h₁; cases h₁ with
| inl h₁ => cases h₁ with
| inj h₁ => apply analz_subset_parts at h₁
aapply no_nonce_NS1_NS2_helper2
| crypt h₁ => cases h₁ with
| inj => apply analz.fst; aapply analz.snd
| mpair _ h₁ => aapply no_nonce_NS1_NS2_helper1
| inr h₁ => aapply no_nonce_NS1_NS2_helper2
| inr h₁ => simp[spies, knows] at h₂; aapply no_nonce_NS1_NS2_helper2
| NS1 =>
simp[spies] at h₁; simp[spies] at h₂; cases h₂ with
| inl h => rcases h with _ , n , _;
apply parts.body at h₁; apply parts.snd at h₁; apply parts.fst at h₁
apply parts_knows_Spy_subset_used at h₁; rw[n] at h₁; contradiction
| inr => rw[spies, knows]; apply analz_mono; apply Set.subset_insert; simp_all
| NS2 =>
simp[spies] at h₁; simp[spies] at h₂; cases h₁ with
| inl h => rcases h with _, _, n, _
apply parts.body at h₂; apply parts.fst at h₂
apply parts_knows_Spy_subset_used at h₂; rw[n] at h₂; contradiction
| inr => rw[spies, knows]; apply analz_mono; apply Set.subset_insert; simp_all
| NS3 => rw[spies, knows]; apply analz_mono; apply Set.subset_insert; simp_all
lemma unique_NA_apply_ih {P : Prop}
{a_ih : Crypt (pubEK B) Nonce NA, Msg.Agent A parts (spies evsf)
Crypt (pubEK B') Nonce NA, Msg.Agent A' parts (spies evsf)
Nonce NA analz (spies evsf) P}
{h₃ : Nonce NA analz (spies (Says Agent.Spy C X :: evsf))}
{h₁ : Crypt (pubEK B) Nonce NA, Msg.Agent A parts (spies evsf)}
{h₂ : Crypt (pubEK B') Nonce NA, Msg.Agent A' parts (spies evsf)}
: P := by
simp[spies, knows] at h₃; apply Set.notMem_subset at h₃
· aapply a_ih;
· apply analz_mono; apply Set.subset_insert
lemma unique_NA_contradict
{h₃ : Nonce NA analz (spies (Says Agent.Spy B X :: evsf))}
{h₂ : synth (analz (spies evsf)) Nonce NA, Msg.Agent A'}
{P : Prop}
: P := by
apply MPair_synth_analz.mp at h₂; rcases h₂ with n, m;
simp[spies, knows] at h₃; apply Set.notMem_subset at h₃
· contradiction;
· apply analz_mono; apply Set.subset_insert
-- Unicity for NS1: nonce NA identifies agents A and B
theorem unique_NA { h : ns_public evs } :
(Crypt (pubEK B) Nonce NA, Agent A parts (spies evs)
(Crypt (pubEK B') Nonce NA, Agent A' parts (spies evs)
(Nonce NA analz (spies evs)
A = A' B = B'))) := by
induction h with
| Nil => aesop (add norm spies, norm knows, safe analz_insertI)
| Fake _ a a_ih =>
apply Fake_parts_sing at a; intro h₁ h₂ h₃;
simp[spies, knows] at h₁; cases h₁ with
| inl h₁ => apply a at h₁; cases h₁ with
| inl h₁ => cases h₁ with
| inj h₁ => simp[spies, knows] at h₂; cases h₂ with
| inl h₂ => apply a at h₂; cases h₂ with
| inl h₂ => cases h₂ with
| inj h₂ => apply analz_subset_parts at h₁
apply analz_subset_parts at h₂
aapply unique_NA_apply_ih
| crypt h₂ => aapply unique_NA_contradict
| inr h₂ => apply analz_subset_parts at h₁
aapply unique_NA_apply_ih
| inr h₂ => apply analz_subset_parts at h₁
aapply unique_NA_apply_ih
| crypt h₁ => aapply unique_NA_contradict
| inr h₁ => simp[spies] at h₁; simp[spies, knows] at h₂; cases h₂ with
| inl h₂ => apply a at h₂; cases h₂ with
| inl h₂ => cases h₂ with
| inj h₂ => apply analz_subset_parts at h₂
aapply unique_NA_apply_ih
| crypt => aapply unique_NA_contradict
| inr => aapply unique_NA_apply_ih
| inr => aapply unique_NA_apply_ih
| inr => simp[spies, knows] at h₂; cases h₂ with
| inl h₂ => apply a at h₂; cases h₂ with
| inl h₂ => cases h₂ with
| inj h₂ => apply analz_subset_parts at h₂
aapply unique_NA_apply_ih
| crypt => aapply unique_NA_contradict
| inr => aapply unique_NA_apply_ih
| inr => aapply unique_NA_apply_ih
| NS1 _ _ a_ih => intro h₁ h₂ h₃; simp at h₁; cases h₁ with
| inl => sorry
| inr => simp at h₂; cases h₂ with
| inl h₂ => simp at h₃; rw[analz_Crypt] at h₃
rcases h₂ with _, nonce_eq, _; rw[nonce_eq] at h₃; simp at h₃;
| inr => aapply unique_NA_apply_ih;
| NS2 => sorry
| NS3 => sorry
-- Spy does not see the nonce sent in NS1 if A and B are secure
theorem Spy_not_see_NA { h : ns_public evs }:
Says A B (Crypt (pubEK B) Nonce NA, Agent A) evs
A bad
B bad
Nonce NA analz (spies evs) := by
intro h
induction h <;> simp_all [analz_insertI, no_nonce_NS1_NS2]
-- If NS3 has been sent and the nonce NB agrees with the nonce B joined with NA, then A initiated the run using NA
theorem B_trusts_protocol { h : ns_public evs }:
A bad
B bad
Crypt (pubEK B) (Nonce NB) parts (spies evs)
Says B A (Crypt (pubEK A) Nonce NA, Nonce NB, Agent B) evs
Says A B (Crypt (pubEK B) Nonce NA, Agent A) evs := by
intro h
induction h <;> simp_all [analz_insertI, no_nonce_NS1_NS2]
end NS_Public