Deep Embedding Packages #
This file defines packages for the deep embedding of CatCrypt computations.
Main definitions #
DeepInterface- Specifies operation signatures (id, domain, codomain)ValidCode- Code that only uses declared locationsDeepPackage- A package with location support and interface specificationsDeepPackage.link- Sequential composition of packagesDeepPackage.par- Parallel composition of packagesDeepPackage.sep- Separation predicate (disjoint locations)
Nominal Structure #
Packages support nominal operations for automatic state separation:
NomPackage.atoms- Get the atoms used by a packageNomPackage.atomSep- Separation based on disjoint atomsNomPackage.sep_of_atomSep- Atom separation implies location separation
Overview #
In the deep embedding, packages represent cryptographic protocol implementations with explicit state management. Each package:
- Has a finite set of locations (memory cells) it uses
- Imports operations from other packages
- Exports operations it implements
- Contains code implementations for exported operations
Separation reasoning can be based on either:
- Location id disjointness (DeepPackage.sep)
- Atom disjointness (NomPackage.atomSep) for nominal reasoning
References #
- Larsen and Schürmann, Nominal State-Separating Proofs
- SSProve Rocq:
theories/Crypt/nominal/Nominal.v,free_code.v
Interfaces #
An interface specifies the signature of operations.
Each operation has an id (for identification), a domain type, and a codomain type.
All types are at the same universe u, matching RawCode.oracleCall.
Example: A PRF interface might have:
- Operation 0: Unit → BitVec 128 (key generation)
- Operation 1: BitVec 128 → BitVec 128 (evaluation)
The operations in this interface. Each entry is (operation_id, domain_type, codomain_type).
Instances For
The empty interface with no operations
Instances For
Equations
- CatCrypt.Deep.DeepInterface.instEmptyCollection = { emptyCollection := CatCrypt.Deep.DeepInterface.empty }
Equations
Two interfaces are equal if they have the same operations
Valid Code (Inductive Definition) #
Following Rocq SSProve, we define validity inductively. This approach:
- Avoids the problem of computing continuation locations for bind
- Makes HEq proofs trivial via proof irrelevance
- Matches the Rocq implementation exactly
Valid code uses only locations from a declared set.
Defined inductively following Rocq SSProve's valid_code.
Each constructor checks that location accesses are within the declared set L.
Note: We use LocSet (= Finset Nat) for location id sets.
- ret {L : Core.LocSet} {α : Type u} (x : α) : ValidCode L α (RawCode.ret x)
- bind {L : Core.LocSet} {α β : Type u} (c : RawCode α) (k : α → RawCode β) : ValidCode L α c → (∀ (a : α), ValidCode L β (k a)) → ValidCode L β (c.bind k)
- sample {L : Core.LocSet} (T : Type u) [Fintype T] [Nonempty T] : ValidCode L T (RawCode.sample T)
- get {L : Core.LocSet} (ℓ : Core.Location) : ℓ.id ∈ L → ValidCode L (ULift.{u, 0} ℓ.ty) (RawCode.get ℓ)
- put {L : Core.LocSet} (ℓ : Core.Location) (v : ℓ.ty) : ℓ.id ∈ L → ValidCode L (ULift.{u, 0} Unit) (RawCode.put ℓ v)
- fail {L : Core.LocSet} {α : Type u} : ValidCode L α RawCode.fail
- oracleCall {L : Core.LocSet} (op : ℕ) (dom codom : Type u) (x : dom) : ValidCode L codom (RawCode.oracleCall op dom codom x)
- embed {L : Core.LocSet} {α : Type u} (c : Core.SPComp α) : ValidCode L α (RawCode.embed c)
Instances For
Monotonicity: if code is valid for L and L ⊆ L', then code is valid for L'.
A valid code bundle: code together with its validity proof. This is the structure used in packages.
- code : RawCode α
Instances For
Type Class for Automatic Validity Proofs #
The IsValid type class provides automatic synthesis of ValidCode proofs.
This hybrid approach gives the best of both worlds:
- RawCode remains a simple free monad without validity constraints
- ValidCode proofs are synthesized automatically via type class inference
- Manual proofs are still possible when needed
ret x is always valid.
sample T is always valid.
get ℓ is valid if ℓ.id ∈ L.
Uses Fact (ℓ.id ∈ L) to allow instance synthesis when membership is decidable.
put ℓ v is valid if ℓ.id ∈ L.
Uses Fact (ℓ.id ∈ L) to allow instance synthesis when membership is decidable.
fail is always valid.
oracleCall is always valid (no location access).
embed c is always valid: an embedded shallow computation reads no declared
location syntactically, so it is valid for every location set. This is the
missing companion to the other IsValid instances and is what lets a reified
opaque/abstract subterm carry an automatic validity proof.
Convert an IsValid instance to a ValidCode proof.
Create a ValidCodeBundle automatically using type class synthesis.
Equations
- CatCrypt.Deep.ValidCodeBundle.auto c = { code := c, valid := ⋯ }
Instances For
Monotonicity: if code bundle is valid for L, we can extend to any superset L'.
Equations
- CatCrypt.Deep.ValidCodeBundle.mono h_sub vc = { code := vc.code, valid := ⋯ }
Instances For
Two ValidCodeBundles with the same location set and code are equal (proof irrelevance).
Oracle Substitution Validity #
When we substitute oracle calls with valid code, the result is valid.
Substituting oracle calls with valid code preserves validity.
If c is valid for locations L₁ and every oracle call's replacement
is valid for locations L₂, then c.substOracle env is valid for L₁ ∪ L₂.
This is needed for DeepPackage.link: p₁'s code is valid for p₁.locs,
and p₂'s implementations are valid for p₂.locs, so the linked code
is valid for p₁.locs ∪ p₂.locs.
Deep Packages #
A package bundles code implementations with interface specifications.
A package consists of:
- A finite set of location ids (state) it uses
- An import interface (operations it calls)
- An export interface (operations it implements)
- Code implementations for each exported operation
The key invariant is that implementations only use declared locations, enabling modular composition and separation reasoning.
- locs : Core.LocSet
The finite set of location ids used by this package
- imports : DeepInterface
Operations this package imports (calls from other packages)
- exports : DeepInterface
Operations this package exports (implements)
- impl (op : ℕ) (dom codom : Type u) : (op, dom, codom) ∈ self.exports.ops → dom → ValidCodeBundle self.locs codom
Implementation of exported operations. For each operation in the export interface, we provide code (bundled with validity proof) that maps domain values to a computation producing codomain values. All types are at universe
u, matchingRawCode.oracleCallandsubstOracle.
Instances For
Basic operations #
Empty package with no locations, no imports, no exports
Equations
Instances For
Equations
- CatCrypt.Deep.DeepPackage.instEmptyCollection = { emptyCollection := CatCrypt.Deep.DeepPackage.empty }
Equations
Separation #
Two packages are separated if their location ids are disjoint.
This is the key property for modular reasoning: separated packages cannot interfere with each other's state.
Instances For
Package Composition #
Sequential composition (linking) of packages.
link p₁ p₂ connects p₂'s exported operations to p₁'s imports.
The resulting package:
- Uses locations from both packages
- Imports p₂'s imports (operations not provided by p₂)
- Exports p₁'s exports
- Implementations from p₁, with oracle calls resolved via
substOracle
Oracle calls in p₁'s code are resolved as follows:
- If the called operation is in p₂'s exports, the call is replaced with p₂'s implementation (extended to the union of locations)
- If not, the oracle call is left as-is (evaluates to failure or is resolved by further linking)
Equations
- One or more equations did not get rendered due to their size.
Instances For
Link a specific operation's code with an oracle environment.
Given code c at universe u and an oracle environment env that
provides implementations for oracle calls, this produces linked code
where oracle calls are substituted with implementations.
This is a lower-level building block than link. Use it when you need
custom oracle environments rather than linking two packages.
Equations
- CatCrypt.Deep.DeepPackage.linkCode vc env henv = { code := vc.code.substOracle env, valid := ⋯ }
Instances For
Parallel composition of packages with disjoint locations.
par p₁ p₂ sep_proof combines two packages that don't share state.
The resulting package:
- Uses locations from both packages (guaranteed disjoint)
- Imports operations from both packages
- Exports operations from both packages
- Implementations from both packages (extended to the larger location set)
The separation proof ensures no interference between packages.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Par Implementation Characterization #
When the operation is in p₁'s exports, par dispatches to p₁'s implementation. The code is the same (mono only affects the validity proof, not the code).
When the operation is NOT in p₁'s exports, par dispatches to p₂'s implementation.
Properties #
Separation is preserved by parallel composition
Separation is preserved by parallel composition (right)
Parallel composition is commutative up to reordering
Identity Package #
The identity (passthrough) package for an interface. It forwards all operations
from its exports to its imports by making oracle calls. This is the unit of
linking: link p (id p.imports) = p and link (id p.exports) p = p
(up to evaluation equivalence).
The identity package for an interface: forwards every operation to the oracle.
For each operation in the interface, the implementation is simply an oracle call, i.e., it passes the request through unchanged. This package has no locations (no state of its own).
This is the monoidal unit for link:
link p (id p.imports)is evaluation-equivalent toplink (id p.exports) pis evaluation-equivalent top
Equations
- One or more equations did not get rendered due to their size.
Instances For
Linking Properties #
The oracle environment built by link from a package p₂.
This extracts the oracle substitution function from link's definition
for use in compositional reasoning. For each operation:
Equations
Instances For
Linking with the identity package on the right preserves the code of each exported operation (up to oracle calls becoming identity).
Specifically, for any operation in p.exports, the linked code
(link p (id p.imports)).impl op dom codom h x has the same
substOracle structure: oracle calls not in p.imports become fail,
oracle calls in p.imports remain as oracle calls.
At the evaluation level, this means link p (id p.imports) behaves
the same as p (since unlinked oracle calls evaluate to fail anyway).
Nominal Packages #
NomPackage wraps DeepPackage with a location registry, enabling
atom-based separation reasoning.
Nominal package: DeepPackage with an associated location registry. This enables nominal reasoning (atom-based separation) while maintaining compatibility with evaluation.
The key invariant locs_eq ensures that the location set is exactly
the image of atoms under the registry mapping. This enables proving
that atom separation implies location separation.
- pkg : DeepPackage
The underlying DeepPackage
- registry : LocRegistry
The registry mapping atoms to Core.Location ids
- usedAtoms : Finset Nominal.Atom
The atoms used by this package
Invariant: locs is exactly the image of atoms under atomToId
Instances For
Get the location ids used by the package
Instances For
Get the atoms used by the package
Instances For
Empty nominal package
Equations
Instances For
Equations
- CatCrypt.Deep.NomPackage.instEmptyCollection = { emptyCollection := CatCrypt.Deep.NomPackage.empty }
Equations
Two packages are atom-separated if their atoms are disjoint. This is the key property for nominal modular reasoning.
Instances For
If packages are atom-separated with the same registry, they are location-separated. This follows from the locs_eq invariant and injectivity of the registry.
Parallel composition of nominal packages. Requires atom separation and the same registry.
Equations
Instances For
Sequential composition (linking) of nominal packages.
link p₁ p₂ connects p₂'s exports to p₁'s imports.
The resulting package uses atoms from both packages.
Equations
Instances For
Documentation #
This implementation provides the core package structure for the deep embedding. Key completed features:
- DeepInterface: Operation signatures with (id, domain, codomain)
- ValidCode: Code restricted to declared locations
- DeepPackage: Packages with location sets and interface specifications
- Composition:
link(sequential) andpar(parallel) operations - Separation: The
seppredicate for disjoint location reasoning
Nominal Extension #
The NomPackage type adds nominal structure:
NomPackage.atoms- Atoms used by the packageNomPackage.atomSep- Atom-based separationNomPackage.sep_of_atomSep- Atom separation implies location separation