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:
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)