barrettReduce computes T % p for every input word, not only for inputs
below p^2. The single-word reducer only needs T < 2^64, which holds for every
UInt64; the p^2 bound in toNat_barrettReduce_eq_mod is stronger than
necessary. This is the reduction the wide accumulator flushes through.
The full-range reducer returns a canonical residue for every input word.
The value carried by a two-word accumulator (lo, hi) in radix 2^64.
Equations
- BarrettCtx.accVal lo hi = lo.toNat + hi.toNat * UInt64.word
Instances For
Add a single product word q into the two-word accumulator (lo, hi),
propagating the carry into the high word.
Equations
Instances For
Adding a product word to the accumulator increases its value by exactly the
product, provided the high word does not overflow (hi.toNat + 1 < 2^64).
accAddWord in inline-carry form: the wrapped word add, with the carry read
off the wraparound compare (lo + q < lo) and added to the high word as a bit.
This is the shape the delayed-reduction kernel's scalar loop computes per term
(no addCarry extern call); the equality identifies that loop's step with
accStep below.
Reduce the two-word accumulator (lo, hi) modulo p, using the precomputed
constant cR = 2^64 % p. The scheme reduces each half, folds the high half in
through cR, and reduces once more:
(lo + hi * 2^64) % p = ((hi % p) * (2^64 % p) + lo % p) % p.
Equations
- ctx.accReduce cR lo hi = barrettReduce ctx (barrettReduce ctx (barrettReduce ctx hi * cR) + barrettReduce ctx lo)
Instances For
accReduce returns a canonical residue below p.
The radix residue 2^64 % p, stored as a context-level constant so callers
of accReduce/foldReduce need not carry the word and its correctness proof.
Computed entirely in machine words: 0 - p wraps to 2^64 - p ≡ 2^64 (mod p),
so one word-level reduction yields 2^64 % p with no 128-bit literal and no
bignum Nat reduction of the radix (the former Nat-level computation cost a
bignum mod on every call, which the delayed-reduction kernel pays once per
dot product).
Equations
- _ctx.radixResidue = (0 - p) % p
Instances For
radixResidue stores exactly 2^64 % p, the hcR side condition every
accReduce/foldReduce lemma needs.
Number of one-word products accumulated between reductions. Any value below
2^64 keeps the two-word accumulator's high word from overflowing (the add
grows it by at most one per step). The 2^12 window keeps the periodic path
operationally testable while amortizing each reduction across 4096 products; the
committed window sweep compares it with shorter and effectively single-flush
alternatives.
Equations
- BarrettCtx.barrettWindow = 2 ^ 12
Instances For
One delayed-reduction step: add the product word q into the accumulator
(lo, hi), and when the window count reaches barrettWindow flush the two-word
value through accReduce back to a single reduced word, resetting the count.
Deliberately not @[expose]: leaving the body opaque to the kernel keeps
reductions of foldl accStep … from unfolding the accReduce/barrettReduce
machinery (which mentions the 2^64 radix) during defeq checks; all reasoning
goes through accFold_spec, never kernel reduction of accStep.
Equations
- One or more equations did not get rendered due to their size.
Instances For
accStep in inline-carry scalar form: the state transition the delayed-
reduction kernel's scalar loops compute per term. This is the exported equation
for identifying an unfolded scalar loop with the (deliberately opaque) accStep
fold step.
Sum of the Nat values of a list of accumulator product words.
Equations
- BarrettCtx.wordsSum ws = List.foldr (fun (w : UInt64) (a : Nat) => w.toNat + a) 0 ws
Instances For
Per-window no-overflow invariant for the delayed-reduction fold. From any
in-window start state (hi ≤ count < barrettWindow), folding accStep over a
list of product words keeps the state in-window (hi ≤ count < barrettWindow,
so the next add cannot overflow the high word) and preserves the residue: the
accumulator's value modulo p equals the starting value plus the sum of the
added words modulo p.
Reduce a list of product words modulo p with periodic reduction: fold
accStep from an empty accumulator and flush the final partial window.
Equations
- ctx.foldReduce ws = ctx.accReduce ctx.radixResidue (List.foldl ctx.accStep (0, 0, 0) ws).fst (List.foldl ctx.accStep (0, 0, 0) ws).snd.fst
Instances For
foldReduce computes (Σ words) % p: the delayed-reduction fold is exact for
a run of any length, matching the residue of the fully-accumulated sum.