ppad-hmac-drbg 0.1.3 → 0.2.0
raw patch · 5 files changed
+39/−17 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Crypto.DRBG.HMAC: MaxBytesExceeded :: Error
+ Crypto.DRBG.HMAC: ReseedRequired :: Error
+ Crypto.DRBG.HMAC: data Error
+ Crypto.DRBG.HMAC: instance GHC.Classes.Eq Crypto.DRBG.HMAC.Error
+ Crypto.DRBG.HMAC: instance GHC.Show.Show Crypto.DRBG.HMAC.Error
- Crypto.DRBG.HMAC: gen :: PrimMonad m => ByteString -> Word64 -> DRBG (PrimState m) -> m ByteString
+ Crypto.DRBG.HMAC: gen :: PrimMonad m => ByteString -> Word64 -> DRBG (PrimState m) -> m (Either Error ByteString)
Files
- CHANGELOG +8/−0
- bench/Main.hs +4/−4
- lib/Crypto/DRBG/HMAC.hs +24/−10
- ppad-hmac-drbg.cabal +1/−1
- test/Main.hs +2/−2
CHANGELOG view
@@ -1,5 +1,13 @@ # Changelog +- 0.2.0 (2026-01-10)+ * In order to better-match the spec, 'gen' now returns an+ 'Either Error BS.ByteString'. The new 'Error' value is returned+ either in the exceptionally rare case that the DRBG needs a reseed+ (previously this was just "error <msg>"), or, more likely to occur+ in practice, if more than 65536 bytes are requested from the DRBG at+ a time.+ - 0.1.3 (2025-12-28) * Adds an 'llvm' build flag and tests with GHC 9.10.3.
bench/Main.hs view
@@ -22,14 +22,14 @@ bgroup "HMAC-SHA256" [ bench "new" $ whnfAppIO (DRBG.new SHA256.hmac mempty mempty) mempty , bench "reseed" $ whnfAppIO (DRBG.reseed mempty mempty) drbg256- , bench "gen (32B)" $ nfAppIO (DRBG.gen mempty 32) drbg256- , bench "gen (256B)" $ nfAppIO (DRBG.gen mempty 256) drbg256+ , bench "gen (32B)" $ whnfAppIO (DRBG.gen mempty 32) drbg256+ , bench "gen (256B)" $ whnfAppIO (DRBG.gen mempty 256) drbg256 ] , bgroup "HMAC-SHA512" [ bench "new" $ whnfAppIO (DRBG.new SHA512.hmac mempty mempty) mempty , bench "reseed" $ whnfAppIO (DRBG.reseed mempty mempty) drbg512- , bench "gen (32B)" $ nfAppIO (DRBG.gen mempty 32) drbg512- , bench "gen (256B)" $ nfAppIO (DRBG.gen mempty 256) drbg512+ , bench "gen (32B)" $ whnfAppIO (DRBG.gen mempty 32) drbg512+ , bench "gen (256B)" $ whnfAppIO (DRBG.gen mempty 256) drbg512 ] ]
lib/Crypto/DRBG/HMAC.hs view
@@ -14,9 +14,10 @@ module Crypto.DRBG.HMAC ( -- * DRBG and HMAC function types DRBG+ , HMAC+ , Error(..) , _read_v , _read_k- , HMAC -- * DRBG interaction , new@@ -53,6 +54,12 @@ -- types ---------------------------------------------------------------------- +-- | A DRBG error.+data Error =+ MaxBytesExceeded -- ^ More than 65536 bytes have been requested.+ | ReseedRequired -- ^ The DRBG must be reseeded (via 'reseed').+ deriving (Eq, Show)+ -- see SP 800-90A table 2 _RESEED_COUNTER :: Word64 _RESEED_COUNTER = (2 :: Word64) ^ (48 :: Word64)@@ -143,10 +150,14 @@ -- | Generate bytes from a DRBG, optionally injecting additional bytes -- per SP 800-90A. --+-- Per SP 800-90A, the maximum number of bytes that can be requested+-- on any invocation is 65536. Larger requests will return+-- 'MaxBytesExceeded'.+-- -- >>> import qualified Data.ByteString.Base16 as B16 -- >>> drbg <- new SHA256.hmac entropy nonce personalization_string--- >>> bytes0 <- gen addl_bytes 16 drbg--- >>> bytes1 <- gen addl_bytes 16 drbg+-- >>> Right bytes0 <- gen addl_bytes 16 drbg+-- >>> Right bytes1 <- gen addl_bytes 16 drbg -- >>> B16.encode bytes0 -- "938d6ca6d0b797f7b3c653349d6e3135" -- >>> B16.encode bytes1@@ -156,12 +167,14 @@ => BS.ByteString -- ^ additional bytes to inject -> Word64 -- ^ number of bytes to generate -> DRBG (PrimState m)- -> m BS.ByteString+ -> m (Either Error BS.ByteString) gen addl bytes (DRBG mut) = do drbg0 <- P.readMutVar mut- let !(Pair bs drbg1) = gen_pure addl bytes drbg0- P.writeMutVar mut drbg1- pure bs+ case gen_pure addl bytes drbg0 of+ Left e -> pure (Left e)+ Right !(Pair bs drbg1) -> do+ P.writeMutVar mut drbg1+ pure (Right bs) -- | Reseed a DRBG. --@@ -237,14 +250,15 @@ :: BS.ByteString -> Word64 -> DRBGState- -> Pair BS.ByteString DRBGState+ -> Either Error (Pair BS.ByteString DRBGState) gen_pure addl bytes drbg0@(DRBGState h@(HMACEnv hmac outlen) _ _ _)- | r > _RESEED_COUNTER = error "ppad-hmac-drbg: reseed required"+ | bytes > 0x10000 = Left MaxBytesExceeded+ | r > _RESEED_COUNTER = Left ReseedRequired | otherwise = let !(Pair temp drbg1) = loop mempty 0 v1 returned_bits = BS.take (fi bytes) temp drbg = update_pure addl drbg1- in Pair returned_bits drbg+ in Right (Pair returned_bits drbg) where !(DRBGState _ r v1 k1) | BS.null addl = drbg0
ppad-hmac-drbg.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: ppad-hmac-drbg-version: 0.1.3+version: 0.2.0 synopsis: HMAC-based deterministic random bit generator license: MIT license-file: LICENSE
test/Main.hs view
@@ -103,7 +103,7 @@ assertEqual "k0" k0 caseK0 DRBG.reseed caseEntropy1 caseAddl1 drbg- _ <- DRBG.gen mempty bytes drbg+ Right _ <- DRBG.gen mempty bytes drbg v1 <- DRBG._read_v drbg k1 <- DRBG._read_k drbg @@ -111,7 +111,7 @@ assertEqual "k1" k1 caseK1 DRBG.reseed caseEntropy2 caseAddl2 drbg- returned <- DRBG.gen mempty bytes drbg+ Right returned <- DRBG.gen mempty bytes drbg v2 <- DRBG._read_v drbg k2 <- DRBG._read_k drbg