One-wayness of the random oracle #
A 101-crypto example mirroring CollisionResistance.lean. The OW game:
- Sample challenge input
x ← uniform. - Compute
y := oracle(x)and publishyviaow_challenge_y. - Run the adversary
ow_advforqrounds with oracle access; the adversary writes its candidate preimage toow_response. - Check whether
oracle(ow_response) = y.
The high-level claims:
ow_transfer— the win-bit distribution is identical under lazy and eager RO.ow_lazy_bound— the lazy win probability is at most2(q + 1) / |output|(the standard linear bound:(q+1)/|output|from auseful_preimageunion bound over theqloop queries and 1 final query, plus(q+1)/|input|≤(q+1)/|output|for the chance the adversary's response happens to equal the uniformly randomow_challenge_x).ow_eager_bound— the same bound, viaow_transfer.
The bound is linear in q (not quadratic like CR's birthday bound), because
each lazy_query has at most 1 / |output| chance of producing the fixed
challenge value y.
The challenge value y published to the adversary (= oracle(x) for a
random x).
The original challenge input x (kept in state for the bound analysis).
The adversary's response: its candidate preimage of the challenge.
Disjointness: game-specific variables don't alias the random oracle.
Game-specific variables are disjoint from the loop's scratch variables.
Needed so that ow_loop_body's ProgramDenotation.get oracle_input /
ProgramDenotation.set oracle_output / random_oracle_state operations preserve
ow_challenge_y (and similarly for ow_response).
Game definition (parameterized over the adversary) #
One round of the OW loop body: the adversary computes (and writes
oracle_input), then we run one oracle query. Thin alias for the generic
oracle_step in RO.lean (same shape as cr_loop_body).
Equations
- ow_loop_body ow_adv oracle = oracle_step ow_adv oracle
Instances For
Run the adversary-and-query loop for q rounds. Thin alias for the generic
oracle_loop_n in RO.lean.
Equations
- ow_loop ow_adv q oracle = oracle_loop_n ow_adv q oracle
Instances For
The OW experiment parameterised by query budget q, init, and oracle.
Sample x, set y := oracle(x), publish y, run adversary for q rounds,
read the adversary's response, and check whether oracle(response) = y.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Phase 2 — Transfer (lazy = eager) #
Mirrors cr_transfer from CollisionResistance.lean.
Transfer theorem: the marginal distribution of the win-bit is identical under lazy and eager random oracle.
Phase 3 — Bookkeeping: win implies preimage in RO #
State predicate: at the end of the experiment, if result = true, then
RO[ow_response] = some ow_challenge_y. This is the OW analog of
cr_true_implies_collision_wp.
The "is a preimage" state predicate: RO σ (ow_response σ) = some (ow_challenge_y σ).
Equations
- is_preimage σ = (random_oracle_state.get σ (ow_response.get σ) = some (ow_challenge_y.get σ))
Instances For
Equations
0/1-valued indicator that ow_response is a preimage of ow_challenge_y
in the random oracle.
Equations
- preimage_indicator σ = if is_preimage σ then 1 else 0
Instances For
Bookkeeping: if the experiment's result bit is true, then the final
random oracle has ow_response as a preimage of ow_challenge_y.
Phase 4 — Probability bound on preimage_indicator #
The bookkeeping lemma reduces P[win] to P[preimage_indicator at end],
which we now bound by 2(q + 1) / |output| (the standard linear OW bound).
Decomposed into layers analogous to CR's Layer A–D, but with a linear
bound instead of quadratic (since each lazy_query has at most 1/|output|
chance of producing the fixed challenge value, rather than RO_size/|output|).
Layer A_OW (per-query bound): each lazy_query bumps the expected
"useful preimage" indicator by at most 1/|output|. The "useful preimage"
is a preimage of ow_challenge_y other than ow_challenge_x — i.e., a
preimage the adversary actually "found" rather than the trivially-cached
challenge entry.
Layer C_OW (loop accumulation): by induction on q, ow_loop q bumps
the useful_preimage indicator by ≤ q / |output|.
Layer D_OW (full composition): decompose preimage ≤ useful_preimage + [resp = ow_challenge_x ∧ preimage], where:
E[useful_preimage]≤(q+1)/|output|: the loop contributesq/|output|(Layer C_OW); the finallazy_query respcontributes1/|output|(Layer A_OW); the initiallazy_query x_origcontributes 0 becausex_orig = ow_challenge_x(tight self-step).E[[resp = ow_challenge_x ∧ preimage]]≤(q+1)/|input|: the standard "guessing the secret" bound —ow_challenge_xis uniform overinput, and the adversary can identify it only bylazy_querying it amongq+1total queries.
Total: 2(q+1)/|output|, using |input| ≥ |output|.
Standard hash-function assumption: the input space is at least as large as the output space.
Definitions: useful_preimage #
A useful preimage is a preimage of ow_challenge_y other than the trivially
cached ow_challenge_x. We track this separately because:
lazy_query x'bumpsuseful_preimageby exactly[x' ≠ ow_challenge_x ∧ fresh-sample = ow_challenge_y](at most1/|output|in expectation).useful_preimagedepends only onrandom_oracle_state,ow_challenge_x,ow_challenge_y— variables disjoint from the adversary's range — so the adversary cannot affect it directly.
Equations
- useful_preimage σ = ∃ (x' : input), x' ≠ ow_challenge_x.get σ ∧ random_oracle_state.get σ x' = some (ow_challenge_y.get σ)
Instances For
Equations
Equations
- useful_preimage_indicator σ = if useful_preimage σ then 1 else 0
Instances For
Structural decomposition: preimage implies either the response is the
trivially cached challenge input, or there's a useful preimage.
Layer A_OW: per-query bump for useful_preimage_indicator #
Layer C_OW: loop accumulation #
Layer D_OW: full bound #
The expected useful_preimage_indicator at the end of the experiment is
at most (q+1)/|output|: the initial lazy_query on ow_challenge_x adds
nothing (handled by lazy_query_useful_preimage_step_self), the loop adds
at most q/|output| (Layer C_OW), and the final lazy_query on the
adversary's response adds at most 1/|output| (Layer A_OW).
Transfer of ow_transfer from the SubProb marginal level to the
wp level, for postconditions that depend only on the result bit.
Thin wrapper over the generic ProgramDenotation.wp_eq_of_marginal_eq.
The OW lazy/eager bounds (ow_lazy_bound, ow_eager_bound) and their
intermediate ow_preimage_bound are proved in PlonkLean/RO/QueryHit.lean,
which provides the deferred-sampling infrastructure needed to close the
[resp = ow_challenge_x ∧ is_preimage] bound without axioms.