Core.lean
Declarations on this page (61)
- structure Sig
- inductive Ty
-
def Ty.
denote - inductive Var
- inductive Env
-
def Env.
get - structure Ops
-
def Ops.
sum - def bits
-
def Ty.
Fits - abbrev ValFits
- def OpsSizeHonest
- inductive Expr
-
def Expr.
eval -
def Expr.
cost -
def Expr.
size - def reductionSizeBudget
- structure Samplers
- def SampSizeHonest
- structure Iface
-
def Iface.
liftP - inductive Comp
- def iterM
- def findML
- def anyML
- def mapML
- def consumeFirstML
- def foldML
-
def Comp.
eval -
def Comp.
cost -
def Comp.
queries -
def Comp.
size - structure GameCodec
- def handlerImpl
- structure CostedReduction
-
def CostedReduction.
impl -
def CostedReduction.
eval -
def CostedReduction.
totalCost -
def CostedReduction.
totalQueries -
def CostedReduction.
size - inductive Mid
- structure TwoStageCostedReduction
-
def TwoStageCostedReduction.
run1 - def runFuel
-
def TwoStageCostedReduction.
eval1 -
def TwoStageCostedReduction.
eval2 -
def TwoStageCostedReduction.
totalCost -
def TwoStageCostedReduction.
totalQueries -
def TwoStageCostedReduction.
size - def AllGameQueriesFit
- def supportWhen
-
def Iface.
AnswerFits -
def Expr.
costAt -
def Comp.
pureEval? -
def Comp.
costAt -
def CostedReduction.
ValidKindCosts -
def CostedReduction.
totalCostByKind -
def CostedReduction.
CostBoundedByKind -
def TwoStageCostedReduction.
ValidKindCosts -
def TwoStageCostedReduction.
totalCostByKind -
def TwoStageCostedReduction.
CostBoundedByKind
ReductionDsl: a costed deep embedding for game reductions
Trusted in part. Every definition in this file except the variable shorthands Expr. to Expr. is part of the trusted base (Computational/): a reduction named by a headline statement is a CostedReduction or TwoStageCostedReduction value whose efficiency claims use totalCost, totalQueries, size, and the per-query-kind cost definitions (Expr., Comp., Comp., ValidKindCosts, totalCostByKind, CostBoundedByKind). The auxiliary size, table-cost, and dual-fuel definitions (Ty., OpsBaseBounded, SampBaseBounded, Ty., Ty., Ty., Ty., Expr., Comp., GameCodec., GameCodec., CostedReduction., TwoStageCostedReduction., runFuelBounded, TwoStageCostedReduction., TwoStageCostedReduction., TwoStageCostedReduction.) are proof-support definitions outside every headline's closure.
ReductionDsl is the first-order language in which security reductions of the computational proof stack are written. It defines pure expressions (Expr) over inspectable data types (unit, bool, nat, opt, prod, sum, list, tbl) and opaque abstract sorts S. accessed solely through declared operation tables (Ops); monadic programs (Comp) with coin-only Samplers, target-game oracle queries (Iface), and statically bounded loops; interpretation into VCVio OracleComp (Expr., Comp.); structural and input-specialized step-cost, query, and syntax-size measures (cost, costAt, queries, size); and single- and two-stage transducers (CostedReduction, TwoStageCostedReduction) over source-game codecs (GameCodec). Shared operation tables, uniform samplers, and target codecs live in AtomicOps.lean, Samplers.lean, and Computational/; see Computational/.
The efficiency model rests on five invariants:
-
Sort opacity and table honesty.
Expreliminates.base bonly viaExpr.. Each table entryop O.bounds the work ofcost o O.up toeval o O.under block measurecost o × (max input blocks) S.and satisfiessz OpsSizeHonest; each query tag'sI.covers reading its argument and answer,qCost I.covers one forwarded uniform coin draw, and each coin-only sampler's constantuCost I.bounds output width (smp. sCost SampSizeHonest). Reductions use only sharedOps,Samplers,Iface, andGameCodectables. -
Bounded value growth. Every value-growing constructor pays at least its output growth in blocks, bit-length, or list length, so run values stay within input size plus step cost plus a run-local oracle-answer bound (
Comp.infits_eval Computational/).Proofs/ ReductionDsl/ Size.lean -
Single-pass black-box execution.
CostedReduction.executes the adversaryeval Aonce viasimulateQwithout rewinding (TwoStageCostedReductionpausesAat most once at a challenge query and resumes its continuation in stage 2), sototalCostandtotalQueriesbound work outsideAand target queries (Computational/).Proofs/ ReductionDsl/ Soundness.lean -
Syntax-size bound. Because branch cost takes
maxover arms, step cost alone allows a depth-ddecision tree to embed a2 ^ d-entry non-uniform lookup table. Headline boundedness predicates therefore also require size ≤reductionSizeBudget(2 ^ 24syntax nodes; both branch arms, numeric literal bit-lengths,Ops.literal payloads, and each loop body count once).opSize -
Input-specialized per-kind cost.
Expr.andcostAt Comp.charge branches only for the arm selected atcostAt ρ(computed viaExpr.), andeval Comp.specializes its continuation only after an effect-free prefix (bind Comp.), falling back to staticpureEval? k.after any sample, query, or monadic loop.cost ValidKindCostsquantifies over all statessand queriest, bounding per-query-kind work viatotalCostByKind(Computational/).Proofs/ ReductionDsl/ KindedCost.lean
@[expose] public sectionnamespace ReductionDslstructure Sig
Signature of abstract base sorts Base with carrier den and block-size measure sz (e.g. ⌈len / w⌉ for byte strings of block width w, or 1 for fixed-width values).
structure Sig where
Base : Type
den : Base → Type
sz : (b : Base) → den b → ℕvariable {S : Sig}inductive Ty
First-order value types over abstract sorts S: inspectable unit, booleans, naturals, options, products, sums, finite lists, and total ℕ-indexed tables tbl t.
def Ty.
Carrier of a value type.
inductive Var
Typed de Bruijn variables in context Γ.
inductive Env
Evaluation environments for typed context Γ.
def Env.
structure Ops
def Ops.
Disjoint union of two operation tables over S.
def bits
Bit-length cost ⌊log₂ n⌋ + 1 of a natural-number literal or constant operand n.
def bits (n : ℕ) : ℕ := Nat.log 2 n + 1
def Ty.
Recursive size bound B on a value: S. on base sorts, bits n ≤ B on .nat, length and element bounds on .list, and pointwise bounds on .tbl.
def Ty.Fits (B : ℕ) : (t : Ty S) → t.denote → Prop
| .base b, x => S.sz b x ≤ B
| .unit, _ => True
| .bool, _ => True
| .nat, n => bits n ≤ B
| .opt _, none => True
| .opt t, some a => t.Fits B a
| .prod t u, x => t.Fits B x.1 ∧ u.Fits B x.2
| .sum t _, .inl a => t.Fits B a
| .sum _ u, .inr b => u.Fits B b
| .list t, l => l.length ≤ B ∧ ∀ x ∈ l, t.Fits B x
| .tbl t, m => ∀ i, t.Fits B (m i)def OpsSizeHonest
Size-honesty obligation on O: every operator o grows the Ty. bound B by at most O..
6 declarations not shown (lines 168–217): theorems, which Lean checks, or definitions that no headline statement uses
ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl.
inductive Expr
Pure expressions in context Γ. Multiplication, division, and modulus allow only constant operands (mulK, divK, modK); bounded list combinators (*B) inspect at most the first K entries.
inductive Expr (O : Ops S) : List (Ty S) → Ty S → Type
| var {Γ t} : Var Γ t → Expr O Γ t
| unit {Γ} : Expr O Γ .unit
| bool {Γ} : Bool → Expr O Γ .bool
| nat {Γ} : ℕ → Expr O Γ .nat
| add {Γ} : Expr O Γ .nat → Expr O Γ .nat → Expr O Γ .nat
| sub {Γ} : Expr O Γ .nat → Expr O Γ .nat → Expr O Γ .nat
| mulK {Γ} : ℕ → Expr O Γ .nat → Expr O Γ .nat
| divK {Γ} : ℕ → Expr O Γ .nat → Expr O Γ .nat
| modK {Γ} : ℕ → Expr O Γ .nat → Expr O Γ .nat
| lt {Γ} : Expr O Γ .nat → Expr O Γ .nat → Expr O Γ .bool
| eqN {Γ} : Expr O Γ .nat → Expr O Γ .nat → Expr O Γ .bool
| not {Γ} : Expr O Γ .bool → Expr O Γ .bool
| and {Γ} : Expr O Γ .bool → Expr O Γ .bool → Expr O Γ .bool
| ite {Γ t} : Expr O Γ .bool → Expr O Γ t → Expr O Γ t → Expr O Γ t
| pair {Γ t u} : Expr O Γ t → Expr O Γ u → Expr O Γ (.prod t u)
| fst {Γ t u} : Expr O Γ (.prod t u) → Expr O Γ t
| snd {Γ t u} : Expr O Γ (.prod t u) → Expr O Γ u
| inl {Γ t u} : Expr O Γ t → Expr O Γ (.sum t u)
| inr {Γ t u} : Expr O Γ u → Expr O Γ (.sum t u)
| none {Γ t} : Expr O Γ (.opt t)
| some {Γ t} : Expr O Γ t → Expr O Γ (.opt t)
| caseOpt {Γ t u} : Expr O Γ (.opt t) → Expr O Γ u → Expr O (t :: Γ) u → Expr O Γ u
| caseSum {Γ t u v} : Expr O Γ (.sum t u) → Expr O (t :: Γ) v → Expr O (u :: Γ) v →
Expr O Γ v
| letE {Γ t u} : Expr O Γ t → Expr O (t :: Γ) u → Expr O Γ u
| op {Γ} (o : O.Op) : Expr O Γ (O.dom o) → Expr O Γ (O.cod o)
| nil {Γ t} : Expr O Γ (.list t)
| cons {Γ t} : Expr O Γ t → Expr O Γ (.list t) → Expr O Γ (.list t)
| len {Γ t} : Expr O Γ (.list t) → Expr O Γ .nat
| take {Γ t} : Expr O Γ .nat → Expr O Γ (.list t) → Expr O Γ (.list t)
/-- Concatenation truncated to the first `K` entries. -/
| appendL {Γ t} (K : ℕ) : Expr O Γ (.list t) → Expr O Γ (.list t) → Expr O Γ (.list t)
/-- First among the first `K` entries satisfying predicate `p` (entry bound at `v0`). -/
| findB {Γ t} (K : ℕ) : Expr O Γ (.list t) → Expr O (t :: Γ) .bool → Expr O Γ (.opt t)
| anyB {Γ t} (K : ℕ) : Expr O Γ (.list t) → Expr O (t :: Γ) .bool → Expr O Γ .bool
| mapB {Γ t u} (K : ℕ) : Expr O Γ (.list t) → Expr O (t :: Γ) u → Expr O Γ (.list u)
/-- Right fold over the first `K` entries (entry bound at `v0`, accumulator at `v1`). -/
| foldrB {Γ t u} (K : ℕ) : Expr O Γ (.list t) → Expr O Γ u → Expr O (t :: u :: Γ) u →
Expr O Γ u
| tconst {Γ t} : Expr O Γ t → Expr O Γ (.tbl t)
| tget {Γ t} : Expr O Γ (.tbl t) → Expr O Γ .nat → Expr O Γ t
| tset {Γ t} : Expr O Γ (.tbl t) → Expr O Γ .nat → Expr O Γ t → Expr O Γ (.tbl t)variable {O : Ops S}7 declarations not shown (lines 269–278): theorems, which Lean checks, or definitions that no headline statement uses
ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl.
def Expr.
Evaluates a pure expression in environment ρ.
def Expr.eval : {Γ : List (Ty S)} → {t : Ty S} → Expr O Γ t → Env Γ → t.denote
| _, _, .var v, ρ => ρ.get v
| _, _, .unit, _ => ()
| _, _, .bool b, _ => b
| _, _, .nat n, _ => n
| _, _, .add a b, ρ => a.eval ρ + b.eval ρ
| _, _, .sub a b, ρ => a.eval ρ - b.eval ρ
| _, _, .mulK k a, ρ => k * a.eval ρ
| _, _, .divK k a, ρ => a.eval ρ / k
| _, _, .modK k a, ρ => a.eval ρ % k
| _, _, .lt a b, ρ => decide (a.eval ρ < b.eval ρ)
| _, _, .eqN a b, ρ => decide (a.eval ρ = b.eval ρ)
| _, _, .not a, ρ => !a.eval ρ
| _, _, .and a b, ρ => a.eval ρ && b.eval ρ
| _, _, .ite c a b, ρ => if c.eval ρ then a.eval ρ else b.eval ρ
| _, _, .pair a b, ρ => (a.eval ρ, b.eval ρ)
| _, _, .fst a, ρ => (a.eval ρ).1
| _, _, .snd a, ρ => (a.eval ρ).2
| _, _, .inl a, ρ => Sum.inl (a.eval ρ)
| _, _, .inr a, ρ => Sum.inr (a.eval ρ)
| _, _, .none, _ => Option.none
| _, _, .some a, ρ => Option.some (a.eval ρ)
| _, _, .caseOpt e n s, ρ => match e.eval ρ with
| Option.none => n.eval ρ
| Option.some x => s.eval (.cons x ρ)
| _, _, .caseSum e l r, ρ => match e.eval ρ with
| Sum.inl x => l.eval (.cons x ρ)
| Sum.inr y => r.eval (.cons y ρ)
| _, _, .letE e b, ρ => b.eval (.cons (e.eval ρ) ρ)
| _, _, .op o a, ρ => O.eval o (a.eval ρ)
| _, _, .nil, _ => []
| _, _, .cons x l, ρ => x.eval ρ :: l.eval ρ
| _, _, .len l, ρ => (l.eval ρ).length
| _, _, .take n l, ρ => (l.eval ρ).take (n.eval ρ)
| _, _, .appendL K a b, ρ => (a.eval ρ ++ b.eval ρ).take K
| _, _, .findB K l p, ρ => ((l.eval ρ).take K).find? fun x => p.eval (.cons x ρ)
| _, _, .anyB K l p, ρ => ((l.eval ρ).take K).any fun x => p.eval (.cons x ρ)
| _, _, .mapB K l f, ρ => ((l.eval ρ).take K).map fun x => f.eval (.cons x ρ)
| _, _, .foldrB K l z f, ρ =>
((l.eval ρ).take K).foldr (fun x acc => f.eval (.cons x (.cons acc ρ))) (z.eval ρ)
| _, _, .tconst a, ρ => fun _ => a.eval ρ
| _, _, .tget m i, ρ => m.eval ρ (i.eval ρ)
| _, _, .tset m i a, ρ => fun j => if j = i.eval ρ then a.eval ρ else m.eval ρ j
def Expr.
Static step cost of an expression: branches charge max of their arms, loops charge K times their body, and .tget/.tset charge 64/128.
def Expr.cost : {Γ : List (Ty S)} → {t : Ty S} → Expr O Γ t → ℕ
| _, _, .var _ => 1
| _, _, .unit => 1
| _, _, .bool _ => 1
| _, _, .nat n => bits n
| _, _, .add a b => a.cost + b.cost + 1
| _, _, .sub a b => a.cost + b.cost + 1
| _, _, .mulK k a => a.cost + bits k
| _, _, .divK k a => a.cost + bits k
| _, _, .modK k a => a.cost + bits k
| _, _, .lt a b => a.cost + b.cost + 1
| _, _, .eqN a b => a.cost + b.cost + 1
| _, _, .not a => a.cost + 1
| _, _, .and a b => a.cost + b.cost + 1
| _, _, .ite c a b => c.cost + max a.cost b.cost + 1
| _, _, .pair a b => a.cost + b.cost + 1
| _, _, .fst a => a.cost + 1
| _, _, .snd a => a.cost + 1
| _, _, .inl a => a.cost + 1
| _, _, .inr a => a.cost + 1
| _, _, .none => 1
| _, _, .some a => a.cost + 1
| _, _, .caseOpt e n s => e.cost + max n.cost s.cost + 1
| _, _, .caseSum e l r => e.cost + max l.cost r.cost + 1
| _, _, .letE e b => e.cost + b.cost + 1
| _, _, .op o a => a.cost + O.cost o
| _, _, .nil => 1
| _, _, .cons x l => x.cost + l.cost + 1
| _, _, .len l => l.cost + 1
| _, _, .take n l => n.cost + l.cost + 1
| _, _, .appendL K a b => a.cost + b.cost + K + 1
| _, _, .findB K l p => l.cost + K * (p.cost + 1) + 1
| _, _, .anyB K l p => l.cost + K * (p.cost + 1) + 1
| _, _, .mapB K l f => l.cost + K * (f.cost + 1) + 1
| _, _, .foldrB K l z f => l.cost + z.cost + K * (f.cost + 1) + 1
| _, _, .tconst a => a.cost + 1
| _, _, .tget m i => m.cost + i.cost + 64
| _, _, .tset m i a => m.cost + i.cost + a.cost + 128
def Expr.
Syntax-tree size of an expression: counts both branch arms, each loop body once, bit-lengths of numeric literals and loop bounds, and O. for operator payloads.
def Expr.size : {Γ : List (Ty S)} → {t : Ty S} → Expr O Γ t → ℕ
| _, _, .var _ => 1
| _, _, .unit => 1
| _, _, .bool _ => 1
| _, _, .nat n => bits n
| _, _, .add a b => a.size + b.size + 1
| _, _, .sub a b => a.size + b.size + 1
| _, _, .mulK k a => a.size + bits k
| _, _, .divK k a => a.size + bits k
| _, _, .modK k a => a.size + bits k
| _, _, .lt a b => a.size + b.size + 1
| _, _, .eqN a b => a.size + b.size + 1
| _, _, .not a => a.size + 1
| _, _, .and a b => a.size + b.size + 1
| _, _, .ite c a b => c.size + a.size + b.size + 1
| _, _, .pair a b => a.size + b.size + 1
| _, _, .fst a => a.size + 1
| _, _, .snd a => a.size + 1
| _, _, .inl a => a.size + 1
| _, _, .inr a => a.size + 1
| _, _, .none => 1
| _, _, .some a => a.size + 1
| _, _, .caseOpt e n s => e.size + n.size + s.size + 1
| _, _, .caseSum e l r => e.size + l.size + r.size + 1
| _, _, .letE e b => e.size + b.size + 1
| _, _, .op o a => a.size + O.opSize o + 1
| _, _, .nil => 1
| _, _, .cons x l => x.size + l.size + 1
| _, _, .len l => l.size + 1
| _, _, .take n l => n.size + l.size + 1
| _, _, .appendL K a b => a.size + b.size + bits K + 1
| _, _, .findB K l p => l.size + p.size + bits K + 1
| _, _, .anyB K l p => l.size + p.size + bits K + 1
| _, _, .mapB K l f => l.size + f.size + bits K + 1
| _, _, .foldrB K l z f => l.size + z.size + f.size + bits K + 1
| _, _, .tconst a => a.size + 1
| _, _, .tget m i => m.size + i.size + 1
| _, _, .tset m i a => m.size + i.size + a.size + 1def reductionSizeBudget
Syntax-tree size budget (2 ^ 24 nodes) for headline-named reductions; bounds the non-uniform lookup-table advice an existentially quantified reduction can embed.
def reductionSizeBudget : ℕ := 2 ^ 24structure Samplers
2 declarations not shown (lines 420–435): theorems, which Lean checks, or definitions that no headline statement uses
ReductionDsl., ReductionDsl.
def SampSizeHonest
Size-honesty obligation on X: every sampled output grows the Ty. bound B by at most X..
2 declarations not shown (lines 443–493): theorems, which Lean checks, or definitions that no headline statement uses
ReductionDsl., ReductionDsl.
structure Iface
Oracle interface into target specification T: typed query tags encoded as single T-queries with step cost qCost, uniform-coin forwarding fwdU of cost uCost, and samplers smp.
structure Iface (S : Sig) {ι : Type} (T : OracleSpec ι) where
/-- Forwards an adversary uniform-coin draw `Fin (n + 1)` (`unifSpec`) into `OracleComp T`. -/
fwdU : (n : ℕ) → OracleComp T (Fin (n + 1))
/-- Step cost of forwarding one uniform coin draw via `fwdU`. -/
uCost : ℕ
Tag : Type
dom : Tag → Ty S
cod : Tag → Ty S
enc : (g : Tag) → (dom g).denote → ι
dec : (g : Tag) → (x : (dom g).denote) → T (enc g x) → (cod g).denote
qCost : Tag → ℕ
smp : Samplers S1 declaration not shown (lines 510–512): theorems, which Lean checks, or definitions that no headline statement uses
ReductionDsl.
def Iface.
Lifts a coin-only ProbComp into OracleComp T by forwarding coin draws via I..
variable {ι : Type} {T : OracleSpec ι} {I : Iface S T}inductive Comp
Monadic programs over O and I: pure returns, sequencing, branching, sampling, target queries, and statically bounded loops (n iterations or at most the first K list entries).
inductive Comp (O : Ops S) (I : Iface S T) : List (Ty S) → Ty S → Type
| ret {Γ t} : Expr O Γ t → Comp O I Γ t
| bind {Γ t u} : Comp O I Γ t → Comp O I (t :: Γ) u → Comp O I Γ u
| ite {Γ t} : Expr O Γ .bool → Comp O I Γ t → Comp O I Γ t → Comp O I Γ t
| caseOpt {Γ t u} : Expr O Γ (.opt t) → Comp O I Γ u → Comp O I (t :: Γ) u → Comp O I Γ u
| caseSum {Γ t u v} : Expr O Γ (.sum t u) → Comp O I (t :: Γ) v → Comp O I (u :: Γ) v →
Comp O I Γ v
| sample {Γ} (s : I.smp.Samp) : Expr O Γ (I.smp.sDom s) → Comp O I Γ (I.smp.sTy s)
| query {Γ} (g : I.Tag) : Expr O Γ (I.dom g) → Comp O I Γ (I.cod g)
/-- Runs `n` iterations of `body` from initial accumulator `init` (bound at `v0`). -/
| iter {Γ t} (n : ℕ) : Expr O Γ t → Comp O I (t :: Γ) t → Comp O I Γ t
/-- Short-circuiting monadic search over the first `K` entries. -/
| findM {Γ t} (K : ℕ) : Expr O Γ (.list t) → Comp O I (t :: Γ) .bool → Comp O I Γ (.opt t)
/-- Short-circuiting monadic existential check over the first `K` entries. -/
| anyM {Γ t} (K : ℕ) : Expr O Γ (.list t) → Comp O I (t :: Γ) .bool → Comp O I Γ .bool
| mapM {Γ t u} (K : ℕ) : Expr O Γ (.list t) → Comp O I (t :: Γ) u → Comp O I Γ (.list u)
/-- Replaces the first among the first `K` entries passing the test with `mark` of it; yields
`(found, updatedPrefix)`. -/
| consumeFirstM {Γ t} (K : ℕ) : Expr O Γ (.list t) → Comp O I (t :: Γ) .bool →
Expr O (t :: Γ) t → Comp O I Γ (.prod .bool (.list t))
/-- Monadic left fold over the first `K` entries (entry bound at `v0`, accumulator at `v1`). -/
| foldM {Γ t u} (K : ℕ) : Expr O Γ (.list t) → Expr O Γ u → Comp O I (t :: u :: Γ) u →
Comp O I Γ udef iterM
def iterM {m : Type → Type} [Monad m] {α : Type} (f : α → m α) : ℕ → α → m α
| 0, a => pure a
| n + 1, a => f a >>= iterM f ndef findML
def findML {m : Type → Type} [Monad m] {α : Type} (p : α → m Bool) : List α → m (Option α)
| [] => pure Option.none
| x :: xs => do if ← p x then pure (Option.some x) else findML p xsdef anyML
def anyML {m : Type → Type} [Monad m] {α : Type} (p : α → m Bool) : List α → m Bool
| [] => pure false
| x :: xs => do if ← p x then pure true else anyML p xsdef mapML
def mapML {m : Type → Type} [Monad m] {α β : Type} (f : α → m β) : List α → m (List β)
| [] => pure []
| x :: xs => do let y ← f x; let ys ← mapML f xs; pure (y :: ys)def consumeFirstML
Short-circuiting replacement of the first entry passing p by mark of it.
def consumeFirstML {m : Type → Type} [Monad m] {α : Type} (p : α → m Bool) (mark : α → α) :
List α → m (Bool × List α)
| [] => pure (false, [])
| x :: xs => do
if ← p x then pure (true, mark x :: xs)
else do let r ← consumeFirstML p mark xs; pure (r.1, x :: r.2)def foldML
def foldML {m : Type → Type} [Monad m] {α β : Type} (f : α → β → m β) : β → List α → m β
| b, [] => pure b
| b, x :: xs => do let b' ← f x b; foldML f b' xs
def Comp.
Interprets a Comp program into OracleComp T.
def Comp.eval : {Γ : List (Ty S)} → {t : Ty S} → Comp O I Γ t → Env Γ → OracleComp T t.denote
| _, _, .ret e, ρ => pure (e.eval ρ)
| _, _, .bind c k, ρ => c.eval ρ >>= fun x => k.eval (.cons x ρ)
| _, _, .ite b c d, ρ => if b.eval ρ then c.eval ρ else d.eval ρ
| _, _, .caseOpt e n s, ρ => match e.eval ρ with
| Option.none => n.eval ρ
| Option.some x => s.eval (.cons x ρ)
| _, _, .caseSum e l r, ρ => match e.eval ρ with
| Sum.inl x => l.eval (.cons x ρ)
| Sum.inr y => r.eval (.cons y ρ)
| _, _, .sample s e, ρ => I.liftP (I.smp.samp s (e.eval ρ))
| _, _, .query g e, ρ =>
let x := e.eval ρ
I.dec g x <$> (liftM (T.query (I.enc g x)) : OracleComp T _)
| _, _, .iter n e body, ρ => iterM (fun a => body.eval (.cons a ρ)) n (e.eval ρ)
| _, _, .findM K l p, ρ => findML (fun x => p.eval (.cons x ρ)) ((l.eval ρ).take K)
| _, _, .anyM K l p, ρ => anyML (fun x => p.eval (.cons x ρ)) ((l.eval ρ).take K)
| _, _, .mapM K l f, ρ => mapML (fun x => f.eval (.cons x ρ)) ((l.eval ρ).take K)
| _, _, .consumeFirstM K l p mk, ρ =>
consumeFirstML (fun x => p.eval (.cons x ρ)) (fun x => mk.eval (.cons x ρ))
((l.eval ρ).take K)
| _, _, .foldM K l z f, ρ =>
foldML (fun x acc => f.eval (.cons x (.cons acc ρ))) (z.eval ρ) ((l.eval ρ).take K)
def Comp.
Static step cost of a program: branches charge max of their arms and loops charge n or K times their body.
def Comp.cost : {Γ : List (Ty S)} → {t : Ty S} → Comp O I Γ t → ℕ
| _, _, .ret e => e.cost + 1
| _, _, .bind c k => c.cost + k.cost + 1
| _, _, .ite b c d => b.cost + max c.cost d.cost + 1
| _, _, .caseOpt e n s => e.cost + max n.cost s.cost + 1
| _, _, .caseSum e l r => e.cost + max l.cost r.cost + 1
| _, _, .sample s e => e.cost + I.smp.sCost s
| _, _, .query g e => e.cost + I.qCost g
| _, _, .iter n e body => e.cost + n * (body.cost + 1) + 1
| _, _, .findM K l p => l.cost + K * (p.cost + 1) + 1
| _, _, .anyM K l p => l.cost + K * (p.cost + 1) + 1
| _, _, .mapM K l f => l.cost + K * (f.cost + 1) + 1
| _, _, .consumeFirstM K l p mk => l.cost + K * (p.cost + mk.cost + 1) + 1
| _, _, .foldM K l z f => l.cost + z.cost + K * (f.cost + 1) + 1
def Comp.
Static weighted upper bound on target queries (w) and samples (ws).
def Comp.queries (w : I.Tag → ℕ) (ws : I.smp.Samp → ℕ) :
{Γ : List (Ty S)} → {t : Ty S} → Comp O I Γ t → ℕ
| _, _, .ret _ => 0
| _, _, .bind c k => c.queries w ws + k.queries w ws
| _, _, .ite _ c d => max (c.queries w ws) (d.queries w ws)
| _, _, .caseOpt _ n s => max (n.queries w ws) (s.queries w ws)
| _, _, .caseSum _ l r => max (l.queries w ws) (r.queries w ws)
| _, _, .sample s _ => ws s
| _, _, .query g _ => w g
| _, _, .iter n _ body => n * body.queries w ws
| _, _, .findM K _ p => K * p.queries w ws
| _, _, .anyM K _ p => K * p.queries w ws
| _, _, .mapM K _ f => K * f.queries w ws
| _, _, .consumeFirstM K _ p _ => K * p.queries w ws
| _, _, .foldM K _ _ f => K * f.queries w ws
def Comp.
Syntax-tree size of a program: counts both branch arms, each loop body once, and bit-lengths of loop bounds n and K.
def Comp.size : {Γ : List (Ty S)} → {t : Ty S} → Comp O I Γ t → ℕ
| _, _, .ret e => e.size + 1
| _, _, .bind c k => c.size + k.size + 1
| _, _, .ite b c d => b.size + c.size + d.size + 1
| _, _, .caseOpt e n s => e.size + n.size + s.size + 1
| _, _, .caseSum e l r => e.size + l.size + r.size + 1
| _, _, .sample _ e => e.size + 1
| _, _, .query _ e => e.size + 1
| _, _, .iter n e body => e.size + body.size + bits n + 1
| _, _, .findM K l p => l.size + p.size + bits K + 1
| _, _, .anyM K l p => l.size + p.size + bits K + 1
| _, _, .mapM K l f => l.size + f.size + bits K + 1
| _, _, .consumeFirstM K l p mk => l.size + p.size + mk.size + bits K + 1
| _, _, .foldM K l z f => l.size + z.size + f.size + bits K + 1structure GameCodec
Encoding of source-game G queries into Q (qenc) and decoding of R values into G answers (rdec), with per-query encoding/decoding overhead codecCost.
variable {κ : Type} {G : OracleSpec κ} {C : GameCodec S G}def handlerImpl
Simulates unifSpec + G in state σ by forwarding coins via I. and answering G-queries with h (in context [σ, C.).
structure CostedReduction
Single-stage black-box reduction against game G (codec C) with state σ: init maps reduction input rIn to (aIn, σ), handle maps (σ, C. to (C., and finish maps (σ, aOut) to out.
variable {rIn aIn aOut out : Ty S}
def CostedReduction.
def CostedReduction.impl (R : CostedReduction O I G C rIn aIn aOut out) :
QueryImpl (unifSpec + G) (StateT R.σ.denote (OracleComp T)) :=
handlerImpl R.handle
def CostedReduction.
Runs reduction R once around adversary A on input x in OracleComp T.
def CostedReduction.eval (R : CostedReduction O I G C rIn aIn aOut out)
(A : aIn.denote → OracleComp (unifSpec + G) aOut.denote) (x : rIn.denote) :
OracleComp T out.denote := do
let (a, s) ← R.init.eval (.cons x .nil)
let (b, s') ← (simulateQ R.impl (A a)).run s
R.finish.eval (.cons s' (.cons b .nil))
def CostedReduction.
Upper bound on step cost outside A when A makes at most q total unifSpec + G queries.
def CostedReduction.
Weighted upper bound on target queries and samples when A makes at most q G-queries.
def CostedReduction.
Total syntax-tree size of R (init, handle, and finish counted once each).
Two-stage reductions
inductive Mid
Stage-1 termination state: either A finished (done), or A paused (paused) at query t with stage-1 challenge output c, saved pause data p, state s, and continuation k.
inductive Mid (G : OracleSpec κ) (α π σ χ : Type) where
| done (a : α) (s : σ)
| paused (t : κ) (c : χ) (p : π) (s : σ) (k : G t → OracleComp (unifSpec + G) α)structure TwoStageCostedReduction
Two-stage black-box reduction against G (codec C) for a target taking stage-1 output ch and supplying stage-2 input rIn2. In stage 1, handlePre either answers a G-query (inl) or pauses (inr) with (c, p, σ'), and chDone produces c if A finishes without pausing; in stage 2, resume answers the paused query from rIn2, handlePost answers subsequent queries, and finish computes the final output.
In eval1 and eval2, fuel caps G-queries per stage (returning dflt on exhaustion) while coin draws are forwarded without consuming fuel; setting fuel := q when A makes at most q G-queries across both stages makes the fallback unreachable. See eval1Bounded and eval2Bounded for explicit coin and game-query fuel.
structure TwoStageCostedReduction (O : Ops S) (I : Iface S T) {κ : Type} (G : OracleSpec κ) (C : GameCodec S G)
(rIn aIn aOut ch rIn2 out : Ty S) where
σ : Ty S
π : Ty S
init : Comp O I [rIn] (.prod aIn σ)
handlePre : Comp O I [σ, C.Q] (.sum (.prod C.R σ) (.prod ch (.prod π σ)))
chDone : Comp O I [σ, aOut] ch
resume : Comp O I [σ, π, rIn2] (.prod C.R σ)
handlePost : Comp O I [σ, C.Q] (.prod C.R σ)
finish : Comp O I [σ, aOut, rIn2] outvariable {ch rIn2 : Ty S}
def TwoStageCostedReduction.
Runs stage 1 on oa for at most fuel G-queries (coins forwarded via I.); returns .done dflt s on fuel exhaustion.
def TwoStageCostedReduction.run1 (R : TwoStageCostedReduction O I G C rIn aIn aOut ch rIn2 out) {α : Type} (dflt : α)
(oa : OracleComp (unifSpec + G) α) :
ℕ → R.σ.denote → OracleComp T (Mid G α R.π.denote R.σ.denote ch.denote) :=
OracleComp.construct
(C := fun _ => ℕ → R.σ.denote → OracleComp T (Mid G α R.π.denote R.σ.denote ch.denote))
(fun a _ s => pure (.done a s))
(fun q k r f s => match q with
| .inl n => do let u ← I.fwdU n; r u f s
| .inr t => match f with
| 0 => pure (.done dflt s)
| f + 1 => do
match ← R.handlePre.eval (.cons s (.cons (C.qenc t) .nil)) with
| .inl (v, s') => r (C.rdec t v) f s'
| .inr (c, p, s') => pure (.paused t c p s' k))
oadef runFuel
Runs oa under handler h for at most fuel G-queries (coins forwarded via I.); returns (dflt, s) on fuel exhaustion.
def runFuel {σ : Ty S} (h : Comp O I [σ, C.Q] (.prod C.R σ)) {α : Type} (dflt : α)
(oa : OracleComp (unifSpec + G) α) : ℕ → σ.denote → OracleComp T (α × σ.denote) :=
OracleComp.construct (C := fun _ => ℕ → σ.denote → OracleComp T (α × σ.denote))
(fun a _ s => pure (a, s))
(fun q _ r f s => match q with
| .inl n => do let u ← I.fwdU n; r u f s
| .inr t => match f with
| 0 => pure (dflt, s)
| f + 1 => do
let p ← h.eval (.cons s (.cons (C.qenc t) .nil))
r (C.rdec t p.1) f p.2)
oa
def TwoStageCostedReduction.
Executes stage 1 of R on adversary A and input x with G-query budget fuel and fallback output dflt; yields the target's stage-1 input and Mid state.
def TwoStageCostedReduction.eval1 (R : TwoStageCostedReduction O I G C rIn aIn aOut ch rIn2 out)
(A : aIn.denote → OracleComp (unifSpec + G) aOut.denote) (x : rIn.denote) (fuel : ℕ)
(dflt : aOut.denote) :
OracleComp T (ch.denote × Mid G aOut.denote R.π.denote R.σ.denote ch.denote) := do
let (a, s) ← R.init.eval (.cons x .nil)
let m ← R.run1 dflt (A a) fuel s
match m with
| .done b s' => do let c ← R.chDone.eval (.cons s' (.cons b .nil)); pure (c, m)
| .paused _ c _ _ _ => pure (c, m)
def TwoStageCostedReduction.
Resumes m with stage-2 target input y under G-query budget fuel and fallback dflt, then runs R..
def TwoStageCostedReduction.eval2 (R : TwoStageCostedReduction O I G C rIn aIn aOut ch rIn2 out)
(m : Mid G aOut.denote R.π.denote R.σ.denote ch.denote) (y : rIn2.denote) (fuel : ℕ)
(dflt : aOut.denote) : OracleComp T out.denote := do
let (b, s) ← match m with
| .done b s => pure (b, s)
| .paused t _ p s k => do
let (v, s') ← R.resume.eval (.cons s (.cons p (.cons y .nil)))
runFuel R.handlePost dflt (k (C.rdec t v)) fuel s'
R.finish.eval (.cons s (.cons b (.cons y .nil)))
def TwoStageCostedReduction.
Upper bound on step cost outside A across both stages when A makes at most q total unifSpec + G queries.
def TwoStageCostedReduction.
Weighted upper bound on target queries and samples across both stages when A makes at most q G-queries.
def TwoStageCostedReduction.totalQueries (R : TwoStageCostedReduction O I G C rIn aIn aOut ch rIn2 out) (w : I.Tag → ℕ)
(ws : I.smp.Samp → ℕ) (q : ℕ) : ℕ :=
R.init.queries w ws + q * max (R.handlePre.queries w ws) (R.handlePost.queries w ws) +
max (R.chDone.queries w ws) (R.resume.queries w ws) + R.finish.queries w ws
def TwoStageCostedReduction.
Total syntax-tree size of R across all six stage components, counted once each.
Run-local size premises
def AllGameQueriesFit
Run-local query-size bound: along every execution branch of oa, each game query .inr t satisfies C. (coin queries .inl n are unconstrained). Adapted from an earlier definition by Swarat Chaudhuri.
open OracleSpec OracleComp in
def AllGameQueriesFit {κ : Type} {G : OracleSpec κ}
(B : ℕ) (C : GameCodec S G) {α : Type}
(oa : OracleComp (unifSpec + G) α) : Prop :=
OracleComp.construct
(C := fun _ => Prop)
(fun _ => True)
(fun q _ r => match q with
| .inl _ => ∀ u, r u
| .inr t => C.Q.Fits B (C.qenc t) ∧ ∀ u, r u)
oadef supportWhen
Outputs reachable by oa along execution branches where every oracle query t receives an answer u satisfying P t u (equals support oa when P is True).
open OracleSpec OracleComp in
def supportWhen {ι' : Type} {spec : OracleSpec ι'} {α : Type}
(P : (t : ι') → spec t → Prop) (oa : OracleComp spec α) : Set α :=
OracleComp.construct
(C := fun _ => Set α)
(fun a => {a})
(fun t _ r => {y | ∃ u, P t u ∧ y ∈ r u})
oa
def Iface.
Run-local answer-size predicate: target answer u : T i decodes within Ty. B under every tag g and input x with I..
Input-specialized per-query-kind cost bounds
def Expr.
Input-specialized cost of evaluating e in ρ: matches Expr., except ite, caseOpt, caseSum, and letE charge their guard or bound expression plus only the branch taken at ρ (bounded list loops still charge static body .cost).
def Expr.costAt : {Γ : List (Ty S)} → {t : Ty S} → Expr O Γ t → Env Γ → ℕ
| _, _, .var _, _ => 1
| _, _, .unit, _ => 1
| _, _, .bool _, _ => 1
| _, _, .nat n, _ => bits n
| _, _, .add a b, ρ => a.costAt ρ + b.costAt ρ + 1
| _, _, .sub a b, ρ => a.costAt ρ + b.costAt ρ + 1
| _, _, .mulK k a, ρ => a.costAt ρ + bits k
| _, _, .divK k a, ρ => a.costAt ρ + bits k
| _, _, .modK k a, ρ => a.costAt ρ + bits k
| _, _, .lt a b, ρ => a.costAt ρ + b.costAt ρ + 1
| _, _, .eqN a b, ρ => a.costAt ρ + b.costAt ρ + 1
| _, _, .not a, ρ => a.costAt ρ + 1
| _, _, .and a b, ρ => a.costAt ρ + b.costAt ρ + 1
| _, _, .ite c a b, ρ => c.costAt ρ + (if c.eval ρ then a.costAt ρ else b.costAt ρ) + 1
| _, _, .pair a b, ρ => a.costAt ρ + b.costAt ρ + 1
| _, _, .fst a, ρ => a.costAt ρ + 1
| _, _, .snd a, ρ => a.costAt ρ + 1
| _, _, .inl a, ρ => a.costAt ρ + 1
| _, _, .inr a, ρ => a.costAt ρ + 1
| _, _, .none, _ => 1
| _, _, .some a, ρ => a.costAt ρ + 1
| _, _, .caseOpt e n s, ρ =>
e.costAt ρ + (match e.eval ρ with
| Option.none => n.costAt ρ
| Option.some x => s.costAt (.cons x ρ)) + 1
| _, _, .caseSum e l r, ρ =>
e.costAt ρ + (match e.eval ρ with
| Sum.inl x => l.costAt (.cons x ρ)
| Sum.inr y => r.costAt (.cons y ρ)) + 1
| _, _, .letE e b, ρ => e.costAt ρ + b.costAt (.cons (e.eval ρ) ρ) + 1
| _, _, .op o a, ρ => a.costAt ρ + O.cost o
| _, _, .nil, _ => 1
| _, _, .cons x l, ρ => x.costAt ρ + l.costAt ρ + 1
| _, _, .len l, ρ => l.costAt ρ + 1
| _, _, .take n l, ρ => n.costAt ρ + l.costAt ρ + 1
| _, _, .appendL K a b, ρ => a.costAt ρ + b.costAt ρ + K + 1
| _, _, .findB K l p, ρ => l.costAt ρ + K * (p.cost + 1) + 1
| _, _, .anyB K l p, ρ => l.costAt ρ + K * (p.cost + 1) + 1
| _, _, .mapB K l f, ρ => l.costAt ρ + K * (f.cost + 1) + 1
| _, _, .foldrB K l z f, ρ => l.costAt ρ + z.costAt ρ + K * (f.cost + 1) + 1
| _, _, .tconst a, ρ => a.costAt ρ + 1
| _, _, .tget m i, ρ => m.costAt ρ + i.costAt ρ + 64
| _, _, .tset m i a, ρ => m.costAt ρ + i.costAt ρ + a.costAt ρ + 128
def Comp.
Evaluates an effect-free prefix of c in ρ; returns none if execution reaches a sample, target query, or monadic loop.
def Comp.pureEval? : {Γ : List (Ty S)} → {t : Ty S} → Comp O I Γ t → Env Γ → Option t.denote
| _, _, .ret e, ρ => Option.some (e.eval ρ)
| _, _, .bind c k, ρ => (c.pureEval? ρ).bind fun x => k.pureEval? (.cons x ρ)
| _, _, .ite b c d, ρ => if b.eval ρ then c.pureEval? ρ else d.pureEval? ρ
| _, _, .caseOpt e n s, ρ => match e.eval ρ with
| Option.none => n.pureEval? ρ
| Option.some x => s.pureEval? (.cons x ρ)
| _, _, .caseSum e l r, ρ => match e.eval ρ with
| Sum.inl x => l.pureEval? (.cons x ρ)
| Sum.inr y => r.pureEval? (.cons y ρ)
| _, _, .sample _ _, _ => Option.none
| _, _, .query _ _, _ => Option.none
| _, _, .iter _ _ _, _ => Option.none
| _, _, .findM _ _ _, _ => Option.none
| _, _, .anyM _ _ _, _ => Option.none
| _, _, .mapM _ _ _, _ => Option.none
| _, _, .consumeFirstM _ _ _ _, _ => Option.none
| _, _, .foldM _ _ _ _, _ => Option.none
def Comp.
Input-specialized cost of running c in ρ: branches charge only the arm taken at ρ, bind specializes its continuation when c. (and charges static k. otherwise), and loops charge static body .cost.
def Comp.costAt : {Γ : List (Ty S)} → {t : Ty S} → Comp O I Γ t → Env Γ → ℕ
| _, _, .ret e, ρ => e.costAt ρ + 1
| _, _, .bind c k, ρ =>
c.costAt ρ + (match c.pureEval? ρ with
| Option.some x => k.costAt (.cons x ρ)
| Option.none => k.cost) + 1
| _, _, .ite b c d, ρ => b.costAt ρ + (if b.eval ρ then c.costAt ρ else d.costAt ρ) + 1
| _, _, .caseOpt e n s, ρ =>
e.costAt ρ + (match e.eval ρ with
| Option.none => n.costAt ρ
| Option.some x => s.costAt (.cons x ρ)) + 1
| _, _, .caseSum e l r, ρ =>
e.costAt ρ + (match e.eval ρ with
| Sum.inl x => l.costAt (.cons x ρ)
| Sum.inr y => r.costAt (.cons y ρ)) + 1
| _, _, .sample s e, ρ => e.costAt ρ + I.smp.sCost s
| _, _, .query g e, ρ => e.costAt ρ + I.qCost g
| _, _, .iter n e body, ρ => e.costAt ρ + n * (body.cost + 1) + 1
| _, _, .findM K l p, ρ => l.costAt ρ + K * (p.cost + 1) + 1
| _, _, .anyM K l p, ρ => l.costAt ρ + K * (p.cost + 1) + 1
| _, _, .mapM K l f, ρ => l.costAt ρ + K * (f.cost + 1) + 1
| _, _, .consumeFirstM K l p mk, ρ => l.costAt ρ + K * (p.cost + mk.cost + 1) + 1
| _, _, .foldM K l z f, ρ => l.costAt ρ + z.costAt ρ + K * (f.cost + 1) + 1
def CostedReduction.
Per-kind handler cost bound: from any state s, handling game query t costs at most hCost (kind t) under costAt.
def CostedReduction.
Step-cost bound outside A when A's G-queries are partitioned into n kinds with at most qKind i queries and handler cost hCost i for kind i (forwarded coin draws are not counted in qKind).
def CostedReduction.
Existence of valid per-kind handler cost bounds hCost with R..
def CostedReduction.CostBoundedByKind (R : CostedReduction O I G C rIn aIn aOut out)
{n : ℕ} (kind : κ → Fin n) (qKind : Fin n → ℕ) (B : ℕ) : Prop :=
∃ hCost : Fin n → ℕ, R.ValidKindCosts kind hCost ∧ R.totalCostByKind hCost qKind ≤ B
def TwoStageCostedReduction.
Two-stage per-kind handler cost bound covering both handlePre and handlePost.
def TwoStageCostedReduction.ValidKindCosts
(R : TwoStageCostedReduction O I G C rIn aIn aOut ch rIn2 out)
{n : ℕ} (kind : κ → Fin n) (hCost : Fin n → ℕ) : Prop :=
∀ (s : R.σ.denote) (t : κ),
R.handlePre.costAt (.cons s (.cons (C.qenc t) .nil)) ≤ hCost (kind t) ∧
R.handlePost.costAt (.cons s (.cons (C.qenc t) .nil)) ≤ hCost (kind t)
def TwoStageCostedReduction.
Step-cost bound outside A across both stages when A makes at most qKind i G-queries of kind i in total (forwarded coin draws are not counted in qKind).
def TwoStageCostedReduction.
Two-stage counterpart of CostedReduction..
def TwoStageCostedReduction.CostBoundedByKind
(R : TwoStageCostedReduction O I G C rIn aIn aOut ch rIn2 out)
{n : ℕ} (kind : κ → Fin n) (qKind : Fin n → ℕ) (B : ℕ) : Prop :=
∃ hCost : Fin n → ℕ, R.ValidKindCosts kind hCost ∧ R.totalCostByKind hCost qKind ≤ B9 declarations not shown (lines 992–1097): theorems, which Lean checks, or definitions that no headline statement uses
ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl., ReductionDsl.
end ReductionDsl