Envelope

Difficulty: moderate — 3 definitions, 1 abbreviations, 1 lemmas, 3 theorems.

definition abbreviation lemma theorem
legend

An envelope wraps up a payload together with a check value, computed by a cyclic redundancy check (CRC), that lets a receiver tell whether the payload arrived corrupted. Its payload and check are made of Bits (see Information), not Bools: each one stands for an actual observation, so it genuinely carries information.

A short list of bits (a “check”) computed from a longer list of bits (bits), following a fixed rule (poly) that stays the same for every envelope. Two different inputs almost never produce the same check; in particular, changing even a single bit of bits always changes it (see crc_detects_single_bit_flip below) — that’s what makes it useful for catching corruption.

def crc (poly : List Bool) (bits : List Bool) : List Bool :=
  let k := poly.length
  bits.foldl
    (fun reg bit =>
      let top := reg.headD false
      let shifted := reg.tail ++ [bit]
      if top then List.zipWith xor shifted poly else shifted)
    (List.replicate k false)

Outer dependencies: (none)

An envelope: a payload of n bits, plus a k-bit CRC check computed from it under generator poly.

structure Envelope (poly : List Bool) (n k : Nat) where
  payload : Fin n  Bit
  check : Fin k  Bit

Outer dependencies: (none)

Inner dependencies: Bit

Lean core dependencies: Bool, Eq, Fin, HEq, List, Nat, eq_of_heq

instance {poly : List Bool} {n k : Nat} : Nonempty (Envelope poly n k) :=

Outer dependencies: Envelope

Inner dependencies: Bit

Lean core dependencies: Bool, Fin, List, Nat, Nonempty, inferInstance

instance {poly : List Bool} {n k : Nat} : Norm (Envelope poly n k) where
  norm e := e.payload + e.check

Outer dependencies: Envelope

Mathlib dependencies: Norm, Real

Lean core dependencies: Bool, Fin, List, Nat

Build an envelope from a payload, filling in its check value via crc.

def Envelope.make (poly : List Bool) (n : Nat) (payload : Fin n  Bit) :
    Envelope poly n poly.length :=
  { payload
    check := fun i => (crc poly (List.ofFn (fun j => (payload j : Bool))))[(i : Nat)]?.getD false }

Outer dependencies: Bit, Envelope

Inner dependencies: crc

Lean core dependencies: Bool, Fin, List, List.length, List.ofFn, Nat, Option.getD

An envelope is valid exactly when its check value matches what crc recomputes from its payload — a receiver holding a corrupted envelope can tell, as long as the corruption actually changes the check (see crc_detects_single_bit_flip below).

abbrev Envelope.valid (poly : List Bool) {n : Nat} (e : Envelope poly n poly.length) : Prop :=
   i, e.check i = (crc poly (List.ofFn (fun j => (e.payload j : Bool))))[(i : Nat)]?.getD false

Outer dependencies: Envelope

Inner dependencies: Bit, crc

Lean core dependencies: Bool, Eq, Fin, List, List.length, List.ofFn, Nat, Option.getD

An envelope built by Envelope.make is always valid: the check is computed directly from the payload it accompanies, no corruption possible before it’s even sent.

theorem Envelope.make_valid (poly : List Bool) (n : Nat) (payload : Fin n  Bit) :
    Envelope.valid poly (Envelope.make poly n payload) := by

Dependencies: Bit, Envelope.make, Envelope.valid

Lean core dependencies: Bool, Fin, Lean.Name, List, Nat

Used by: (none)

The main point of a CRC: flipping exactly one bit of the payload changes the check value it should have, for any nonzero generator polynomial — so a receiver comparing the check it got against the check it recomputes will notice a single-bit corruption.

theorem crc_detects_single_bit_flip (poly : List Bool) (hpoly : poly.any id)
    (bits : List Bool) (i : Fin bits.length) :
    crc poly (bits.set i (!bits[i]))  crc poly bits := by

Dependencies: crc

Used by: (none)

Dependency diagram

Drag to pan, Ctrl+scroll (or Cmd+scroll) to zoom, click a node to jump to it.

definitionabbreviationlemmatheoremdeclared elsewheredependencyproof dependency
legend