    module Crypto.Random.DRBG.HashDF where

    import qualified Data.ByteString as B
    import qualified Data.ByteString.Lazy as L
    import Crypto.Classes
    import Data.Serialize (encode)
    import Data.Serialize.Put (runPut, putWord32be)
    import Data.Word (Word8, Word32)
    import Crypto.Random.DRBG.Types

    -- Section 10.4.1, pg 65
    hash_df :: Hash c d => (L.ByteString -> d) -> B.ByteString -> BitLen -> B.ByteString
    hash_df :: (ByteString -> d) -> ByteString -> BitLen -> ByteString
    hash_df hashF :: ByteString -> d
    hashF str :: ByteString
    str reqBits :: BitLen
    reqBits = BitLen -> ByteString -> ByteString
    B.take BitLen
    reqBytes (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ ByteString -> Word8 -> ByteString
    getT ByteString
    B.empty (1 :: Word8)
      where
      reqBytes :: BitLen
    reqBytes = BitLen
    reqBits BitLen -> BitLen -> BitLen
    forall a. Integral a => a -> a -> a
    `div` 8
      outlen :: BitLen
    outlen = Tagged d BitLen
    forall ctx d. Hash ctx d => Tagged d BitLen
    outputLength  Tagged d BitLen -> d -> BitLen
    forall a b. Tagged a b -> a -> b
    .::. (ByteString -> d
    hashF ByteString
    forall a. HasCallStack => a
    undefined)
      hash :: ByteString -> ByteString
    hash = d -> ByteString
    forall a. Serialize a => a -> ByteString
    encode (d -> ByteString) -> (ByteString -> d) -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> d
    hashF (ByteString -> d) -> (ByteString -> ByteString) -> ByteString -> d
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ByteString] -> ByteString
    L.fromChunks ([ByteString] -> ByteString)
    -> (ByteString -> [ByteString]) -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . \x :: ByteString
    x -> [ByteString
    x]
      getT :: ByteString -> Word8 -> ByteString
    getT tmp :: ByteString
    tmp cnt :: Word8
    cnt
            | ByteString -> BitLen
    B.length ByteString
    tmp BitLen -> BitLen -> Bool
    forall a. Ord a => a -> a -> Bool
    >= BitLen
    reqBytes = ByteString
    tmp
            | Bool
    otherwise = let new :: ByteString
    new = ByteString -> ByteString
    hash ([ByteString] -> ByteString
    B.concat [Word8 -> ByteString
    B.singleton Word8
    cnt, ByteString
    reqBitsBS, ByteString
    str]) in ByteString -> Word8 -> ByteString
    getT (ByteString -> ByteString -> ByteString
    B.append ByteString
    tmp ByteString
    new) (Word8
    cnt Word8 -> Word8 -> Word8
    forall a. Num a => a -> a -> a
    + 1)
      len :: BitLen
    len = (if BitLen
    reqBits BitLen -> BitLen -> BitLen
    forall a. Integral a => a -> a -> a
    `rem` BitLen
    outlen BitLen -> BitLen -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0 then BitLen
    reqBits BitLen -> BitLen -> BitLen
    forall a. Integral a => a -> a -> a
    `div` BitLen
    outlen else (BitLen
    reqBits BitLen -> BitLen -> BitLen
    forall a. Num a => a -> a -> a
    + BitLen
    outlen) BitLen -> BitLen -> BitLen
    forall a. Integral a => a -> a -> a
    `div` BitLen
    outlen)
      reqBitsBS :: ByteString
    reqBitsBS = Put -> ByteString
    runPut (Put -> ByteString) -> Put -> ByteString
    forall a b. (a -> b) -> a -> b
    $ Putter Word32
    putWord32be (BitLen -> Word32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral BitLen
    reqBits :: Word32)