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 :: forall c d.
Hash c d =>
(ByteString -> d) -> ByteString -> BitLen -> ByteString
hash_df ByteString -> d
hashF ByteString
str 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 (Word8
1 :: Word8)
  where
  reqBytes :: BitLen
reqBytes = BitLen
reqBits BitLen -> BitLen -> BitLen
forall a. Integral a => a -> a -> a
`div` BitLen
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
. \ByteString
x -> [ByteString
x]
  getT :: ByteString -> Word8 -> ByteString
getT ByteString
tmp 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
+ Word8
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
== BitLen
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)