Modules #
A Module T is a closed, well-typed, normal ModuleExpression of type T, together with the
operations on such (application, projections, pairing) and the IsModule bridge from Lean types
to ModuleTypeReps. The underlying expression calculus lives in ModuleExpressions.lean.
- expression : ModuleExpression
- typed : self.expression.HasType [] T
- normal : self.expression.NormalClosed
Instances For
Build a Module from a well-typed closed expression by normalising it.
Instances For
Equations
- GaudisCrypt.instCoeFunModuleArrForall = { coe := fun (f : GaudisCrypt.Module (T.arr U)) (x : GaudisCrypt.Module T) => (f.expression.app x.expression).toModule ⋯ }
Equations
- m.fst' = m.expression.fst.toModule ⋯
Instances For
Equations
- m.snd' = m.expression.snd.toModule ⋯
Instances For
Equations
- m1.pair' m2 = (m1.expression.pair m2.expression).toModule ⋯
Instances For
A module's expression is closed, so a substitution leaves it alone.
A module's expression is closed, so a renaming leaves it alone. (This is what a substitution
going under a binder does to it — liftSubst renames by Nat.succ — so normalising an application
of a curried module needs this as well as Module.substituteSimultaneously_expression.)
Pairing two modules pairs their expressions — no reduce left over, both being normal.
Reducing a pair componentwise: if the components reduce to the expressions of the modules
m1/m2, the pair reduces to the expression of their Module.pair'. Turns a reduce of a
whole record into the record of the reduced components, with no detour through termination —
normality of the result comes from the modules m1/m2. (Currently unused: module_apply
used to peel X.apply_simp's record with it, but now normalises both sides with
reduce_simp instead.)
Instances For
Instances For
- moduleTypeRep : ModuleTypeRep
Instances
Equations
- GaudisCrypt.instIsModuleModule = { moduleTypeRep := t, isModule := ⋯ }
Instances For
Equations
- GaudisCrypt.Module.cast T m = ⋯ ▸ m
Instances For
Equations
- GaudisCrypt.Module.cast' T m = ⋯ ▸ m
Instances For
Equations
Instances For
Equations
- GaudisCrypt.instIsModuleArr M N = { moduleTypeRep := (GaudisCrypt.Module.moduleTypeRep M).arr (GaudisCrypt.Module.moduleTypeRep N), isModule := ⋯ }
Equations
Instances For
Equations
- GaudisCrypt.instIsModuleProc = { moduleTypeRep := GaudisCrypt.ModuleTypeRep.proc sig, isModule := ⋯ }
Equations
- m.app' m' = (m.expression.app m'.expression).toModule ⋯
Instances For
Instances For
Simplification procedure
Equations
- One or more equations did not get rendered due to their size.
Instances For
Simp set collecting the field accessors moduletype emits (X.f : X → Tᵢ, a chain of
Module.fst'/Module.snd').
A goal about a field of an abstract module — S : CommitmentScheme a parameter, not a literal
record — can only make progress by unfolding the accessor, and a tactic cannot know the accessor's
name. This set is how proc_apply reaches them.
Equations
- One or more equations did not get rendered due to their size.
Instances For
What is derivable about a field accessor acc : M → T of a module type, bundled into one
declaration.
The moduletype command emits one of these per field, as X.f.utilities, rather than a separate
declaration per fact — the facts are reached as X.f.utilities.accessorModule and so on. It is a
structure and not a class: there is nothing to synthesise, the command hands the value over by
name.
- proj : ModuleExpression → ModuleExpression
The projection
accimplements, as it acts onModuleExpressions (fun e => e.snd.fst, …). - accessorModule : Module.Arr M T
The accessor as a module of its own: a projection is a module morphism.
…and applying that module is the accessor.
- expression_eq (m : M) : (Module.cast T (acc m)).expression = (self.proj (Module.cast M m).expression).reduce
The accessor at the level of expressions: it is
proj, reduced. The.reduceis not removable —Module.expressionis always a reduct, andproj m.expressionneed not be normal.
Instances For
Equations
Instances For
Equations
- GaudisCrypt.instIsModuleProd M N = { moduleTypeRep := (GaudisCrypt.Module.moduleTypeRep M).prod (GaudisCrypt.Module.moduleTypeRep N), isModule := ⋯ }
Equations
- GaudisCrypt.Module.fst m = ⋯ ▸ (⋯ ▸ m).fst'
Instances For
Equations
- GaudisCrypt.Module.snd m = ⋯ ▸ (⋯ ▸ m).snd'
Instances For
Instances For
Equations
Instances For
Canonical forms at procedure type: a closed normal expression of type .proc sig is
literally a .proc p node.
The procedure of a proc-typed module — the inverse of Module.proc. (Classical.choose
only escapes the Prop-to-data restriction; the witness is unique — see
Module.procedure_spec and Module.procedure_proc.)
Instances For
Module.procedure is characterized by its defining equation (the witness of
proc_type_is_proc is unique by constructor injectivity).
Round-trip: wrapping a procedure as a module and extracting recovers it.
A module's expression is well-typed in any context, not just the empty one — it is closed.
This is what lets moduletyping type an expression built from already-formed modules (whose
leaves are m.expression rather than a HasType constructor).
Equations
- GaudisCrypt.Module.const m = (⋯ ▸ m).expression.abs.toModule ⋯
Instances For
Equations
Instances For
Applying a procedure-with-holes to its callees #
The δ-rule ReductionStep.delta fires only on a literal tuple of .proc nodes
(HoleSigs.Instantiation.toModuleExpr). What one has in practice is a tuple of arbitrary module
expressions — the callees, as they were written — which merely reduce to such a tuple, each of
them to the .proc of a Module.procedure. These lemmas bridge the two: reduce_tuple_nil/
reduce_tuple_cons build the reduction of the tuple component by component, and
reduce_app_procWithHoles then takes the δ-step. Together they are what the proc_apply tactic
(GaudisCrypt/Language/Syntax2.lean) runs on the X.<f>.apply_simp goals the module command
emits.
A tuple of procedures is normal: it is built from .proc nodes and .unit alone.
The empty tuple: .unit is already the instantiation of no holes.
One component of the tuple: if c reduces to the expression of a proc-typed module m — which
by canonicity is a .proc node, namely .proc m.procedure — and the rest of the tuple reduces to
inst's, then the whole pair reduces to that of inst extended by m.procedure.
The δ-step, on an argument that only reduces to a tuple of procedures: applying
Module.procWithHoles p to it is the procedure p with its holes instantiated. With no holes at
all Module.procWithHoles p is the constant function Module.proc p, and instantiating changes
nothing (ProcedureWithHoles.instantiate_empty) — so the statement covers that case too.