packages feed

ppad-sha512 0.1.5 → 0.2.0

raw patch · 8 files changed

+100/−41 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Crypto.Hash.SHA512: MAC :: ByteString -> MAC
+ Crypto.Hash.SHA512: newtype MAC
- Crypto.Hash.SHA512: hmac :: ByteString -> ByteString -> ByteString
+ Crypto.Hash.SHA512: hmac :: ByteString -> ByteString -> MAC
- Crypto.Hash.SHA512: hmac_lazy :: ByteString -> ByteString -> ByteString
+ Crypto.Hash.SHA512: hmac_lazy :: ByteString -> ByteString -> MAC

Files

CHANGELOG view
@@ -1,5 +1,10 @@ # Changelog +- 0.2.0 (2026-01-10)+  * The HMAC functions now produce a value of type MAC, which is a+    newtype over a ByteString. The 'Eq' instance for MAC compares values+    in constant time.+ - 0.1.5 (2026-01-08)   * We now check if the ARM cryptographic extensions are available, and,     if so, use them to calculate hashes. If they're unavailable we
bench/Main.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-}  module Main where@@ -14,22 +15,31 @@   ]  suite :: Benchmark-suite = env setup $ \ ~(bs, bl) ->-    bgroup "ppad-sha512" [-      bgroup "SHA512 (32B input)" [-        bench "hash" $ whnf SHA512.hash bs-      , bench "hash_lazy" $ whnf SHA512.hash_lazy bl-      , bench "SHA.sha512" $ whnf SHA.sha512 bl-      ]-    , bgroup "HMAC-SHA512 (32B input)" [-        bench "hmac" $ whnf (SHA512.hmac "key") bs-      , bench "hmac_lazy" $ whnf (SHA512.hmac_lazy "key") bl-      , bench "SHA.hmacSha512" $ whnf (SHA.hmacSha512 "key") bl+suite =+  let !bs    = BS.replicate 32 0+      !bl    = BL.fromStrict bs+      !mac0  = SHA512.hmac "key" "foo"+      !mac1  = SHA512.hmac "key" "bar"+      !mac2  = SHA512.hmac "key" "foo"+      !macl0 = SHA512.hmac_lazy "key" "foo"+      !macl1 = SHA512.hmac_lazy "key" "bar"+      !macl2 = SHA512.hmac_lazy "key" "foo"+  in  bgroup "ppad-sha512" [+        bgroup "SHA512 (32B input)" [+          bench "hash" $ whnf SHA512.hash bs+        , bench "hash_lazy" $ whnf SHA512.hash_lazy bl+        , bench "SHA.sha512" $ whnf SHA.sha512 bl+        ]+      , bgroup "HMAC-SHA512 (32B input)" [+          bench "hmac" $ whnf (SHA512.hmac "key") bs+        , bench "hmac_lazy" $ whnf (SHA512.hmac_lazy "key") bl+        , bench "SHA.hmacSha512" $ whnf (SHA.hmacSha512 "key") bl+        ]+      , bgroup "MAC comparison" [+          bench "hmac, unequal" $ whnf (mac0 ==) mac1+        , bench "hmac, equal" $ whnf (mac0 ==) mac2+        , bench "hmac_lazy, unequal" $ whnf (macl0 ==) macl1+        , bench "hmac_lazy, equal" $ whnf (macl0 ==) macl2+        ]       ]-    ]-  where-    setup = do-      let bs_32B = BS.replicate 32 0-          bl_32B = BL.fromStrict bs_32B-      pure (bs_32B, bl_32B) 
bench/Weight.hs view
@@ -1,13 +1,18 @@ {-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns -fno-warn-type-defaults #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-}  module Main where +import Control.DeepSeq import qualified Crypto.Hash.SHA512 as SHA512 import qualified Data.ByteString as BS import Weigh +instance NFData SHA512.MAC where+  rnf (SHA512.MAC b) = rnf b+ -- note that 'weigh' doesn't work properly in a repl main :: IO () main = mainWith $ do@@ -21,10 +26,10 @@       !bs2 = BS.replicate 128 0       !bs3 = BS.replicate 12288 0   in  wgroup "hash" $ do-        func' "hash (32B  input)" SHA512.hash bs0-        func' "hash (64B  input)" SHA512.hash bs1-        func' "hash (128B input)" SHA512.hash bs2-        func' "hash (12288B input)" SHA512.hash bs3+        func "hash (32B  input)" SHA512.hash bs0+        func "hash (64B  input)" SHA512.hash bs1+        func "hash (128B input)" SHA512.hash bs2+        func "hash (12288B input)" SHA512.hash bs3  hmac :: Weigh () hmac =@@ -34,8 +39,8 @@       !bs2 = BS.replicate 128 0       !bs3 = BS.replicate 12288 0   in  wgroup "hmac" $ do-        func' "hmac (32B  input)" (SHA512.hmac key) bs0-        func' "hmac (64B  input)" (SHA512.hmac key) bs1-        func' "hmac (128B input)" (SHA512.hmac key) bs2-        func' "hmac (12288B input)" (SHA512.hmac key) bs3+        func "hmac (32B  input)" (SHA512.hmac key) bs0+        func "hmac (64B  input)" (SHA512.hmac key) bs1+        func "hmac (128B input)" (SHA512.hmac key) bs2+        func "hmac (12288B input)" (SHA512.hmac key) bs3 
lib/Crypto/Hash/SHA512.hs view
@@ -22,6 +22,7 @@   , Lazy.hash_lazy    -- * SHA512-based MAC functions+  , MAC(..)   , hmac   , Lazy.hmac_lazy   ) where@@ -94,15 +95,15 @@ hmac   :: BS.ByteString -- ^ key   -> BS.ByteString -- ^ text-  -> BS.ByteString+  -> MAC hmac mk@(BI.PS _ _ l) text     | sha512_arm_available =         let !inner = hash_arm_with ipad 128 text-        in  hash_arm (opad <> inner)+        in  MAC (hash_arm (opad <> inner))     | otherwise =         let !ipad_state = block_hash iv (prepare_schedule (parse_block ipad 0))             !inner = cat (process_with ipad_state 128 text)-        in  hash (opad <> inner)+        in  MAC (hash (opad <> inner))   where     !step1 = k <> BS.replicate (128 - lk) 0x00     !ipad  = BS.map (B.xor 0x36) step1
lib/Crypto/Hash/SHA512/Internal.hs view
@@ -1,5 +1,7 @@ {-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RecordWildCards #-}  -- |@@ -15,6 +17,8 @@   , Block(..)   , Schedule(..) +  , MAC(..)+   , iv   , block_hash   , prepare_schedule@@ -41,6 +45,31 @@ import Foreign.Marshal.Utils (copyBytes, fillBytes) import Foreign.Ptr (Ptr, plusPtr) import Foreign.Storable (poke)++-- MAC type ------------------------------------------------------------------++-- | A message authentication code.+--+--   Note that you should compare MACs for equality using the 'Eq'+--   instance, which performs the comparison in constant time, instead+--   of unwrapping and comparing the underlying 'ByteStrings'.+--+--   >>> let foo@(MAC bs0) = hmac key "hi"+--   >>> let bar@(MAC bs1) = hmac key "there"+--   >>> foo == bar -- do this+--   False+--   >>> bs0 == bs1 -- don't do this+--   False+newtype MAC = MAC BS.ByteString+  deriving newtype Show++instance Eq MAC where+  -- | A constant-time equality check for message authentication codes.+  --+  --   Runs in variable-time only for invalid inputs.+  (MAC a@(BI.PS _ _ la)) == (MAC b@(BI.PS _ _ lb))+    | la /= lb  = False+    | otherwise = BS.foldl' (B..|.) 0 (BS.packZipWith B.xor a b) == 0  -- preliminary utils --------------------------------------------------------- 
lib/Crypto/Hash/SHA512/Lazy.hs view
@@ -21,6 +21,7 @@   , hmac_lazy   ) where +import Crypto.Hash.SHA512.Internal import qualified Data.Bits as B import qualified Data.ByteString as BS import qualified Data.ByteString.Builder as BSB@@ -30,7 +31,6 @@ import qualified Data.ByteString.Lazy.Internal as BLI import Data.Word (Word64) import Foreign.ForeignPtr (plusForeignPtr)-import Crypto.Hash.SHA512.Internal  -- preliminary utils @@ -136,7 +136,7 @@ hmac_lazy   :: BS.ByteString -- ^ key   -> BL.ByteString -- ^ text-  -> BS.ByteString+  -> MAC hmac_lazy mk@(BI.PS _ _ l) text =     let step1 = k <> BS.replicate (128 - lk) 0x00         step2 = BS.map (B.xor 0x36) step1@@ -144,7 +144,7 @@         step4 = hash_lazy step3         step5 = BS.map (B.xor 0x5C) step1         step6 = step5 <> step4-    in  hash step6+    in  MAC (hash step6)   where     hash bs = cat (go iv (pad bs)) where       go :: Registers -> BS.ByteString -> Registers
ppad-sha512.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               ppad-sha512-version:            0.1.5+version:            0.2.0 synopsis:           The SHA-512 and HMAC-SHA512 algorithms license:            MIT license-file:       LICENSE
test/Main.hs view
@@ -46,7 +46,8 @@     let key = decodeLenient (TE.encodeUtf8 mt_key)         msg = decodeLenient (TE.encodeUtf8 mt_msg)         pec = decodeLenient (TE.encodeUtf8 mt_tag)-        out = BS.take bytes (SHA512.hmac key msg)+        SHA512.MAC mac = SHA512.hmac key msg+        out = BS.take bytes mac     if   mt_result == "invalid"     then assertBool "invalid" (pec /= out)     else assertEqual mempty pec out@@ -83,13 +84,16 @@     , cmp_hmac "hmv3" hmv3_key hmv3_put hmv3_pec     , cmp_hmac "hmv4" hmv4_key hmv4_put hmv4_pec     , testCase "hmv5" $ do-        let out = BS.take 32 $ B16.encode (SHA512.hmac hmv5_key hmv5_put)+        let SHA512.MAC mac = SHA512.hmac hmv5_key hmv5_put+            out = BS.take 32 $ B16.encode mac         assertEqual mempty hmv5_pec out     , testCase "hmv6" $ do-        let out = B16.encode (SHA512.hmac hmv6_key hmv6_put)+        let SHA512.MAC mac = SHA512.hmac hmv6_key hmv6_put+            out = B16.encode mac         assertEqual mempty hmv6_pec out     , testCase "hmv7" $ do-        let out = B16.encode (SHA512.hmac hmv7_key hmv7_put)+        let SHA512.MAC mac = SHA512.hmac hmv7_key hmv7_put+            out = B16.encode mac         assertEqual mempty hmv7_pec out     ]   , testGroup "hmac_lazy" [@@ -99,15 +103,18 @@     , cmp_hmac_lazy "hmv4" hmv4_key hmv4_put hmv4_pec     , testCase "hmv5" $ do         let lut = BL.fromStrict hmv5_put-            out = BS.take 32 $ B16.encode (SHA512.hmac_lazy hmv5_key lut)+            SHA512.MAC mac = SHA512.hmac_lazy hmv5_key lut+            out = BS.take 32 $ B16.encode mac         assertEqual mempty hmv5_pec out     , testCase "hmv6" $ do         let lut = BL.fromStrict hmv6_put-            out = B16.encode (SHA512.hmac_lazy hmv6_key lut)+            SHA512.MAC mac = SHA512.hmac_lazy hmv6_key lut+            out = B16.encode mac         assertEqual mempty hmv6_pec out     , testCase "hmv7" $ do         let lut = BL.fromStrict hmv7_put-            out = B16.encode (SHA512.hmac_lazy hmv7_key lut)+            SHA512.MAC mac = SHA512.hmac_lazy hmv7_key lut+            out = B16.encode mac         assertEqual mempty hmv7_pec out     ]   ]@@ -229,12 +236,14 @@ cmp_hmac   :: String -> BS.ByteString -> BS.ByteString -> BS.ByteString -> TestTree cmp_hmac msg key put pec = testCase msg $ do-  let out = B16.encode (SHA512.hmac key put)+  let SHA512.MAC mac = SHA512.hmac key put+      out = B16.encode mac   assertEqual mempty pec out  cmp_hmac_lazy   :: String -> BS.ByteString -> BS.ByteString -> BS.ByteString -> TestTree cmp_hmac_lazy msg key (BL.fromStrict -> put) pec = testCase msg $ do-  let out = B16.encode (SHA512.hmac_lazy key put)+  let SHA512.MAC mac = SHA512.hmac_lazy key put+      out = B16.encode mac   assertEqual mempty pec out