Skip to content

feat(UAKE): UAKE security notion#476

Open
protoben wants to merge 9 commits into
Verified-zkEVM:mainfrom
GaloisInc:uake
Open

feat(UAKE): UAKE security notion#476
protoben wants to merge 9 commits into
Verified-zkEVM:mainfrom
GaloisInc:uake

Conversation

@protoben

@protoben protoben commented Jul 10, 2026

Copy link
Copy Markdown

This PR adds a model of unilaterally authenticated key exchange, a la Dodis & Fiore 2017. I've put it into CryptoFoundations/AKE, since it seems likely that multiple AKE definitions would be useful. This is just a simple and well accepted one.

Some caveats about the model are in the doc comment at the top of UAKE/Defs.lean.

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown

🤖 PR Summary

This PR adds the formalization of Unilaterally Authenticated Key Exchange (UAKE) following Dodis & Fiore 2017. New definitions and structures are introduced across four files under VCVio/CryptoFoundations/AKE/UAKE/. The core definitions, oracle model, party structures, transcript handling, and execution logic are included, with no sorry or admit placeholders. The changes are self-contained and ready for review.


Statistics

Metric Count
📝 Files Changed 4
Lines Added 464
Lines Removed 0

Lean Declarations

✏️ Added: 26 declaration(s)

VCVio/CryptoFoundations/AKE/UAKE/Defs.lean (11)

  • def CorrectExp [DecidableEq K] [Monad m] (proto : Scheme m K UK TK W) : m Bool
  • def Exp [SampleableType K] [DecidableEq W] [Monad m] (lift : ProbCompLift m)
  • def PerfectlyCorrect [DecidableEq K] [Monad m] (proto : Scheme m K UK TK W)
  • def challengeSession [Monad m] (lift : ProbCompLift m)
  • def finalize [DecidableEq W] [Monad m] (lift : ProbCompLift m)
  • def fullPingPong [DecidableEq W] {proto : Scheme m K UK TK W}
  • def isPingPong [DecidableEq W] {proto : Scheme m K UK TK W}
  • def opImpl [Monad m] (proto : Scheme m K UK TK W) (tk : TK) :
  • def oracleImpl [Monad m] (lift : ProbCompLift m) (proto : Scheme m K UK TK W) (tk : TK) :
  • def oracleSpec (K W : Type) : OracleSpec (Op W)
  • noncomputable def advantage [SampleableType K] [DecidableEq W] [Monad m]

VCVio/CryptoFoundations/AKE/UAKE/Party.lean (6)

  • @[simp] def opening {State W : Type} : InitResult State W → Option W
  • @[simp] def state {State W : Type} : InitResult State W → State
  • def OutputsAtCompletion [MonadLiftT m SetM] (P : Party m In W Out) : Prop
  • def RecoveryDeterministic [Monad m] (P : Party m In W Out) : Prop
  • def runHonest [Monad m] {InP OutP InQ OutQ : Type}
  • def runHonestLoop [Monad m] {InP OutP InQ OutQ : Type}

VCVio/CryptoFoundations/AKE/UAKE/Transcript.lean (9)

  • def Matching (oracleLeadsFirst : Bool) (T Tstar : Transcript W) : Prop
  • def combine {A B : Type} (ta : Transcript A) (tb : Transcript B) :
  • def interleave : Bool → List (ℕ × ℕ) → List ℕ
  • def merge {A : Type} (t1 t2 : Transcript A) : Transcript A
  • def pingPong [DecidableEq W] (oracleLeadsFirst : Bool)
  • def prefixWith {A B : Type} (a : A) (t : ℕ) (tb : Transcript B) :
  • def recordOne (tr : Transcript W) (w : W) (clock : ℕ) : Transcript W × ℕ
  • def recordOpt (tr : Transcript W) : Option W → ℕ → Transcript W × ℕ
  • def relabel {A B : Type} (f : A → B) (t : Transcript A) : Transcript B

sorry Tracking

  • No sorrys were added, removed, or affected.

📋 **Additional Analysis**

The diff adds new files and imports for the UAKE module. Two minor style violations are noted: The new files lack module docstrings (Defs.lean docstring is a module overview but may be intended as docstring placement is slightly off), and Matching returns a Prop but its name is capitalized as a Prop-like definition. Additionally, the change adds autoImplicit = false style via variable {K UK TK W : Type} which might be acceptable but should be checked against global settings. Otherwise, the diff follows the project's structure and documentation guidelines.


📄 **Per-File Summaries**
  • VCVio.lean: This change adds three new import statements for VCVio.CryptoFoundations.AKE.UAKE.Defs, VCVio.CryptoFoundations.AKE.UAKE.Party, and VCVio.CryptoFoundations.AKE.UAKE.Transcript to the file. This makes the definitions, party structures, and transcript-related material from the UAKE (Unilateral Authenticated Key Exchange) component of the project available in this file.
  • VCVio/CryptoFoundations/AKE/UAKE/Defs.lean: Added new file Defs.lean defining the core types and game for a Unilaterally Authenticated Key Exchange (UAKE) scheme. Introduces Scheme structure (with fields rounds, setup, U, T), CorrectExp/PerfectlyCorrect correctness definitions, TSession/Env state structures, an Op oracle inductive and its implementation opImpl, and oracleSpec, oracleImpl, Adversary, ChallengeResult, isPingPong, fullPingPong, finalize, Exp, and advantage definitions for the full security experiment. Establishes the model's conventions (early reveals return none, rejected messages are dropped, ≥2 rounds required) and links the definitions to the Dodis–Fiore 2017 paper. No sorry or admit appear in the diff.
  • VCVio/CryptoFoundations/AKE/UAKE/Party.lean: This file introduces the core algebraic structures for modeling a UAKE party as a Mealy machine, as described in DF'17. It defines InitResult and StepResult inductive types to represent the outcome of initialization (whether the party speaks first or waits for a message) and each step (accept, complete, reject), along with helper projections state and opening. The Party structure bundles a state type State, an init function In → m (InitResult State W), a step function State → W → m (StepResult State W), and an output function State → m (Option Out). Two properties are formalized: RecoveryDeterministic, which asserts that output is deterministic (i.e., solely a function of state), and OutputsAtCompletion, which requires that output returns none except after protocol completion (enforced via a condition on init and step using support). Finally, runHonestLoop and runHonest define the honest execution of a two-party protocol, alternating steps between parties driven by a fuel bound and returning each party's final output.
  • VCVio/CryptoFoundations/AKE/UAKE/Transcript.lean: This diff adds the file VCVio/CryptoFoundations/AKE/UAKE/Transcript.lean, which defines the Transcript structure (a list of messages with timestamps) for the UAKE protocol from DF'17, along with operations: relabel, merge (sorted by timestamp), combine (mixing two transcripts via disjoint union), and prefixWith (prepends a labeled message). It also defines Session (a state plus a transcript), the interleave helper, the Matching relation (Def. 3: two transcripts match if their messages are identical and their timestamps interleave in alternating order), with a Decidable instance for Matching, and the predicates pingPong (checks if any oracle transcript matches a challenge transcript) and recordOne/recordOpt for appending messages to a transcript. The file contains no sorry or admit.

Last updated: 2026-07-15 19:25 UTC.

@protoben protoben changed the title UAKE security notion feat(UAKE): UAKE security notion Jul 10, 2026
@alexanderlhicks

Copy link
Copy Markdown
Collaborator

Dodis & Fiore 2017.

Wrong link 😅

@alexanderlhicks alexanderlhicks left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated review

This review was produced by an AI assistant (Claude Code), invoked and supervised by @alexanderlhicks. Each finding was validated before posting (methods noted per comment), but please treat it as reviewer input to verify, not authority.

Soundness vs. the reference

First, a housekeeping item: the PR description links the wrong ePrint entry2014/144 is Andreeva et al., How to Securely Release Unverified Plaintext in Authenticated Encryption. The docstring in Defs.lean has the right one: ePrint 2017/109 (Dodis & Fiore, Unilaterally-Authenticated Key Exchange, FC 2017). Worth fixing the description for posterity.

I cross-checked the formalization against the paper, and it holds up well:

  • Exp/finalize match the Sec. 3 Exp^UAKE-Sec experiment branch-for-branch: K0 = ⊥ ⟹ K1 = ⊥; K0 ≠ ⊥ ∧ not ping-pong adversary wins (authenticity); otherwise real-or-random K1 with the full-ping-pong coin-flip nullifier. The reveal bookkeeping (revealed persisting into the post phase, fullPingPong checked on post-phase state against the challenge-phase transcript snapshot) correctly captures the paper's “one additional query” formulation.
  • Matching realizes Def. 3: simulating the oracle's clock/recording logic for honest relays of 2–7 rounds (both leader parities) reproduces the paper's alternation exactly; message substitution and cross-session confusion correctly fail to match; and — a nice robustness property of the snapshot design — sessions opened or extended after the challenge completes can never retroactively match, by clock monotonicity. Details in the inline comment on Matching.
  • CorrectExp is faithful to Def. 7, including its (the paper's own) weak conditional form; the docstring is upfront about this.
  • The documented model deviations (early reveal, reject-and-retry, unenforced well-formedness) are all adversary-favoring, so security in this model implies security in the paper's model. The “Model simplifications” docstring is genuinely excellent — more definitions PRs should do this.

Two soundness-adjacent polish items are flagged inline (post-phase stepChallenge availability; rounds semantics being load-bearing but undocumented) — both easy to validate and cheap to address.

Main suggestions (details inline)

  1. Adopt ProbCompRuntime in place of the [MonadLiftT ProbComp m] / [MonadLiftT m SPMF] constraints — this is the established pattern across CryptoFoundations, and it keeps UAKE composable with the reduction infrastructure already stated against it.
  2. Connect advantage to the SecExp.lean helpers, or document the deliberate paper-convention choice.
  3. Trim or wire in currently-unused definitions (Transcript.relabel/merge/combine/prefixWith, Party.RecoveryDeterministic, Party.OutputsAtCompletion).

Minor

  • Docstring gaps on the public surface: Scheme fields (especially rounds), PerfectlyCorrect, oracleSpec, Adversary/ChallengeResult fields, challengeSession, finalize, advantage, Session, interleave, pingPong, recordOne/recordOpt, runHonest(Loop), and the StepResult.acceptAndSend done flag (“this send is my final message”). A sentence on the deliberate double-Option in Party.output (outer = “no output yet”, inner = “output ⊥”) would also help readers — it takes a while to reconstruct.
  • Peer files are universe-polymorphic in the ambient monad (m : Type → Type v, cf. INDCCA.lean); consider matching.
  • Naming: peers use *_Game / *_Advantage (e.g. IND_CCA_Game); AKE.UAKE.Exp/advantage are fine namespaced, but worth a consistency thought.
  • challengeSession returns the tk it was handed only to thread it to finalize; passing tk to finalize directly would simplify the tuple.

Suggested follow-up (not blocking)

A machine-checked sanity lemma that the honest-relay adversary is ping-pong (for a toy protocol), and/or a toy instantiation under Examples/, would lock in the trickiest machinery and validate the definition's ergonomics.

Overall: careful, well-documented work — the two-phase stateful Adversary and the HasQuery.toQueryImpl … + opImpl composition mirror the INDCCA idiom nicely, and the game logic is faithful to the paper precisely in the places that are easiest to get wrong.

Comment thread VCVio/CryptoFoundations/AKE/UAKE/Defs.lean
Comment thread VCVio/CryptoFoundations/AKE/UAKE/Defs.lean Outdated
| .acceptAndSend st' w' done =>
let (tr1, c1) := recordOne t.transcript w env.clock
let (tr2, c2) := recordOne tr1 w' c1
let key ← if done then (proto.T.output st' : m _) else pure none

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated comment

Corner case worth a note in TSession.key's docstring: if proto.T.output st' returns none on a done step, then key = none is recorded, which the rest of the oracle reads as “session not completed” — the session stays steppable through the t.key gate above, and revealT returns none. This is only reachable for protocols violating the outputs-at-completion discipline, and it errs in the adversary-favoring (safe) direction, so no code change is needed — but the docstring currently states none ⟺ “session has not yet completed”, which this corner contradicts.

Comment thread VCVio/CryptoFoundations/AKE/UAKE/Defs.lean Outdated
Comment on lines +247 to +250
noncomputable def advantage [SampleableType K] [DecidableEq W] [Monad m]
[MonadLiftT ProbComp m] [MonadLiftT m SPMF] {proto : Scheme m K UK TK W}
(A : Adversary proto) : ℝ :=
|(Pr[= true | Exp A]).toReal - 1 / 2|

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated comment

Consider connecting this to the existing advantage API in SecExp.lean rather than introducing a new formulation: peers define e.g. IND_CCA_Advantage runtime adversary := (IND_CCA_Game runtime adversary).boolBiasAdvantage. For a total (failure-free) game the two conventions differ by exactly a factor of 2, and the bridging lemma already exists (SPMF.boolBiasAdvantage_eq_two_mul_abs_sub_half). |Pr[true] − 1/2| matches DF'17's Def. 8 directly, so keeping it is defensible — in that case a short comment noting the deliberate paper-convention choice and its relation to boolBiasAdvantage (plus routing through runtime.evalDist per the comment on PerfectlyCorrect) would keep downstream reduction algebra consistent.

Comment on lines +63 to +72
/-- True if the final output message of a party is deterministic given the
state. I.e., all non-determinism is in the init and step functions. -/
def RecoveryDeterministic [Monad m] (P : Party m In W Out) : Prop :=
∀ st : P.State, ∃ out, P.output st = pure out

/-- True if a party outputs a final message only once the protocol is complete. -/
def OutputsAtCompletion [MonadLiftT m SetM] (P : Party m In W Out) : Prop :=
(∀ i r, r ∈ support (P.init i) → ∀ out ∈ support (P.output r.state), out = none) ∧
(∀ st w st' w', StepResult.acceptAndSend st' w' false ∈ support (P.step st w) →
∀ out ∈ support (P.output st'), out = none)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated comment

Both predicates are currently unused — git grep -n 'RecoveryDeterministic\|OutputsAtCompletion' shows only these definitions. Notably, OutputsAtCompletion is exactly the property that model-simplification bullet 3 in Defs.lean leans on (“we do not enforce that U outputs K0 only at completion, which DF'17 (implicitly) assumes”). Two reasonable options:

  1. Bundle them into a named well-formedness predicate (e.g. Scheme.WellFormed) that future security theorems take as a hypothesis, and reference it from that docstring; or
  2. Defer them to the PR that first needs them.

Option 1 seems more in the spirit of a foundational definitions PR — it turns the docstring's informal WLOG argument into a checkable interface.

Comment on lines +25 to +37
def relabel {A B : Type} (f : A → B) (t : Transcript A) : Transcript B :=
⟨t.entries.map fun p => (f p.1, p.2)⟩

def merge {A : Type} (t1 t2 : Transcript A) : Transcript A :=
⟨(t1.entries ++ t2.entries).mergeSort fun p q => decide (p.2 ≤ q.2)⟩

def combine {A B : Type} (ta : Transcript A) (tb : Transcript B) :
Transcript (A ⊕ B) :=
(ta.relabel Sum.inl).merge (tb.relabel Sum.inr)

def prefixWith {A B : Type} (a : A) (t : ℕ) (tb : Transcript B) :
Transcript (A ⊕ B) :=
⟨(Sum.inl a, t) :: tb.entries.map fun p => (Sum.inr p.1, p.2)⟩

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated comment

relabel, merge, combine, and prefixWith have no consumers in this PR — they are used only by each other (validate: git grep -nE 'relabel|combine|prefixWith' -- VCVio returns only these lines). If they're groundwork for a later development (e.g. assembling the global interleaved transcript for proofs about Matching), a one-line doc comment saying so would justify keeping them; otherwise consider deferring them to the PR that uses them, keeping this foundational file minimal.

Comment on lines +45 to +56
def interleave : Bool → List (ℕ × ℕ) → List ℕ
| _, [] => []
| ab, (a, b) :: rest => (if ab then [a, b] else [b, a]) ++ interleave (!ab) rest

/-- Def. 3 from DF'17. A pair of transcripts match (T ⊆ T*) if their messages
are elementwise identical and their timestamps are "interleaved" as t₁ < t₁*
< t₂* < t₂ < ... or t₁* < t₁ < t₂ < t₂* < ..., depending on which party
speaks first. -/
def Matching (oracleLeadsFirst : Bool) (T Tstar : Transcript W) : Prop :=
T.entries.map Prod.fst = Tstar.entries.map Prod.fst ∧
List.IsChain (· < ·)
(interleave oracleLeadsFirst ((T.entries.map Prod.snd).zip (Tstar.entries.map Prod.snd)))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated comment

A positive one: this machinery was stress-tested externally (a faithful re-implementation of the recordOne/opImpl clock bookkeeping plus this Matching predicate), and it checks out against DF'17 Def. 3 in every case tried: honest relays for 2–7 rounds under both leader parities match exactly; single-message substitution fails to match; with two interleaved oracle sessions, only the honestly-relayed one matches; and a session opened or extended after the challenge completes can never retroactively match a challenge snapshot — its final message's timestamp violates the alternation, by clock monotonicity. That last point means the fullPingPong-on-snapshot design in Defs.lean can't be gamed from the post phase.

Suggested (non-blocking) follow-up: a machine-checked version of the first fact — e.g. a lemma that the honest-relay adversary against a toy 2-round protocol satisfies isPingPong — would lock in the parity flag and interleave bookkeeping, the easiest places for a silent regression later.

@protoben

Copy link
Copy Markdown
Author

Dodis & Fiore 2017.

Wrong link 😅

Oops! Fixed. Thanks for catching that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants