poly1305

The Poly1305 message authentication code (docs.ppad.tech/poly1305).
git clone git://git.ppad.tech/poly1305.git
Log | Files | Refs | README | LICENSE

commit dc3b3ee876ed880155d3e88ea47b90acf18dcd3b
parent f1bfda4ddeea526b1991b0ad425117a980e63d09
Author: Jared Tobin <jared@jtobin.io>
Date:   Fri,  3 Jul 2026 16:34:31 -0230

lib: fuse the constant-time MAC comparison

Fold the bytewise XORs of the two buffers into the accumulator
directly, rather than materialising their XOR as an intermediate
ByteString via packZipWith: no per-comparison allocation, and no
secret-derived difference bytes ever hit the heap. Semantics and
the data-independent full walk are unchanged.

The implementation was checked with ppad-censor against
ppad-sha256's identical instance: mismatch-position independence
(byte 0 vs byte 31) passes at full budget under wall clock, with
the mean position effect bounded within ~1.4 ns per call.

Diffstat:
MCHANGELOG | 5+++++
Mlib/Crypto/MAC/Poly1305.hs | 17++++++++++++++---
2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,5 +1,10 @@ # Changelog +- Unreleased + * The constant-time 'Eq' on 'MAC' now folds over the two buffers + directly, rather than materialising an intermediate ByteString + holding their XOR on the heap. Semantics are unchanged. + - 0.4.2 (2026-05-16) * Features order-of-magnitude performance improvements, especially on ARM platforms where NEON intrinsics are available. diff --git a/lib/Crypto/MAC/Poly1305.hs b/lib/Crypto/MAC/Poly1305.hs @@ -154,9 +154,20 @@ instance Eq MAC where -- -- Runs in variable-time only for invalid inputs. (MAC a@(BI.PS _ _ la)) == (MAC b@(BI.PS _ _ lb)) - | la /= lb = False - | otherwise = - BS.foldl' (B..|.) 0 (BS.packZipWith B.xor a b) == 0 + | la /= lb = False + | otherwise = go 0 0 + where + -- fused fold: OR the bytewise XORs into an accumulator + -- directly, rather than via packZipWith, so no intermediate + -- ByteString holding the (secret-derived) difference bytes + -- is ever materialised on the heap. + go :: Word8 -> Int -> Bool + go !acc !i + | i == la = acc == 0 + | otherwise = + let !x = BU.unsafeIndex a i + !y = BU.unsafeIndex b i + in go (acc B..|. B.xor x y) (i + 1) -- | Produce a Poly1305 MAC for the provided message, given the -- provided key.