PKEY: Public Key Management Game #
The PKEY game manages public key generation and corruption tracking.
Overview #
Two variants parameterized by b : Bool:
b = false(real): No collision checking in GENb = true(collision-free): GEN asserts no pk collision
The PKEY Switching Lemma bounds the advantage by collision probability via FEL.
References #
- Rocq SSProve: theories/Cryptobox/PKEY.v
- Dupressoir et al., CSF 2022 (Section 4.1)
Heap Locations #
State is stored in the global heap via typed locations.
Locations are @[reducible] so that .ty reduces for type checking.
Honesty flags: PK → Bool. Default: all false (unregistered).
Equations
- CatCrypt.Examples.Cryptobox.pkHonestLoc = { id := 100, ty := CatCrypt.Examples.Cryptobox.CryptoTypes.PK → Bool, fintype := Pi.instFintype, inhabited := Pi.instInhabited }
Instances For
Secret key storage: PK → SK. Only meaningful for honest keys.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Corruption flags: PK → Bool. Default: all false.
Equations
- CatCrypt.Examples.Cryptobox.pkCorruptLoc = { id := 102, ty := CatCrypt.Examples.Cryptobox.CryptoTypes.PK → Bool, fintype := Pi.instFintype, inhabited := Pi.instInhabited }
Instances For
Oracle Definitions #
Each oracle is an SPComp computation that reads/writes heap locations.
The b : Bool parameter in GEN switches collision behavior.
GEN oracle: generate a fresh honest key pair.
If b = true, asserts no collision with existing registered keys.
Equations
- One or more equations did not get rendered due to their size.
Instances For
CSETPK oracle: register an adversary-chosen public key as corrupt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
GETSK oracle: retrieve the secret key for an honest public key.
Equations
- One or more equations did not get rendered due to their size.
Instances For
HONPK oracle: check whether a public key is one the challenger generated (rather than adversarially chosen).
Equations
- CatCrypt.Examples.Cryptobox.honpkOracle pk = do let honest ← CatCrypt.Core.SPComp.get CatCrypt.Examples.Cryptobox.pkHonestLoc CatCrypt.Core.SPComp.pure (honest pk)
Instances For
Oracle Record #
Oracle interface for PKEY games.
- gen : Unit → Core.SPComp CryptoTypes.PK
- csetpk : CryptoTypes.PK → Core.SPComp Unit
- getsk : CryptoTypes.PK → Core.SPComp CryptoTypes.SK
- honpk : CryptoTypes.PK → Core.SPComp Bool
Instances For
PKEY Game #
PKEY game parameterized by collision behavior b.
Equations
- One or more equations did not get rendered due to their size.
Instances For
PKEY switching advantage.
Equations
Instances For
PKEY Collision Analysis #
The PKEY game switching argument is a failure event lemma (FEL) application.
The key insight is that genOracle N false and genOracle N true differ only
in the collision check: when honest pk || corrupt pk = false (no collision),
both branches execute identically. When a collision DOES occur, the b=true
version fails (produces 0 mass) while the b=false version continues.
Proof Structure #
To prove pkeyAdvantage N A ≤ ε via FEL, one needs:
Up-to-bad agreement:
PKEY N false AandPKEY N true Aagree on outcomes where no collision occurred during execution. This follows from the observation thatgenOracle N falseandgenOracle N truediverge only at the collision check, and all other oracles (csetpk, getsk, honpk) are identical.Bad probability bound: The probability that a collision occurs during
PKEY N false Ais at most ε. With q_gen GEN queries and q_csetpk CSETPK queries, each GEN call samples a pk uniformly, and the collision probability is at most(#honest + #corrupt) / |PK|per call. By union bound:Pr[collision] ≤ q_gen * q_csetpk / |PK|.
Comparison with Other Formalizations #
- EasyCrypt (~200 lines): Proved via
feltactic with automatic oracle decomposition - Rocq SSProve (~150 lines): ADMITTED (structural equivalence axiom)
- Our approach: The reduction
PKAE → PKEYis proven (see GameHopping.lean); the FEL bound itself requires oracle composition reasoning not yet available
Collision bad event for a single GEN call.
A collision occurs when the newly generated pk matches an existing honest or corrupt key. This is checked on the heap state BEFORE the honest flag is updated.
Equations
Instances For
Collision predicate on final heap.
The "bad event" for the FEL: there exists a pk that is registered as BOTH honest and corrupt. This is a necessary consequence of any collision during execution (since GEN sets honest and CSETPK sets corrupt, a collision means some pk ends up with both flags set).
Note: this is a necessary but not sufficient condition for a collision during execution. A stronger formulation would track the collision flag explicitly (requiring an instrumented game).
Equations
- One or more equations did not get rendered due to their size.
Instances For
PKEY collision-checking oracle record. Convenience for building oracle records.
Equations
- One or more equations did not get rendered due to their size.
Instances For
PKEY non-collision-checking oracle record.
Equations
- One or more equations did not get rendered due to their size.
Instances For
PKEY game with explicit oracle record is definitionally equal to PKEY.
genOracle Analysis #
Properties of the collision check in genOracle. These are building blocks
for proving the up-to-bad agreement condition.
genOracle N false and genOracle N true differ only in the collision check.
When b = false: the collision check is skipped (SPComp.pure ())
When b = true: the collision check may fail (if coll then fail else pure ())
The rest of the oracle body (sample, read honest/corrupt/skMap, update, return pk) is identical in both cases.
PKEY FEL Application #
Application of the Failure Event Lemma to bound the PKEY advantage.
The bad event is pkeyBadFinal: some public key is both honest and corrupt
in the final heap.
PKEY advantage bounded by collision probability via FEL.
This instantiates advantage_le_prBad from FailureEvent.lean with the
PKEY-specific bad event (pkeyBadFinal).
The two hypotheses that must be discharged for a specific adversary B:
Up-to-bad agreement (
h_agree): When no collision occurs (no pk is both honest and corrupt in the final heap), the two PKEY games produce the same distribution. This follows from the fact thatgenOracle N falseandgenOracle N truediffer only in the collision check, which is vacuous when no collision occurs.For a concrete adversary, this requires showing that the adversary's oracle calls compose correctly — see
agree_bind_leftandagree_bind_bothfromFailureEvent.leanfor the composition lemmas.Losslessness (
hll): ThePKEY N false Bgame is lossless (total mass 1). This requires showing thatgenOracle N falsenever fails (it skips the collision check) and that the adversary B doesn't cause failure on its own.
PKEY switching as a game hop: when the two PKEY games agree off the collision
event pkeyBadFinal, the collision-free game is lossless, and the probability of
pkeyBadFinal in the collision-free game is at most coll_bound, the switching
advantage is at most coll_bound. The bound on the collision probability is a
hypothesis on the collision-free game; collision_prob_single_query bounds the
collision probability of one GEN query and collision_prob_multi_query_bound
evaluates the union-bound sum over the queries.
Collision-Flag Instrumented Game Infrastructure #
The pkeyBadFinal bad event (∃ pk, honest[pk] ∧ corrupt[pk]) is insufficient
for a precise FEL argument because genOracle N true also fails on duplicate
honest keys, not just honest-corrupt cross collisions.
We introduce an instrumented variant of the PKEY game that explicitly sets a collision flag whenever the generated pk collides with ANY existing key (honest or corrupt). This gives a stronger, more precise bad event for FEL.
Collision flag location. Set to true when a GEN call produces a pk
that collides with an existing honest or corrupt key.
Equations
- CatCrypt.Examples.Cryptobox.pkeyCollFlag = { id := 103, ty := Bool, fintype := Bool.fintype, inhabited := instInhabitedBool }
Instances For
Instrumented GEN oracle: like genOracle but sets pkeyCollFlag on collision.
When a collision is detected (the newly generated pk is already honest or corrupt):
- Always sets the collision flag to
true - If
b = true: fails (collision-checking mode) - If
b = false: continues without failing (non-collision-checking mode)
When no collision is detected: both b = true and b = false execute identically.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Instrumented bad event: the collision flag is set.
This is a precise characterization of "some GEN call produced a collision
during execution", unlike pkeyBadFinal which only captures the weaker
condition of a pk being both honest and corrupt simultaneously.
Equations
Instances For
Instrumented PKEY game: uses genOracle_instr instead of genOracle.
All other oracles (CSETPK, GETSK, HONPK) are unchanged.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Instrumented oracle records for convenience.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Instrumented PKEY advantage.
Equations
Instances For
Unfolding lemma for genOracle_instr.
Key Theorem: Instrumented Oracles Agree When No Collision #
When the collision flag is NOT set in the final heap, the collision branch was
never taken during execution. Therefore, genOracle_instr N false and
genOracle_instr N true produce identical distributions on non-bad outcomes.
For any outcome (pk, h') with ¬pkeyBadInstr h' (i.e., Heap.get h' pkeyCollFlag ≠ true):
Both
genOracle_instr N falseandgenOracle_instr N truebegin identically: samplepair ← N.pkgen, readhonest,corrupt.At the distribution level, the result at outcome
(pk, h')is a sum over intermediate states:(genOracle_instr N b h₀)(some (pk, h')) = ∑_{pair, h₁} (N.pkgen h₀)(some (pair, h₁)) * (rest_b pair.1 pair.2 h₁)(some (pk, h'))For each intermediate
(pair, h₁), letpk_gen = pair.1. Readhonest = Heap.get h₁ pkHonestLocandcorrupt = Heap.get h₁ pkCorruptLoc.Case:
honest pk_gen || corrupt pk_gen = true(collision detected):- Both variants set
pkeyCollFlag := truein the heap. - The
b = truevariant then callsSPComp.fail, producing 0 mass. - The
b = falsevariant continues and producesh'withpkeyCollFlag = true. - But we assumed
¬pkeyBadInstr h', i.e.,Heap.get h' pkeyCollFlag ≠ true. - The collision flag, once set to
true, persists through subsequentsetcalls on OTHER locations (pkHonestLoc, skStoreLoc have different ids: 100, 101 vs 103). - So
Heap.get h' pkeyCollFlag = true, contradicting¬pkeyBadInstr h'. - Conclusion: this intermediate contributes 0 mass for BOTH
b = falseandb = true.
- Both variants set
Case:
honest pk_gen || corrupt pk_gen = false(no collision):- Both variants execute
SPComp.pure (), then identically update the heap. - The rest of the computation is
b-independent. - Conclusion: identical contribution for both
b = falseandb = true.
- Both variants execute
Therefore, every term in the sum is equal, so the total is equal.
PKEY instrumented advantage bounded by collision probability via FEL.
This is the instrumented analogue of pkeyAdvantage_le_collision.
The stronger bad event pkeyBadInstr (collision flag set) gives a tighter
and more precise bound than pkeyBadFinal (honest-corrupt overlap).
The instrumented bad event implies the original bad event when there exists a key that is both honest and corrupt.
More precisely: if a collision flag was set during a GEN call where
honest pk_gen || corrupt pk_gen = true, then either:
- The pk was already honest, and GEN sets it honest again (duplicate honest key)
- The pk was already corrupt, and GEN sets it honest (honest-corrupt overlap → pkeyBadFinal)
Note: pkeyBadInstr is STRICTLY stronger than pkeyBadFinal because it also
catches duplicate honest-honest collisions.
Per-Query Collision Probability #
For a single GEN query, the probability that the newly sampled pk collides with existing keys depends on the number of already-registered keys and the size of the pk space.
Per-query collision probability bound.
The collision set on heap h₀ is the set of pk whose pkHonestLoc or
pkCorruptLoc flag is set.
If it is covered by a finset S of size q_existing, then a public key sampled
uniformly from CT.PK lands in the collision set with probability at most
q_existing / Fintype.card CT.PK. This is the per-GEN-query collision probability
under uniform key generation.
Multi-query collision bound via union bound.
With q_gen GEN queries, the i-th of which (0-indexed) has at most i existing
challenger-generated keys plus q_csetpk corrupt keys, the union bound over the per-query
collision probabilities is the sum ∑_{i=0}^{q_gen-1} (i + q_csetpk) / |PK|.
This sum equals the birthday closed form
(q_gen * (q_gen - 1) + 2 * (q_gen * q_csetpk)) / (2 * |PK|).
Standalone PKEY sdist Building Block #
Standalone PKEY sdist building block. Reusable by any construction that uses the PKEY game.
Bridges per-adversary advantage bounds (∀ A, pkeyAdvantage N A ≤ ε)
to categorical sdist (sdist (PKEY N false) (PKEY N true) ≤ ε),
giving access to PPLs, composition, and tensor bounds.