Documentation

GaudisCrypt.Lib.RO.OneWayness

One-wayness of the random oracle #

A 101-crypto example mirroring CollisionResistance.lean. The OW game:

  1. Sample challenge input x ← uniform.
  2. Compute y := oracle(x) and publish y via ow_challenge_y.
  3. Run the adversary ow_adv for q rounds with oracle access; the adversary writes its candidate preimage to ow_response.
  4. Check whether oracle(ow_response) = y.

The high-level claims:

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
Instances For

    Run the adversary-and-query loop for q rounds. Thin alias for the generic oracle_loop_n in RO.lean.

    Equations
    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.

        theorem ow_transfer (ow_adv : GaudisCrypt.ProgramDenotation state Unit) (h_ow_adv : ow_adv.inFootprint (GaudisCrypt.Lens.footprint random_oracle_state)ᶜ) (q : ℕ) (σ₀ : state) :
        (do let bσ ← ow_experiment ow_adv q lazy_init lazy_query σ₀ pure bσ.1) = do let bσ ← ow_experiment ow_adv q random_oracle_init random_oracle_query σ₀ pure bσ.1

        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.

        def is_preimage (σ : state) :

        The "is a preimage" state predicate: RO σ (ow_response σ) = some (ow_challenge_y σ).

        Equations
        Instances For
          noncomputable def preimage_indicator (σ : state) :

          0/1-valued indicator that ow_response is a preimage of ow_challenge_y in the random oracle.

          Equations
          Instances For
            theorem ow_true_implies_preimage_wp (ow_adv : GaudisCrypt.ProgramDenotation state Unit) (h_ow_adv_chal_y : ow_adv.inFootprint (GaudisCrypt.Lens.footprint ow_challenge_y)ᶜ) (q : ℕ) (σ₀ : state) :
            (ow_experiment ow_adv q lazy_init lazy_query).wp (fun (bσ : Bool × state) => if bσ.1 = true then 1 else 0) σ₀ ≤ (ow_experiment ow_adv q lazy_init lazy_query).wp (fun (bσ : Bool × state) => preimage_indicator bσ.2) σ₀

            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:

            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:

            Equations
            Instances For
              noncomputable def useful_preimage_indicator (σ : state) :
              Equations
              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).

                theorem ow_transfer_wp_of_bit (ow_adv : GaudisCrypt.ProgramDenotation state Unit) (h_ow_adv : ow_adv.inFootprint (GaudisCrypt.Lens.footprint random_oracle_state)ᶜ) (q : ℕ) (σ₀ : state) (G : Bool → ENNReal) :
                (ow_experiment ow_adv q lazy_init lazy_query).wp (fun (bσ : Bool × state) => G bσ.1) σ₀ = (ow_experiment ow_adv q random_oracle_init random_oracle_query).wp (fun (bσ : Bool × state) => G bσ.1) σ₀

                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.