1-- |
2-- Module      : Crypto.Hash.SHAKE
3-- License     : BSD-style
4-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
5-- Stability   : experimental
6-- Portability : unknown
7--
8-- Module containing the binding functions to work with the
9-- SHA3 extendable output functions (SHAKE).
10--
11{-# LANGUAGE ForeignFunctionInterface #-}
12{-# LANGUAGE DeriveDataTypeable #-}
13{-# LANGUAGE KindSignatures #-}
14{-# LANGUAGE DataKinds #-}
15{-# LANGUAGE ScopedTypeVariables #-}
16{-# LANGUAGE TypeOperators #-}
17{-# LANGUAGE TypeFamilies #-}
18{-# LANGUAGE UndecidableInstances #-}
19module Crypto.Hash.SHAKE
20    (  SHAKE128 (..), SHAKE256 (..), HashSHAKE (..)
21    ) where
22
23import           Control.Monad (when)
24import           Crypto.Hash.Types
25import           Foreign.Ptr (Ptr, castPtr)
26import           Foreign.Storable (Storable(..))
27import           Data.Bits
28import           Data.Data
29import           Data.Word (Word8, Word32)
30
31import           GHC.TypeLits (Nat, KnownNat, type (+))
32import           Crypto.Internal.Nat
33
34-- | Type class of SHAKE algorithms.
35class HashAlgorithm a => HashSHAKE a where
36    -- | Alternate finalization needed for cSHAKE
37    cshakeInternalFinalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
38    -- | Get the digest bit length
39    cshakeOutputLength :: a -> Int
40
41-- | SHAKE128 (128 bits) extendable output function.  Supports an arbitrary
42-- digest size, to be specified as a type parameter of kind 'Nat'.
43--
44-- Note: outputs from @'SHAKE128' n@ and @'SHAKE128' m@ for the same input are
45-- correlated (one being a prefix of the other).  Results are unrelated to
46-- 'SHAKE256' results.
47data SHAKE128 (bitlen :: Nat) = SHAKE128
48    deriving (Show, Data)
49
50instance KnownNat bitlen => HashAlgorithm (SHAKE128 bitlen) where
51    type HashBlockSize           (SHAKE128 bitlen)  = 168
52    type HashDigestSize          (SHAKE128 bitlen) = Div8 (bitlen + 7)
53    type HashInternalContextSize (SHAKE128 bitlen) = 376
54    hashBlockSize  _          = 168
55    hashDigestSize _          = byteLen (Proxy :: Proxy bitlen)
56    hashInternalContextSize _ = 376
57    hashInternalInit p        = c_sha3_init p 128
58    hashInternalUpdate        = c_sha3_update
59    hashInternalFinalize      = shakeFinalizeOutput (Proxy :: Proxy bitlen)
60
61instance KnownNat bitlen => HashSHAKE (SHAKE128 bitlen) where
62    cshakeInternalFinalize = cshakeFinalizeOutput (Proxy :: Proxy bitlen)
63    cshakeOutputLength _ = integralNatVal (Proxy :: Proxy bitlen)
64
65-- | SHAKE256 (256 bits) extendable output function.  Supports an arbitrary
66-- digest size, to be specified as a type parameter of kind 'Nat'.
67--
68-- Note: outputs from @'SHAKE256' n@ and @'SHAKE256' m@ for the same input are
69-- correlated (one being a prefix of the other).  Results are unrelated to
70-- 'SHAKE128' results.
71data SHAKE256 (bitlen :: Nat) = SHAKE256
72    deriving (Show, Data)
73
74instance KnownNat bitlen => HashAlgorithm (SHAKE256 bitlen) where
75    type HashBlockSize           (SHAKE256 bitlen) = 136
76    type HashDigestSize          (SHAKE256 bitlen) = Div8 (bitlen + 7)
77    type HashInternalContextSize (SHAKE256 bitlen) = 344
78    hashBlockSize  _          = 136
79    hashDigestSize _          = byteLen (Proxy :: Proxy bitlen)
80    hashInternalContextSize _ = 344
81    hashInternalInit p        = c_sha3_init p 256
82    hashInternalUpdate        = c_sha3_update
83    hashInternalFinalize      = shakeFinalizeOutput (Proxy :: Proxy bitlen)
84
85instance KnownNat bitlen => HashSHAKE (SHAKE256 bitlen) where
86    cshakeInternalFinalize = cshakeFinalizeOutput (Proxy :: Proxy bitlen)
87    cshakeOutputLength _ = integralNatVal (Proxy :: Proxy bitlen)
88
89shakeFinalizeOutput :: KnownNat bitlen
90                    => proxy bitlen
91                    -> Ptr (Context a)
92                    -> Ptr (Digest a)
93                    -> IO ()
94shakeFinalizeOutput d ctx dig = do
95    c_sha3_finalize_shake ctx
96    c_sha3_output ctx dig (byteLen d)
97    shakeTruncate d (castPtr dig)
98
99cshakeFinalizeOutput :: KnownNat bitlen
100                     => proxy bitlen
101                     -> Ptr (Context a)
102                     -> Ptr (Digest a)
103                     -> IO ()
104cshakeFinalizeOutput d ctx dig = do
105    c_sha3_finalize_cshake ctx
106    c_sha3_output ctx dig (byteLen d)
107    shakeTruncate d (castPtr dig)
108
109shakeTruncate :: KnownNat bitlen => proxy bitlen -> Ptr Word8 -> IO ()
110shakeTruncate d ptr =
111    when (bits > 0) $ do
112        byte <- peekElemOff ptr index
113        pokeElemOff ptr index (byte .&. mask)
114  where
115    mask = (1 `shiftL` bits) - 1
116    (index, bits) = integralNatVal d `divMod` 8
117
118foreign import ccall unsafe "cryptonite_sha3_init"
119    c_sha3_init :: Ptr (Context a) -> Word32 -> IO ()
120
121foreign import ccall "cryptonite_sha3_update"
122    c_sha3_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
123
124foreign import ccall unsafe "cryptonite_sha3_finalize_shake"
125    c_sha3_finalize_shake :: Ptr (Context a) -> IO ()
126
127foreign import ccall unsafe "cryptonite_sha3_finalize_cshake"
128    c_sha3_finalize_cshake :: Ptr (Context a) -> IO ()
129
130foreign import ccall unsafe "cryptonite_sha3_output"
131    c_sha3_output :: Ptr (Context a) -> Ptr (Digest a) -> Word32 -> IO ()
132