module Crypto.Hash.SHAKE
( SHAKE128 (..), SHAKE256 (..)
) where
import Crypto.Hash.Types
import Foreign.Ptr (Ptr)
import Data.Typeable
import Data.Word (Word8, Word32)
import Data.Proxy (Proxy(..))
import GHC.TypeLits (Nat, KnownNat, natVal)
import Crypto.Internal.Nat
data SHAKE128 (bitlen :: Nat) = SHAKE128
deriving (Show, Typeable)
instance (IsDivisibleBy8 bitLen, KnownNat bitLen) => HashAlgorithm (SHAKE128 bitLen) where
hashBlockSize _ = 168
hashDigestSize _ = byteLen (Proxy :: Proxy bitLen)
hashInternalContextSize _ = 376
hashInternalInit p = c_sha3_init p 128
hashInternalUpdate = c_sha3_update
hashInternalFinalize = shakeFinalizeOutput (Proxy :: Proxy bitLen)
data SHAKE256 (bitlen :: Nat) = SHAKE256
deriving (Show, Typeable)
instance (IsDivisibleBy8 bitLen, KnownNat bitLen) => HashAlgorithm (SHAKE256 bitLen) where
hashBlockSize _ = 136
hashDigestSize _ = byteLen (Proxy :: Proxy bitLen)
hashInternalContextSize _ = 344
hashInternalInit p = c_sha3_init p 256
hashInternalUpdate = c_sha3_update
hashInternalFinalize = shakeFinalizeOutput (Proxy :: Proxy bitLen)
shakeFinalizeOutput :: (IsDivisibleBy8 bitLen, KnownNat bitLen)
=> proxy bitLen
-> Ptr (Context a)
-> Ptr (Digest a)
-> IO ()
shakeFinalizeOutput d ctx dig = do
c_sha3_finalize_shake ctx
c_sha3_output ctx dig (fromInteger (natVal d `div` 8))
byteLen :: (KnownNat bitlen, IsDivisibleBy8 bitlen, Num a) => proxy bitlen -> a
byteLen d = fromInteger (natVal d `div` 8)
foreign import ccall unsafe "cryptonite_sha3_init"
c_sha3_init :: Ptr (Context a) -> Word32 -> IO ()
foreign import ccall "cryptonite_sha3_update"
c_sha3_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_sha3_finalize_shake"
c_sha3_finalize_shake :: Ptr (Context a) -> IO ()
foreign import ccall unsafe "cryptonite_sha3_output"
c_sha3_output :: Ptr (Context a) -> Ptr (Digest a) -> Word32 -> IO ()