Skip to content

Commit df52be2

Browse files
hyperpolymathclaude
andcommitted
proof(E5): msg-size + singleton-trace partial secrecy (Session 4)
Session 4 lands the subterm-size argument that Session 3 had to defer. This unblocks a *genuine* partial-secrecy theorem: on a singleton encrypted trace, the attacker cannot derive the body without knowing the key. This is the base case of the eventual full secrecy induction. Session 4 contents (all Qed-closed): - `msg_size : msg -> nat` — structural size counting constructors. - `msg_size_mEnc_eq`: msg_size (mEnc k m) = S (msg_size m). - `msg_no_self_mEnc`: m ≠ mEnc k m for all k, m (via size). - **`singleton_enc_trace_knows_equals_obs`**: on a 1-event encrypted trace, if the attacker does not hold the key, every derivable message equals the ciphertext. Proof is induction on the `knows` derivation tree, with each rule's IH yielding either the base case or a constructor-discrimination vacuity. - **`singleton_enc_trace_without_key_cannot_know_body`**: direct corollary — the body is unreachable without the key. This is the partial-secrecy kernel: Dolev-Yao derivation from a single-ciphertext trace, without the key, cannot extract the body. The proof uses no `Admitted`, no banned constructs, and routes every induction case either through k_obs (identifying the derived message with the observed ciphertext) or through constructor-discrimination inversion on IH-derived equalities. MANIFEST unchanged; runner 35/35 stable; panic-attack 0. Session 5 target: extend to multi-event traces via trace induction; introduce per-session state tracking; close the full secrecy invariant; Qed `needham_schroeder_fixed`. File grew 586 -> 706 LOC. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 02bb334 commit df52be2

1 file changed

Lines changed: 129 additions & 9 deletions

File tree

proofs/canonical-proof-suite/E5_needham_schroeder_fix.v

Lines changed: 129 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -575,12 +575,132 @@ Proof.
575575
apply sub_enc. apply sub_refl.
576576
Qed.
577577

578-
(* The structural partial-secrecy result — "singleton-trace body
579-
needs key" — requires a subterm-size argument that rules out
580-
`m = mEnc k m` as an inductive-msg value. That size argument
581-
is deferred to Session 4 (it requires either a well-founded
582-
recursion on msg size or an explicit "no infinite towers"
583-
lemma via Acc / Fix). For Session 3 we land only the
584-
compromise-model types + the basic contrapositive routed
585-
through `knows_enc_and_key_gives_body`. No banned constructs
586-
lie in this file; the deferred lemma simply isn't here. *)
578+
(* Session 3 deferred the structural partial-secrecy result
579+
(singleton-trace body needs key) to Session 4 because it
580+
requires a subterm-size argument. Session 4 now lands it —
581+
see the `Session 4` section below. *)
582+
583+
(* ============================================================ *)
584+
(* Session 4 (2026-04-18) — msg-size + singleton-trace secrecy *)
585+
(* ============================================================ *)
586+
587+
(* Structural size of a `msg` — counts constructor occurrences.
588+
The only use in this file is ruling out `m = mEnc k m` style
589+
self-cycles, which inductive `msg` cannot host. Session 3's
590+
deferred singleton-trace-body-needs-key lemma lands on top of
591+
this. *)
592+
593+
Fixpoint msg_size (m : msg) : nat :=
594+
match m with
595+
| mAgent _ => 1
596+
| mNonce _ => 1
597+
| mKey _ => 1
598+
| mPair l r => S (msg_size l + msg_size r)
599+
| mEnc _ b => S (msg_size b)
600+
end.
601+
602+
Lemma msg_size_mEnc_eq :
603+
forall k m, msg_size (mEnc k m) = S (msg_size m).
604+
Proof. intros; simpl; reflexivity. Qed.
605+
606+
(* A `msg` is never its own `mEnc` wrapper. *)
607+
Lemma msg_no_self_mEnc :
608+
forall (k : key) (m : msg), m <> mEnc k m.
609+
Proof.
610+
intros k m Heq.
611+
assert (H : msg_size m = msg_size (mEnc k m))
612+
by (rewrite <- Heq; reflexivity).
613+
rewrite msg_size_mEnc_eq in H.
614+
(* H : msg_size m = S (msg_size m) — impossible. *)
615+
pose proof (Nat.neq_succ_diag_r (msg_size m)) as Hne.
616+
contradiction.
617+
Qed.
618+
619+
(* Session-3's deferred lemma, now closed. On a trace containing
620+
exactly one event — an encrypted message mEnc k body — if the
621+
attacker does NOT know the key k, then every derivable message
622+
equals mEnc k body (i.e., the attacker has no capability except
623+
re-observing the wire). *)
624+
625+
Lemma singleton_enc_trace_knows_equals_obs :
626+
forall (a : agent) (k : key) (body m : msg),
627+
let tr := [mkEvent a (mEnc k body)] in
628+
~ knows tr (mKey k) ->
629+
knows tr m ->
630+
m = mEnc k body.
631+
Proof.
632+
intros a k body m tr Hno_key Hknow.
633+
(* We cannot use an ordinary `induction Hknow` because `tr` is
634+
a `let`-bound local — the induction principle would generalise
635+
`tr` away from our hypothesis. `remember` + `induction` on
636+
the generalised `tr0` gives the right shape. *)
637+
unfold tr in *.
638+
remember ([mkEvent a (mEnc k body)]) as tr0 eqn:Htr0.
639+
induction Hknow as
640+
[ ev Hin
641+
| l r Hpair IHpair
642+
| l r Hpair IHpair
643+
| k' mbody Henc IHenc Hkey IHkey ].
644+
- (* k_obs: ev ∈ tr0 = [mkEvent a (mEnc k body)], so ev is that event. *)
645+
subst tr0. simpl in Hin. destruct Hin as [Heq | []].
646+
(* Heq : mkEvent a (mEnc k body) = ev *)
647+
subst ev. simpl. reflexivity.
648+
- (* k_pairL: knows tr0 (mPair m r) implies mPair m r = mEnc k body by IH.
649+
But mPair <> mEnc by constructor discrimination — vacuous. *)
650+
assert (Heq : mPair l r = mEnc k body) by (apply IHpair; exact Htr0).
651+
inversion Heq.
652+
- (* k_pairR: symmetric. *)
653+
assert (Heq : mPair l r = mEnc k body) by (apply IHpair; exact Htr0).
654+
inversion Heq.
655+
- (* k_dec: knows tr (mEnc k' mbody) and knows tr (mKey k').
656+
IH on mKey k': mKey k' = mEnc k body — impossible by
657+
constructor discrimination. *)
658+
assert (Hkeyeq : mKey k' = mEnc k body) by (apply IHkey; exact Htr0).
659+
inversion Hkeyeq.
660+
Qed.
661+
662+
(* Corollary: on such a singleton trace, the attacker cannot derive
663+
the body unless body = mEnc k body — which msg_no_self_mEnc
664+
rules out. *)
665+
Lemma singleton_enc_trace_without_key_cannot_know_body :
666+
forall (a : agent) (k : key) (body : msg),
667+
let tr := [mkEvent a (mEnc k body)] in
668+
~ knows tr (mKey k) ->
669+
~ knows tr body.
670+
Proof.
671+
intros a k body tr Hno_key Hknow_body.
672+
assert (Hbody_eq : body = mEnc k body).
673+
{ eapply singleton_enc_trace_knows_equals_obs.
674+
- exact Hno_key.
675+
- exact Hknow_body. }
676+
exact (msg_no_self_mEnc Hbody_eq).
677+
Qed.
678+
679+
(* ============================================================ *)
680+
(* Session 4 status note (2026-04-18) *)
681+
(* ============================================================ *)
682+
(* *)
683+
(* Added in Session 4 (above): *)
684+
(* * msg_size (structural size, ruling out self-cycles). *)
685+
(* * msg_size_mEnc_eq (definitional rewrite). *)
686+
(* * msg_no_self_mEnc: m <> mEnc k m for all k, m. *)
687+
(* * singleton_enc_trace_knows_equals_obs: on a 1-event *)
688+
(* encrypted trace, without the key, every derivable *)
689+
(* message equals the ciphertext. Session 3's deferred *)
690+
(* lemma, now Qed-closed. *)
691+
(* * singleton_enc_trace_without_key_cannot_know_body: *)
692+
(* corollary — body is unreachable without the key. *)
693+
(* *)
694+
(* This is a genuine partial-secrecy result: the attacker's *)
695+
(* knowledge closure is bounded on the simplest protocol-like *)
696+
(* trace (one ciphertext event, no key leak). It is the *)
697+
(* base case of the final secrecy induction. *)
698+
(* *)
699+
(* Session 5 target: *)
700+
(* * Extend the singleton-trace result to arbitrary traces *)
701+
(* via trace induction. *)
702+
(* * Per-session state record. *)
703+
(* * Final secrecy invariant + needham_schroeder_fixed Qed. *)
704+
(* ============================================================ *)
705+
(* End of E5 in-progress scaffold. *)
706+
(* ============================================================ *)

0 commit comments

Comments
 (0)