{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE Trustworthy #-}

-- |
--
-- Module: LibSodium.Bindings.GenericHashing
-- Description: Direct bindings to the Blake2 hashing primitives of Libsodium.
-- Copyright: (C) Hécate Moonlight 2022
-- License: BSD-3-Clause
-- Maintainer: The Haskell Cryptography Group
-- Stability: Stable
-- Portability: GHC only
module LibSodium.Bindings.GenericHashing
  ( -- * Introduction
    -- $introduction

    -- * Operations
    CryptoGenericHashState
  , cryptoGenericHash
  , cryptoGenericHashKeyGen
  , withGenericHashState
  , withGenericHashStateOfSize
  , cryptoGenericHashInit
  , cryptoGenericHashUpdate
  , cryptoGenericHashFinal

    -- * Constants
  , cryptoGenericHashBytes
  , cryptoGenericHashBytesMin
  , cryptoGenericHashBytesMax
  , cryptoGenericHashKeyBytes
  , cryptoGenericHashKeyBytesMin
  , cryptoGenericHashKeyBytesMax
  , cryptoGenericHashStateBytes
  )
where

import Foreign (Ptr, allocaBytes)
import Foreign.C (CInt (CInt), CSize (CSize), CUChar, CULLong (CULLong))

-- $introduction
-- This API computes a fixed-length fingerprint for an arbitrarily long message.
-- It is backed by the [BLAKE2b](https://blake2.net) algorithm.
--
-- Sample use cases:
--
--   * File integrity checking
--   * Creating unique identifiers to index arbitrarily long data
--
-- ⚠️ Do not use this API module to hash passwords!
--
-- Whenever there is a @'Ptr' 'CryptoGenericHashState'@, it must point to enough memory
-- to hold the hash state.
-- This is at least 'cryptoGenericHashBytesMin', at most
-- 'cryptoGenericHashBytesMax', and should typically be 'cryptoGenericHashBytes'.
-- It is the caller's responsibility to ensure that this holds.

-- | Opaque tag representing the hash state struct @crypto_generichash_state@ used by the C API.
--
-- To use a 'CryptoGenericHashState', use 'withGenericHashState'.
--
-- @since 0.0.1.0
data CryptoGenericHashState

-- | This function allocates a 'CryptoGenericHashState' of size 'cryptoGenericHashBytes'.
-- If you want more control over the size of the hash state, use 'withGenericHashStateOfSize'.
--
-- ⚠️ Do not leak the 'CryptoGenericHashState' outside of the lambda,
-- otherwise you will point at deallocated memory!
--
-- @since 0.0.1.0
withGenericHashState :: (Ptr CryptoGenericHashState -> IO a) -> IO a
withGenericHashState :: forall a. (Ptr CryptoGenericHashState -> IO a) -> IO a
withGenericHashState Ptr CryptoGenericHashState -> IO a
action = CSize -> (Ptr CryptoGenericHashState -> IO a) -> IO a
forall a. CSize -> (Ptr CryptoGenericHashState -> IO a) -> IO a
withGenericHashStateOfSize CSize
cryptoGenericHashBytes Ptr CryptoGenericHashState -> IO a
action

-- | This function allocates a 'CryptoGenericHashState' of the desired size.
--
-- Use the following constants as parameter to this function:
--
--   * 'cryptoGenericHashBytesMin' (16U)
--   * 'cryptoGenericHashBytes' (32U)
--   * 'cryptoGenericHashBytesMax' (64U)
--
-- @since 0.0.1.0
withGenericHashStateOfSize :: CSize -> (Ptr CryptoGenericHashState -> IO a) -> IO a
withGenericHashStateOfSize :: forall a. CSize -> (Ptr CryptoGenericHashState -> IO a) -> IO a
withGenericHashStateOfSize CSize
size Ptr CryptoGenericHashState -> IO a
action = Int -> (Ptr CryptoGenericHashState -> IO a) -> IO a
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
size) Ptr CryptoGenericHashState -> IO a
action

-- | Put a fingerprint of the message (the @in@ parameter) of length @inlen@ into
-- the @out@ buffer.
-- The minimum recommended output size (@outlen@) is 'cryptoGenericHashBytes'.
-- However, for specific use cases, the size can be any value between 'cryptoGenericHashBytesMin' (included)
-- and 'cryptoGenericHashBytesMax' (included).
--
-- The @key@ parameter can be 'Foreign.nullPtr' and keylen can be 0. In this case, a message will always have the same fingerprint
-- But a key can also be specified. A message will always have the same fingerprint for a given key, but different
-- keys used to hash the same message are very likely to produce distinct fingerprints.
-- In particular, the key can be used to make sure that different applications generate different fingerprints even
-- if they process the same data.
--
-- The recommended key size is 'cryptoGenericHashKeyBytes' bytes.
--
-- However, the key size can be any value between 0 (included) and 'cryptoGenericHashKeyBytesMax' (included).
-- If the key is meant to be secret, the recommended minimum length is 'cryptoGenericHashKeyBytesMin'.
--
-- /See:/ [crypto_generichash()](https://doc.libsodium.org/hashing/generic_hashing#usage)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_generichash"
  cryptoGenericHash
    :: Ptr CUChar
    -- ^ @out@ parameter.
    -> CSize
    -- ^ @outlen@ parameter.
    -> Ptr CUChar
    -- ^ @in@ parameter.
    -> CULLong
    -- ^ @inlen@ parameter.
    -> Ptr CUChar
    -- ^ @key@ parameter.
    -> CSize
    -- ^ @keylen@ parameter.
    -> IO CInt
    -- ^ Returns 0 on success, -1 on error.

-- | Initialise a hash state with a key of a specified length, and
-- produce an output with the specified length in bytes.
--
-- The @'Ptr' 'CUChar'@ argument must point to enough memory to hold a key,
-- which must also be initialised.
-- This is at least 'cryptoGenericHashKeyBytesMin', at most
-- 'cryptoGenericHashKeyBytesMax', and should typically be 'cryptoGenericHashKeyBytes'.
-- It is the caller's responsibility to ensure that these hold.
--
-- /See:/ [crypto_generichash_init()](https://doc.libsodium.org/hashing/generic_hashing#usage)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_generichash_init"
  cryptoGenericHashInit
    :: Ptr CryptoGenericHashState
    -- ^ Pointer to the hash state
    -> Ptr CUChar
    -- ^ Pointer to a key
    -> CSize
    -- ^ Length of the key
    -> CSize
    -- ^ Length of the result
    -> IO CInt
    -- ^ Returns 0 on success, -1 on error.

-- | If you process a message in chunks, you can sequentially process each chunk by calling 'cryptoGenericHashUpdate'
-- by providing a pointer to the previously initialised state, a pointer to the input chunk,
-- and the length of the chunk in bytes.
--
-- /See:/ [crypto_generichash_update()](https://doc.libsodium.org/hashing/generic_hashing#usage)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_generichash_update"
  cryptoGenericHashUpdate
    :: Ptr CryptoGenericHashState
    -- ^ Pointer to the hash state
    -> Ptr CUChar
    -- ^ Pointer to a chunk to be processed
    -> CULLong
    -- ^ Length of the chunk in bytes
    -> IO CInt
    -- ^ Returns 0 on success, -1 on error.

-- | After processing everything you need with 'cryptoGenericHashUpdate', you can finalise the operation
-- with 'cryptoGenericHashFinal'.
--
-- /See:/ [crypto_generichash_final()](https://doc.libsodium.org/hashing/generic_hashing#usage)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_generichash_final"
  cryptoGenericHashFinal
    :: Ptr CryptoGenericHashState
    -- ^ The hash state used throughout the previous hashing operations.
    -> Ptr CUChar
    -- ^ The pointer to the resulting fingerprint.
    -> CSize
    -- ^ Size of the hash.
    -> IO CInt
    -- ^ Returns 0 on success, -1 if called twice.

-- | This function creates a key of the recommended length 'cryptoGenericHashKeyBytes'.
--
-- /See:/ [crypto_generichash_keygen()](https://doc.libsodium.org/hashing/generic_hashing#usage)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_generichash_keygen"
  cryptoGenericHashKeyGen
    :: Ptr CUChar
    -- ^ A pointer to the key
    -> IO ()

-- | Size of the generated hash.
--
-- /See:/ [crypto_generichash_BYTES](https://doc.libsodium.org/hashing/generic_hashing#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_generichash_BYTES"
  cryptoGenericHashBytes :: CSize

-- | Minimum size of a generated hash
--
-- /See:/ [crypto_generichash_BYTES_MIN](https://doc.libsodium.org/hashing/generic_hashing#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_generichash_BYTES_MIN"
  cryptoGenericHashBytesMin :: CSize

-- | Maximum size of a generated hash
--
-- /See:/ [crypto_generichash_BYTES_MAX](https://doc.libsodium.org/hashing/generic_hashing#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_generichash_BYTES_MAX"
  cryptoGenericHashBytesMax :: CSize

-- | Size of a generated key
--
-- /See:/ [crypto_generichash_KEYBYTES](https://doc.libsodium.org/hashing/generic_hashing#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_generichash_KEYBYTES"
  cryptoGenericHashKeyBytes :: CSize

-- | Minimum size of a generated key
--
-- /See:/ [crypto_generichash_KEYBYTES_MIN](https://doc.libsodium.org/hashing/generic_hashing#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_generichash_KEYBYTES_MIN"
  cryptoGenericHashKeyBytesMin :: CSize

-- | Maximum size of a generated key
--
-- /See:/ [crypto_generichash_KEYBYTES_MAX](https://doc.libsodium.org/hashing/generic_hashing#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_generichash_KEYBYTES_MAX"
  cryptoGenericHashKeyBytesMax :: CSize

-- | Size of a 'CryptoGenericHashState'
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_generichash_blake2b_statebytes"
  cryptoGenericHashStateBytes :: CSize