Documentation

VCVio.OracleComp.Constructions.SampleableType

Uniform Selection Over a Type #

This file defines a typeclass SampleableType β for types β with a canonical uniform selection operation, using the ProbComp monad.

Unlike HasUniformSelect, the class certifies full support and the uniform output measure.

All points have the same mass under a canonical uniform sampler.

@[simp]
theorem probOutput_uniformSample (α : Type) [ : SampleableType α] [Fintype α] (x : α) :
Pr[= x | $ᵗ α] = (↑(Fintype.card α))⁻¹

Every element of a uniform sample over a Fintype has output probability card⁻¹.

theorem probOutput_uniformSample_inj (α : Type) [ : SampleableType α] (x y : α) :
Pr[= x | $ᵗ α] = Pr[= y | $ᵗ α]
theorem probOutput_map_bijective_uniformSample (α : Type) [ : SampleableType α] {f : αα} (hf : Function.Bijective f) (x : α) :
Pr[= x | f <$> ($ᵗ α)] = Pr[= x | $ᵗ α]

Pushing a uniform sample through a bijection of α preserves each output probability.

theorem probOutput_map_bijective_uniform_cross (α : Type) [ : SampleableType α] {β : Type} [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (y : β) :
Pr[= y | f <$> ($ᵗ α)] = Pr[= y | $ᵗ β]

Pushing forward uniform sampling along a bijection preserves output probabilities.

theorem probOutput_bind_bijective_uniform_cross (α : Type) [ : SampleableType α] {β γ : Type} [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (g : βProbComp γ) (z : γ) :
Pr[= z | do let x$ᵗ α g (f x)] = Pr[= z | do let y$ᵗ β g y]

Binding after pushing forward uniform sampling along a bijection preserves output probabilities.

theorem probOutput_add_left_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m x : α) :
Pr[= x | (fun (x : α) => m + x) <$> ($ᵗ α)] = Pr[= x | $ᵗ α]

Left-translation by a constant in AddGroup α preserves the uniform output distribution, since (m + ·) is a bijection on α with inverse (-m + ·).

theorem probOutput_bind_add_left_uniform (α : Type) [ : SampleableType α] [AddGroup α] {β : Type} (m : α) (f : αProbComp β) (z : β) :
Pr[= z | do let y$ᵗ α f (m + y)] = Pr[= z | do let y$ᵗ α f y]

Left-translating the bound variable of a uniform sample by a constant in AddGroup α preserves the output distribution of the subsequent computation.

theorem probOutput_add_right_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m x : α) :
Pr[= x | (fun (x : α) => x + m) <$> ($ᵗ α)] = Pr[= x | $ᵗ α]

Right-translation analogue of probOutput_add_left_uniform: right-adding a constant to a uniform sample in AddGroup α preserves the output distribution, since (· + m) is a bijection on α with inverse (· + (-m)).

theorem probOutput_bind_add_right_uniform (α : Type) [ : SampleableType α] [AddGroup α] {β : Type} (m : α) (f : αProbComp β) (z : β) :
Pr[= z | do let y$ᵗ α f (y + m)] = Pr[= z | do let y$ᵗ α f y]

Right-translating the bound variable of a uniform sample by a constant in AddGroup α preserves the output distribution of the subsequent computation.

theorem evalSPMF_add_left_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m : α) :
𝒮[(fun (x : α) => m + x) <$> ($ᵗ α)] = 𝒮[$ᵗ α]

Translating a uniform additive sample preserves the full evaluation distribution.

theorem evalSPMF_add_left_uniform_eq (α : Type) [ : SampleableType α] [AddGroup α] (m₁ m₂ : α) :
𝒮[(fun (x : α) => m₁ + x) <$> ($ᵗ α)] = 𝒮[(fun (x : α) => m₂ + x) <$> ($ᵗ α)]

Two additive translations of a uniform sample have the same evaluation distribution.

theorem evalSPMF_add_right_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m : α) :
𝒮[(fun (x : α) => x + m) <$> ($ᵗ α)] = 𝒮[$ᵗ α]

Right-translation analogue of evalSPMF_add_left_uniform: right-adding a constant to a uniform sample in AddGroup α preserves the full evaluation distribution.

theorem evalSPMF_add_right_uniform_eq (α : Type) [ : SampleableType α] [AddGroup α] (m₁ m₂ : α) :
𝒮[(fun (x : α) => x + m₁) <$> ($ᵗ α)] = 𝒮[(fun (x : α) => x + m₂) <$> ($ᵗ α)]

Two right-translations of a uniform sample have the same evaluation distribution.

theorem evalSPMF_map_bijective_uniform_cross (α : Type) [ : SampleableType α] {β : Type} [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) :

Pushing forward uniform sampling via a bijection preserves the full evaluation distribution.

theorem evalSPMF_bind_bijective_add_right_uniform (α : Type) [ : SampleableType α] {β γ : Type} [AddGroup β] [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (m : β) (cont : βProbComp γ) :
𝒮[do let x$ᵗ α cont (f x + m)] = 𝒮[do let y$ᵗ β cont y]

Bijective uniform + right-translation gives uniform. Sampling x ← $ᵗ α, transporting through a bijection f : α → β, and right-adding any fixed m : β yields the same distribution as sampling y ← $ᵗ β directly, as observed by any continuation cont : β → ProbComp γ.

This is the "one-time pad" fact underlying many cryptographic reductions: bijective transport makes f x uniform on β, and in any AddGroup β right-translation (· + m) is a bijection on the uniform measure, so the sum is again uniform.

theorem evalSPMF_bind_bijective_add_right_eq (α : Type) [ : SampleableType α] {β γ : Type} [AddGroup β] [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (m₁ m₂ : β) (cont : βProbComp γ) :
𝒮[do let x$ᵗ α cont (f x + m₁)] = 𝒮[do let x$ᵗ α cont (f x + m₂)]

Constant-irrelevance form of evalSPMF_bind_bijective_add_right_uniform: sampling through a bijection and right-adding a constant has a distribution independent of the constant. Any two offsets produce the same evaluation distribution.

@[simp]
theorem probEvent_uniformSample (α : Type) [ : SampleableType α] [Fintype α] (p : αProp) [DecidablePred p] :
theorem evalSPMF_uniformSample_bind_update {D R : Type} [Finite D] [DecidableEq D] [Finite R] [Nonempty R] [SampleableType R] [SampleableType (DR)] (t : D) :
𝒮[do let u$ᵗ R let g$ᵗ (DR) pure (Function.update g t u)] = 𝒮[$ᵗ (DR)]

Overwriting one coordinate of a uniform function table is measure-preserving.

Drawing a value u uniformly from R, then a full function table g : D → R uniformly, and returning Function.update g t u yields the same distribution as drawing the table directly.

This is the t-marginal independence of the uniform (product) distribution on D → R: the value at coordinate t is uniform and independent of the others, so replacing it with a fresh independent uniform draw leaves the joint distribution unchanged. It is the marginalization step behind eager-sampling reformulations of oracle responses.

The first coordinate of a uniform pair is uniform.

Mapping the uniform distribution on α × β through Prod.fst yields the uniform distribution on α: the Prod.fst-marginal of a uniform (product) distribution is uniform.

theorem evalSPMF_uniformSample_map_comp_injective {A B R : Type} [Finite A] [Finite B] [Finite R] [Nonempty R] [SampleableType (AR)] [SampleableType (BR)] {e : AB} (he : Function.Injective e) :
𝒮[do let g$ᵗ (BR) pure (g e)] = 𝒮[$ᵗ (AR)]

Restricting a uniform function table to a subdomain along an injection is uniform.

For an injection e : A → B between finite types, drawing a uniform table g : B → R and restricting it along e (i.e. g ∘ e) yields the uniform distribution on A → R.

This is the marginalization of the uniform (product) distribution on B → R onto the block of coordinates indexed by Set.range e: those coordinates are jointly uniform and independent of the rest, and e reindexes the block by A. It underlies eager-sampling reformulations that project a fine-grained random-oracle table onto a coarser one.

def patchTable {D R : Type} [DecidableEq D] [SampleableType R] :
List D(DR)ProbComp (DR)

Patch a uniform function table at every point of a list l, drawing one fresh uniform value per list entry. With l = [] the table is returned unchanged; with l = d :: ds the tail is patched first and the head point d is then overwritten with a fresh uniform draw.

This is the iterated form of Function.update used by evalSPMF_uniformSample_patchList: the outermost update is at the head, so the list is consumed head-first.

Instances For
    @[simp]
    theorem patchTable_nil {D R : Type} [DecidableEq D] [SampleableType R] (g : DR) :
    theorem patchTable_cons {D R : Type} [DecidableEq D] [SampleableType R] (d : D) (ds : List D) (g : DR) :
    patchTable (d :: ds) g = do let g'patchTable ds g let u$ᵗ R pure (Function.update g' d u)
    theorem evalDist_uniformSample_patchList {D R : Type} [Finite D] [DecidableEq D] [Finite R] [Nonempty R] [MeasurableSpace R] [MeasurableSingletonClass R] [SampleableType R] [SampleableType (DR)] (l : List D) :
    𝒟[do let g$ᵗ (DR) patchTable l g] = 𝒟[$ᵗ (DR)]

    Patching a uniform table at a finite list of coordinates with independent uniform draws preserves its output measure. Repeated coordinates are allowed.

    theorem evalSPMF_uniformSample_patchList {D R : Type} [Finite D] [DecidableEq D] [Finite R] [Nonempty R] [SampleableType R] [SampleableType (DR)] (l : List D) :
    𝒮[do let g$ᵗ (DR) patchTable l g] = 𝒮[$ᵗ (DR)]

    Patching a uniform function table at finitely many points preserves uniformity.

    Drawing a uniform table g : D → R and then patchTable l g — overwriting g at every point of l with independent fresh uniform draws — yields the same distribution as drawing the table directly. The points of l need not be distinct: each Function.update is the outermost operation of its recursion step, so evalSPMF_uniformSample_bind_update applies regardless of overlap. This is the marginalization step behind trace-conditioned eager-table reformulations, where the patched points are determined only after the table is sampled.

    theorem probOutput_uniformBool_not_decide_eq_decide {ob : ProbComp Bool} :
    Pr[= true | do let b$ᵗ Bool let b'ob pure !decide (b = b')] = Pr[= true | do let b$ᵗ Bool let b'ob pure (decide (b = b'))]

    Given an independent probabilistic computation ob : ProbComp Bool, the probability that its output b' differs from a uniformly chosen boolean b is the same as the probability that they are equal. In other words, P(b ≠ b') = P(b = b') where b is uniform.

    theorem probOutput_bind_uniformBool {α : Type} (f : BoolProbComp α) (x : α) :
    Pr[= x | do let b$ᵗ Bool f b] = (Pr[= x | f true] + Pr[= x | f false]) / 2

    Conditioning on a uniform boolean averages the two branch probabilities.

    theorem probOutput_uniformBool_branch_toReal_sub_half (real rand : ProbComp Bool) :
    Pr[= true | do let b$ᵗ Bool have __do_jp : BoolProbComp Bool := fun (z : Bool) => pure (b == z) if b = true then do let zreal __do_jp z else do let zrand __do_jp z].toReal - 1 / 2 = (Pr[= true | real].toReal - Pr[= true | rand].toReal) / 2

    Guessing a uniformly random bit after branching between real and rand decomposes into the difference of the branch success probabilities.

    theorem probOutput_decide_eq_uniformBool_half (f : BoolProbComp Bool) (heq : 𝒮[f true] = 𝒮[f false]) :
    Pr[= true | do let b$ᵗ Bool let b'f b pure (decide (b = b'))] = 1 / 2

    If the distribution of f b is independent of b, then guessing a uniformly random bit by running f has success probability exactly 1/2. This is the core lemma behind "all-random hybrid has probability 1/2" arguments.

    theorem evalSPMF_uniformSample_eq_query {ι : Type u_1} {spec : OracleSpec ι} [(i : ι) → SampleableType (spec.Range i)] [spec.IsUniformSpec] (t : spec.Domain) :

    Uniformly sampling a response has the same distribution as issuing the corresponding query to a uniform oracle specification.

    theorem probOutput_uniformSample_eq_query {ι : Type u_1} {spec : OracleSpec ι} [(i : ι) → SampleableType (spec.Range i)] [spec.IsUniformSpec] (t : spec.Domain) (u : spec.Range t) :

    Uniformly sampling a response and issuing the corresponding uniform-oracle query assign the same probability to every output.

    theorem probEvent_uniformSample_eq_query {ι : Type u_1} {spec : OracleSpec ι} [(i : ι) → SampleableType (spec.Range i)] [spec.IsUniformSpec] (t : spec.Domain) (p : spec.Range tProp) :

    Uniformly sampling a response and issuing the corresponding uniform-oracle query assign the same probability to every event.

    @[simp]
    theorem uniformSampleImpl.evalSPMF_simulateQ {ι : Type u_1} {spec : OracleSpec ι} [(i : ι) → SampleableType (spec.Range i)] [spec.IsUniformSpec] {α : Type} (oa : OracleComp spec α) :
    @[simp]
    theorem uniformSampleImpl.probOutput_simulateQ {ι : Type u_1} {spec : OracleSpec ι} [(i : ι) → SampleableType (spec.Range i)] [spec.IsUniformSpec] {α : Type} (oa : OracleComp spec α) (x : α) :
    @[simp]
    theorem uniformSampleImpl.probEvent_simulateQ {ι : Type u_1} {spec : OracleSpec ι} [(i : ι) → SampleableType (spec.Range i)] [spec.IsUniformSpec] {α : Type} (oa : OracleComp spec α) (p : αProp) :