Documentation

VCVio.OracleComp.QueryTracking.Unpredictability

ROM Unpredictability and Collision Win Bounds #

Fresh query uniformity, cache preimage bounds, and the collision-based win probability theorem.

Unpredictability #

theorem OracleComp.probOutput_fresh_cachingOracle_query {ι : Type} [DecidableEq ι] {spec' : OracleSpec ι} [spec'.Fintype] [spec'.Inhabited] (t : spec'.Domain) (u : spec'.Range t) (cache₀ : spec'.QueryCache) (hfresh : cache₀ t = none) :
Pr[= (u, cache₀.cacheQuery t u) | (cachingOracle t).run cache₀] = (↑(Fintype.card (spec'.Range t)))⁻¹

Fresh query uniformity: querying cachingOracle at an uncached point yields each value with probability 1/|C|.

theorem OracleComp.probEvent_unqueried_match_le {ι : Type} [DecidableEq ι] {spec' : OracleSpec ι} [spec'.Fintype] [spec'.Inhabited] {α : Type} {t : } (oa : OracleComp spec' α) (_hbound : oa.IsPerIndexQueryBound fun (x : ι) => t) (predict : spec'.Domain) (_target : spec'.Range predict) :
(probEvent ((simulateQ cachingOracle oa).run ) fun (z : α × spec'.QueryCache) => z.2 predict = none) * (↑(Fintype.card (spec'.Range predict)))⁻¹ (↑(Fintype.card (spec'.Range predict)))⁻¹

WARNING: trivially true. The proof uses only probEvent_le_one; the query bound hbound and target are completely unused. The conclusion Pr[...] * |C|⁻¹ ≤ |C|⁻¹ holds for any computation regardless of how many queries it makes.

A meaningful unpredictability bound should use hbound to establish that the queried point is fresh, giving a tight 1/|C| bound on the probability of guessing the ROM output.

theorem OracleComp.probEvent_cache_has_value_le_of_unique_preimage {ι : Type} [DecidableEq ι] {spec : OracleSpec ι} [spec.DecidableEq] [spec.Fintype] [spec.Inhabited] {α : Type} [Inhabited ι] (oa : OracleComp spec α) (n : ) (hbound : oa.IsTotalQueryBound n) (hrange : ∀ (t : ι), Fintype.card (spec.Range default) Fintype.card (spec.Range t)) (v₀ : spec.Range default) (cache₀ : spec.QueryCache) (hunique_v₀ : ∀ (t₀ t₁ : spec.Domain) (v₁ : spec.Range t₀) (v₂ : spec.Range t₁), cache₀ t₀ = some v₁cache₀ t₁ = some v₂v₁ v₀v₂ v₀t₀ = t₁) :
(probEvent ((simulateQ cachingOracle oa).run cache₀) fun (z : α × spec.QueryCache) => ∃ (t₀ : spec.Domain) (v : spec.Range t₀), z.2 t₀ = some v cache₀ t₀ = none v v₀) n * (↑(Fintype.card (spec.Range default)))⁻¹

Cache preimage bound: if the initial cache contains at most one preimage of a target value v₀, then the probability that simulateQ cachingOracle oa creates a fresh cache entry equal to v₀ is at most n / |C|, where n is the total query bound. Each cache miss is a fresh uniform draw, so a union bound over the at most n misses gives the result.

This is the reusable ROM lemma for the extractability "fresh target hit" case.

theorem OracleComp.probEvent_cache_has_value_le_of_noCollision {ι : Type} [DecidableEq ι] {spec : OracleSpec ι} [spec.DecidableEq] [spec.Fintype] [spec.Inhabited] {α : Type} [Inhabited ι] (oa : OracleComp spec α) (n : ) (hbound : oa.IsTotalQueryBound n) (hrange : ∀ (t : ι), Fintype.card (spec.Range default) Fintype.card (spec.Range t)) (v₀ : spec.Range default) (cache₀ : spec.QueryCache) (hno : ¬CacheHasCollision cache₀) :
(probEvent ((simulateQ cachingOracle oa).run cache₀) fun (z : α × spec.QueryCache) => ∃ (t₀ : spec.Domain) (v : spec.Range t₀), z.2 t₀ = some v cache₀ t₀ = none v v₀) n * (↑(Fintype.card (spec.Range default)))⁻¹

Special case of probEvent_cache_has_value_le_of_unique_preimage when the initial cache contains at most one preimage of v₀ because the cache is collision-free.

theorem OracleComp.probEvent_cache_has_value_le {ι : Type} [DecidableEq ι] {spec : OracleSpec ι} [spec.DecidableEq] [spec.Fintype] [spec.Inhabited] {α : Type} [Inhabited ι] (oa : OracleComp spec α) (n : ) (hbound : oa.IsTotalQueryBound n) (hrange : ∀ (t : ι), Fintype.card (spec.Range default) Fintype.card (spec.Range t)) (v₀ : spec.Range default) (cache₀ : spec.QueryCache) (hno_v₀ : ∀ (t₀ : spec.Domain) (v : spec.Range t₀), cache₀ t₀ = some v¬v v₀) :
(probEvent ((simulateQ cachingOracle oa).run cache₀) fun (z : α × spec.QueryCache) => ∃ (t₀ : spec.Domain) (v : spec.Range t₀), z.2 t₀ = some v cache₀ t₀ = none v v₀) n * (↑(Fintype.card (spec.Range default)))⁻¹

Special case of probEvent_cache_has_value_le_of_unique_preimage when the initial cache contains no preimage of v₀.

Collision-Based Win Bound #

theorem OracleComp.probEvent_collision_win_le {ι : Type} [DecidableEq ι] {spec : OracleSpec ι} [spec.DecidableEq] [spec.Fintype] [spec.Inhabited] {α : Type} {t : } [Inhabited ι] [Unique ι] (oa : OracleComp spec α) (win : α × spec.QueryCacheProp) (hbound : oa.IsPerIndexQueryBound fun (x : ι) => t) (hC : 0 < Fintype.card (spec.Range default)) (hrange : ∀ (t : ι), Fintype.card (spec.Range default) Fintype.card (spec.Range t)) (hwin : zsupport ((simulateQ cachingOracle oa).run ), win zCacheHasCollision z.2) :
probEvent ((simulateQ cachingOracle oa).run ) win t ^ 2 / (2 * (Fintype.card (spec.Range default)))

WARNING: vacuously true. The [Unique ι] hypothesis means ι has exactly one element, but CacheHasCollision (used via probEvent_cacheCollision_le_birthday') requires two distinct oracle indices t₁ ≠ t₂ : ι, which is impossible when ι is unique. The event CacheHasCollision z.2 is therefore always false, making the bound trivially 0 ≤ ....

For a useful single-oracle collision bound, state it over LogHasCollision (which checks for equal outputs on distinct inputs within the same oracle index) rather than CacheHasCollision (which requires distinct indices).