Documentation

GaudisCrypt.Logic.EagerProc

The eager abstract-call rule (EasyCrypt's eager proc/eager call) #

The instantiation layer of the eager calculus: for a procedure-with-holes A and two hole-instantiations, the whole procedure is eager for a block S provided each hole is (hhole) and A's own operations swap with the lifted block (SwapLoc). This is the calculus-level rule whose soundness is a once-and-for-all induction over the adversary's syntax — the analogue of EasyCrypt's trusted eager proc rule (justified by induction in the metatheory); client derivations only ever apply it.

Locality #

Swap-locality: every operation of A outside the holes swaps with the block SL (self-transferBy). For a hole, this is the surrounding read (get p) and write (set x) — the hole call itself is not required to swap (it is handled by the per-hole hypothesis).

Equations
Instances For
    theorem GaudisCrypt.eagerR_self_of_transferBy {s : Type u_1} {α : Type} {SL : ProgramDenotation s Unit} {p : ProgramDenotation s α} (h : SL.transferBy p p) :
    SL.eagerR SL (fun (σ₁ σ₂ : s) => σ₁ = σ₂) p p fun (u v : α × s) => u = v

    A self-transferBy fact is a (diagonal) self-eager judgment.

    The body induction (EC's eager proc) #

    Eager body induction: an arbitrary syntactic body A is eager for the block SL across two hole-instantiations, given swap-locality of its own operations and a per-hole eager hypothesis. The eagerR rules are threaded over the statement structure.

    The block slides through the procedure wrapper #

    The lifted block slides in: S before the wrapper = zoom globalL S before the body, inside the wrapper. Structural.

    ProgramDenotation.get rv reads rv and threads the state through unchanged.

    From the return-value swap: reading rv commutes with the lifted block (clean form).

    Reading rv is invariant under the block changing the global component.

    The block slides out: S after the wrapper = the lifted block after the body, inside the wrapper. Consumes hret (the return value swaps with the block, so reading it commutes with the block changing the globals).

    The assembled rule #

    theorem GaudisCrypt.eager_wrapper {holes : HoleSigs} {sig : ProcedureSignature} (eagerInst lazyInst : holes.Instantiation) (A : ProcedureWithHoles holes sig) (args : sig.ParamType) (S : ProgramDenotation VariableAssignment Unit) (hbody : (ProgramDenotation.zoom ProgramState.globalL S).eagerR (ProgramDenotation.zoom ProgramState.globalL S) (fun (σ₁ σ₂ : ProgramState) => σ₁ = σ₂) (programDenotation (A.body.instantiate eagerInst)) (programDenotation (A.body.instantiate lazyInst)) fun (u v : Unit × ProgramState) => u = v) (hret : (ProgramDenotation.zoom ProgramState.globalL S).transferBy (ProgramDenotation.get A.return_val) (ProgramDenotation.get A.return_val)) :
    S.eagerR S (fun (σ₁ σ₂ : VariableAssignment) => σ₁ = σ₂) (procedureDenotation (A.instantiate eagerInst) args) (procedureDenotation (A.instantiate lazyInst) args) fun (u v : sig.ret × VariableAssignment) => u = v

    Procedure wrapper for the eager judgment: a body-level eager judgment (block zoom globalL S) lifts to a state-level eager judgment (block S) of the whole procedure denotations, provided the return value swaps with the lifted block.

    EC's eager call on an abstract procedure (equality invariants): the whole procedure is eager for S across two hole-instantiations, given swap-locality of its own operations, a swapping return read, and the per-hole eager hypothesis.

    EC's eager call: a (closed) call site is eager, given a proven procedure-level eager specification and swap-stability of the surrounding argument read and result write.

    theorem GaudisCrypt.eager_call_inv {holes : HoleSigs} {sig : ProcedureSignature} (eagerInst lazyInst : holes.Instantiation) (A : ProcedureWithHoles holes sig) (args : sig.ParamType) (S : ProgramDenotation VariableAssignment Unit) {P : VariableAssignment → VariableAssignment → Prop} {Q : sig.ret × VariableAssignment → sig.ret × VariableAssignment → Prop} (hloc : SwapLoc (ProgramDenotation.zoom ProgramState.globalL S) A.body) (hret : (ProgramDenotation.zoom ProgramState.globalL S).transferBy (ProgramDenotation.get A.return_val) (ProgramDenotation.get A.return_val)) (hhole : ∀ {sig' : ProcedureSignature} (n : HoleIndex holes sig') (x : Setter sig'.ret ProgramState) (p : Getter sig'.ParamType ProgramState), (ProgramDenotation.zoom ProgramState.globalL S).transferBy (ProgramDenotation.get p) (ProgramDenotation.get p) → (∀ (ret : sig'.ret), (ProgramDenotation.zoom ProgramState.globalL S).transferBy (ProgramDenotation.set x ret) (ProgramDenotation.set x ret)) → (ProgramDenotation.zoom ProgramState.globalL S).eagerR (ProgramDenotation.zoom ProgramState.globalL S) (fun (σ₁ σ₂ : ProgramState) => σ₁ = σ₂) (programDenotation (StmtWithHoles.call x (eagerInst.lookup n) p)) (programDenotation (StmtWithHoles.call x (lazyInst.lookup n) p)) fun (u v : Unit × ProgramState) => u = v) (hself : ProgramDenotation.prhl2 P (do let a ← procedureDenotation (A.instantiate lazyInst) args S pure a) (do let a ← procedureDenotation (A.instantiate lazyInst) args S pure a) Q) :
    S.eagerR S P (procedureDenotation (A.instantiate eagerInst) args) (procedureDenotation (A.instantiate lazyInst) args) Q

    EC's eager proc I on an abstract procedure: the equality-level abstract-call rule strengthened to an invariant P, given a framing self-coupling of the lazy composite under P — the packaged form of EC's per-oracle fl ~ fl / s ~ s : I ==> I side conditions (which discharge it via the standard relational body machinery).