Invariants for Relational Reasoning #
This file defines invariants - predicates on heap pairs that are preserved by package operations. Invariants are central to proving perfect indistinguishability.
Main definitions #
IsInvariant- A class for valid invariants on location pairsheapEq- The simplest invariant: heap equalitytrueInv- The trivial invariant that always holds
Usage #
When relating two packages up to an invariant, we choose an invariant and prove that all operations preserve it while establishing equal behavior.
References #
- Larsen and Schürmann, Nominal State-Separating Proofs
- SSProve: theories/Crypt/package/pkg_invariants.v
Invariant Class #
An invariant is a precondition that is well-formed with respect to location sets. It only talks about locations in L₀ (for the left heap) and L₁ (for the right heap).
The key property is that the invariant should be:
- Preserved by operations that only access the declared locations
- Restorable after writes to declared locations
The invariant only depends on locations in L₀ for the left heap
The invariant only depends on locations in L₁ for the right heap
Instances
Standard Invariants #
Heap equality invariant: the heaps are equal
Instances For
Note on heapEq and IsInvariant #
Heap equality (heapEq) is not a proper invariant for the locality framework.
The IsInvariant class requires that if heaps agree on L₀/L₁, then the
invariant is preserved. But heapEq requires complete heap equality,
not just equality on specific locations.
For empty location sets, the locality hypothesis ∀ l ∈ ∅, ... is vacuously
true, giving us no information about the relationship between h₀ and h₀'.
We cannot prove h₀' = h₀ from this.
Design Decision: We intentionally do NOT provide an IsInvariant instance
for heapEq with empty location sets. Users should use:
trueInvfor cases where no invariant is needed- Location-specific invariants like
syncsAtfor tracking equality at specific locations
In the original CatCrypt/Rocq, the heap-equality case is handled specially,
outside the locality framework.
For Lean 4, we follow the same pattern: use rHoare_eq (defined in Rules.lean) for
the heap equality case directly, bypassing the IsInvariant machinery.
True invariant: always holds (used when location sets are empty)
Instances For
Invariant Combinators #
Conjunction of invariants
Instances For
Conjunction of invariants is an invariant.
The mathematical proof is straightforward: if hloc : ∀ l ∈ L₀, h₀.get l = h₀'.get l
and both inv₁ and inv₂ are invariants for L₀, L₁, then both left_local properties
apply with the same hloc.
Note: Earlier versions of this codebase had universe polymorphism issues here. These were resolved by fixing Location.ty to Type (Type 0) in Core/Location.lean.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Invariant Operations #
Setting a location on both sides preserves the invariant when the location is outside both L₀ and L₁.
This is because the invariant only depends on locations in L₀/L₁, so writes outside these sets don't affect the invariant.
Mathematical proof:
- For any
l' ∈ L₀, we havel'.id ≠ l.id(sincel ∉ L₀meansl.id ∉ L₀.ids) - Therefore
(h₀.set l v).get l' = h₀.get l'(byget_set_other) - Apply
left_localwith this agreement to getinv (h₀.set l v) h₁ - Similarly, apply
right_localto getinv (h₀.set l v) (h₁.set l v)
Note: Earlier versions of this codebase had universe polymorphism issues here. These were resolved by fixing Location.ty to Type (Type 0) in Core/Location.lean.
Special Invariants for Games #
Invariant for equal initial state: heaps are equal