sha512

Pure Haskell SHA-512, HMAC-SHA512 (docs.ppad.tech/sha512).
git clone git://git.ppad.tech/sha512.git
Log | Files | Refs | README | LICENSE

commit 5b9548d5d9d51c88920f900cd401a8cae4b88478
parent c00f86e2e27071f84f1f728de5eb21c5357eeb8c
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat, 10 Oct 2026 15:31:01 +0400

lib: simplify lazy padding and reuse the strict pure hash

hmac_lazy carried its own builder-based strict SHA-512 for the outer
hash and for long keys; it now uses Crypto.Hash.SHA512.Pure.hash.

'sol' computes the padding length with Word64 mask arithmetic rather
than via Integer, and pad_lazy builds its padding block in one go
rather than one zero byte at a time.

Diffstat:
Mlib/Crypto/Hash/SHA512/Lazy.hs | 59+++++++++++------------------------------------------------
1 file changed, 11 insertions(+), 48 deletions(-)

diff --git a/lib/Crypto/Hash/SHA512/Lazy.hs b/lib/Crypto/Hash/SHA512/Lazy.hs @@ -22,10 +22,10 @@ module Crypto.Hash.SHA512.Lazy ( ) where import Crypto.Hash.SHA512.Internal +import qualified Crypto.Hash.SHA512.Pure as Pure import qualified Data.Bits as B import qualified Data.ByteString as BS import qualified Data.ByteString.Builder as BSB -import qualified Data.ByteString.Builder.Extra as BE import qualified Data.ByteString.Internal as BI import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy.Internal as BLI @@ -77,26 +77,20 @@ to_strict = BL.toStrict . BSB.toLazyByteString -- k such that (l + 1 + k) mod 128 = 112 sol :: Word64 -> Word64 -sol l = - let r = 112 - fi l `rem` 128 - 1 :: Integer -- fi prevents underflow - in fi (if r < 0 then r + 128 else r) +sol l = (111 - l) B..&. 127 -- wraps mod 2^64, a multiple of 128 -- RFC 6234 4.1 (lazy) pad_lazy :: BL.ByteString -> BL.ByteString pad_lazy (BL.toChunks -> m) = BL.fromChunks (walk 0 m) where walk !l bs = case bs of (c:cs) -> c : walk (l + fi (BS.length c)) cs - [] -> padding l (sol l) (BSB.word8 0x80) - - padding l k bs - | k == 0 = - pure - . to_strict - -- more efficient for small builder - $ bs <> BSB.word64BE 0x00 <> BSB.word64BE (l * 8) - | otherwise = - let nacc = bs <> BSB.word8 0x00 - in padding l (pred k) nacc + [] -> [padding l] + + padding l = to_strict $ + BSB.word8 0x80 + <> BSB.byteString (BS.replicate (fi (sol l)) 0x00) + <> BSB.word64BE 0x00 + <> BSB.word64BE (l * 8) -- | Compute a condensed representation of a lazy bytestring via -- SHA-512. @@ -137,37 +131,6 @@ hmac_lazy mk@(BI.PS _ _ l) text = step4 = hash_lazy step3 step5 = BS.map (B.xor 0x5C) step1 step6 = step5 <> step4 - in MAC (hash step6) + in MAC (Pure.hash step6) where - hash bs = cat (go (iv ()) (pad bs)) where - go :: Registers -> BS.ByteString -> Registers - go !acc b - | BS.null b = acc - | otherwise = case unsafe_splitAt 128 b of - SSPair c r -> go (update acc (parse c 0)) r - - pad m@(BI.PS _ _ (fi -> len)) - | len < 256 = to_strict_small padded - | otherwise = to_strict padded - where - padded = BSB.byteString m - <> fill (sol len) (BSB.word8 0x80) - <> BSB.word64BE 0x00 - <> BSB.word64BE (len * 8) - - to_strict_small = BL.toStrict . BE.toLazyByteStringWith - (BE.safeStrategy 256 BE.smallChunkSize) mempty - - fill j !acc - | j `rem` 8 == 0 = loop64 j acc - | otherwise = loop8 j acc - - loop64 j !acc - | j == 0 = acc - | otherwise = loop64 (j - 8) (acc <> BSB.word64BE 0x00) - - loop8 j !acc - | j == 0 = acc - | otherwise = loop8 (pred j) (acc <> BSB.word8 0x00) - - !(k, lk) = if l > 128 then (hash mk, 64) else (mk, l) + !(k, lk) = if l > 128 then (Pure.hash mk, 64) else (mk, l)