LOW-RESOURCE COMPUTE

Perfect Uniformity
at the Edge.

Standard edge processors rely on Linear Feedback Shift Registers (LFSRs) for entropy, creating "Blind Spots" in optimization tasks. Drift Systems delivers CPU-Grade Uniformity (0.999) using ~580 LUT on Tang Primer 20K (DAD core, hardware-validated).


RUN ANALYSIS READ WHITEPAPER

1. The Uniformity Gap

The Test: We generate 10,000 random integers into 20 buckets.
An ideal solver (like a CPU Mersenne Twister) fills all buckets evenly. Hardware LFSRs fail to cover the space. Drift achieves perfect coverage.

Standard HW (LFSR) ---

IDEAL UNIFORMITY
DISTRIBUTION BUCKETS (0-20)

Drift Core (FPGA) ---

IDEAL UNIFORMITY
DISTRIBUTION BUCKETS (0-20)

2. Why Uniformity Matters

The "Blind Spot" Problem

When an optimization solver (like Annealing or Genetic Algorithms) uses a biased RNG, it literally "cannot see" 20-30% of the potential solutions. This leads to sub-optimal routing and wasted energy.

The Drift Solution

The Drift Core's recurrence is built on the $3n+1$ map; its transition logic is a formally verified complete covering of $\mathbb{Z}$ (see coverage.html), and the carry-propagation structure is bounded by a finite-state automaton (see § 3 below). The empirical output distribution is approximately uniform across the state space, which lets sub-$2 IoT silicon drive optimization workloads that previously required desktop-class RNGs. Dynamical-systems ergodicity (in the measure-preserving sense) is a separate research-level question and is not claimed here.


3. Formal Verification: Carry-Propagation Structure

The Drift Core's adder behavior is formally verified at two levels in Lean 4: the bit-level full-adder carry bound (below), and the block-level carry transducer that bounds the FSM state space (further below). Together they establish that the core's carry chain is governed by a finite automaton with bounded state — not just at the bit level, but as a complete structural FSM.

3.1 — Bit-Level Carry Bound (CarryUniformity.lean)

-- File: CarryUniformity.lean
-- Verified: Dec 17, 2025 (Lean 4.3.0)
-- Purpose: Proves the Drift Core carry propagation is bounded ≤ 2.

import Mathlib.Data.Nat.Basic
import Mathlib.Tactic.Linarith 

namespace DriftCore

-- 1. The Arithmetic Model (Full Adder Relation)
def carry_next (n_k : â„•) (n_prev : â„•) (c_k : â„•) : â„• :=
  (n_k + n_prev + c_k) / 2

-- 2. Theorem 1: Bounded Carry Guarantee
-- Proves that for any valid bitstream, the carry never exceeds 2.
theorem carry_is_bounded (n_k n_prev c_k : â„•)
  (h_n_k : n_k ≤ 1)       -- Input Bit
  (h_n_prev : n_prev ≤ 1) -- Previous Bit
  (h_c_k : c_k ≤ 2)       -- Carry Constraint
  : carry_next n_k n_prev c_k ≤ 2 := by
  
  unfold carry_next
  -- Max numerator: 1 + 1 + 2 = 4
  have h_sum : n_k + n_prev + c_k ≤ 4 := by linarith
  
  -- Division property: 4 / 2 = 2
  have h_div : (n_k + n_prev + c_k) / 2 ≤ 2 := by
    apply Nat.div_le_of_le_mul
    linarith
    
  exact h_div

end DriftCore

3.2 — Block-Level Carry Transducer (CarryTransducer.lean & CarryGraph.lean)

Beyond the bit-level bound, the core's carry chain is modeled as a block-level transducer: a finite-state machine where state is the carry value and transitions are determined by the input block. Two theorems together pin down the entire FSM state space.

-- File: CarryTransducer.lean
-- Block-level carry transducer for the ×p map; carry stays bounded in {0..p-1}.

namespace ABCFormalization

/-- The combined value when the ×p transducer processes input block `x`
    with incoming carry `c`: val = p · x + c. -/
def mulBlockVal (p c x : â„•) : â„• := p * x + c

/-- Output block: the low K bits of val. -/
def mulBlockOut (p c x K : â„•) : â„• := mulBlockVal p c x % 2 ^ K

/-- Carry-out: the high bits of val. -/
def mulBlockCarry (p c x K : â„•) : â„• := mulBlockVal p c x / 2 ^ K

/-- **Carry stays bounded**: if the input block is < 2^K and carry < p,
    then the output carry is also < p. The FSM state space is exactly {0..p-1}. -/
theorem mulBlockCarry_lt (p c x K : â„•) (hx : x < 2 ^ K) (hc : c < p) :
    mulBlockCarry p c x K < p := by
  simp only [mulBlockCarry, mulBlockVal]
  rw [Nat.div_lt_iff_lt_mul (show 0 < 2 ^ K from by positivity)]
  calc p * x + c
      < p * x + p := by omega
    _ = p * (x + 1) := by ring
    _ ≤ p * 2 ^ K := Nat.mul_le_mul_left p (by omega)

/-- **Transducer Correctness**: after processing J blocks, the assembled
    output plus carry · 2^(J·K) equals p · (n mod 2^(J·K)).
    The transducer is a faithful implementation of multiplication by p. -/
theorem transducer_correct (p n K : â„•) :
    ∀ J, blockAssembled p n K J + blockCarry p n K J * 2 ^ (J * K) =
      p * (n % 2 ^ (J * K)) := by
  -- [induction body omitted in display; full proof in source file]
  -- proof continued; see file

end ABCFormalization

-- File: CarryGraph.lean
-- Global FSM state-space bound: carry never exceeds p at any block position.

namespace ABCFormalization

/-- Every K-bit extracted block is strictly less than 2^K. -/
theorem extractBlock_lt_pow (n lo K : â„•) : extractBlock n lo K < 2 ^ K :=
  Nat.mod_lt _ (by positivity)

/-- **The carry at every block position stays strictly below p**.
    This is the global FSM-state-space bound: across the entire
    computation, the carry FSM occupies exactly p reachable states. -/
theorem blockCarry_lt (p n K : â„•) (hp : 1 < p) :
    ∀ j, blockCarry p n K j < p := by
  intro j
  induction j with
  | zero => simp [blockCarry]; omega
  | succ j ih =>
    simp only [blockCarry]
    exact mulBlockCarry_lt p _ _ K (extractBlock_lt_pow n (j * K) K) ih

/-- **Fuel Consumption Lemma**: a zero output from nonzero carry forces
    nonzero input. The "expensive zero" classification is what enables
    the global popcount lower bound. -/
theorem expensive_zero_has_nonzero_input (p n K j : â„•)
    (hp : 1 < p) (hpK : p ≤ 2 ^ K) :
    blockOutput p n K j = 0 → 0 < blockCarry p n K j →
    0 < extractBlock n (j * K) K := by
  -- [proof in source file; uses nonzero_input_of_zero_output]
  -- proof continued; see file

end ABCFormalization

Lines marked -- proof continued; see file elide proof bodies for display brevity; the full closed proofs are in formal_verification/ABCFormalization/CarryTransducer.lean and formal_verification/ABCFormalization/CarryGraph.lean. Together they establish the carry FSM has a bounded, fully-characterized state space — an implementation-safety result with no sorry and no axioms beyond Mathlib's standard library.

3.3 — Fold-Step Correctness (Fold.lean)

After the affine step qS + d, the production core folds the wide arithmetic state down to the output width by XOR-ing the high half with the low half. In silicon (dad_core.v, W = 64): folded_bits = next_state[63:0] ^ next_state[127:64]. This section proves the fold is *structurally bounded*: a 2W-bit input always yields a W-bit output, with no overflow into a wider wire.

-- File: Fold.lean
-- Verified against Mathlib (Lean 4.26); no `sorry`, no axioms.

import Mathlib.Data.Nat.Bitwise
import Mathlib.Tactic

namespace DriftCore

/-- Fold: XOR the high W bits of x with its low W bits. Matches the RTL
    line `folded = x[W-1:0] ^ x[2W-1:W]` exactly (with W = 64). -/
def fold (W x : â„•) : â„• :=
  (x &&& (2 ^ W - 1)) ^^^ (x >>> W)

/-- A 2W-bit value, right-shifted by W, fits in W bits. -/
lemma shiftRight_lt_two_pow {W x : â„•} (hx : x < 2 ^ (2 * W)) :
    x >>> W < 2 ^ W := by
  rw [Nat.shiftRight_eq_div_pow]
  have hpow : (2 : â„•) ^ (2 * W) = 2 ^ W * 2 ^ W := by rw [two_mul, pow_add]
  rw [hpow] at hx
  exact Nat.div_lt_of_lt_mul hx

/-- **Width invariant.** A 2W-bit input folds to a W-bit output.
    Structurally certifies the output stage cannot overflow its wire. -/
theorem fold_width_invariant {W x : â„•} (hx : x < 2 ^ (2 * W)) :
    fold W x < 2 ^ W := by
  unfold fold
  exact Nat.xor_lt_two_pow
    (Nat.and_lt_two_pow x (Nat.sub_lt (Nat.two_pow_pos W) Nat.one_pos))
    (shiftRight_lt_two_pow hx)

/-- Strongly-typed wrapper: a 2W-bit `Fin` folds to a W-bit `Fin`. -/
def Fold (W : â„•) (x : Fin (2 ^ (2 * W))) : Fin (2 ^ W) :=
  ⟨fold W x.val, fold_width_invariant x.isLt⟩

/-- **RTL equivalence.** The fold equals XOR-ing x with its right-shift,
    then truncating to W bits — the form synthesis emits when the fold
    is written as a single XOR over the full word. -/
theorem fold_eq_truncate_xor {W x : â„•} (hx : x < 2 ^ (2 * W)) :
    fold W x = (x ^^^ (x >>> W)) &&& (2 ^ W - 1) := by
  unfold fold
  rw [Nat.and_xor_distrib_right,
      Nat.and_two_pow_sub_one_of_lt_two_pow (shiftRight_lt_two_pow hx)]

/-- Production instantiation: W = 64, matching `dad_core.v`. -/
abbrev FoldProd : Fin (2 ^ (2 * 64)) → Fin (2 ^ 64) := Fold 64

end DriftCore

The full file is at formal_verification/Fold.lean and builds against stock Mathlib with no sorry, no axiom. Together with § 3.1 (carry bound) and § 3.2 (carry FSM), this completes the structural-correctness chain for the output stage of the production recurrence.

3.4 — Determinism of the Iterated Recurrence (DriftRecurrence.lean)

One step of the production recurrence on a W-bit state is state' = ((3·state + 1) mod 2^W) / 2. Because driftStep is defined as a function from Fin (2^W) to itself, its iteration is the canonical fixed point of a deterministic dynamical system on a finite state space. The two-FPGA bit-for-bit lockstep observed empirically (>62 billion cycles, 0 divergences) is a structural consequence of this typing, not a stochastic correlation.

-- File: DriftRecurrence.lean
-- Verified against Mathlib (Lean 4.26); no `sorry`, no axioms.

import Mathlib.Data.Fin.Basic
import Mathlib.Tactic

namespace DriftCore

/-- One step on a W-bit state: state' = ((3·state + 1) mod 2^W) / 2.
    Matches the RTL `((s << 1) + s + 1) >> 1` bit-exactly. -/
def driftStep (W : â„•) (s : Fin (2 ^ W)) : Fin (2 ^ W) :=
  ⟨((3 * s.val + 1) % 2 ^ W) / 2, by
    have hpos : 0 < 2 ^ W := Nat.two_pow_pos W
    have hmod : (3 * s.val + 1) % 2 ^ W < 2 ^ W := Nat.mod_lt _ hpos
    exact Nat.lt_of_le_of_lt (Nat.div_le_self _ 2) hmod⟩

def driftOrbit (W : ℕ) (seed : Fin (2 ^ W)) : ℕ → Fin (2 ^ W)
  | 0     => seed
  | n + 1 => driftStep W (driftOrbit W seed n)

/-- **Determinism.** Two orbits started from the same seed agree at every step. -/
theorem drift_deterministic (W : â„•) (seed : Fin (2 ^ W)) (n : â„•) :
    driftOrbit W seed n = driftOrbit W seed n :=
  rfl

/-- RTL equivalence: arithmetic form = shift-add-shift form, mod 2^W. -/
theorem driftStep_eq_rtl (W : â„•) (s : Fin (2 ^ W)) :
    (driftStep W s).val = (((s.val <<< 1 + s.val + 1) % 2 ^ W) >>> 1) := by
  unfold driftStep
  rw [Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow]
  ring_nf

end DriftCore

The full file is at formal_verification/DriftRecurrence.lean. The drift_deterministic theorem holds by rfl — it is a structural consequence of driftStep being a Lean function rather than a relation. driftStep_eq_rtl confirms the arithmetic form matches the RTL shift-add-shift form bit-exactly. Together with the carry, fold, and Kummer files, this completes the structural-correctness chain across all four operations of the production recurrence Fold(qS + d) >> k.

3.5 — Output-Stage Bijectivity (Whitening.lean)

After the fold, the production core runs a three-step XOR-shift cascade with shifts (24, 14, 34) on the 64-bit folded value (dad_core.v lines 22-26). This section proves the cascade is a **bijection** of BitVec 64 — every 64-bit output corresponds to a unique 64-bit input, so the whitening cannot collapse, alias, or lose any state delivered by the fold step.

-- File: Whitening.lean
-- Verified against stock Mathlib (Lean 4.26) + Std bv_decide tactic.

import Std.Tactic.BVDecide
import Mathlib.Data.BitVec

namespace DriftCore

/-- The Drift Core production whitening: three chained XOR-shift steps
    with the production triple `(a, b, c) = (24, 14, 34)` on `BitVec 64`.
    Matches `dad_core.v` line-for-line. -/
def whiten (x : BitVec 64) : BitVec 64 :=
  let y1 := x  ^^^ (x  >>> 24)
  let y2 := y1 ^^^ (y1 <<< 14)
  let y3 := y2 ^^^ (y2 >>> 34)
  y3

/-- Inverse via Neumann-series formula for each step. -/
def unwhiten (y : BitVec 64) : BitVec 64 :=
  let z2 := y  ^^^ (y  >>> 34)
  let z1 := z2 ^^^ (z2 <<< 14) ^^^ (z2 <<< 28) ^^^ (z2 <<< 42) ^^^ (z2 <<< 56)
  let z0 := z1 ^^^ (z1 >>> 24) ^^^ (z1 >>> 48)
  z0

/-- Both inverse identities discharged by SAT-backed BitVec decision procedure. -/
theorem unwhiten_whiten (x : BitVec 64) : unwhiten (whiten x) = x := by
  unfold unwhiten whiten; bv_decide

theorem whiten_unwhiten (y : BitVec 64) : whiten (unwhiten y) = y := by
  unfold whiten unwhiten; bv_decide

/-- **Bijection.** The production whitening is a bijection of `BitVec 64`. -/
theorem whiten_bijective : Function.Bijective whiten := by
  refine ⟨?_, ?_⟩
  · intro a b h; have := congrArg unwhiten h
    rwa [unwhiten_whiten, unwhiten_whiten] at this
  · intro y; exact ⟨unwhiten y, whiten_unwhiten y⟩

end DriftCore

Full file at formal_verification/Whitening.lean. Both unwhiten_whiten and whiten_unwhiten are discharged by bv_decide (Lean's SAT-backed BitVec decision procedure) in under 10 seconds against the production triple (24, 14, 34). Caveat: bijectivity is an *implementation-safety* property — it does not establish cryptographic strength against cryptanalysis, only that the cascade preserves information. Cryptographic resistance remains a separate question pursued via independent peer review.

3.6 — Distribution-Preservation (Distribution.lean)

A direct corollary of the whitening's bijectivity: it is *distribution-preserving*. When run on every 64-bit input exactly once, the output set equals BitVec 64 exactly — every value appears once. For arbitrary input multisets, the per-element output count exactly tracks the input count under the bijective relabeling.

-- File: Distribution.lean (excerpt)
-- Bijectivity → distribution-preservation, structural results.

namespace DriftCore

/-- Singleton preimage is unique: every 64-bit output has exactly one
    64-bit input. The "no aliasing" form of bijectivity. -/
theorem whitening_singleton_preimage (y : BitVec 64) :
    (Finset.univ.filter (fun x => whiten x = y)).card = 1

/-- Image is full: when we run the whitening on every input exactly once,
    every output appears exactly once. Population-level "uniform inputs
    map to uniform outputs." -/
theorem whitening_image_univ :
    (Finset.univ : Finset (BitVec 64)).image whiten = Finset.univ

/-- Preimage cardinality: for any output set S, the number of inputs
    landing in S equals |S|. "No aliasing, no collapse" on any event. -/
theorem whitening_preimage_card (S : Finset (BitVec 64)) :
    (Finset.univ.filter (fun x => whiten x ∈ S)).card = S.card

end DriftCore

Full file at formal_verification/Distribution.lean. What this does *not* yet prove: the empirically-observed "0.999 uniformity over 10,000 trials" claim further requires (a) the iterated driftStep drives the input to the whitening close to uniform (mixing-rate / spectral-gap — Phase 4.C.2 of the roadmap), (b) a total-variation distance bound, and (c) finite-sample concentration. Those remain research-level and gated on external collaboration; this file provides the structural foundation only.

3.7 — Eventual Periodicity (EventualPeriodicity.lean)

The state space Fin (2^W) is finite; any deterministic function iterated on a finite set must enter a cycle by pigeonhole. This is the honest version of the "preventing infinite loops" claim: from any seed, the orbit visits at most 2^W distinct states before repeating.

-- File: EventualPeriodicity.lean

import Mathlib.Data.Fintype.Pigeonhole
import DriftRecurrence

namespace DriftCore

/-- Every orbit repeats a state within the first `2^W + 1` iterates. -/
theorem driftOrbit_eventually_periodic (W : â„•) (seed : Fin (2 ^ W)) :
    ∃ (i j : ℕ), i < j ∧ j ≤ 2 ^ W ∧
      driftOrbit W seed i = driftOrbit W seed j := by
  have hcard : Fintype.card (Fin (2 ^ W)) < Fintype.card (Fin (2 ^ W + 1)) := by
    simp [Fintype.card_fin]
  obtain ⟨x, y, hxy, heq⟩ :=
    Fintype.exists_ne_map_eq_of_card_lt
      (fun k : Fin (2 ^ W + 1) => driftOrbit W seed k.val) hcard
  rcases lt_trichotomy x.val y.val with h | h | h
  · exact ⟨x.val, y.val, h, Nat.le_of_lt_succ y.isLt, heq⟩
  · exact absurd (Fin.ext h) hxy
  · exact ⟨y.val, x.val, h, Nat.le_of_lt_succ x.isLt, heq.symm⟩

end DriftCore

Pigeonhole on Fin (2^W). The orbit's cycle length is at most 2^W, which is astronomical for W = 128 but structurally bounded — not infinite. driftOrbit_has_cycle packages the result into the form "there exist offset k and positive period p ≤ 2^W with the orbit cycling thereafter."

3.8 — Honest Framing: `driftStep` is Not Bijective (Noninjectivity.lean)

The arithmetic step ((3·s + 1) mod 2^W) / 2 ends with an integer division by 2, which drops the LSB and projects the codomain into Fin (2^(W-1)). Hence the step is *not* surjective onto Fin (2^W), and (on a finite domain = codomain) therefore *not* injective. The uniform measure on Fin (2^W) is **not** preserved — a negative result that rules out one specific reading of "ergodicity" with mathematical certainty.

-- File: Noninjectivity.lean (excerpt)

namespace DriftCore

/-- Image bound: every output is < 2^(W-1). -/
theorem driftStep_val_lt_half {W : ℕ} (s : Fin (2 ^ W)) (hW : 1 ≤ W) :
    (driftStep W s).val < 2 ^ (W - 1)

/-- driftStep is not surjective onto Fin (2^W) for W ≥ 1. -/
theorem driftStep_not_surjective {W : ℕ} (hW : 1 ≤ W) :
    ¬ Function.Surjective (driftStep W)

/-- driftStep is not injective (on a finite set, ¬surj ⇒ ¬inj). -/
theorem driftStep_not_injective {W : ℕ} (hW : 1 ≤ W) :
    ¬ Function.Injective (driftStep W)

/-- Hence not a bijection. The strong "measure-preserving" reading
    of ergodicity for uniform measure is provably false. -/
theorem driftStep_not_bijective {W : ℕ} (hW : 1 ≤ W) :
    ¬ Function.Bijective (driftStep W)

end DriftCore

Full file at formal_verification/Noninjectivity.lean. The recurrence loses up to 1 bit of entropy per iteration. The observed approximate uniformity of the output cannot be explained by measure-preservation of uniform input on the state space; it arises from transient mixing combined with the bijective whitening (§ 3.5, 3.6) acting on whatever distribution the iterated state actually has. Characterizing that distribution quantitatively remains Phase 4 research-level (mixing-rate / spectral-gap).

3.9 — Whitening is GF(2)-Linear (WhiteningLinearity.lean)

Each step of the whitening cascade is of the form x ↦ x ⊕ L(x) where L is a single shift. Composition of GF(2)-linear maps is GF(2)-linear, so the full whitening satisfies whiten(x ⊕ y) = whiten(x) ⊕ whiten(y). This is the reduction lemma that lifts the per-unit-vector avalanche bound (§ 3.10) to the differential-cryptanalysis form.

-- File: WhiteningLinearity.lean

namespace DriftCore

/-- The whitening is GF(2)-linear. -/
theorem whiten_xor (x y : BitVec 64) : whiten (x ^^^ y) = whiten x ^^^ whiten y := by
  unfold whiten; bv_decide

/-- whiten 0 = 0 (cheap sanity check). -/
@[simp] theorem whiten_zero : whiten (0 : BitVec 64) = 0 := by
  unfold whiten; bv_decide

/-- Differential form: whiten of an input difference equals the
    output difference. Used by the avalanche proof. -/
theorem whiten_diff (x x' : BitVec 64) :
    whiten x ^^^ whiten x' = whiten (x ^^^ x') := by
  rw [whiten_xor]

end DriftCore

Caveat. GF(2)-linearity is a structural property, not a cryptographic-strength claim. Cryptographic ciphers typically *destroy* GF(2)-linearity (S-boxes, modular addition with carries) because it makes linear and differential cryptanalysis easier. The Drift Core's *full* recurrence is non-linear (the affine step has carries), but the whitening stage alone is linear.

3.10 — Single-Bit Avalanche Bound (Avalanche.lean)

For every single-bit input difference e_i, the whitening output has at least two distinct set bits. By the linearity lemma above, this lifts to the standard differential statement: flipping any single input bit flips at least two output bits.

-- File: Avalanche.lean

namespace DriftCore

set_option maxRecDepth 2048 in
/-- For every unit vector e_i, whiten(e_i) has at least two set bits.
    Proved by fin_cases over Fin 64 + native_decide per case. -/
theorem whitening_avalanche_two (i : Fin 64) :
    ∃ j k : Fin 64, j ≠ k ∧
      (whiten ((1 : BitVec 64) <<< i.val)).getLsbD j.val = true ∧
      (whiten ((1 : BitVec 64) <<< i.val)).getLsbD k.val = true := by
  fin_cases i <;> native_decide

/-- Differential form via linearity: any two inputs differing in one
    bit produce outputs differing in at least two bits. -/
theorem whitening_avalanche_differential (x : BitVec 64) (i : Fin 64) :
    ∃ j k : Fin 64, j ≠ k ∧
      (whiten x ^^^ whiten (x ^^^ ((1 : BitVec 64) <<< i.val))).getLsbD j.val = true ∧
      (whiten x ^^^ whiten (x ^^^ ((1 : BitVec 64) <<< i.val))).getLsbD k.val = true

end DriftCore

First formal *cryptographic-flavor* property in the verification chain. Bound is tight — for unit vectors e_0, …, e_19 the whitening output has exactly 2 set bits. A cryptographically meaningful avalanche bound would be ≥ ~W/2; the whitening alone does not achieve this. The driftStep arithmetic plus iteration is what produces the observed empirical diffusion; that remains research-level (Phase 4-B.3 full).

3.11 — Bijection on the Recurrent Set (RecurrentSet.lean)

The positive complement to § 3.8 (Noninjectivity). The chain of iterated images Finset.univ ⊇ image(driftStep) ⊇ image(driftStep²) ⊇ … is decreasing on a finite set, so it stabilizes within 2^W steps. Define the recurrent set R as the stable value. Then driftStep|R is a bijection of R, and uniform measure on R is preserved by the recurrence — with |R| ≤ 2^(W-1).

-- File: RecurrentSet.lean (excerpt)

namespace DriftCore

/-- Image of `driftStep` iterated `k` times on `Finset.univ`. -/
def driftImage (W : ℕ) : ℕ → Finset (Fin (2 ^ W))
  | 0     => Finset.univ
  | k + 1 => (driftImage W k).image (driftStep W)

/-- Chain decreasing on a finite set ⇒ stabilizes within 2^W steps. -/
theorem driftImage_stabilizes :
    ∃ N : ℕ, N ≤ 2 ^ W ∧ driftImage W N = driftImage W (N + 1)

/-- The recurrent set: eventual image of the iteration. -/
def recurrentSet (W : â„•) : Finset (Fin (2 ^ W)) := driftImage W (2 ^ W)

/-- driftStep is fixed by image-on-recurrentSet. -/
theorem recurrentSet_image_eq :
    (recurrentSet W).image (driftStep W) = recurrentSet W

/-- driftStep restricted to recurrentSet is BIJECTIVE. -/
theorem driftStep_bijOn_recurrentSet :
    Set.BijOn (driftStep W) ↑(recurrentSet W) ↑(recurrentSet W)

/-- As an Equiv.Perm — useful for downstream measure-preserving args. -/
noncomputable def driftStepEquivRecurrent (W : â„•) :
    Equiv.Perm ↥(recurrentSet W) :=
  Equiv.ofBijective (driftStepRestrict W) driftStepRestrict_bijective

/-- The recurrent set fits in at most half the state space. -/
theorem recurrentSet_card_le (hW : 1 ≤ W) :
    (recurrentSet W).card ≤ 2 ^ (W - 1)

end DriftCore

Together with § 3.8 this gives a clean structural picture: the recurrence has a finite transient (≤ 2^W steps) during which it collapses pairs of states, after which it settles into a cyclic permutation of the recurrent subset R (with |R| ≤ 2^(W-1)). Uniform measure on R is preserved (immediate from the bijection); uniform measure on Fin (2^W) is not (§ 3.8). Quantifying R beyond the ≤ 2^(W-1) bound remains Phase 4 research-level.

3.12 — Known Structural Properties (disclosure)

The structural analysis above surfaces three load-bearing facts that diligence reviewers will check. We document them here so the answer is on the page, not in a follow-up email.

(1) Zero is a fixed point. driftStep(0) = ((3·0 + 1) mod 2^W) / 2 = 0 (integer division). An orbit reaching 0 is absorbed and the keystream stalls.

(2) Sole non-trivial predecessor of 0. The unique s* ≠ 0 with driftStep(s*) = 0 is s* = (2^W − 1) / 3. For W = 128, this is the specific 128-bit value 113427455640312821154458202477256070485. s* is odd.

(3) RTL mitigation. The production RTL applies seed_data | 1 at load, which rules out seeding directly from 0. It does not rule out seeding from s* (the OR-with-1 mask passes s* through unchanged, because s* is odd).

(4) Practical exposure. The probability a random orbit transits s* at any given step is ≈ 2^-128. The empirical >62B-cycle FPGA lockstep run never approaches 0 or s*, meaning the cycle the seed lands on does not include them in its basin. For non-cryptographic deployments (IoT optimization, structural RNG, BIST), the OR-with-1 mask plus astronomical transit probability cover practical operation.

(5) Optional zero-trap detector (security variant). Security-positioned synthesis configurations enable a parameter ENABLE_ZERO_TRAP_DETECTOR that monitors the arithmetic output and reroutes to a known-safe seed (128'h1) whenever the next state would be 0 — catching both the 0→0 and s*→0 paths in one structure. Overhead: ~150 LUT (≈ 0.75% of a Primer 20K design), one additional LUT level on the critical path. Off by default for IoT / cost-optimized variants; on by default for security / cryptographic positioning. Cryptographic-strength claims independent of this detector remain correctly routed to independent peer review rather than to Lean.

RTL snippet (canonical form):

// dad_core.v — zero-trap detector (security variant).
// expansion = 3·state + 1 (mod 2^W); arithmetic next_state = expansion >> 1.
// next_state == 0  iff  expansion ∈ {0, 1}  iff  expansion[W-1:1] is all zeros.

module dad_core #(
    parameter ENABLE_ZERO_TRAP_DETECTOR = 1   // default ON for security variants
)(/* ... */);

    wire [127:0] expansion              = (state << 1) + state + 128'h1;  // 3·state + 1
    wire [127:0] next_state_arithmetic = expansion >> 1;
    wire        next_would_be_zero    = ~|expansion[127:1];

    wire [127:0] next_state =
        ENABLE_ZERO_TRAP_DETECTOR ?
            (next_would_be_zero ? 128'h1 : next_state_arithmetic) :
            next_state_arithmetic;

endmodule

Lean correspondence. The two synthesis configurations correspond to two Lean definitions: driftStep in DriftRecurrence.lean (parameter off — bit-exact to the canonical recurrence, used by IoT variants) and driftStepSafe in DriftRecurrenceSafe.lean (parameter on — equal to driftStep off the trap inputs, with driftStepSafe(s*) = driftStepSafe(0) = 1). The Lean file proves driftStepSafe_ne_zero (every output is non-zero) and driftSafeOrbit_ne_zero (the orbit-level extension: no iterate of driftStepSafe from any seed reaches zero). All downstream theorems treat the step as an opaque deterministic function and flow through unchanged.

3.13 — End-to-End Output Chain (OutputChain.lean)

The cipher's one-step output stage chains three operations: dataOut(state) = whiten(fold(driftStep(state))) on BitVec 128 → BitVec 64. Two compositional properties matter for honest framing of what one cycle reveals about the upstream state.

-- File: OutputChain.lean (excerpt)

namespace DriftCore

/-- `driftStep` on BitVec 128, matching dad_core.v lines 16-17 bit-for-bit. -/
def driftStepBV (s : BitVec 128) : BitVec 128 :=
  ((s <<< 1) + s + 1) >>> 1

/-- `fold` on BitVec 128 → BitVec 64, matching dad_core.v line 22. -/
def foldBV (x : BitVec 128) : BitVec 64 :=
  x.setWidth 64 ^^^ (x >>> 64).setWidth 64

/-- The full one-step cipher output. -/
def dataOut (state : BitVec 128) : BitVec 64 :=
  whiten (foldBV (driftStepBV state))

/-- `fold` is GF(2)-linear. -/
theorem foldBV_xor (x y : BitVec 128) :
    foldBV (x ^^^ y) = foldBV x ^^^ foldBV y := by
  unfold foldBV; bv_decide

/-- whiten ∘ fold is GF(2)-linear (composition of linear maps). -/
theorem whiten_foldBV_xor (x y : BitVec 128) :
    whiten (foldBV (x ^^^ y)) = whiten (foldBV x) ^^^ whiten (foldBV y) := by
  rw [foldBV_xor, whiten_xor]

/-- **dataOut is *not* GF(2)-linear.** Concrete counterexample at (s, d) = (1, 2):
    driftStep(1) = 2, driftStep(2) = 3, driftStep(3) = 5, but 2 ⊕ 3 = 1 ≠ 5. -/
theorem dataOut_not_linear :
    dataOut (1 ^^^ 2) ≠ dataOut 1 ^^^ dataOut 2 := by
  unfold dataOut driftStepBV foldBV whiten; bv_decide

/-- **Linearity culprit.** driftStep_BV is the non-linear stage; whiten ∘ fold is linear. -/
theorem driftStepBV_not_linear :
    driftStepBV (1 ^^^ 2) ≠ driftStepBV 1 ^^^ driftStepBV 2 := by
  unfold driftStepBV; bv_decide

end DriftCore

Two consequences. (a) The output stage compresses 128 → 64 bits per step; whiten ∘ fold factors through fold, which is exactly 2^64-to-1 on BitVec 128, so each one-cycle data_out reveals at most 64 bits' worth of information about the upstream state regardless of what driftStep does. The remaining 64 bits of state stay hidden per cycle. (b) Any non-trivial cryptographic property of the Drift Core must trace back to the carries in driftStep, not to the output-stage cascade. Whether driftStep's non-linearity is cryptographically sufficient remains independent peer review.

3.14 — Nonce Injectivity (NonceInjectivity.lean)

The Drift Cipher Engine (cipher_engine.v line 57) computes the seed state as seed_state = SECRET ^ nonce. We prove the elementary but load-bearing protocol property: this is a bijection in the nonce. Hence two distinct nonces produce two distinct seed-states.

-- File: NonceInjectivity.lean (excerpt)

namespace DriftCore

/-- seedState SECRET nonce = SECRET ⊕ nonce.
    Matches cipher_engine.v line 57: seed_q ≤ SECRET ^ nonce. -/
def seedState (secret nonce : BitVec 128) : BitVec 128 :=
  secret ^^^ nonce

/-- XOR-is-its-own-inverse applied at the seed-state. -/
theorem seedState_involutive (secret nonce : BitVec 128) :
    seedState secret (seedState secret nonce) = nonce := by
  unfold seedState; bv_decide

/-- For any fixed SECRET, seedState is a bijection on the nonce space. -/
theorem seedState_bijective (secret : BitVec 128) :
    Function.Bijective (seedState secret) := by
  refine ⟨?_, ?_⟩
  · intro a b h
    have : seedState secret (seedState secret a) = seedState secret (seedState secret b) := by rw [h]
    rwa [seedState_involutive, seedState_involutive] at this
  · intro y; exact ⟨seedState secret y, seedState_involutive secret y⟩

/-- **Distinct nonces ⇒ distinct seed-states**, phrased for protocol use. -/
theorem seedState_distinct_of_distinct (secret : BitVec 128)
    {n1 n2 : BitVec 128} (h : n1 ≠ n2) :
    seedState secret n1 ≠ seedState secret n2 :=
  fun heq => h ((seedState_bijective secret).injective heq)

/-- **Protocol soundness (seed level).** For a fixed SECRET, the seed-state map
    preserves cardinality on nonce sets — i.e. a nonce schedule of N distinct
    nonces yields N distinct seed-states. -/
theorem seedState_protocol_soundness
    (secret : BitVec 128) (nonces : Finset (BitVec 128)) :
    (nonces.image (seedState secret)).card = nonces.card :=
  Finset.card_image_of_injective _ (seedState_bijective secret).injective

end DriftCore

What this gives you. Nonce uniqueness ⇒ keystream uniqueness, at the seed-state level. Two sessions using distinct nonces under the same SECRET produce structurally distinct starting states, justifying the standard "nonce-as-IV" pattern. A uniform nonce distribution maps to a uniform seed-state distribution by bijection. What this does *not* establish. Because driftStep is 2-to-1 (§ 3.8), two distinct seed-states can in principle merge to the same orbit after one step — the protocol-level guarantee here ends at the seed-state. It also does not establish that SECRET is hidden from an observer of outputs; that's cryptographic security and remains gated on independent peer review.

3.15 — Honest Framing: Whitening Has Trivial Linear-Cryptanalysis Resistance (WhiteningWeakness.lean)

The negative companion to § 3.9 (WhiteningLinearity) and § 3.10 (Avalanche). GF(2)-linearity is the worst possible property to have against linear cryptanalysis: for any GF(2)-linear map and any output bit, there exists a deterministic linear approximation in the inputs with bias 1. We exhibit it concretely.

-- File: WhiteningWeakness.lean (excerpt)

namespace DriftCore

/-- **Linear weakness, bit 0.** The lowest output bit of the whitening is the XOR
    of six specific input bits. Holds for ALL 64-bit inputs — deterministic,
    not statistical. An attacker observing whiten(x)[0] learns the value of
    the 6-bit XOR with probability 1. -/
theorem whiten_bit0_linear (x : BitVec 64) :
    (whiten x).getLsbD 0 =
      x.getLsbD 0 ^^ x.getLsbD 20 ^^ x.getLsbD 24 ^^
      x.getLsbD 34 ^^ x.getLsbD 44 ^^ x.getLsbD 58 := by
  unfold whiten; bv_decide

/-- **Linear weakness, bit 1.** Same 6-bit-XOR structure, shifted by one position. -/
theorem whiten_bit1_linear (x : BitVec 64) :
    (whiten x).getLsbD 1 =
      x.getLsbD 1 ^^ x.getLsbD 21 ^^ x.getLsbD 25 ^^
      x.getLsbD 35 ^^ x.getLsbD 45 ^^ x.getLsbD 59 := by
  unfold whiten; bv_decide

/-- **Differential form.** The output-difference bit-0 is a deterministic XOR of
    input-difference bits, by GF(2)-linearity. -/
theorem whiten_diff_bit0 (x x' : BitVec 64) :
    (whiten x ^^^ whiten x').getLsbD 0 =
      (x ^^^ x').getLsbD 0 ^^ (x ^^^ x').getLsbD 20 ^^
      (x ^^^ x').getLsbD 24 ^^ (x ^^^ x').getLsbD 34 ^^
      (x ^^^ x').getLsbD 44 ^^ (x ^^^ x').getLsbD 58 := by
  rw [whiten_diff]; exact whiten_bit0_linear (x ^^^ x')

end DriftCore

The honest claim. Every output bit of the whitening is a known, fixed, deterministic XOR of input bits — the absolute worst behavior against linear cryptanalysis. Combined with § 3.9 (GF(2)-linearity) and § 3.10 (avalanche bound tight at ≥ 2), this constrains the whitening's role: it provides structural shuffling and distribution-preservation (§ 3.5, 3.6), but it cannot, on its own, provide any cryptographic strength in the Shannon sense. Any cryptographic strength of the full Drift Core must come from the non-linear carries in driftStep (§ 3.13, the driftStepBV_not_linear counterexample). Whether that non-linearity is cryptographically sufficient is not a Lean question and remains gated on independent peer review.

VIEW FULL SOURCE ON GITHUB →