Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 48 additions & 36 deletions src/Proven/SafeNetwork/Proofs.idr
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,35 @@ public export
portAlwaysValid : (p : Port) -> ValidPort p
portAlwaysValid p = MkValidPort p

-- | mkPort succeeds for values <= 65535.
-- | Postulated: mkPort uses a runtime Bool check (`n <= 65535`), and the
-- | connection between the runtime `<=` and the type-level `LTE` requires
-- | showing that `(n <= 65535) = True` implies `checkPort n = Just ItIsPort`,
-- | which involves the opaque primitive Nat comparison.
-- TODO: Update for Idris2 0.8.0 -- prove via decidability of Nat comparison.
export
mkPortSucceeds : (n : Nat) -> LTE n 65535 -> IsJust (mkPort n)
||| OWED: `mkPort n` returns `Just _` whenever `n <= 65535`. Held back
||| by Idris2 0.8.0 not bridging the runtime `Bool` test
||| `n <= 65535 = True` (used by `checkPort`) to the type-level `LTE n
||| 65535` witness: `mkPort` branches on `checkPort n`, which evaluates
||| the opaque primitive Nat `<=`, so `IsJust (mkPort n)` does not
||| reduce by Refl from an `LTE` premise. Discharge once a Nat
||| decidability bridge (`lteReflectsLTE : (n <= m) = True -> LTE n m`)
||| is exposed by `Data.Nat`, or `mkPort` is refactored to take the
||| `LTE` proof directly.
public export
0 mkPortSucceeds : (n : Nat) -> LTE n 65535 -> IsJust (mkPort n)

-- | Network address is always contained in its own CIDR.
-- | Postulated: `contains` does not reduce on abstract `CIDRBlock` in
-- | Idris 2 0.8.0 because it involves runtime Nat comparisons
-- | (`ipToNat ... >= ipToNat ...`) that are opaque at the type level.
-- TODO: Update for Idris2 0.8.0 -- prove via ipToNat monotonicity lemmas.
export
networkInOwnCIDR : (cidr : CIDRBlock) -> contains cidr (networkAddress cidr) = True
||| OWED: every CIDR block contains its own network address. Held back
||| by Idris2 0.8.0 not reducing `contains` on an abstract `CIDRBlock`:
||| `contains` is defined via `ipToNat ... >= ipToNat ...`, and those
||| primitive Nat `>=` comparisons stay opaque at the type level when
||| the `CIDRBlock` is a free variable rather than a concrete literal.
||| Discharge once `ipToNat` monotonicity lemmas are proven and a
||| reflective bridge from primitive `>=` to `GTE` is available.
public export
0 networkInOwnCIDR : (cidr : CIDRBlock) -> contains cidr (networkAddress cidr) = True

-- | Broadcast address is always contained in its own CIDR.
-- | Postulated for same reason as networkInOwnCIDR.
-- TODO: Update for Idris2 0.8.0 -- prove via ipToNat monotonicity lemmas.
export
broadcastInOwnCIDR : (cidr : CIDRBlock) -> contains cidr (broadcastAddress cidr) = True
||| OWED: every CIDR block contains its own broadcast address. Same
||| blocker family as `networkInOwnCIDR` — `contains` does not reduce
||| on an abstract `CIDRBlock` argument because of opaque primitive
||| Nat `>=`. Discharge once `ipToNat` monotonicity + a `>=`-to-`GTE`
||| reflective bridge are in place.
public export
0 broadcastInOwnCIDR : (cidr : CIDRBlock) -> contains cidr (broadcastAddress cidr) = True

||| CIDR subset transitivity: if A is a subset of B and B is a subset of C then A is a subset of C
||| This follows from the transitivity of the containment relation
Expand All @@ -59,23 +66,28 @@ data SubsetTransitive : CIDRBlock -> CIDRBlock -> CIDRBlock -> Type where
isSubsetOf b c = True ->
SubsetTransitive a b c

-- | System ports are always < 1024.
-- | Postulated: requires connecting the runtime Bool classification
-- | (`isSystemPort`) with the type-level `LTE` relation, which involves
-- | the opaque Nat comparison primitives.
-- TODO: Update for Idris2 0.8.0 -- prove via decidability of Nat comparison.
export
systemPortBound : (p : Port) -> isSystemPort p = True -> LTE (portValue p) 1023
||| OWED: a port classified as a system port has value `<= 1023`.
||| Held back by Idris2 0.8.0's Bool-to-LTE bridge: `isSystemPort` is a
||| runtime classification that pattern-matches on the result of
||| `classify`, and the `True` outcome does not type-level reduce to a
||| `LTE` witness without an opaque primitive Nat comparison.
||| Discharge once `classify` is reformulated to return a dependent
||| witness (e.g. `(c : Class ** ClassifiedAs p c)`) carrying the
||| `LTE` proof, or once a primitive-Nat reflective bridge lands.
public export
0 systemPortBound : (p : Port) -> isSystemPort p = True -> LTE (portValue p) 1023

-- | Every port value is <= 65535.
-- | Postulated: Port construction now uses a runtime bounds check via
-- | `checkPort` with an erased `IsPort` witness, rather than a
-- | constructive `LTE n 65535` proof. The bound holds by the runtime
-- | check in mkPort/unsafeMkPort.
-- TODO: Update for Idris2 0.8.0 -- either restore LTE proof with
-- efficient representation, or prove from IsPort witness semantics.
export
portBounded : (p : Port) -> LTE (portValue p) 65535
||| OWED: every well-typed `Port` has `portValue p <= 65535`. Held
||| back by the move to runtime bounds checking: `mkPort` / `unsafeMkPort`
||| now carry an erased `IsPort` witness (`data IsPort : Nat -> Type
||| where ItIsPort : IsPort n`) rather than a constructive `LTE n
||| 65535` proof, so the bound is enforced dynamically by `checkPort`
||| but not recoverable at the type level by Refl. Discharge once
||| `IsPort` is refined to a non-trivial witness carrying the `LTE`
||| (i.e. `IsPort n := LTE n 65535`), or `Port` is rebuilt to store
||| the `LTE` proof directly.
public export
0 portBounded : (p : Port) -> LTE (portValue p) 65535

||| Proof that host count is positive for prefix < 32
public export
Expand Down