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