Caching Queries Made by a Computation #
This file defines a modifier QueryImpl.withCaching that modifies a query implementation to
cache results to return to the same query in the future.
We also define cachingOracle, which caches queries to the oracles in spec,
querying fresh values from spec if no cached value exists.
Modify a query implementation to cache previous call and return that output in the future.
Instances For
Caching with auxiliary state #
Cache responses while threading an auxiliary state component.
The cache is consulted first. On a hit, the cached response is returned and the auxiliary state is
updated by hit. On a miss, miss produces both the response and the next auxiliary state; the
response is then installed in the cache.
Instances For
Projecting away the auxiliary state of withCachingAux recovers ordinary caching whenever
the miss handler has the same output marginal as the base implementation.
Output-only corollary of withCachingAux_run_proj_eq.
One-step invariant preservation for the auxiliary component of withCachingAux.
A withCachingAux handler preserves an invariant on its auxiliary component when both hit and
miss auxiliary updates preserve it.
Running withCaching at state cache produces a result whose cache is ≥ cache.
On a cache hit the state is unchanged; on a miss a single entry is added.
withCaching preserves the invariant (cache₀ ≤ ·) (the cache only grows).
Forward query bounds for withCaching #
A wrapped step makes ≤ 1 underlying query (zero on a hit, one on a miss), so any bound on
so t transfers to (so.withCaching t).run cache.
Parametric simulateQ lifts for withCaching #
Oracle for caching queries to the oracles in spec, querying fresh values if needed.
Instances For
Definitional unfold of cachingOracle as caching wrapped around the lifting handler.
Cache hit: cachingOracle t returns the stored value without an underlying query.
Cache miss: cachingOracle t issues a single underlying query t and stores it.
Trivially true via probFailure_eq_zero since both sides are OracleComp computations.
A generic withCaching version for arbitrary base monads would require a separate argument
because caching changes the oracle semantics (cache hits skip the underlying oracle call).
Trivially true via probFailure_eq_zero; see probFailure_run_simulateQ.
Forward query bounds for cachingOracle #
Forward only — the reverse fails because cache hits strictly reduce the simulated count.
Run an OracleComp with a QueryCache as a priority layer over the real oracle.
Cached entries are returned directly (no oracle query), misses fall through to the real
oracle and get cached for subsequent lookups within the same computation.
This is the fundamental "programmable random oracle" primitive: pre-fill the cache with programmed entries, then run the computation. Concretely:
withCacheOverlay cache oa = StateT.run' (simulateQ cachingOracle oa) cache
Key properties:
withCacheOverlay ∅ oadeduplicates queries but is otherwise equivalent tooa.withCacheOverlay cache (query t)returnsvwithout an external query whencache t = some v, and queries the real oracle whencache t = none.
The cache-parametric runtime built on top of this combinator lives in
VCVio.CryptoFoundations.FiatShamir.Sigma as FiatShamir.runtimeWithCache cache, with
FiatShamir.runtime defined as runtimeWithCache ∅.
Instances For
simulateQ cachingOracle only grows the cache: for any oa, if
z ∈ support ((simulateQ cachingOracle oa).run cache₀) then cache₀ ≤ z.2.
After running cachingOracle on a single query at t, the resulting cache
maps t to the returned value.