sha256

Pure Haskell SHA-256, HMAC-SHA256 (docs.ppad.tech/sha256).
git clone git://git.ppad.tech/sha256.git
Log | Files | Refs | README | LICENSE

commit 3060645abfec415f8dae8c08a613f7c51cc9c36c
parent c832ff090cd2f301d18c8f04886a2124d392a75f
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun,  1 Feb 2026 14:26:34 +0400

lib: export list and noinline pragma

The NOINLINE pragma is required with the explicit export list to stop
GHC from mis-optimizing the unsaf efunctions.

Diffstat:
MREADME.md | 9++++-----
Mlib/Crypto/Hash/SHA256/Arm.hs | 9++++++++-
2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md @@ -64,11 +64,10 @@ benchmark suite): ``` benchmarking ppad-sha256/SHA256 (32B input)/hash - time 67.70 ns (66.08 ns .. 71.11 ns) - 0.992 R² (0.979 R² .. 1.000 R²) - mean 66.55 ns (65.91 ns .. 68.79 ns) - std dev 3.919 ns (720.2 ps .. 8.253 ns) - variance introduced by outliers: 78% (severely inflated) + time 65.85 ns (65.76 ns .. 65.95 ns) + 1.000 R² (1.000 R² .. 1.000 R²) + mean 65.90 ns (65.80 ns .. 65.99 ns) + std dev 307.5 ps (256.0 ps .. 392.9 ps) benchmarking ppad-sha256/HMAC-SHA256 (32B input)/hmac time 135.7 ns (135.2 ns .. 136.1 ns) diff --git a/lib/Crypto/Hash/SHA256/Arm.hs b/lib/Crypto/Hash/SHA256/Arm.hs @@ -46,6 +46,7 @@ fi :: (Integral a, Num b) => a -> b fi = fromIntegral {-# INLINE fi #-} + peek_registers :: Ptr Word32 -> Registers @@ -174,7 +175,7 @@ _hmac rp bp k m = do poke_registers rp (iv ()) update rp bp (xor k (Exts.wordToWord32# 0x5C5C5C5C##)) update rp bp block -{-# INLINABLE _hmac #-} +{-# NOINLINE _hmac #-} _hmac_rr :: Ptr Word32 -- ^ register state @@ -204,6 +205,8 @@ _hmac_bb rp bp k m = do update rp bp inner {-# INLINABLE _hmac_bb #-} +-- | HMAC(key, v || sep || data) using ARM crypto extensions. +-- Writes result to destination pointer. _hmac_rsb :: Ptr Word32 -- ^ destination (8 Word32s) -> Ptr Word32 -- ^ scratch block buffer (16 Word32s) @@ -223,6 +226,8 @@ _hmac_rsb rp bp k v sep dat = do update rp bp inner {-# INLINABLE _hmac_rsb #-} +-- | Hash (v || sep || dat) with ARM crypto extensions. +-- Assumes register state already initialized at rp. _hash_vsb :: Ptr Word32 -- ^ register state -> Ptr Word32 -- ^ block buffer @@ -236,9 +241,11 @@ _hash_vsb rp bp el v sep dat@(BI.PS _ _ l) -- first block is complete: v || sep || dat[0:31] let !b0 = parse_vsb v sep dat update rp bp b0 + -- hash remaining complete blocks from dat[31:] let !rest = BU.unsafeDrop 31 dat !restLen = l - 31 hash_blocks rp bp rest + -- handle final padding let !finLen = restLen `rem` 64 !fin = BU.unsafeDrop (restLen - finLen) rest !total = el + 33 + fi l