Query-Bounded Adversary Infrastructure #
This file provides infrastructure for modeling adversaries with bounded query access to oracles. This is fundamental to cryptographic security proofs where security bounds depend on the number of oracle queries.
Main definitions #
boundedOracleCall- Single oracle call with query countingqueryCountPre- Precondition: query count is below boundqueryCountPost- Postcondition: query count incremented by 1
Main results #
pHoare_bounded_call- pHL rule for a single bounded oracle callpHoare_query_bound- After q bounded calls, counter ≤ qlossless_bounded_call- Bounded oracle call is lossless when under budgetprBad_induction- Inductive bound: Pr[bad after q calls] ≤ q * ε
Design #
Rather than implementing query-bounded oracles as stateful wrappers (which would require specific location assignments), we provide:
Abstract query counting: A precondition/postcondition pair that tracks a query count value through pHL judgments.
Inductive probability bounds: Theorems that bound the probability of bad events by
q * εwhen each query contributes at mostε.Oracle call patterns: Composable patterns for reasoning about sequences of oracle calls.
This approach integrates with the existing pHL rules from Rules.lean
and the FEL machinery from Bridge.lean / FailureEvent.lean.
References #
- EasyCrypt:
phoarewith oracle call counting - Bellare & Rogaway: birthday bound via query counting
- Shoup: "Sequences of Games" (query counting methodology)
Query Counting via pHL Predicates #
Instead of tracking query counts in specific heap locations, we parametrize over an abstract "counter" function on the heap. This allows the user to choose their own counter representation.
A query counter is a function from heaps to natural numbers. The user defines this based on their specific heap layout.
Equations
Instances For
Precondition: the query counter is at value n
Equations
- CatCrypt.Unary.counterAt count n h = (count h = n)
Instances For
Precondition: the query counter is at most q
Equations
- CatCrypt.Unary.counterBounded count q h = (count h ≤ q)
Instances For
Postcondition: the counter was incremented by exactly 1
Equations
- CatCrypt.Unary.counterIncremented count x✝ h' = ∀ (h₀ : CatCrypt.Core.Heap), count h₀ + 1 = count h'
Instances For
Abstract Bounded Oracle Call #
A bounded oracle call is modeled as: check counter, if under budget then call oracle and increment counter, else return default/fail.
A single oracle call that increments a counter.
This represents the pattern:
let n ← get counter_loc
if n < q then
set counter_loc (n + 1)
oracle k
else
fail -- or return default
We model this abstractly: the computation oracleCall k is wrapped
with counter tracking.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A single oracle call that always proceeds (no budget check). Used when the budget is known to be sufficient from context.
Equations
Instances For
pHL Rules for Query Counting #
pHoare rule for bounded oracle call: if the call computation satisfies a postcondition Q, then the full bounded oracle call also satisfies Q (since it either calls the oracle or returns default).
The user proves pHoare P oracleCall Q and
∀ h, P h → Q default h (the default case satisfies Q too),
and gets pHoare P (boundedOracleCall ...) Q.
Key theorem: after q calls to countedOracleCall, the counter
has been incremented q times.
This is stated abstractly: if we start with counter = 0 and make exactly q calls, the counter ends at q.
Inductive Probability Bounds #
The key result: if each oracle call has at most ε probability of triggering a bad event, and we make at most q calls, then the overall bad probability is at most q * ε.
Rather than proving this inductively over the number of calls (which requires tracking execution traces), we provide it as a composition lemma that the user applies.
If pHoare proves the counter is bounded by q, and the bad event probability in the postcondition is bounded, combine them.
Birthday bound pattern: q queries to a domain of size N gives collision probability at most q * (q-1) / (2 * N).
This is a definitional helper that states the standard birthday bound formula. The actual proof obligation is pushed to the user, who must show the per-query collision probability and compose with the query count.
Composition Patterns #
Reusable patterns for composing query-bounded computations.
Sequential composition preserves query bounds.
If c₁ uses at most q₁ queries and c₂ uses at most q₂ queries, then c₁ >> c₂ uses at most q₁ + q₂ queries.
If the counter starts at 0 and the computation makes at most q calls, the count is bounded by q. This is a simple wrapper for readability.
Integration with Failure Event Lemma #
Combine query bounds with the FEL to obtain concrete security bounds.
Combined FEL + query bound: advantage ≤ q * ε.
Given:
- Games agree on non-bad outcomes
- G₀ is lossless
- Bad probability under G₀ is at most q * ε Then advantage is at most q * ε.
Combined FEL + birthday bound: advantage ≤ q²/(2N).
Specialization of advantage_le_query_bound for the common
birthday-bound case (e.g., PRF/PRP switching).