Programmable Oracles #
This file defines combinators for programming an oracle: forcing chosen query points to return chosen pre-decided values, with a bookkeeping flag tracking whether the programming has been used (the canonical "bad event" of the identical-until-bad pattern).
Main definitions #
OracleSpec.ProgrammingPolicy spec— partial functiont ↦ Option (programmed answer).OracleSpec.ProgrammingPolicy.empty— the all-nonepolicy (no programming).QueryImpl.withRedirect so redirect— replace every query with a user-supplied callback.QueryImpl.withProgramming so policy— wrapsoinStateT (QueryCache × Bool)so that policy hits override the underlying impl, set the bad flag, and are cached for consistency.
Design notes #
The state of withProgramming is (QueryCache × Bool):
- The
QueryCacheensures consistent answering: re-querying a programmed point returns the same value (so the adversary cannot detect programming via repeat queries). - The
Boolflag is set the first time the policy fires on an uncached query — i.e. when the programming would be observable relative to standard caching semantics. This is the canonical bad event for the identical-until-bad bound coming in a follow-up PR.
The flag is monotone (bad_monotone): once set, it stays set throughout execution. With the
empty policy, the flag stays false and the impl is structurally an extendState-lift of
withCaching (withProgramming_empty_run_proj_eq).
Auxiliary tracker #
QueryImpl.withCachingTrackingPolicy so policy is withCaching so lifted to
StateT (QueryCache × Bool) m, with the bad flag set on the same cache-miss-and-policy-fire
condition as withProgramming but without actually programming: the oracle is queried
normally and the (fresh) value is cached. Its purpose is to be the relational bridge between
withCaching (cache-side projection) and withProgramming (the "identical-until-bad" partner
of withProgramming); see OracleComp.ProgramLogic.Relational.ProgrammingOracle for the
actual TV-distance bound (tvDist_simulateQ_withCaching_withProgramming_le_probEvent_bad)
and its programming_collision_bound{,_qP_qH_β} repackagings.
A programming policy: a partial assignment of programmed answers to oracle inputs.
policy t = some v means "force the oracle to return v when queried at t".
policy t = none means "leave the oracle unchanged at t".
Instances For
The empty programming policy: no point is programmed. Specializing withProgramming to
this policy recovers withCaching (modulo the auxiliary Bool flag).
Instances For
Redirect #
Redirect every oracle query to a user-supplied callback. The base impl so is discarded
on every query, and redirect t : m (spec.Range t) is consulted instead.
withRedirect so redirect = redirect definitionally; the named wrapper exists to expose intent
at call sites and to compose with withProgramming (which uses withRedirect internally for the
"programmed branch" of each query).
Instances For
Programming #
Wrap a query implementation so to honor a programming policy.
State: StateT (spec.QueryCache × Bool) m.
- The
QueryCacheis consulted first; cache hits return the cached value (consistent answers on repeated queries). - On a cache miss:
policy t = some v→ returnv, cache it, set the bad flag.policy t = none→ fall through toso t, cache the result, leave the flag untouched.
Specialising to policy = ProgrammingPolicy.empty recovers withCaching lifted via
extendState; see withProgramming_empty_run_proj_eq.
Instances For
Bad-flag monotonicity #
The bad flag of withProgramming is monotone: once set, every query keeps it set.
PreservesInv packaging of withProgramming_bad_monotone for ProbComp.
Tracker partner of withProgramming #
withCaching lifted to StateT (QueryCache × Bool) m with the bad flag set on
exactly the same cache-miss-and-policy-fire condition as withProgramming, but without
actually programming: the underlying oracle is queried normally and the fresh value u is
cached.
This is the "identical-until-bad" partner of withProgramming: at every step they either
- produce the same
(value, cache, bad)distribution (cache hit, or cache miss with no policy hit), or - both produce a step whose output flags
bad := true, with possibly differentvalue/cachecomponents on the bad branch.
That is the exact shape needed to apply the output-bad version of "identical until bad".
Instances For
The bad flag of withCachingTrackingPolicy is monotone: once set, every query keeps it
set.
PreservesInv packaging of withCachingTrackingPolicy_bad_monotone for ProbComp.
withProgramming empty ≡ withCaching (cache-side projection) #
Cache-side projection: running withProgramming so empty and projecting away the bad flag
gives the same distribution as running so.withCaching directly.
This is the "specializes to caching" sanity check for withProgramming, witnessing that the
empty policy adds no observable behavior beyond withCaching plus a trivial bookkeeping flag.
run' projection corollary of withProgramming_empty_run_proj_eq.
withCachingTrackingPolicy ≡ withCaching (cache-side projection) #
Cache-side projection (general spec'): running so.withCachingTrackingPolicy policy and
projecting away the bad flag gives the same distribution as running so.withCaching directly,
irrespective of the initial bad value or the policy used to compute the (discarded) tracking.
run' projection corollary of withCachingTrackingPolicy_run_proj_eq'.
ProbComp specialization of withCachingTrackingPolicy_run_proj_eq'.
ProbComp specialization of withCachingTrackingPolicy_run'_eq'.
Forward query bounds for withCachingTrackingPolicy #
The bad-flag overlay projects away to withCaching (via withCachingTrackingPolicy_run_proj_eq')
and makes no underlying queries, so the withCaching bounds transfer directly.
Forward query bounds for withProgramming #
A wrapped step makes ≤ 1 underlying query (zero on a cache hit or programmed value, one on
a true miss). Unlike withCachingTrackingPolicy, the policy can short-circuit on cache
miss, so the proof case-splits on cache × policy rather than reusing the withCaching
projection.