The {\module{mathdata}} module contains the code for representing types,
terms and proofs
and the code for type checking and proof checking.
This is arguably the most important module in Qeditas.
A bug in this module could lead to non-theorems being accepted as theorems
undermining the primary purpose of the Qeditas system.
Fortunately the {\file{mathdata.ml}} file is not long (currently less than 1500 lines of code)
and depends very little on the rest of Qeditas (using only
code for serialization and cryptographic hashing).
It is intended to satisfy the {\defin{de Bruijn criterion}}
in that the code can be manually audited to determine its correctness.
We attempt to give enough information in this chapter for someone who wishes to undertake such an audit.

The original version of the code for this module was taken from the code for the
Egal system~\cite{Brown2014},
but has since undergone extensive changes.
One major difference in the syntax is the explicit support for type variables in Qeditas.
Support for theories and signatures have also been added, and the type of documents has been modified
(adding support for importing signatures and declaring conjectures but removing all presentation level items).
Additionally, the checking functions are parameterized by functions to verify a term
identified only by its hash root has a type in a theory
and to verify a proposition identified only by its hash root is known to be a theorem in a theory.
Such information will be looked up in the ledger tree (see Chapter~\ref{chap:ctre}) by checking what is held at corresponding term addresses.
Finally, a significant portion of the Egal proof checking code was apparently
intended to avoid expanding definitions unnecessarily.
This code has been deleted and replaced by
simpler code to expand all definitions during proof checking.

One might argue that it would be safer to use an older, established proof checker.
However, experience has shown that even established systems can be vulnerable to ``tricks''
which can be used to prove what should be a non-theorem.
For example, on {\tt{proofmarket.org}}~\cite{ProofMarket}
a bitcoin bounty was placed on the proposition {\sf{False}} in Coq~\cite{Coq:manual}.
In spite of the fact that Coq is an advanced tool used by many people for many projects,
such a ``proof'' of {\sf{False}} was given.\footnote{In fact, two different proofs were given.}
The ``proofs'' were related to implementation issues rather than an inconsistency
in the underlying logic, but only the implementation will matter in a system like Qeditas.
By using a simple underlying logic (simple type theory)
and isolating the implementation in the reasonably small module {\module{mathdata}}
it is hoped that such apparent inconsistencies can be avoided.

The underlying logic is a form of simple type theory~\cite{Church40}
with support for prefix polymorphism.
The basic proof calculus is natural deduction~\cite{gent36,praw65}
with Curry-Howard style $\lambda$-terms proof terms~\cite{howa80}.
This leads the type checker and proof checker in {\module{mathdata}}
to be very similar to the oldest proof checker, AUTOMATH~\cite{DeBruijn80}.
The logic is designed to allow for multiple theories to be
declared and for signatures to be used to import previous
typed terms and proven propositions.
Of the popular proof assistants at the moment,
the closest would probably be Isabelle~\cite{Nipkow-Paulson-Wenzel:2002},
although Isabelle follows the LCF style~\cite{GORDON79} instead of
Curry-Howard.

{\bf{Note:}} Unit tests for the {\module{mathdata}} module are in {\file{mathunittests.ml}}
in the {\dir{src/unittests}}
directory in the {\branch{testing}} branch.
These unit tests give a number of examples demonstrating how the functions described below should behave.
The {\branch{testing}} branch is, however, out of date with the code in the {\branch{dev}} and {\branch{master}} branches.
A few examples of types, terms and proof terms used in these unit tests are
in {\file{unittestsaux.ml}} in the same directory.
Likewise, examples of publications (encoded versions of documents released with Egal~\cite{Brown2014}) are in
{\file{testpubs1.ml}} and {\file{testpubs2.ml}} in the same directory.

{\bf{Note:}} The Coq module {\coqmod{MathData}} is intended to correspond to {\module{mathdata}},
except that the checking code is omitted and left abstract.

\section{Simple Types}

Simple types ($\alpha$, $\beta$) are described by the following grammar:
$$
\alpha,\beta ::=  \delta_n |o|\iota_n|(\alpha\to\beta)|(\Pi \alpha)
$$
We treat $\to$ as right associative to omit parentheses.
For example, $\iota_0\to\iota_0\to o$
means $(\iota_0\to (\iota_0\to o))$.
Also, we will omit parentheses in $\Pi \alpha$ since
$\Pi$ will always be used above $\to$ and so no
ambiguity can result.

Simple types are implemented as the inductive type {\type{tp}}.
We describe each constructor:
\begin{itemize}
\item ${\mbox{\constr{TpVar}}}(n)$ means the type variable $\delta_n$, where
the $n$ should be interpreted as a de Bruijn index~\cite{deBruijn72}.
For example, $\Pi \Pi \delta_1 \to \delta_0 \to \delta_1$
means the type
of a function which expects two types $\alpha$ and $\beta$,
a term of type $\alpha$, a term of type $\beta$
and returns a term of type $\alpha$.
\item {\constr{Prop}} means the type $o$ of propositions.
\item ${\mbox{\constr{Base}}}(n)$ means the $n^{th}$ base type $\iota_n$. Only finitely many base types will be explicitly used in
a theory. In fact, so far only theories using one base type
$\iota_0$ have been considered, but the support for multiple
base types is included in case it is needed later.
\item ${\mbox{\constr{TpAll}}}(\alpha)$ means $\Pi \alpha$, binding a type variable. Only types of the form $\Pi\cdots\Pi\alpha$
where $\alpha$ has no occurrence of a $\Pi$ will be used in practice.
\end{itemize}

The functions {\serfunc{seo\_tp}} and {\serfunc{sei\_tp}} serialize and deserialize types.
% {\func{tp\_to\_str}} returns a string representation of the type and {\func{str\_to\_tp}} returns a type given a string representation of the type.\footnote{These are included to help with testing, and are not currently used outside {\module{mathdata}} otherwise.}

{\func{hashtp}} takes a type and returns a hash value obtained by serializing the type
to a string, hashing the string, and then hashing the result tagged with $64$.
(The intention of hashing tagged results is to ensure that, for example, the hash value
associated with a type will not accidentally be the same as the the hash value associated
with a term, proof or anything else.)

\section{Terms and Propositions}

Terms $s,t,u$ are described by the following grammar:
$$
s,t ::=  x_n |\tmh{h}|c_n|(st)|(\lambda_\alpha s)|(s\to t)|(\forall_\alpha s)|(s \alpha)|(\Lambda s)|(\tforall s)
$$
Here $n$ ranges over non-negative integers
and $h$ ranges over hash values.

Terms $x_n$ are variables,
where $n$ should be interpreted as a de Bruijn index~\cite{deBruijn72}.
For example, $\lambda_o x_0 \to \forall_o x_1\to x_0$
would be written as $\lambda y:o . y\to\forall z:o.y\to z$
in a named representation.
A term $\tmh{h}$ is an abbreviation for a term which has $h$ as its hash root (see {\func{tm\_hashroot}} below).
Note that there are two kinds of application:
(1) $(st)$ of a term $s$ to a term $t$ and
(2) $(s\alpha)$ of a term $s$ to a type $\alpha$.
Likewise there are two abstractions and two universal quantifiers:
one for the term level and one for the type level.
First, $(\lambda_\alpha s)$ is a term level abstraction representing
a function expecting an input of type $\alpha$ 
with return value determined by this input and $s$.
Likewise, $(\forall_\alpha s)$ corresponds to universally quantifying
over the elements of type $\alpha$.
On the other hand, $(\Lambda s)$ is a type level abstraction
and represents a function which expects a type $\alpha$
and then returns a value determined by $\alpha$ and $s$.
Likewise, $(\tforall s)$ corresponds to universally quantifying
over all types.
We refer to 
$\lambda_\alpha$, $\forall_\alpha$, $\Lambda$ or $\tforall$
collectively as {\defin{binders}}
and say the term $s$ in
$(\lambda_\alpha s)$, $(\forall_\alpha s)$, $(\Lambda s)$ or $(\tforall s)$
is in the {\defin{scope}} of the binder.

We often omit parentheses.
Application is assumed to be left associative
and so $s\alpha\beta t u$ means $((((s\alpha)\beta)t)u)$
If parenthesis around the body
of a binder
are omitted, then they are assumed to be such that the
scope of the binder is as large as possible.
For example, $\forall_o x_0\to x_0$ means
$(\forall_o (x_0\to x_0))$.

The corresponding type in the OCaml code is {\type{tm}}.
We describe each constructor:
\begin{itemize}
\item ${\mbox{\constr{DB}}}(n)$ corresponds to the variable $x_n$  (i.e., the de Bruijn index).
\item ${\mbox{\constr{TmH}}}(h)$ corresponds to the term $\tmh{h}$
and should be considered an abbreviation (which is sometimes opaque and sometimes transparent, depending on the current signature).
\item ${\mbox{\constr{Prim}}}(n)$ corresponds to the primitive $c_n$.
\item ${\mbox{\constr{Ap}}}(s,t)$ corresponds to term level application $st$.
\item ${\mbox{\constr{Lam}}}(\alpha,s)$ corresponds to term level abstraction $\lambda_\alpha s$.
\item ${\mbox{\constr{Imp}}}(s,t)$ corresponds to implication $s\to t$.
\item ${\mbox{\constr{All}}}(\alpha,s)$ corresponds to term level universal quantification $\forall_\alpha s$.
\item ${\mbox{\constr{TTpAp}}}(s,\alpha)$ corresponds to type level application $s\alpha$.
\item ${\mbox{\constr{TTpLam}}}(s)$ corresponds to type level abstraction $\Lambda s$
\item ${\mbox{\constr{TTpAll}}}(s)$ corresponds to type level universal quantification $\tforall s$.
\end{itemize}

The functions {\serfunc{seo\_tm}} and {\serfunc{sei\_tm}} serialize and deserialize terms.
% {\func{tm\_to\_str}} returns a string representation of the term and {\func{str\_to\_tm}} returns a term given a string representation of the type.\footnote{These are included to help with testing, and are not currently used outside {\module{mathdata}} otherwise.}

There are two functions {\func{hashtm}} 
and
{\func{tm\_hashroot}} which take terms and return
a corresponding hash value.
In the case of {\func{hashtm}},
a hash value is obtained by serializing the term
to a string, hashing the string, and then hashing the result tagged with $66$.
This (effectively) guarantees that different terms
will always be given different hash values.
On the other hand, {\func{tm\_hashroot}} takes a term and computes its {\defin{hash root}}.
The hash root of a term does not distinguish between a term
$\tmh{h}$ and a term $t$ which has $h$ as its hash root.
In effect, {\func{tm\_hashroot}} views all such abbreviations
as transparent.

The {\defin{hash root}} $\tmhr{t}$ of a term $t$ can be defined as follows:
\begin{itemize}
\item $\tmhr{\tmh{h}}$ is $h$
\item $\tmhr{c_n}$ is the hash of $n$ tagged with $96$.
\item $\tmhr{x_n}$ is the hash of $n$ tagged with $97$.
\item $\tmhr{st}$ is the hash of the hashed pair of $\tmhr{s}$ and $\tmhr{t}$ tagged with $98$.
\item $\tmhr{\lambda_\alpha s}$ is the hash of the hashed pair of the hash of $\alpha$ and $\tmhr{s}$ tagged with $99$.
\item $\tmhr{s\to t}$ is the hash of the hashed pair of $\tmhr{s}$ and $\tmhr{t}$ tagged with $100$.
\item $\tmhr{\forall_\alpha s}$ is the hash of the hashed pair of the hash of $\alpha$ and $\tmhr{s}$ tagged with $101$.
\item $\tmhr{s\alpha}$ is the hash of the hashed pair of $\tmhr{s}$ and the hash of $\alpha$ tagged with $102$.
\item $\tmhr{\Lambda s}$ is the hash of $\tmhr{s}$ tagged with $103$.
\item $\tmhr{\tforall s}$ is the hash of $\tmhr{s}$ tagged with $104$.
\end{itemize}
The reader can verify that this corresponds to the
definition of {\func{tm\_hashroot}} in the code.
The tags are used to record which term constructor was
traversed and is also used to ensure that hash roots
of terms are not the hash values computed in other contexts.

A proposition is a certain kind of term (in a given context).
In short, propositions are always of the form
$\tforall \cdots \tforall t$
where $t$ has type $o$.
Usually a proposition is simply of the form
$t$ where $t$ has type $o$.

\section{Proof Terms}

Proof terms $\cD,\cE$ are described by the following grammar:
$$
\cD,\cE ::= \gpa{h} | \hyp{n} | \known{h} | (\cD s) | (\cD \cE) | (\lambda_s \cD) | (\lambda_\alpha \cD) | (\cD \alpha) | (\Lambda \cD)
$$
Here $n$ ranges over non-negative integers
and $h$ ranges over hash values.
We sometimes simply say ``proofs'' instead of ``proof terms.''

The proof term $\gpa{h}$
is an abbreviation for a proof term which has hash root $h$
(see {\func{pf\_hashroot}} below).
The proof term $\hyp{n}$
is the proof of a hypothesis (in a hypothesis context).
The proof term $\known{h}$
simply asserts that the proposition with hash root
$h$ is known. (The current signature maintains a list
of known propositions and their hash root.
Inclusion of such a proposition in the signature may require
checking that the term address corresponding to $h$
is owned as a proposition in the ledger. The only
way this could have happened is if the term is the axiom
of the current theory or was previously proven.)
There are three kinds of application and three kinds of abstractions.
At the proof level there are applications
$(\cD\cE)$
and abstractions
$(\lambda_s \cD)$.
These correspond to the elimination and introduction
rules for implication.
At the term level there are applications
$(\cD t)$
and abstractions
$(\lambda_\alpha\cD)$.
These correspond to the elimination and introduction
rules for universal quantification.
Finally at the type level there are applications
$(\cD\alpha)$
and abstractions
$(\Lambda\cD)$.
Type level application is the way polymorphic known propositions
are applied at specific types.
Type level abstraction is the way polymorphic propositions are
proven.

As with terms, we omit parentheses assuming application
associates to the left and
assuming abstraction (binders) have as large a scope as possible.

The corresponding type in the OCaml code is {\type{pf}}.
We describe each constructor:

The functions {\serfunc{seo\_pf}} and {\serfunc{sei\_pf}} serialize and deserialize proof terms.
% {\func{pf\_to\_str}} returns a string representation of the proof term and {\func{str\_to\_pf}} returns a proof term given a string representation of the type.\footnote{These are included to help with testing, and are not currently used outside {\module{mathdata}} otherwise.}

Again, there are two functions taking a proof term
and returning a hash value:
{\func{hashpf}}
and
{\func{pf\_hashroot}}.
The function {\func{hashpf}} takes a term and returns a hash value obtained by serializing the term
to a string, hashing the string, and then hashing the result tagged with $67$.
This implies {\func{hashpf}} returns an effectively unique hash value for each proof term.
The function {\func{pf\_hashroot}} computes a {\defin{hash root}}
similar to the way hash roots for terms are computed.
In this case, the hash root for a proof term abbreviation
$\gpa{h}$ is $h$.

\section{Publications}

There are three kinds of publications: theories, signatures and documents.
A theory declares the types of some primitives $c_n$ and gives some axioms.
A signature is to be interpreted within a given theory
and is intended to make some terms and propositions accessible for use within
another publication (a document or another signature).
A signature declares some parameters (opaque terms of the form $\tmh{h}$) giving
the hash root and the simple type,
declares some definitions
and declares some propositions to be known (either axioms of the theory or previously
proven propositions).
A document is similar to a signature except proofs of theorems are also allowed.
In addition, a document may declare a proposition to be a conjecture.

For all three kinds of publications there is a representation as a list of ``items.''
This list is perhaps best thought of as being in reverse order.
The idea is that after one has processed the ``rest'' of the list, then one
has sufficient information to process the ``head'' of the list.

In practice there is a distinction between the specification of a theory
and the theory itself. The same is true of signatures.
In essence a theory specification or signature specification corresponds to a list
of declarations, where a theory or signature itself is a ``compiled'' format which
other publications may used. This ``compiled'' format must be stored by
every node in order to check later publications. For this reasons,
Qeditas currency units must be burned in order to publish a theory or publication.
In particular, $21$ zerms must be burned for each byte in the serialized representation
of the theory or signature. The idea behind a fee of $21$ zerms is that since there
is an upper bound of $21$ million fraenks ($21$ billion zerms) we can be sure that
no more than $1$ GB worth of theories and signatures will ever be published.

\subsection{Theories}

A {\defin{theory item}} is one of the following:
\begin{itemize}
\item a declaration of a primitive to have type $\alpha$,
\item a declaration of a definition of type $\alpha$ defined by a term $s$, or
\item a declaration of proposition $s$ as an axiom.
\end{itemize}
A {\defin{theory specification}} is a list of theory items.

A {\defin{theory}} $\cT$ is a pair $(\cP,\cA)$
of a list $\cP$ of simple types $\alpha_0,\ldots,\alpha_{n-1}$
and a list $\cA$ of hash values $\overline{h}$.
The idea is that the primitive $c_i$ has the type $\alpha_i$ for $i<n$
and that $s$ is an axiom of the theory if $\tmhr{s}$ is in the list $\overline{h}$.

In the OCaml code the corresponding types are
{\type{theoryitem}}, {\type{theoryspec}} and
{\type{theory}}.
The type {\type{theoryitem}} has three constructors corresponding to the three cases above.
\begin{itemize}
\item $\mbox{\constr{ThyPrim}}(\alpha)$ declares that the primitive $c_n$ has type $\alpha$.
In practice $n$ is the number of {\constr{ThyPrim}} theory items in the rest of the
theory specification.
\item $\mbox{\constr{ThyDef}}(\alpha,s)$ declares that $s$ has type $\alpha$ and so $\tmh{\tmhr{s}}$ can
be used as an abbreviation.
\item $\mbox{\constr{ThyAxiom}}(t)$ declares that $t$ is a proposition and an axiom of the theory.
\end{itemize}
As usual, 
{\serfunc{seo\_theoryspec}} and {\serfunc{sei\_theoryspec}} serialize and deserialize theory specifications
while
{\serfunc{seo\_theory}} and {\serfunc{sei\_theory}} serialize and deserialize theories.

% The function
% {\func{hashtheoryspec}} takes a theory specification and returns a hash value obtained by serializing the
% theory specification to a string, hashing the string, and then hashing the result tagged with $68$.
% This effectively guarantees that different theory specifications will be given different hash values.
% This function is used to obtain a unique publication address where the publication will be
% stored in the ledger if it is published.\footnote{Shouldn't hashtheory be used for this? Otherwise
% someone could publish the same theory with two different specs. This isn't fatal, but it would mean vacuous burns and overwrites in the ttree.}

The function {\func{theoryspec\_theory}} converts a theory specification to a theory.
This is done by extracting the declared types of the first $n$ primitives (see {\func{theoryspec\_primtps}})
and by extracting the hash roots of declared axioms (see {\func{theoryspec\_hashedaxioms}}).
The pair is the intended theory. Note that declared definitions are not used to construct the theory.
Definitions in a theory may be required to check the theory specification is valid (e.g.,
to check that a term for an axiom is, in fact, a proposition).

The function {\func{hashtheory}} computes an optional hash value corresponding to a theory.
This hash value will be the identifier for the theory.
For the empty theory (no typed primitives and no axioms) the optional hash value will be {\val{None}}.
The empty theory is not explicitly stored and cannot be explicitly published.
For nonempty theories, the hash value is used to determine the $160$-bit location
where the theory is stored in the {\type{ttree}}
and the publication address where the theory specification is stored in the ledger tree.\footnote{There is actually no need to store theory publications in the ledger tree since the useful information will be in the {\type{ttree}}. However, it seems simplest to publish theory specifications as a special kind of asset created by a transaction. Such assets are stored in the ledger tree at the given address. Making an exception for theories (and signatures) would be needlessly awkward.}

The function {\func{theoryspec\_burncost}} computes the number of cants that must be burned
to publish the theory specification. It does this by computing the underlying theory with {\func{theoryspec\_theory}},
serializing the theory, taking the number of bytes of the serialization and multiplying this by
$2.1$ billion).

% {\func{theory\_to\_str}} returns a string representation of the theory and {\func{str\_to\_theory}} returns a theory given a string representation of the type. In this case, {\func{theory\_to\_str}} is used elsewhere in the code. In particular, the length of the string (the serialization of the theory) is used to calculate how many zerms must be burned in order to publish the theory (21 zerms must be burned for each character in the string). There is a burn fee for publishing theories since every node must keep the theory locally (in a {\type{ttree}}) in order to check documents.

\subsection{Signatures}

A {\defin{signature item}} is one of the following:
\begin{itemize}
\item a reference to another signature to import,
\item a declaration of a parameter with a given term hash root and given type,
\item a declaration of a definition with a certain type and a term which should have this type, or
\item a declaration of a proposition as known.
\end{itemize}
A {\defin{signature specification}} is a list of signature items.

A {\defin{global signature}} $\Sigma$ is a pair $(\cO,\cK)$ of lists:
\begin{itemize}
\item The first list $\cO$ is a list of hash roots, types and optionally terms.
      That is, each element is $(h,\alpha,{\mbox{\val{None}}})$ or $(h,\alpha,s)$
      where $h$ is the term hash root of a term of type $\alpha$ (the term $s$ if it is given).
      The intention is that we know the term $\tmh{h}$ abbreviates a term of type $\alpha$.
      If $s$ is given, we also know $\tmh{h}$ can be expanded to be $s$.
\item The second list $\cK$ is a list of hash roots and terms.
      That is, each element is $(h,s)$ where $s$ has hash root $h$
      and $s$ is either an axiom of the theory or a previously proven theorem.
      (Technically, it is $h$ that is the hash root of an axiom or previously proven theorem.
      Hence we know $s$ is equal to an axiom or previously proven theorem if all hash value
      abbreviations are expanded.)
\end{itemize}
A {\emph{signature}} is a pair of a list of hash values and a global signature.
The list of hash values is a list of references to other signatures to import.
A signature here is a certain kind of publication which allows
easy importation of previous results
and should not be confused with cryptographic signatures as discussed in Chapter~\ref{chap:cryptocurr}.
In the OCaml code we typically write {\tt{signat}} when referring to cryptographic signatures
and {\tt{signa}} when referring to the kinds of signatures as publications under consideration here.

The corresponding types in OCaml are
{\type{signaitem}} (for {\defin{signature item}}),
{\type{signaspec}} (for {\defin{signature specification}}),
{\type{gsigna}} (for {\defin{global signature}}) and
{\type{signa}} (for {\defin{signature}}).
The type {\type{sigitem}} has four constructors corresponding to the four cases above.
\begin{itemize}
\item $\mbox{\constr{SignaSigna}}(h)$ declares the importation of the signature with hash value identifier $h$.
The signature must have been previously published.
\item $\mbox{\constr{SignaParam}}(h,\alpha)$ declares that $\tmh{h}$ has type $\alpha$ and can be used
as an opaque abbreviation (a ``parameter'').
\item $\mbox{\constr{SignaDef}}(\alpha,s)$ declares that $s$ has type $\alpha$ and so $\tmh{\tmhr{s}}$ can
be used as an abbreviation.
\item $\mbox{\constr{SignaKnown}}(t)$ declares that $t$ is a proposition which is already known.
\end{itemize}
As usual,
{\serfunc{seo\_signaspec}} and {\serfunc{sei\_signaspec}} serialize and deserialize signature specifications.
{\serfunc{seo\_signa}} and {\serfunc{sei\_signa}} serialize and deserialize signatures.

The function
{\func{signaspec\_signa}}
compiles a signature specification into a signature.
The function {\func{signaspec\_signas}} computes the signatures which should be imported
by filtering out the declared signatures to import.
The function {\func{signaspec\_trms}} computes the term hash roots along with their types
and optional term definitions by filtering out the parameter and definition
declarations.
Finally, {\func{signaspec\_knowns}} computes the term hash roots and corresponding known
propositions by filtering the declared knowns and computing their hash roots.

The function {\func{hashsigna}} computes a hash value to identify the signature.
This hash value, combined with the hash value identifier of the intended theory,
is used to create both the $160$-bit location where the signature is stored
in the {\type{stree}}
and the publication address where the signature specification is stored in the ledger tree.\footnote{As with theories, there is actually no need to store signature publications in the ledger tree since the useful information will be in the {\type{stree}}. Signature specifications are stored in the ledger tree simply to
avoid having exceptional cases.}

The function {\func{signaspec\_burncost}} computes the number of cants which must
be burned
to publish the signature specification. It does this by computing the underlying signature with {\func{signaspec\_signa}},
serializing the signature, taking the number of bytes of the serialization and multiplying this by
$2.1$ billion).

% {\func{signa\_to\_str}} returns a string representation of the signature and {\func{str\_to\_signa}} returns a signature given a string representation of the type. As with theories, {\func{signa\_to\_str}} is used elsewhere in the code.  In particular, the length of the string (the serialization of the signature) is used to calculate how many zerms must be burned in order to publish the signature (21 zerms must be burned for each character in the string). There is a burn fee for publishing signatures since every node must keep the signature locally (in an {\type{stree}}) in order to check documents.

\subsection{Documents}

A {\defin{document item}} is one of the following:
\begin{itemize}
\item a declaration of a signature to import,
\item a declaration of a parameter with a term hash root and type,
\item a declaration of a definition with a type and a term of this type,
\item a declaration of a proposition as known,
\item a declaration of a proposition as a conjecture, or
\item a declaration of a proposition as a theorem with a proof.
\end{itemize}
A {\defin{document}} is a list of document items.

The corresponding OCaml types are {\type{docitem}} and {\type{doc}}.
The type {\type{docitem}} has six constructors corresponding to the six cases above.
\begin{itemize}
\item $\mbox{\constr{DocSigna}}(h)$ declares the importation of the signature with hash value identifier $h$.
The signature must have been previously published.
\item $\mbox{\constr{DocParam}}(h,\alpha)$ declares that $\tmh{h}$ has type $\alpha$ and can be used
as an opaque abbreviation (a ``parameter'').
\item $\mbox{\constr{DocDef}}(\alpha,s)$ declares that $s$ has type $\alpha$ and so $\tmh{\tmhr{s}}$ can
be used as an abbreviation.
\item $\mbox{\constr{DocKnown}}(t)$ declares that $t$ is a proposition which is already known.
\item $\mbox{\constr{DocConj}}(t)$ declares that $t$ is a proposition to be treated as a conjecture.
\item $\mbox{\constr{DocPfOf}}(t,\cD)$ declares that $t$ is a proposition proven by the proof term $\cD$.
\end{itemize}

As always, {\serfunc{seo\_doc}} and {\serfunc{sei\_doc}} serialize and deserialize documents.

There are two functions computing hash values for documents.
The function
{\func{hashdoc}}
computes a unique hash value for each distinct document.
This hash value is used to calculate the publication address where the document will be stored
in the ledger tree.
The function
{\func{doc\_hashroot}}
computes a hash root for a document.
This is done by combining hash roots for document items computed by {\func{docitem\_hashroot}}.

The purpose of hash roots for documents is to allow for the representation of parts
of the document in a way that still allow the hash root to be computed (as with any Merkle tree~\cite{Merkle1980}).
The type {\type{pdoc}} is the type of {\defin{partial documents}}.
Partial documents are an approximation of a document 
nodes can use for proof of storage in a block header.

The functions
{\serfunc{seo\_pdoc}} and {\serfunc{sei\_pdoc}} serialize and deserialize partial documents.

There are again two functions computing hash values.
The function {\func{hashpdoc}} computes a unique hash value for each partial document.
This is used to compute the hash of the block header in case a partial document
is used for proof of storage.
The function {\func{pdoc\_hashroot}} computes the hash root of the partial document.
If a partial document approximates a document, then both will have the same hash root.

\section{Dependency Checking}

There are a number of functions for computing the dependencies
of signatures and documents on objects and propositions.
In some cases the functions are used to check if the publisher has the
right to use the object or proposition.
In other cases the functions are used to justify the publisher claiming
ownership of an object or proposition.
Ownership of an object or proposition allows the control of the right to use
the object or proposition later.
Finally, some of the functions compute the hash values used to check the ledger
tree to see if a term with a given hash root has a given type in a given theory
or if a proposition with a given hash root is known in a given theory.

\begin{itemize}
\item {\func{signaspec\_uses\_objs}} collects the
parameters ({\constr{SignaParam}}) imported into a signature
as pairs $(h,k)$ where $h$ is the hash root of the (omitted) term defining the parameter
and $k$ is the hash of the type (given by {\func{hashtp}}).
It is defined via a tail recursive function {\func{signaspec\_uses\_objs\_aux}}
which also ensures the list is duplicate free.
This information is needed to check that there is in fact a previously published term
with hash root $h$ with the type with hash $k$
in the appropriate theory. It is also needed to check that the publisher has the right
to make use of the parameter in this way.
The function is used in {\func{output\_signaspec\_uses\_objs}}
in the {\module{assets}} module
where $(h,k)$ is converted into a pair $(h,k')$ where $k'$
depends on $h$, $k$ and the (optional) hash value identifier of the theory.
The idea is that $h$ is the identifier of the ``pure'' object (across all theories)
while $k'$ is the identifier of the object in the specific theory.
Both $h$ and $k'$ can be owned as objects.
In order to use an object as a parameter in a signature, both $h$ and $k'$ must be free to use
as objects (without requiring rights).
After an object has been published in a signature, every
signature and document can freely use everything in
the signature simply by importing it.
\item {\func{signaspec\_uses\_props}} collects the
hash roots of the known propositions ({\constr{SignaKnown}}) imported into a signature.
It is defined via a tail recursive function {\func{signaspec\_uses\_props\_aux}}
which also ensures the list is duplicate free.
This information is needed to check that there is in fact a proposition 
with hash root $h$
was previously published with a proof
in the appropriate theory (or that there is a corresponding axiom of the theory).
It is also needed to check that the publisher has the right
to make use of the known in this way.
The function is used in {\func{output\_signaspec\_uses\_props}}
in the {\module{assets}} module
where $h$ is converted into a pair $(h,k)$ where $k$
depends on $h$ and the (optional) hash value identifier of the theory.
The idea is that $h$ is the identifier of the ``pure'' proposition (across all theories)
while $k$ is the identifier of the proposition in the specific theory.
Both $h$ and $k$ can be owned as propositions.
In order to use a proposition as a known in a signature, both $h$ and $k$ must be free to use
as propositions (without requiring rights).
After a proposition has been published in a signature, every 
signature and document can freely use everything in
the signature simply by importing it.
\item {\func{doc\_uses\_objs}} is similar to {\func{signa\_uses\_objs}}
except it collects parameter declarations in documents ({\constr{DocParam}}).
It is used in {\func{output\_doc\_uses\_objs}}
in the {\module{assets}} module
to collect $(h,k)$ where $h$ is the identifier for the ``pure'' object
and $k$ is the identifier for the object in the relevant theory.
In order to use the object in the document as a parameter, the transaction publishing
the document is required to consume a sufficient number of object rights.
The cost of obtaining rights (which may range from ``free'' to ``impossible'')
is determined by the owners of $h$ and $k$ as objects.
\item {\func{doc\_uses\_props}} is similar to {\func{signa\_uses\_objs}}
except it collects parameter declarations in documents ({\constr{DocKnown}}).
It is used in {\func{output\_doc\_uses\_props}}
in the {\module{assets}} module
to collect $(h,k)$ where $h$ is the identifier for the ``pure'' proposition
and $k$ is the identifier for the proposition in the relevant theory.
In order to use the proposition in the document as a known, the transaction publishing
the document is required to consume a sufficient number of proposition rights.
The cost of obtaining rights (which may range from ``free'' to ``impossible'')
is determined by the owners of $h$ and $k$ as propositions.
\item {\func{doc\_creates\_objs}} collects definitions ({\constr{DocDef}})
as pairs $(h,k)$
where $h$ is the hash root of the term and $k$ is the hash of the type.
This is modified in {\func{output\_creates\_objs}} in the module {\module{assets}}
to be $(h,k')$ where $k'$ depends on $h$, $k$ and the (optional) hash value identifier of the theory.
Again, $h$ is the identifier for the ``pure'' object (across all theories)
and $k'$ is the identifier for the object in the specific theory.
If a document creates objects which are not yet owned as objects, then an owner must be declared with
the transaction publishing the document.
(The fact that an identifier for an object in a specific theory has an owner as an object
implies that the term has the type in the theory. Hence it can later be safely imported as a parameter
of the appropriate type in the theory.)
\item {\func{doc\_creates\_props}} collects the hash roots of proven propositions ({\constr{DocPfOf}}).
Each hash root $h$ is modified in {\func{output\_creates\_props}} in the module {\module{assets}}
to be a pair $(h,k)$ where $k$ depends on the theory.
Again, $h$ is the identifier for the ``pure'' proposition (across all theories)
and $k$ is the identifier for the proposition in the theory.
If a document creates propositions which are not yet owned as propositions, then an
owner must be declared with the transaction publishing the document.
(The fact that an identifier for a proposition in a specific theory has an owner as a proposition
implies that the proposition has been proven in the theory. Hence the proposition can safely
be imported as something known in the theory.)
\item {\func{doc\_creates\_neg\_props}} collects the hash roots of propositions $p$
 where the negation of $p$ is proven in the document.
 (Here the negation of $p$ is either $p\to\forall_o x_0$, i.e., $p$ implies false,
 or $\neg p$ where $\neg$ is $\lambda_o x_0\to\forall_o x_0$.)
 In {\func{output\_creates\_neg\_props}} in the module {\module{assets}} combines the hash
 root with the theory to obtain an identifier for the proposition in the theory.
 If a document proves the negation of a proposition, then the {\constr{OwnsNegProp}}
 preasset must be published into the corresponding identifier.
 The purpose of {\constr{OwnsNegProp}} is to allow the collection of bounties by
 proving the negation of a proposition instead of the original proposition.
 This makes sense as in a consistent theory proving either a proposition or its negation
 resolves the conjecture.
\end{itemize}

\section{Trees of Theories and Signatures}

In order to check the correctness of a signature specification
or document, the intended theory is required.
Likewise, correctness of the new signature specification
or document depends on all signatures imported.
For this reason, each Qeditas node needs to store every theory
and every signature published so far in order to verify the correctness of
new signature specifications and documents.
Theories and signatures are stored in trees indexed by their associated
hash values. The polymorphic type {\type{htree}} in the module {\module{htree}}
provides the general infrastructure.
The two special cases are
{\type{ttree}}
and
{\type{stree}}.
A {\type{ttree}} is simply an {\type{htree}} for storing theories (elements the type {\type{theory}}).
An {\type{stree}} is an {\type{htree}} for storing signatures (elements the type {\type{signa}}).
Each signature is associated with a specific theory (possibly the empty theory)
and can only be imported into signature specification and documents
within the same theory. This is enforced by storing the signature by an index that
depends on the hash value identifier of the theory.

\begin{itemize}
\item {\func{ottree\_insert}} takes an optional {\type{ttree}}, a bit sequence and a theory
      and returns the {\type{ttree}} resulting from inserting the theory at the location of the bit sequence.
      Giving {\val{None}} instead of a {\type{ttree}} corresponds to starting with the empty {\type{ttree}},
      and so the returned {\type{ttree}} will have exactly one entry.
      The bit sequence should be the $160$-bit hash returned by {\func{hashtheory}} when called on the given theory.
\item {\func{ostree\_insert}} takes an optional {\type{stree}}, a bit sequence and a signature
      and returns the {\type{stree}} resulting from inserting the signature at the location of the bit sequence.
      Giving {\val{None}} instead of a {\type{stree}} corresponds to starting with the empty {\type{stree}},
      and so the returned {\type{stree}} will have exactly one entry.
      The bit sequence should be the $160$-bit hash returned by 
      {\func{hashopair2}} on the optional hash value identifying the intended theory
      and the hash value returned by {\func{hashsigna}} when called on the given signature.
\item {\func{ottree\_hashroot}} returns an optional hash value representing the Merkle root
      of an optional {\type{ttree}}.
      This value is sometimes called the {\defin{theory root}} and is in block headers
      as {\field{newtheoryroot}}.
      Before the first theory is published, the optional {\type{ttree}} is {\val{None}}
      and the corresponding hash root is also {\val{None}}.
\item {\func{ostree\_hashroot}} returns an optional hash value representing the Merkle root
      of an optional {\type{stree}}.
      This value is sometimes called the {\defin{signature root}} and is in block headers
      as {\field{newsignaroot}}.
      Before the first signature is published, the optional {\type{ttree}} is {\val{None}}
      and the corresponding hash root is also {\val{None}}.
\item {\func{ottree\_lookup}} lookups a theory in an optional {\type{ttree}} given its optional hash value
      identifier.
      If the optional hash value identifier is {\val{None}}, no lookup is performed: the empty theory is returned.
      Otherwise, the hash value is converted to a bit sequence (list of booleans) and
      {\func{htree\_lookup}} attempts to find the theory in the tree.
      If no entry is found, the exception {\exc{Not\_found}} is raised.
\end{itemize}
Note that there is no {\func{ostree\_lookup}}.
The internal function {\func{import\_signatures}} looks up signatures
as they are required.

\section{Substitution and Normalization}

Type checking and proof checking depend on substitution and $\beta\eta$-normalization.
The functions implementing substitution and $\beta\eta$-normalization are not exposed in the
interface, but it is of fundamental importance that they are bug-free.
Substitutions and normalization can also be defined for proof terms,
but this is not necessary for Qeditas.

Defining substitution requires auxiliary functions to shift
de Bruijn indices.
For example, suppose we wish to substitute a term
$x_0\to x_1$ for the de Bruijn index $x_0$ in the term
$$x_0\to\forall_o x_1\to x_0$$
-- i.e., $x_0\to (\forall_o (x_1\to x_0))$.
Naively one might expect the result to be
$$(x_0\to x_1)\to\forall_o x_1\to (x_0 \to x_1)$$
but this is incorrect.
The first occurrence of $x_0$ is ``free'' and should be replaced
by $x_0\to x_1$.
However, the second occurrence of $x_0$ corresponds to the $\forall_o$ binder
and so is not ``free.'' On the other hand, $x_1$ inside the scope of the $\forall_o$ binder
corresponds to $x_0$ outside the scope of the $\forall_o$ binder.
This might lead one to believe the resulting term should be
$$(x_0\to x_1)\to\forall_o (x_0\to x_1)\to x_0.$$
This is, however, also incorrect as the new $x_0$ and $x_1$ instead the scope of the $\forall_o$ binder
no longer correspond to $x_0$ and $x_1$ outside the scope of the $\forall_o$ binder.
The correct result would be
$$(x_0\to x_1)\to\forall_o (x_1\to x_2)\to x_0.$$
That is, shifting of de Bruijn indices is required when the substitution procedure
passes through a binder.

We say an occurrence $\delta_n$ of a type variable (in a term or type) is {\defin{locally bound for $i$}}
if it is beneath $j$ type level binders ($\Pi$, $\Lambda$ or $\tforall$) where $n < i+j$.
Likewise we say an occurrence of $x_n$ of a term variable (in a term) is {\defin{locally bound for $i$}}
if it is beneath $j$ term level binders ($\lambda_\alpha$ or $\forall_\alpha$) where $n < i+j$.
We will simply say ``locally bound'' when the intended $i$ is clear.

We write $\dbtpsh{i}{j}{T}$ as notation for the term or type 
where each $\delta_n$ is shifted to $\delta_{n+j}$ unless it is locally bound for $i$.
We write $\dbsh{i}{j}{t}$ as notation for the term $t$
where each $x_n$ are shifted to $x_{n+j}$ unless it is locally bound for $i$.
We write $\dbsub{i}{S}{T}$ as notation for the result of substituting a
type or term $S$ for the variable $\delta_i$ or $x_i$ in the type or term $T$.

Returning to the example above, we can outline the necessary calculations
in order to compute
$$\dbsub{0}{x_0\to x_1}{(x_0\to\forall_o x_1\to x_0)}$$
as follows:
\begin{eqnarray*}
\dbsub{0}{x_0\to x_1}{(x_0\to\forall_o x_1\to x_0)} \\
 = (\dbsub{0}{x_0\to x_1}{x_0})\to(\dbsub{0}{x_0\to x_1}{(\forall_o x_1\to x_0)}) \\
 = 
(x_0\to x_1)\to\forall_o (\dbsub{1}{x_0\to x_1}{(x_1\to x_0)}) \\
 = 
(x_0\to x_1)\to\forall_o ((\dbsub{1}{x_0\to x_1}{x_1}) \to (\dbsub{1}{x_0\to x_1}{x_0})) \\
 = 
(x_0\to x_1)\to\forall_o (\dbsh{0}{1}{(x_0\to x_1)}) \to x_0 \\
 = 
(x_0\to x_1)\to\forall_o (x_1\to x_2) \to x_0 \\
\end{eqnarray*}

We briefly describe the internal functions for shifting and performing substitutions at the different levels.
For these functions to behave as mathematically intended, we
need to assume that for each occurrence of $\tmh{h}$ 
$h$ is the hash root of a term where every occurrence of a variable is locally bound (also called a {\defin{closed}} term).
\begin{itemize}
\item {\func{tpshift}} defines $\dbtpsh{i}{j}{\alpha}$ for shifting type variables in a type $\alpha$.
The defining cases are:
\begin{itemize}
\item $\dbtpsh{i}{j}{\delta_k} = \delta_k$ if $k<i$. In particular, locally bound type variables are not shifted.
\item $\dbtpsh{i}{j}{\delta_k} = \delta_{k+j}$ if $k\geq i$.
\item $\dbtpsh{i}{j}{(\alpha\to\beta)} = (\dbtpsh{i}{j}{\alpha} \to\dbtpsh{i}{j}{\beta})$.
\item $\dbtpsh{i}{j}{(\Pi\alpha)} = \Pi (\dbtpsh{i+1}{j}{\alpha})$. The idea in this case is that passing
through the $\Pi$ binder means one more type variable is considered locally bound.
\item $\dbtpsh{i}{j}{\alpha} = \alpha$ otherwise.
\end{itemize}
\item {\func{tmtpshift}} defines $\dbtpsh{i}{j}{t}$ for shifting type variables in a term $t$.
The defining cases are:
\begin{itemize}
\item $\dbtpsh{i}{j}{(st)} = (\dbtpsh{i}{j}{s}) (\dbtpsh{i}{j}{t})$.
\item $\dbtpsh{i}{j}{(\lambda_\alpha t)} = \lambda_{\dbtpsh{i}{j}{\alpha}} (\dbtpsh{i}{j}{t})$. The term level $\lambda_\alpha$ binder does not affect which type variables are locally bound.
\item $\dbtpsh{i}{j}{(s\to t)} = (\dbtpsh{i}{j}{s}) \to (\dbtpsh{i}{j}{t})$.
\item $\dbtpsh{i}{j}{(\forall_\alpha t)} = \forall_{\dbtpsh{i}{j}\alpha} (\dbtpsh{i}{j}{t})$. The term level $\forall_\alpha$ binder does not affect which type variables are locally bound.
\item $\dbtpsh{i}{j}{(s\alpha)} = (\dbtpsh{i}{j}{s}) (\dbtpsh{i}{j}\alpha)$.
\item $\dbtpsh{i}{j}{(\Lambda t)} = \Lambda (\dbtpsh{i+1}{j}{t})$. The type level $\Lambda$ binder means one more type variable is locally bound.
\item $\dbtpsh{i}{j}{(\tforall t)} = \tforall (\dbtpsh{i+1}{j}{t})$. The type level $\tforall$ binder means one more type variable is locally bound.
\item $\dbtpsh{i}{j}{t} = t$ otherwise. In particular, $\dbtpsh{i}{j}{\tmh{h}} = \tmh{h}$.
Assuming $h$ is the hash root of a term $s$ where every type variable is locally bound,
then $\dbtpsh{i}{j}{s} = s$
and $h$ is still the term root of $\dbtpsh{i}{j}{s}$.
\end{itemize}
\item {\func{tmshift}} defines $\dbsh{i}{j}{t}$ for shifting term variables in a term $t$.
The defining cases are:
\begin{itemize}
\item $\dbsh{i}{j}{x_k} = x_k$ if $k<i$.
\item $\dbsh{i}{j}{x_k} = x_{k+j}$ if $k\geq i$.
\item $\dbsh{i}{j}{(st)} = (\dbsh{i}{j}{s}) (\dbsh{i}{j}{t})$.
\item $\dbsh{i}{j}{(\lambda_\alpha t)} = \lambda_\alpha (\dbsh{i+1}{j}{t})$. The term level $\lambda_\alpha$ binder makes one more term variable locally bound.
\item $\dbsh{i}{j}{(s\to t)} = (\dbsh{i}{j}{s}) \to (\dbsh{i}{j}{t})$.
\item $\dbsh{i}{j}{(\forall_\alpha t)} = \forall_\alpha (\dbsh{i+1}{j}{t})$. The term level $\forall_\alpha$ binder makes one more term variable locally bound.
\item $\dbsh{i}{j}{(s\alpha)} = (\dbsh{i}{j}{s}) \alpha$.
\item $\dbsh{i}{j}{(\Lambda t)} = \Lambda (\dbsh{i}{j}{t})$. The type level $\Lambda$ binder does not change which term level variables are locally bound.
\item $\dbsh{i}{j}{(\tforall t)} = \tforall (\dbsh{i}{j}{t})$. The type level $\tforall$ binder does not change which term level variables are locally bound.
\item $\dbsh{i}{j}{t} = t$ otherwise. In particular, $\dbsh{i}{j}{\tmh{h}} = \tmh{h}$.
Assuming $h$ is the hash root of a term $s$ where every term variable is locally bound,
then $\dbsh{i}{j}{s} = s$
and $h$ is still the term root of $\dbsh{i}{j}{s}$.
\end{itemize}
\item {\func{tpsubst}} defines $\dbsub{j}{\beta}{\alpha}$ for types $\alpha$ and $\beta$.
The defining cases are:
\begin{itemize}
\item $\dbsub{j}{\beta}{\delta_j} = \dbtpsh{0}{j}{\beta}$.
In the special case where $j=0$ we know $\dbtpsh{0}{j}{\beta} = \beta$
and so we can simply take $\dbsub{0}{\beta}{\delta_0} = \beta$.
\item $\dbsub{j}{\beta}{\delta_i} = \delta_{i-1}$ if $i>j$. This corresponds to the ``removal'' of the variable $\delta_j$ during the substitution.
\item $\dbsub{j}{\beta}{(\alpha_1\to\alpha_2)} = (\dbsub{j}{\beta}{\alpha_1})\to (\dbsub{j}{\beta}{\alpha_2})$
\item $\dbsub{j}{\beta}{(\Pi \alpha)} = (\Pi (\dbsub{j+1}{\beta}{\alpha}))$
\item $\dbsub{j}{\beta}{\alpha} = \alpha$ otherwise.
\end{itemize}
\item {\func{tmtpsubst}} defines $\dbsub{j}{\beta}{s}$ for terms $s$ and types $\beta$.
The defining cases are:
\begin{itemize}
\item $\dbsub{j}{\beta}{(st)} = (\dbsub{j}{\beta}{s}) (\dbsub{j}{\beta}{t})$.
\item $\dbsub{j}{\beta}{(\lambda_\alpha t)} = \lambda_{\dbsub{j}{\beta}{\alpha}} (\dbsub{j}{\beta}{t})$. The term level $\lambda_\alpha$ binder does not affect which type variables are locally bound.
\item $\dbsub{j}{\beta}{(s\to t)} = (\dbsub{j}{\beta}{s}) \to (\dbsub{j}{\beta}{t})$.
\item $\dbsub{j}{\beta}{(\forall_\alpha t)} = \forall_{\dbsub{j}{\beta}\alpha} (\dbsub{j}{\beta}{t})$. The term level $\forall_\alpha$ binder does not affect which type variables are locally bound.
\item $\dbsub{j}{\beta}{(s\alpha)} = (\dbsub{j}{\beta}{s}) \alpha$.
\item $\dbsub{j}{\beta}{(\Lambda t)} = \Lambda (\dbsub{j+1}{\beta}{t})$. The type level $\Lambda$ binder means one more type variable is locally bound.
\item $\dbsub{j}{\beta}{(\tforall t)} = \tforall (\dbsub{j+1}{\beta}{t})$. The type level $\tforall$ binder means one more type variable is locally bound.
\item $\dbsub{j}{\beta}{t} = t$ otherwise. In particular, $\dbsub{j}{\beta}{\tmh{h}} = \tmh{h}$.
Assuming $h$ is the hash root of a term $s$ where every type variable is locally bound,
then $\dbsub{j}{\beta}{s} = s$
and $h$ is still the term root of $\dbsub{j}{\beta}{s}$.
\end{itemize}
\item {\func{tmsubst}} defines $\dbsub{j}{u}{s}$ for terms $s$ and $u$.
The defining cases are:
\begin{itemize}
\item $\dbsub{j}{u}{x_j} = \dbsh{0}{j}{u}$.
In the special case where $j=0$ we know $\dbsh{0}{j}{u} = u$
and so we can simply take $\dbsub{0}{u}{x_0} = u$.
\item $\dbsub{j}{u}{x_i} = x_{i-1}$ if $i>j$. This corresponds to the ``removal'' of the variable $x_j$ during the substitution.
\item $\dbsub{j}{u}{(st)} = (\dbsub{j}{u}{s}) (\dbsub{j}{u}{t})$.
\item $\dbsub{j}{u}{(\lambda_\alpha t)} = \lambda_\alpha (\dbsub{j+1}{u}{t})$. The term level $\lambda_\alpha$ binder makes one more term variable locally bound.
\item $\dbsub{j}{u}{(s\to t)} = (\dbsub{j}{u}{s}) \to (\dbsub{j}{u}{t})$.
\item $\dbsub{j}{u}{(\forall_\alpha t)} = \forall_\alpha (\dbsub{j+1}{u}{t})$. The term level $\forall_\alpha$ binder makes one more term variable locally bound.
\item $\dbsub{j}{u}{(s\alpha)} = (\dbsub{j}{u}{s}) \alpha$.
\item $\dbsub{j}{u}{(\Lambda t)} = \Lambda (\dbsub{j}{u}{t})$. The type level $\Lambda$ binder does not change which term level variables are locally bound.
\item $\dbsub{j}{u}{(\tforall t)} = \tforall (\dbsub{j}{u}{t})$. The type level $\tforall$ binder does not change which term level variables are locally bound.
\item $\dbsub{j}{u}{t} = t$ otherwise. In particular, $\dbsub{j}{u}{\tmh{h}} = \tmh{h}$.
Assuming $h$ is the hash root of a term $s$ where every term variable is locally bound,
then $\dbsub{j}{u}{s} = s$
and $h$ is still the term root of $\dbsub{j}{u}{s}$.
\end{itemize}
\end{itemize}

Next we need to say what it means for a type variable $\delta_j$ to be {\defin{free}}
in a type or term, and what it means for a term variable $x_j$ to be {\defin{free}}
in a term.
There are three relevant definitions:
\begin{itemize}
\item The function {\func{free\_tpvar\_in\_tp\_p}} determines if a type variable $\delta_j$
is {\defin{free}} in a type $\alpha$. The definition is by recursion on $\alpha$ and the $j$ must be
increased by 1 in the $\Pi$ binder case to account for the new locally bound variable.
\item The function {\func{free\_tpvar\_in\_tm\_p}} determines if a type variable $\delta_j$
is {\defin{free}} in a term $t$. The definition is by recursion on $t$ and the $j$ must be
increased by 1 in the $\Lambda$ and $\tforall$ binder cases.
\item The function {\func{free\_in\_tm\_p}} determines if a term variable $x_j$
is {\defin{free}} in a term $t$. The definition is by recursion on $t$ and the $j$ must be
increased by 1 in the $\lambda_\alpha$ and $\forall_\alpha$ binder cases.
\end{itemize}

We can now turn to $\beta\eta$-normalization.
We begin by considering four kinds of {\defin{redexes}} and their corresponding
{\defin{reducts}}. Normalization is performed by reducing redexes to their reducts
until no more redexes remain.
A theorem of various type theories is that normalization terminates in a
unique normal form for well-typed terms, and that is true for the type theory
under consideration here.
\begin{itemize}
\item A term of the form $(\lambda_\alpha s)t$
is a {\defin{term level $\beta$-redex}}
with reduct $\dbsub{0}{t}{s}$.
\item A term of the form $(\Lambda s)\alpha$
is a {\defin{type level $\beta$-redex}}
with reduct $\dbsub{0}{\alpha}{s}$.
\item A term of the form $\lambda_\alpha (s x_0)$ where $x_0$ is not free in $s$
is a {\defin{term level $\eta$-redex}}
with reduct $\dbsh{0}{-1}{s}$. (The shift of term variables by $-1$ is required
since $s$ was in the scope of one term level binder $\lambda_\alpha$ which is removed from the reduct.)
\item A term of the form $\Lambda (s \delta_0)$ where $\delta_0$ is not free in $s$
is a {\defin{type level $\eta$-redex}}
with reduct $\dbtpsh{0}{-1}{s}$. (The shift of type variables by $-1$ is required
since $s$ was in the scope of one type level binder $\Lambda$ which is removed from the reduct.)
\end{itemize}
A term is {\defin{normal}} if it has no redexes.
The function {\func{tm\_norm\_p}} checks if a term is normal.
In theory specifications, signature specifications and documents
all definitions, knowns, conjectures and theorems are required to be normal.
The exception {\exc{NonNormalTerm}} is raised if this requirement is violated.

The normalization procedure is {\func{tm\_beta\_eta\_norm}}.
It proceeds by repeatedly calling {\func{tm\_beta\_eta\_norm\_1}}.
In simple terms, the function {\func{tm\_beta\_eta\_norm\_1}} recursively traverses a term
reducing each redex it finds and returning the reduced term along with a boolean
indicating if at least one reduction was performed. If no reductions were performed,
then the term is normal and the procedure ends.

In certain examples, $\beta$-normalization (and hence $\beta\eta$-normalization)
leads to large terms and can require
an unrealistic number of $\beta$-reductions.
This problem is dealt with by having resource bounds
represented internally by {\var{beta\_count}}
and {\var{term\_count}}.
Before a signature specification or document is checked,
these resource bounds are reset (by {\func{reset\_resource\_limits}}).
(Checking a theory specification requires no $\beta$-reductions.)
There are $200,000$ beta reductions and $10$ million term traversal steps
allowed per signature specification or document.
Each $\beta$-reduction step decrements {\var{beta\_count}} by one.
If {\var{beta\_count}} reaches $0$, then the exception {\exc{BetaLimit}} is raised.
For each recursive call of a shift or substitution function
decrements {\var{term\_count}}.
If {\var{term\_count}} reaches $0$, then the exception {\exc{TermLimit}} is raised.
If either of these exceptions are thrown, it essentially means that checking
the signature specification or document is too resource intensive and
it cannot be published in its current form.
If this occurs, a possible solution is to factor the publication into multiple publications.

It is worth noting that some well-known ill-typed terms do not have a normal form.
For example, $(\lambda_o x_0 x_0) (\lambda_o x_0 x_0)$ is a term level $\beta$-redex
with itself as a reduct. Without resource bounds, calling {\func{tm\_beta\_eta\_norm}}
with this term would result in an infinite loop. With the resource bound, {\exc{BetaLimit}}
would be raised.
In practice, {\func{tm\_beta\_eta\_norm}} should never be called with such a term
since during the checking of publications {\func{tm\_beta\_eta\_norm}} is only
called with terms which are already known to be well-typed.

We write $\benorm{s}$ for the $\beta\eta$-normal form of $s$, assuming it exists.

\section{Type Checking and Proof Checking}

We now turn to the most important functions: those which check that a type
is valid, check that a term has a type, check that a term is a proposition,
and check that a proof term is a proof of a proposition.

Checking attempts typically either succeed
(possibly returning some information)
or raise an exception.
The exception {\exc{CheckingFailure}} is raised
if checking fails.
One of the exceptions {\exc{BetaLimit}} or {\exc{TermLimit}} is raised
if one of the corresponding resource bounds is reached.

All the properties defined will be relative to a
{\defin{type context}}.
Since type variables are represented
as de Bruijn indices, the {\defin{type context}}
can be taken to simply be a non-negative integer $v$.

We say a type $\alpha$ is {\defin{valid as a simple type}} in type context $v$
(and write $v\vdash \alpha \stp$) if
it contains no occurrence of $\Lambda$ and every type variable $\delta_i$ satisfies $i<v$.
The function {\func{check\_tp}} performs this check.
A type $\alpha$ is {\defin{valid as a polymorphic type}} in type context $v$
(and write $v\vdash \alpha \ptp$) if
if
it is of the form
$$\underbrace{\Lambda\cdots\Lambda}_m\beta$$
where $\beta$ is valid as a simple type in type context $v+m$.
The function {\func{check\_ptp}} performs this check.

Properties such as these are often defined
using rules. One can often understand the functions checking the properties
better by comparing them to such rules.
Rules defining $v\vdash \alpha\stp$
and $v\vdash \alpha\ptp$
are given in Figure~\ref{fig:tp}.

\begin{figure}
\begin{center}
\begin{mathpar}
\inferrule*{i < v}{v\vdash \delta_i\stp}
\and
\inferrule*{v\vdash\alpha\stp \\ v\vdash\beta\stp}{v\vdash \alpha\to\beta\stp}
\and
\inferrule*{v\vdash\alpha\stp}{v\vdash\alpha\ptp}
\and
\inferrule*{v+1\vdash \alpha\ptp}{v\vdash \Pi\alpha\ptp}
\end{mathpar}
\end{center}
\caption{Rules for validity of types}\label{fig:tp}
\end{figure}

The notion of types being valid is independent of the theory or a signature.
It would make sense to restrict types to only mention base types 
mentioned in the current theory, but there is no strong reason to do so.
For simplicity, we ignore the theory when asking if a type is valid.

The property of when a term has a type
depends on both a type context and a {\defin{term context}}.
A {\defin{term context}} $\Gamma$ is a list of types
$\alpha_0,\ldots,\alpha_{m-1}$
giving the types of the term level de Bruijn indices
in the current context.
We write $\dbtpsh{i}{j}\Gamma$ for the term context
$\dbtpsh{i}{j}{\alpha_0},\ldots,\dbtpsh{i}{j}{\alpha_{m-1}}$
when $\Gamma$ is $\alpha_0,\ldots,\alpha_{m-1}$.

We now define $\Sigma;v;\Gamma \vdash t : \alpha$ -- i.e.,
when a term $t$ has type $\alpha$ in a signature $\Sigma$, type context $v$
and term context $\Gamma$.
The definition also depends on the current theory, but we will leave this implicit in the notation.
Suppose the current theory assings the types $\gamma_0,\ldots,\gamma_{n-1}$ to the first $n$ primitives.
This information is needed to know $c_i:\gamma_i$ for $i<n$.
(The corresponding function is {\func{tp\_of\_prim}}.)
Rules defining $\Sigma;v;\Gamma \vdash t : \alpha$ are given in Figure~\ref{fig:tmtp}.

\begin{figure}
\begin{center}
\begin{mathpar}
\inferrule*{\Gamma = \alpha_0,\ldots,\alpha_{m-1}\\ i<m}{\Sigma;v;\Gamma\vdash x_i : \alpha_i}
\and
\inferrule*{i<n}{\Sigma;v;\Gamma\vdash c_i : \gamma_i}
\and
\inferrule*{\Sigma=(\cO,\cK)\\(h,\alpha,d)\in\cO}{\Sigma;v;\Gamma\vdash \tmh{h} : \alpha}
\and
\inferrule*{\Sigma;v;\Gamma\vdash s : \alpha\to\beta\\\Sigma;v;\Gamma\vdash t : \alpha}{\Sigma;v;\Gamma\vdash st : \beta}
\and
\inferrule*{\Sigma;v;\alpha,\Gamma\vdash s : \beta}{\Sigma;v;\Gamma\vdash \lambda_\alpha s : \alpha\to\beta}
\and
\inferrule*{\Sigma;v;\Gamma\vdash s : o \\\Sigma;v;\Gamma\vdash t : o}{\Sigma;v;\Gamma\vdash s\to t : o}
\and
\inferrule*{\Sigma;v;\alpha,\Gamma\vdash s : o}{\Sigma;v;\Gamma\vdash \forall_\alpha s : o}
\and
\inferrule*{\Sigma;v;\Gamma\vdash s : \Pi\alpha\\v\vdash \beta \stp}{\Sigma;v;\Gamma\vdash s\beta : \dbsub{0}{\beta}{\alpha}}
\and
\inferrule*{\Sigma;v+1;\dbtpsh{0}{1}{\Gamma}\vdash s : \alpha}{\Sigma;v;\Gamma\vdash \Lambda s : \Pi\alpha}
\end{mathpar}
\end{center}
\caption{Rules for typing terms}\label{fig:tmtp}
\end{figure}

There are two mutually recursive functions
{\func{extr\_tpoftm}} and {\func{check\_tpoftm}}
to check
$\Sigma;v;\Gamma \vdash t : \alpha$.
The function {\func{extr\_tpoftm}} is not given the type $\alpha$
and extracts the type $\alpha$, returning it upon success.
The function {\func{check\_tpoftm}} is given the $\alpha$ and
ensures it matches the extracted type.

In simple type theory a term is often called a ``proposition'' in a given context
when it has type $o$
This will be true here, but
we will have additional polymorphic propositions of the form
$$\underbrace{\tforall\cdots\tforall}_ms$$
where $s$ has type $o$ in the empty context.
The restriction considering such propositions in the empty context is to ensure
that all $\tforall$ type binders occur before term level binders.
We can define $\Sigma;v\vdash s \pprop$ meaning $s$ is a {\defin{polymorphic proposition}}
(under the signature $\Sigma$ and type context $v$)
by the rules in Figure~\ref{fig:pprop}.
We then define $\Sigma;v;\Gamma \vdash s \prop$ meaning $s$ is a {\defin{proposition}}
(under the signature $\Sigma$, type context $v$ and term context $\Gamma$)
to mean $\Sigma;v\vdash s \pprop$
or $\Sigma;v;\Gamma \vdash s:o$.

The function {\func{check\_polyprop}} implements the check for polymorphic propositionhood
and {\func{check\_prop}} implements the check for propositionhood.

\begin{figure}
\begin{center}
\begin{mathpar}
\inferrule*{\Sigma;v;\cdot\vdash s : o}{\Sigma;v\vdash s \pprop}
\and
\inferrule*{\Sigma;v+1\vdash s\pprop}{\Sigma;v\vdash \tforall s \pprop}
\end{mathpar}
\end{center}
\caption{Rules for when terms are polymorphic propositions}\label{fig:pprop}
\end{figure}

In order to determine if a proof term proves a given
proposition, it is necessary to consider the proposition
up to $\beta\eta$-reductions and expansion of definitions in $\Sigma$.
Expansion of definitions is sometimes called $\delta$-reduction.
That is, if $\Sigma=(\cO,\cK)$ is a global signature
and $(h,\alpha,s)\in\cO$, then $\tmh{h}$ is a $\delta$-redex
with $\delta$-reduct $s$.
We write $\dnorm{\Sigma}{s}$ for the $\delta$-normal form of $s$, assuming it exists.
(If there were cycles in the definitions in $\Sigma$, then $\delta$-reduction would not terminate.
In practice, signatures will not have such cycles.)
Note that $\delta$-reduction may (and often will) introduce new $\beta$-redexes.
However, $\beta\eta$-reduction never introduces new $\delta$-redexes.
Hence we can compute the $\beta\eta\delta$-normal form of $s$ by
first computing $\dnorm\Sigma{s}$
and then computing the $\beta\eta$-normal form.
We denote this $\beta\eta\delta$-normal form by $\bednorm\Sigma{s}$.
In the special case where we know $s$ is $\delta$-normal already,
then $\bednorm\Sigma{s}$ is the same as $\benorm{s}$ (the $\beta\eta$-normal form of $s$).

An easy way to consider terms up to $\beta\eta\delta$-reduction is to simply
always normalize the terms. This is what the code does when trying to determine
if a proof term proves a proposition.

The function {\func{tm\_delta\_norm}} computes $\dnorm\Sigma{s}$
and the function {\func{tm\_beta\_eta\_delta\_norm}} computes $\bednorm\Sigma{s}$.

The property of when a proof term is a proof of a given
proposition depends on a type context, a term context
and a {\defin{hypothesis context}}.
A {\defin{hypothesis context}} $\Phi$ is a list
$\rho_0,\ldots,\rho_{k-1}$
of terms
giving the current assumed hypotheses
(proof level de Bruijn indices in the proof term).
We will only work with hypothesis contexts where each hypothesis $\rho$
is $\beta\eta\delta$-normal.
We will also ensure that the terms are of type $o$ (and not, for example,
more general polymorphic propositions).

Let $\Phi$ be $\rho_0,\ldots,\rho_{k-1}$.
We write $\dbsh{i}{j}\Phi$ for the hypothesis context
$\dbsh{i}{j}{\rho_0},\ldots,\dbsh{i}{j}{\rho_{k-1}}$
when $\Phi$ is $\rho_0,\ldots,\rho_{k-1}$.

We now define when a proof term proves a proposition,
given a signature and appropriate contexts.
We denote this relation by
$\Sigma;v;\Gamma;\Phi\vdash \cD : t$
and define it by the rules in Figure~\ref{fig:pf}.
Note that in each rule, we ensure that the proposition $t$ is $\beta\eta\delta$-normal
(assuming every proposition in $\Phi$ is $\beta\eta\delta$-normal).
Also note that proof terms for polymorphic propositions which are not of type $o$
(i.e., have at least one $\tforall$ binder) must either be known $\known{h}$
or must be proven in the empty term and hypothesis contexts.

\begin{figure}
\begin{center}
\begin{mathpar}
\inferrule*{\Phi = \rho_0,\ldots,\rho_{k-1}\\ j<k}{\Sigma;v;\Gamma;\Phi\vdash \hyp{j} : \rho_{j}}
\and
\inferrule*{\Sigma=(\cO,\cK)\\ (h,s)\in\cK}{\Sigma;v;\Gamma;\Phi\vdash \known{h} : \bednorm\Sigma{s}}
\and
\inferrule*{\Sigma;v;\Gamma;\Phi\vdash \cD : \forall_\alpha s\\\Sigma;v;\Gamma;\Phi\vdash t : \alpha}{\Sigma;v;\Gamma;\Phi\vdash \cD t : \benorm{\dbsub{0}{\dnorm\Sigma{t}}{s}}}
\and
\inferrule*{\Sigma;v;\Gamma;\Phi\vdash \cD : s\to t\\\Sigma;v;\Gamma;\Phi\vdash \cE : s}{\Sigma;v;\Gamma;\Phi\vdash \cD \cE : t}
\and
\inferrule*{v\vdash s\stp\\\Sigma;v;\alpha,\Gamma;\dbsh{0}{1}{\Phi}\vdash \cD : s}{\Sigma;v;\Gamma;\Phi\vdash \lambda_\alpha \cD : \forall_\alpha s}
\and
\inferrule*{\Sigma;v;\Gamma\vdash s : o\\ \Sigma;v;\Gamma;\bednorm\Sigma{s},\Phi\vdash \cD : t}{\Sigma;v;\Gamma;\Phi\vdash \lambda_s \cD : \bednorm\Sigma{s}\to t}
\and
\inferrule*{\Sigma;v;\Gamma;\Phi\vdash \cD : \tforall s\\v\vdash \beta \stp}{\Sigma;v;\Gamma;\Phi\vdash \cD \beta : \dbsub{0}{\beta}{s}}
\and
\inferrule*{\Sigma;v+1;\cdot;\cdot\vdash \cD : s}{\Sigma;v;\cdot;\cdot\vdash \Lambda \cD : \tforall s}
%\and
%\inferrule*{\Sigma;v;\Gamma;\Phi\vdash \cD : s \\ \bednorm{\Sigma}{s} = \bednorm{\Sigma}{t}}{\Sigma;v;\Gamma;\Phi\vdash \cD : t}
\end{mathpar}
\end{center}
\caption{Rules for when a proof proves a proposition}\label{fig:pf}
\end{figure}

Like with type checking, there are two mutually recursive functions
{\func{extr\_propofpf}} and {\func{check\_propofpf}}
to check
$\Sigma;v;\Gamma;\Phi\vdash \cD : t$.
In the case of {\func{extr\_propofpf}} no proposition $t$ is given.
If the given proof term does prove a proposition $t$, this $\beta\eta\delta$-normal $t$ is
returned. Otherwise, the exception $\exc{CheckingFailure}$ (or one of the resource bound exceptions) is raised.
In the case of {\func{check\_propofpf}} a $\beta\eta\delta$-normal proposition $t$ is given
and is checked to be equal to the result returned by {\func{extr\_propofpf}}.
If the two are not equal, $\exc{CheckingFailure}$ is raised.

\section{Publication Checking}

We can now turn to the main functions exported by the {\module{mathdata}} module:
the functions for checking theory specifications, signature specifications
and documents.
In each case, if the publication is checked to be correct, a global signature
is returned.
If a theory specification is checked to be correct, then a theory is also returned.
If a publication is determined not to be correct, an exception is raised.
Some of these exceptions have been mentioned above:
{\exc{BetaLimit}} (too many $\beta$-reductions),
{\exc{TermLimit}} (too many large terms),
{\exc{NonNormalTerm}} (a term in a publication was not $\beta\eta$-normal)
and
{\exc{CheckingFailure}} (either type checking or proof checking failed).
In addition, there are three more exceptions:
\begin{itemize}
\item {\exc{NotKnown}} is an exception indicating an attempt to import proposition 
as previously known failed.
\item {\exc{UnknownTerm}} is an exception indicating an attempt to import an object
by the hash root of the term failed.
\item {\exc{UnknownSigna}} is an exception indicating that an attempt was made
to import an unknown signature.
\end{itemize}

Signature specifications and documents may import previous signatures and this 
is handled by {\func{import\_signatures}}.
An extra value {\val{imported}} prevents importing of signatures multiple times.

There are three functions for checking publications:
\begin{itemize}
\item {\func{check\_theoryspec}} checks a theory specification
and (upon success) returns a theory and a global signature.
The empty theory specification returns the empty theory and the empty global signature.
Suppose the theory specification is nonempty. 
We recursively call the procedure on the rest of the specification to obtain a theory
$\cT = (\cP,\cA)$
and global signature
$\Sigma = (\cO,\cK)$.
The head of the specification is then handled as follows:
\begin{itemize}
\item $\mbox{\constr{ThyPrim}}(\alpha)$: check that $0\vdash \alpha\ptp$ ($\alpha$ is valid
as a polymorphic type in type context $0$)
and return the theory $(\cP',\cA)$ where $\cP'$ is $\cP,\alpha$
and global signature $\Sigma$.
This declares the type of the next primitive $c_n$.
\item $\mbox{\constr{ThyDef}}(\alpha,s)$: check that $s$ is $\beta\eta$-normal,
$0\vdash \alpha\ptp$ ($\alpha$ is valid
as a polymorphic type in type context $0$)
and that $\Sigma;0;\cdot\vdash s:\alpha$ ($s$ has type $\alpha$)
and return the theory $\cT$ and the global signature
$(\cO',\cK)$ where $\cO'$ is $\cO$ with the additional entry $(\tmhr{s},\alpha,s)$.
That is, the global signature has enough information to recover the type of $s$
and the term $s$ from the hash root $\tmhr{s}$.
\item $\mbox{\constr{ThyAxiom}}(t)$ check that $t$ is a $\beta\eta$-normal
proposition (in the type context $0$ and empty term context).
Let $k$ be the hash root $\tmhr{t}$.
Let $\cA'$ be $\cA$ with the additional entry $k$ (to record the new axiom of the theory).
Let $\cK'$ be $\cK$ with the additional entry $(k,t)$ (to record that $\known{k}$ is a proof of $t$).
Return the theory $(\cP,\cA')$ and global signature $(\cO,\cK')$.
\end{itemize}
\item {\func{check\_signaspec}} checks a signature specification
and (upon success) returns a global signature.
This is performed within a fixed theory $\cT = (\cP,\cA)$.
The work is done by an auxiliary function {\func{check\_signaspec\_rec}}
which keeps up with which signatures have been imported.
We can define the recursive procedure as follows:
The empty signature specification returns the empty global signature.
Otherwise, we recursively call the procedure on the rest of the document
to obtain a global signature $\Sigma = (\cO,\cK)$.
Then we handle each of the signature item cases as follows:
\begin{itemize}
\item $\mbox{\constr{SignaSigna}}(h)$: import the signature identified by $h$.
If no signature identified by $h$ is found, then raise {\exc{UnknownSigna}}.
Otherwise, the result is a signature $\Sigma'=(\cO',\cK')$ where $\cO \subseteq \cO'$
and $\cK \subseteq \cK'$. (Here $\subseteq$ means each entry in the first list is an entry in the second.)
\item $\mbox{\constr{SignaParam}}(h,\alpha)$: check that $0\vdash \alpha\ptp$
and that the term with hash root $h$ is known to have type $\alpha$.
This second check is performed by calling {\func{tm\_tp\_p}} with a generic test {\var{gvtp}},
the signature, the theory identifier, $h$ and $\alpha$.
The test can succeed by noting $h$ is already declared in the signature to have type $\alpha$
or by verifying {\var{gvtp}} when called on the theory identifier, $h$ and $\alpha$.
Later when {\func{check\_signaspec}} is used, {\var{gvtp}}
is instantiated by a test to determine if a certain term address (formed from the theory identifier,
$h$ and $\alpha$) is owned as an object.
Assuming these checks succeed, return the signature $(\cO',\cK)$
where $\cO'$ is $\cO$ with the additional entry $(h,\alpha,\val{None})$.
\item $\mbox{\constr{SignaDef}}(\alpha,s)$: check $s$ is $\beta\eta$-normal,
$0\vdash \alpha\ptp$
and $\Sigma;0;\cdot\vdash s:\alpha$.
Let $h$ be the hash root $\tmhr{s}$.
If $s$ is $\tmh{h}$, then return $\Sigma$ (since recording $h$ as defined by $\tmh{h}$ would be cyclic).
If $s$ is not $\tmh{h}$, then return 
$(\cO',\cK)$
where $\cO'$ is $\cO$ with the additional entry $(h,\alpha,s)$.
\item $\mbox{\constr{SignaKnown}}(t)$: check $t$ is $\beta\eta$-normal
and that $\Sigma;0;\cdot\vdash t \prop$.
Let $k$ be the hash root $\tmhr{t}$.
Assuming $k$ is a the hash root of a known proposition, return $(\cO,\cK')$ where $\cK'$ is $\cK$
with the additional entry $(k,t)$.
In order for $k$ to be the hash root of a known proposition, we check that 
either $k\in \cA$ (so $k$ is the hash root of an axiom of the theory)
or the test {\func{known\_p}} passes using a generic test {\var{gvkn}} of the signature, theory identifier and $k$ holds.
The test {\func{known\_p}} passes if either $(k,s)\in\cK$ for some $s$ (so $k$ known in the signature)
or {\var{gvkn}} holds for the theory identifier and $k$.
Later when {\func{check\_signaspec}} is used, {\var{gvkn}}
is instantiated by a test to determine if a certain term address (formed from the theory identifier
and $k$) is owned as a proposition.
\end{itemize}
\item {\func{check\_doc}} checks a document
and (upon success) returns a global signature.
The work is done by an auxiliary function {\func{check\_doc\_rec}}
which keeps up with which signatures have been imported.
We can define the recursive procedure as follows:
The empty document returns the empty global signature.
Otherwise, we recursively call the procedure on the rest of the document
to obtain a global signature $\Sigma = (\cO,\cK)$.
Then we handle each of the document item cases as follows:
\begin{itemize}
\item $\mbox{\constr{DocSigna}}(h)$ is handled like ${\mbox{\constr{SignaSigna}}}$ in the case of signature specifications.
\item $\mbox{\constr{DocParam}}(h,\alpha)$ is handled like ${\mbox{\constr{DocParam}}}$ in the case of signature specifications.
\item $\mbox{\constr{DocDef}}(\alpha,s)$ is handled like ${\mbox{\constr{DocDef}}}$ in the case of signature specifications.
\item $\mbox{\constr{DocKnown}}(t)$ is handled like ${\mbox{\constr{DocKnown}}}$ in the case of signature specifications.
\item $\mbox{\constr{DocConj}}(t)$: check that $\Sigma;0;\cdot\vdash t \prop$
and return the same global signature $\Sigma$.
Conjectures do not change the signature and cannot be used in the rest of the document.
\item $\mbox{\constr{DocPfOf}}(t,\cD)$: check that $\Sigma;0;\cdot\vdash t \prop$
and $\Sigma;0;\cdot\vdash \cD : \bednorm\Sigma{t}$.
Return $(\cO,\cK')$ where $\cK'$ is $\cK$ with $(\tmhr{t},t)$. That is, $t$ (identified by its hash root)
is added to the list of known propositions.
\end{itemize}
\end{itemize}

