Theorems about Bytes.* primitives #
The runtime side of every primitive is its C function in bytes_ffi.c,
but the Lean body is the spec: each @[extern]-tagged declaration
has a definitional unfolding that the kernel can reduce. The theorems
below establish the basic algebraic laws over those specs:
- Tier 1 — size preservation, OOB-noop, and store/load roundtrip for every width × endianness.
- Tier 2 — pointwise characterizations of
copy/filland reflection lemmas forequal/compare. - Tier 3 — endianness symmetry:
loadUNBE = (loadUNLE).byteSwapand the corresponding store laws.
Together these let you reason about Lean code that uses the
primitives without having to unfold the cascaded set!s by hand.
This file is opt-in: import Bytes gets only the runtime API;
import Bytes.Theorems brings the theorems in too.
Axiom footprint #
In addition to the three standard axioms (propext, Quot.sound,
Classical.choice), the bit-shuffling roundtrip and endianness
theorems use bv_decide, which emits per-call
_native.bv_decide.ax_* axioms backed by an externally-verified LRAT
proof certificate. These are the standard cost of mechanised
bit-vector reasoning and are accepted upstream.
Helpers on ByteArray #
Stdlib's ByteArray.set! lacks the standard bang-version simp lemmas
(stdlib's set/get lemmas are stated for Array.setIfInBounds/
getElem). The three lemmas below bridge them to ByteArray.set!
and ByteArray.get!. They are local helpers — sound and reusable,
but not the headline API.
extract / append algebra (the get!-flavour lemmas Std skips) #
Stdlib proves the corresponding [i]-flavour facts (getElem_append_left,
extract_append, extract_extract, …), but production code that uses
get!/extract directly needs the bang-version bridges below. The clamp
specialisation extract_eq_extract_size_of_size_le and its append corollary
extract_append_size_of_le close the gap: Std proves the clamp only for
Array (extract_of_size_lt / extract_eq_self_of_le); the ByteArray
version was missing.
Clamp+append fusion: when the start lies in the prefix, extracting through the end of the appended pair gives the prefix tail concatenated with the entire suffix.
Tier 1 — size preservation #
Stores never resize their argument. Trivial via the helper above plus
the fact that the if-branches return data.set!-cascades or data
itself.
Tier 1 — OOB no-op #
When the requested write would fall (partly) outside the buffer, the
store returns data unchanged.
Tier 1 — store/load roundtrip #
Writing a value with storeUNXX and immediately reading it back with
loadUNXX returns the original value, provided the write fits in the
buffer. The single-byte case is direct; the multi-byte cases reduce
to a chain of get!_set!_self/get!_set!_ne and a final bit-vector
identity (bv_decide).
Tier 2 — bulk op invariant helper #
Nat.fold n f init is the spec primitive used by copy, fill,
equal, and compare. Most of the bulk-op lemmas reduce to "this
property is preserved by every step", so we prove that pattern once.
Tier 2 — copy and fill size preservation #
Tier 2 — copy/fill/equal/compare OOB no-op #
Tier 2 — equal/compare reflexivity #
equal a off a off len is true and compare a off a off len is
.eq, provided the range fits. The fold accumulator is invariant: at
every step both sides agree.
Tier 2 — copy / fill pointwise characterizations #
Both copy and fill reduce to a Nat.fold of set! calls at
distinct offsets, so we can characterize the result byte-by-byte:
inside the written window the value is what was written, outside it
the buffer is untouched. The two private fold helpers below capture
the inductive content; the headline _get_in_range / _get_out_range
theorems specialize to fill and copy.
Tier 3 — endianness symmetry #
loadUNBE reads the same bytes as loadUNLE but with the bytes
reversed. We package that observation as loadUNBE = byteSwapN (loadUNLE) (and dually for stores). The byte-swap helpers below are
proof-side conveniences; the runtime never calls them.
16-bit byte swap: high byte ↔ low byte.
Equations
- Bytes.byteSwap16 x = x <<< 8 ||| x >>> 8
Instances For
64-bit byte swap: reverses the eight bytes.
Equations
- One or more equations did not get rendered due to their size.