packages feed

ppad-sha256 0.3.6 → 0.3.7

raw patch · 6 files changed

+89/−1 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Crypto.Hash.SHA256: hash_prefixed :: ByteString -> ByteString -> ByteString

Files

CHANGELOG view
@@ -1,5 +1,11 @@ # Changelog +- 0.3.7 (2026-11-13)+  * Adds 'hash_prefixed', which hashes the concatenation of two strict+    bytestrings. When the length of the first is a multiple of the+    64-byte block size, the second is hashed in place, rather than+    being copied into a new buffer alongside it.+ - 0.3.6 (2026-10-31)   * Uses the x86 SHA extensions on x86_64 CPUs that support them,     detected at runtime, falling back to the pure Haskell
lib/Crypto/Hash/SHA256.hs view
@@ -18,6 +18,7 @@ module Crypto.Hash.SHA256 (   -- * SHA-256 message digest functions     hash+  , hash_prefixed   , Lazy.hash_lazy    -- * SHA256-based MAC functions@@ -52,6 +53,24 @@   | Native.sha256_native_available = Native.hash m   | otherwise = Pure.hash m {-# INLINABLE hash #-}++-- | Compute a condensed representation of the concatenation of two+--   strict bytestrings via SHA-256, i.e. @hash (p <> m)@.+--+--   When the length of the prefix @p@ is a multiple of 64 bytes (the+--   SHA-256 block size), @m@ is hashed in place, rather than being+--   copied into a new buffer. Otherwise both are copied, as for+--   @hash (p <> m)@.+--+--   The 256-bit output digest is returned as a strict bytestring.+--+--   >>> hash_prefixed "64-byte prefix" "strict bytestring input"+--   "<strict 256-bit message digest>"+hash_prefixed :: BS.ByteString -> BS.ByteString -> BS.ByteString+hash_prefixed p m+  | Native.sha256_native_available = Native.hash_prefixed p m+  | otherwise = Pure.hash_prefixed p m+{-# INLINABLE hash_prefixed #-}  -- hmac ---------------------------------------------------------------------- 
lib/Crypto/Hash/SHA256/Native.hs view
@@ -16,6 +16,7 @@ module Crypto.Hash.SHA256.Native (     sha256_native_available   , hash+  , hash_prefixed   , hmac   , _hmac_rr   , _hmac_rsb@@ -111,6 +112,21 @@     _hash rp bp 0 m     let !rs = peek_registers rp     pure (cat rs)++hash_prefixed+  :: BS.ByteString+  -> BS.ByteString+  -> BS.ByteString+hash_prefixed p@(BI.PS _ _ l) m+  | l `rem` 64 /= 0 = hash (p <> m)+  | otherwise = unsafeDupablePerformIO $+      allocaBytes 32 $ \rp ->+      allocaBytes 64 $ \bp -> do+        poke_registers rp (iv ())+        hash_blocks rp bp p+        _hash rp bp (fi l) m+        let !rs = peek_registers rp+        pure (cat rs)  _hash   :: Ptr Word32    -- ^ register state
lib/Crypto/Hash/SHA256/Pure.hs view
@@ -15,6 +15,7 @@  module Crypto.Hash.SHA256.Pure (     hash+  , hash_prefixed   , hmac   , _hmac_rr   , _hmac_rsb@@ -41,6 +42,16 @@ hash :: BS.ByteString -> BS.ByteString hash m = cat (_hash 0 (iv ()) m) {-# INLINABLE hash #-}++-- | Compute a condensed representation of the concatenation of two+--   strict bytestrings via SHA-256, using the pure Haskell+--   implementation. The second bytestring is not copied when the+--   length of the first is a multiple of 64.+hash_prefixed :: BS.ByteString -> BS.ByteString -> BS.ByteString+hash_prefixed p@(BI.PS _ _ l) m+  | l `rem` 64 /= 0 = hash (p <> m)+  | otherwise = cat (_hash (fi l) (_hash_blocks (iv ()) p) m)+{-# INLINABLE hash_prefixed #-}  _hash   :: Word64        -- ^ extra prefix length for padding calculations
ppad-sha256.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               ppad-sha256-version:            0.3.6+version:            0.3.7 synopsis:           The SHA-256 and HMAC-SHA256 algorithms license:            MIT license-file:       LICENSE
test/Property.hs view
@@ -68,6 +68,15 @@     l <- Q.chooseInt (0, 8 * 64)     Msg . BS.pack <$> Q.vectorOf l Q.arbitrary +-- block-aligned prefixes+newtype Prefix = Prefix BS.ByteString+  deriving Show++instance Q.Arbitrary Prefix where+  arbitrary = do+    k <- Q.chooseInt (0, 3)+    Prefix . BS.pack <$> Q.vectorOf (k * 64) Q.arbitrary+ -- register-sized strings newtype Bytes32 = Bytes32 BS.ByteString   deriving Show@@ -101,6 +110,17 @@ hash_matches_pure :: Msg -> Bool hash_matches_pure (Msg m) = hash m == Pure.hash m +hash_prefixed_matches_hash :: Prefix -> Msg -> Bool+hash_prefixed_matches_hash (Prefix p) (Msg m) =+  let expected = hash (p <> m)+  in  hash_prefixed p m == expected && Pure.hash_prefixed p m == expected++-- unaligned prefixes fall back to hashing the concatenation+hash_prefixed_unaligned :: Msg -> Msg -> Bool+hash_prefixed_unaligned (Msg p) (Msg m) =+  let expected = hash (p <> m)+  in  hash_prefixed p m == expected && Pure.hash_prefixed p m == expected+ hmac_matches_pure :: Msg -> Msg -> Bool hmac_matches_pure (Msg k) (Msg m) = unmac (hmac k m) == Pure.hmac k m @@ -132,6 +152,17 @@   H.assertBool mempty $     all (\l -> hash (msg l) == Pure.hash (msg l)) [0 .. 3 * 64] +hash_prefixed_all_lengths :: TestTree+hash_prefixed_all_lengths =+  H.testCase "hash_prefixed ~ hash (all lengths)" $+    H.assertBool mempty $ and [+        hash_prefixed p (msg l) == e && Pure.hash_prefixed p (msg l) == e+      | k <- [0 .. 2]+      , l <- [0 .. 3 * 64]+      , let p = BS.reverse (msg (k * 64))+            e = hash (p <> msg l)+      ]+ hmac_all_lengths :: TestTree hmac_all_lengths = H.testCase "hmac ~ Pure.hmac (all lengths)" $   H.assertBool mempty $@@ -174,6 +205,10 @@   , testGroup "dispatch ~ pure" [       Q.testProperty "hash ~ Pure.hash" $         Q.withMaxSuccess 1000 hash_matches_pure+    , Q.testProperty "hash_prefixed p m ~ hash (p <> m)" $+        Q.withMaxSuccess 1000 hash_prefixed_matches_hash+    , Q.testProperty "hash_prefixed p m ~ hash (p <> m) (unaligned)" $+        Q.withMaxSuccess 1000 hash_prefixed_unaligned     , Q.testProperty "hmac ~ Pure.hmac" $         Q.withMaxSuccess 1000 hmac_matches_pure     , Q.testProperty "_hmac_rr k m ~ hmac (cat k) (cat m)" $@@ -181,6 +216,7 @@     , Q.testProperty "_hmac_rsb k v s d ~ hmac (cat k) (cat v <> s <> d)" $         Q.withMaxSuccess 1000 hmac_rsb_matches_hmac     , hash_all_lengths+    , hash_prefixed_all_lengths     , hmac_all_lengths     , hmac_all_key_lengths     , hmac_rsb_all_lengths