Documentation

GaudisCrypt.Language.Modules

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.

structure GaudisCrypt.Module [ProgramSpec] (T : ModuleTypeRep) :
Type (max 1 u_1)
Instances For
    noncomputable def GaudisCrypt.ModuleExpression.toModule [ProgramSpec] {T : ModuleTypeRep} (m : ModuleExpression) (h : m.HasType [] T := by moduletyping!) :

    Build a Module from a well-typed closed expression by normalising it.

    Equations
    Instances For
      @[implicit_reducible]
      noncomputable instance GaudisCrypt.instCoeFunModuleArrForall [ProgramSpec] {T U : ModuleTypeRep} :
      CoeFun (Module (T.arr U)) fun (x : Module (T.arr U)) => Module T → Module U
      Equations
      noncomputable def GaudisCrypt.Module.fst' [ProgramSpec] {T U : ModuleTypeRep} (m : Module (T.prod U)) :
      Equations
      Instances For
        noncomputable def GaudisCrypt.Module.snd' [ProgramSpec] {T U : ModuleTypeRep} (m : Module (T.prod U)) :
        Equations
        Instances For
          noncomputable def GaudisCrypt.Module.pair' [ProgramSpec] {T U : ModuleTypeRep} (m1 : Module T) (m2 : Module U) :
          Module (T.prod U)
          Equations
          Instances For
            theorem GaudisCrypt.Module.ext [ProgramSpec] {T : ModuleTypeRep} {m1 m2 : Module T} (h : m1.expression = m2.expression) :
            m1 = m2
            @[simp]

            A module's expression is closed, so a substitution leaves it alone.

            @[simp]

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

            @[simp]
            theorem GaudisCrypt.Module.fst_pair' [ProgramSpec] {T U : ModuleTypeRep} (m1 : Module T) (m2 : Module U) :
            (m1.pair' m2).fst' = m1
            @[simp]
            theorem GaudisCrypt.Module.snd_pair' [ProgramSpec] {T U : ModuleTypeRep} (m1 : Module T) (m2 : Module U) :
            (m1.pair' m2).snd' = m2
            theorem GaudisCrypt.Module.pair_fst_snd' [ProgramSpec] {a✝ a✝¹ : ModuleTypeRep} {m : Module (a✝.prod a✝¹)} :
            class GaudisCrypt.IsModule [ProgramSpec] (T : Type (max 1 u_1)) :
            Instances
              @[reducible]
              Equations
              def GaudisCrypt.Module.cast [ProgramSpec] (T : Type (max 1 u_1)) [inst : IsModule T] (m : T) :
              Equations
              Instances For
                def GaudisCrypt.Module.cast' [ProgramSpec] (T : Type (max 1 u_1)) [inst : IsModule T] (m : Module (moduleTypeRep T)) :
                T
                Equations
                Instances For
                  @[implicit_reducible]
                  instance GaudisCrypt.instIsModuleArr [ProgramSpec] (M N : Type (max 1 u_1)) [IsModule M] [IsModule N] :
                  Equations
                  @[implicit_reducible]
                  Equations
                  noncomputable def GaudisCrypt.Module.app' [ProgramSpec] {A B : ModuleTypeRep} (m : Module (A.arr B)) (m' : Module A) :
                  Equations
                  Instances For
                    noncomputable def GaudisCrypt.Module.app [ProgramSpec] {M N : Type (max 1 u)} [iM : IsModule M] [iN : IsModule N] (m : Arr M N) (m' : M) :
                    N
                    Equations
                    Instances For
                      theorem GaudisCrypt.Module.cast_app [ProgramSpec] {M N : Type (max 1 u_1)} [IsModule M] [IsModule N] (a : Arr M N) (b : M) :
                      cast N (app a b) = (cast (Arr M N) a).app' (cast M b)

                      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
                          structure GaudisCrypt.ModuleTypeUtilities [ProgramSpec] (M T : Type (max 1 u_1)) [IsModule M] [IsModule T] (acc : M → T) :
                          Type (max 1 u_1)

                          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.

                          Instances For
                            @[implicit_reducible]
                            instance GaudisCrypt.instIsModuleProd [ProgramSpec] (M N : Type (max 1 u_1)) [IsModule M] [IsModule N] :
                            Equations
                            noncomputable def GaudisCrypt.Module.fst [ProgramSpec] {M N : Type (max 1 u)} [iM : IsModule M] [iN : IsModule N] (m : Prod M N) :
                            M
                            Equations
                            Instances For
                              noncomputable def GaudisCrypt.Module.snd [ProgramSpec] {M N : Type (max 1 u)} [iM : IsModule M] [iN : IsModule N] (m : Prod M N) :
                              N
                              Equations
                              Instances For
                                noncomputable def GaudisCrypt.Module.pair [ProgramSpec] {M N : Type (max 1 u)} [iM : IsModule M] [iN : IsModule N] (m1 : M) (m2 : N) :
                                Prod M N
                                Equations
                                Instances For
                                  @[simp]
                                  theorem GaudisCrypt.Module.fst_pair [ProgramSpec] {M N : Type (max 1 u)} [IsModule M] [IsModule N] (m1 : M) (m2 : N) :
                                  fst (pair m1 m2) = m1
                                  @[simp]
                                  theorem GaudisCrypt.Module.snd_pair [ProgramSpec] {M N : Type (max 1 u)} [IsModule M] [IsModule N] (m1 : M) (m2 : N) :
                                  snd (pair m1 m2) = m2
                                  theorem GaudisCrypt.Module.pair_fst_snd [ProgramSpec] {M N : Type (max 1 u)} [IsModule M] [IsModule N] (m : Prod M N) :
                                  pair (fst m) (snd m) = m

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

                                  Equations
                                  Instances For

                                    Module.procedure is characterized by its defining equation (the witness of proc_type_is_proc is unique by constructor injectivity).

                                    @[simp]

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

                                    noncomputable def GaudisCrypt.Module.const [ProgramSpec] {T U : Type (max 1 u_1)} [IsModule T] [iu : IsModule U] (m : U) :
                                    Arr T U
                                    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.

                                      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.