    -- |
    -- Module      : Data.ByteArray.Hash
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : good
    --
    -- provide the SipHash algorithm.
    -- reference: <http://131002.net/siphash/siphash.pdf>
    --
    {-# LANGUAGE BangPatterns #-}
    module Data.ByteArray.Hash
        (
        -- * SipHash
          SipKey(..)
        , SipHash(..)
        , sipHash
        , sipHashWith
        -- * FNV1 and FNV1a (32 and 64 bits)
        , FnvHash32(..)
        , FnvHash64(..)
        , fnv1Hash
        , fnv1aHash
        , fnv1_64Hash
        , fnv1a_64Hash
        ) where

    import           Data.Memory.Internal.Compat
    import           Data.Memory.Hash.SipHash
    import           Data.Memory.Hash.FNV
    import qualified Data.ByteArray.Types   as B

    -- | Compute the SipHash tag of a byte array for a given key.
    --
    -- 'sipHash` is equivalent to 'sipHashWith 2 4'
    sipHash :: B.ByteArrayAccess ba
            => SipKey
            -> ba
            -> SipHash
    sipHash :: forall ba. ByteArrayAccess ba => SipKey -> ba -> SipHash
    sipHash SipKey
    key ba
    ba = IO SipHash -> SipHash
    forall a. IO a -> a
    unsafeDoIO (IO SipHash -> SipHash) -> IO SipHash -> SipHash
    forall a b. (a -> b) -> a -> b
    $ ba -> (Ptr Word8 -> IO SipHash) -> IO SipHash
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    B.withByteArray ba
    ba ((Ptr Word8 -> IO SipHash) -> IO SipHash)
    -> (Ptr Word8 -> IO SipHash) -> IO SipHash
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    p -> SipKey -> Ptr Word8 -> Int -> IO SipHash
    hash SipKey
    key Ptr Word8
    p (ba -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length ba
    ba)

    -- | Compute the SipHash tag of a byte array for a given key.
    --
    -- The user can choose the C and D numbers of rounds.
    --
    -- calling 'sipHash` is equivalent to 'sipHashWith 2 4'
    sipHashWith :: B.ByteArrayAccess ba
                => Int    -- ^ c rounds
                -> Int    -- ^ d rounds
                -> SipKey -- ^ key
                -> ba     -- ^ data to hash
                -> SipHash
    sipHashWith :: forall ba.
    ByteArrayAccess ba =>
    Int -> Int -> SipKey -> ba -> SipHash
    sipHashWith Int
    c Int
    d SipKey
    key ba
    ba = IO SipHash -> SipHash
    forall a. IO a -> a
    unsafeDoIO (IO SipHash -> SipHash) -> IO SipHash -> SipHash
    forall a b. (a -> b) -> a -> b
    $ ba -> (Ptr Word8 -> IO SipHash) -> IO SipHash
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    B.withByteArray ba
    ba ((Ptr Word8 -> IO SipHash) -> IO SipHash)
    -> (Ptr Word8 -> IO SipHash) -> IO SipHash
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    p -> Int -> Int -> SipKey -> Ptr Word8 -> Int -> IO SipHash
    hashWith Int
    c Int
    d SipKey
    key Ptr Word8
    p (ba -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length ba
    ba)

    -- | Compute the FNV1 32 bit hash value of a byte array
    fnv1Hash :: B.ByteArrayAccess ba
             => ba
             -> FnvHash32
    fnv1Hash :: forall ba. ByteArrayAccess ba => ba -> FnvHash32
    fnv1Hash ba
    ba = IO FnvHash32 -> FnvHash32
    forall a. IO a -> a
    unsafeDoIO (IO FnvHash32 -> FnvHash32) -> IO FnvHash32 -> FnvHash32
    forall a b. (a -> b) -> a -> b
    $ ba -> (Ptr Word8 -> IO FnvHash32) -> IO FnvHash32
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    B.withByteArray ba
    ba ((Ptr Word8 -> IO FnvHash32) -> IO FnvHash32)
    -> (Ptr Word8 -> IO FnvHash32) -> IO FnvHash32
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    p -> Ptr Word8 -> Int -> IO FnvHash32
    fnv1 Ptr Word8
    p (ba -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length ba
    ba)

    -- | Compute the FNV1a 32 bit hash value of a byte array
    fnv1aHash :: B.ByteArrayAccess ba
              => ba
              -> FnvHash32
    fnv1aHash :: forall ba. ByteArrayAccess ba => ba -> FnvHash32
    fnv1aHash ba
    ba = IO FnvHash32 -> FnvHash32
    forall a. IO a -> a
    unsafeDoIO (IO FnvHash32 -> FnvHash32) -> IO FnvHash32 -> FnvHash32
    forall a b. (a -> b) -> a -> b
    $ ba -> (Ptr Word8 -> IO FnvHash32) -> IO FnvHash32
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    B.withByteArray ba
    ba ((Ptr Word8 -> IO FnvHash32) -> IO FnvHash32)
    -> (Ptr Word8 -> IO FnvHash32) -> IO FnvHash32
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    p -> Ptr Word8 -> Int -> IO FnvHash32
    fnv1a Ptr Word8
    p (ba -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length ba
    ba)

    -- | Compute the FNV1 64 bit hash value of a byte array
    fnv1_64Hash :: B.ByteArrayAccess ba
                => ba
                -> FnvHash64
    fnv1_64Hash :: forall ba. ByteArrayAccess ba => ba -> FnvHash64
    fnv1_64Hash ba
    ba = IO FnvHash64 -> FnvHash64
    forall a. IO a -> a
    unsafeDoIO (IO FnvHash64 -> FnvHash64) -> IO FnvHash64 -> FnvHash64
    forall a b. (a -> b) -> a -> b
    $ ba -> (Ptr Word8 -> IO FnvHash64) -> IO FnvHash64
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    B.withByteArray ba
    ba ((Ptr Word8 -> IO FnvHash64) -> IO FnvHash64)
    -> (Ptr Word8 -> IO FnvHash64) -> IO FnvHash64
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    p -> Ptr Word8 -> Int -> IO FnvHash64
    fnv1_64 Ptr Word8
    p (ba -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length ba
    ba)

    -- | Compute the FNV1a 64 bit hash value of a byte array
    fnv1a_64Hash :: B.ByteArrayAccess ba
                 => ba
                 -> FnvHash64
    fnv1a_64Hash :: forall ba. ByteArrayAccess ba => ba -> FnvHash64
    fnv1a_64Hash ba
    ba = IO FnvHash64 -> FnvHash64
    forall a. IO a -> a
    unsafeDoIO (IO FnvHash64 -> FnvHash64) -> IO FnvHash64 -> FnvHash64
    forall a b. (a -> b) -> a -> b
    $ ba -> (Ptr Word8 -> IO FnvHash64) -> IO FnvHash64
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    B.withByteArray ba
    ba ((Ptr Word8 -> IO FnvHash64) -> IO FnvHash64)
    -> (Ptr Word8 -> IO FnvHash64) -> IO FnvHash64
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    p -> Ptr Word8 -> Int -> IO FnvHash64
    fnv1a_64 Ptr Word8
    p (ba -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length ba
    ba)