poly1305

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

commit 6e0b22f061e5bdff78da508aff4ee919feafec9a
parent 03b6dbe88aead7c7d2f2d32e9caf00e450d3ee38
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat, 31 Oct 2026 14:28:16 +0400

cbits: use the scalar kernel on x86-64

The scalar 26-bit-limb kernel is portable C, so compile it on x86-64
as well as aarch64, and have poly1305_native_available report it
there.  The NEON 4-way kernel remains aarch64-only; on x86-64 every
block goes through the scalar kernel.

On an x86-64 AMD EPYC 7642 host, with the LLVM backend, versus the
pure Haskell implementation:

  mac (114B msg):    347 ns -> 234 ns
  mac (1024B msg):  2.33 us -> 1.26 us
  mac (4096B msg):  8.35 us -> 4.84 us

Diffstat:
Mcbits/poly1305_native.c | 21+++++++++++++++------
Mlib/Crypto/MAC/Poly1305/Native.hs | 5+++--
2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/cbits/poly1305_native.c b/cbits/poly1305_native.c @@ -3,20 +3,23 @@ #include <string.h> #if defined(__aarch64__) - #include <arm_neon.h> +#endif + +#if defined(__aarch64__) || defined(__x86_64__) /* - * Poly1305 (RFC 8439). ARM acceleration via two paths: + * Poly1305 (RFC 8439), via two paths: * - * 1. A scalar 26-bit-limb kernel using 64-bit native arithmetic for - * the limb multiplications. Used for setup (precomputing r^k), + * 1. A portable scalar 26-bit-limb kernel using 64-bit native + * arithmetic for the limb multiplications, compiled on both + * aarch64 and x86_64. Used for setup (precomputing r^k), * for messages shorter than 64 bytes, and for the < 4-block tail * of longer messages. Also serves as the stage-1 reference; the * NEON kernel below was added in a separate commit. * - * 2. A NEON 4-way parallel kernel (when at least 4 full blocks - * remain). Layout: 5 'uint32x4_t' limb vectors hold one limb + * 2. On aarch64, a NEON 4-way parallel kernel (when at least 4 full + * blocks remain). Layout: 5 'uint32x4_t' limb vectors hold one limb * position each across 4 message blocks; matching r-power * vectors hold (r^4, r^3, r^2, r^1) at the same limb position. * For each output position d_j we accumulate 5 partial products @@ -109,6 +112,8 @@ static inline void scalar_block(uint32_t h[5], const uint32_t r[5], mul_mod_p(hl, r, h); } +#if defined(__aarch64__) + /* * 4-block NEON update. Computes: * h := (h + m_0)*r^4 + m_1*r^3 + m_2*r^2 + m_3*r^1 mod p @@ -226,6 +231,8 @@ static void neon4_block(uint32_t h[5], h[4] = (uint32_t)d4; } +#endif + /* * Compute a 16-byte Poly1305 MAC over 'msg' (length 'msglen') using * the 32-byte 'key'. Writes the tag to 'mac_out'. @@ -254,6 +261,7 @@ void poly1305_mac_native(const uint8_t key[32], const uint8_t *msg, size_t pos = 0; +#if defined(__aarch64__) /* NEON 4-way path: amortizing the r^2/r^3/r^4 precomputation * (3 scalar mul_mod_p calls) needs about 4 NEON iterations to * break even versus the scalar block loop, so only engage it @@ -269,6 +277,7 @@ void poly1305_mac_native(const uint8_t key[32], const uint8_t *msg, pos += 64; } } +#endif /* Scalar tail: any remaining full blocks (< 4 of them). */ while (pos + 16 <= msglen) { diff --git a/lib/Crypto/MAC/Poly1305/Native.hs b/lib/Crypto/MAC/Poly1305/Native.hs @@ -7,7 +7,8 @@ -- License: MIT -- Maintainer: Jared Tobin <jared@ppad.tech> -- --- ARM acceleration for the Poly1305 MAC. +-- A native C kernel for the Poly1305 MAC on aarch64 and x86_64, with +-- ARM NEON acceleration. module Crypto.MAC.Poly1305.Native ( poly1305_native_available @@ -39,7 +40,7 @@ fi = fromIntegral -- api ------------------------------------------------------------------------ --- | Are ARM extensions available? +-- | Is the native kernel available? poly1305_native_available :: Bool poly1305_native_available = unsafeDupablePerformIO c_poly1305_native_available /= 0