{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Cardano.Crypto.Libsodium.C (
  -- * Initialization
  c_sodium_init,

  -- * Memory management
  c_sodium_memzero,
  c_sodium_malloc,
  c_sodium_free,
  c_sodium_free_funptr,
  c_sodium_mlock,
  c_sodium_munlock,

  -- * Hashing

  -- ** SHA256
  c_crypto_hash_sha256,
  c_crypto_hash_sha256_final,
  c_crypto_hash_sha256_init,
  c_crypto_hash_sha256_update,

  -- ** Blake2b 256
  c_crypto_generichash_blake2b,
  c_crypto_generichash_blake2b_final,
  c_crypto_generichash_blake2b_init,
  c_crypto_generichash_blake2b_update,

  -- * ED25519
  c_crypto_sign_ed25519_seed_keypair,
  c_crypto_sign_ed25519_sk_to_seed,
  c_crypto_sign_ed25519_detached,
  c_crypto_sign_ed25519_verify_detached,
  c_crypto_sign_ed25519_sk_to_pk,

  -- * RNG
  c_sodium_randombytes_buf,

  -- * Helpers
  c_sodium_compare,

  -- * Constants
  CRYPTO_SHA256_BYTES,
  CRYPTO_SHA512_BYTES,
  CRYPTO_BLAKE2B_256_BYTES,
  CRYPTO_SHA256_STATE_SIZE,
  CRYPTO_SHA512_STATE_SIZE,
  CRYPTO_BLAKE2B_256_STATE_SIZE,
  CRYPTO_SIGN_ED25519_BYTES,
  CRYPTO_SIGN_ED25519_SEEDBYTES,
  CRYPTO_SIGN_ED25519_PUBLICKEYBYTES,
  CRYPTO_SIGN_ED25519_SECRETKEYBYTES,
) where

import Foreign.C.Types
import Foreign.Ptr (FunPtr, Ptr)

import Cardano.Crypto.Libsodium.Constants
import Cardano.Foreign

-------------------------------------------------------------------------------
-- Initialization
-------------------------------------------------------------------------------

-- | @void sodium_init();@
--
-- <https://libsodium.gitbook.io/doc/usage>
foreign import capi "sodium.h sodium_init" c_sodium_init :: IO Int

-------------------------------------------------------------------------------
-- Memory management
-------------------------------------------------------------------------------

-- | @void sodium_memzero(void * const pnt, const size_t len);@
--
-- <https://libsodium.gitbook.io/doc/memory_management#zeroing-memory>
foreign import capi unsafe "sodium.h sodium_memzero" c_sodium_memzero :: Ptr a -> CSize -> IO ()

-- | @void *sodium_malloc(size_t size);@
--
-- <https://libsodium.gitbook.io/doc/memory_management>
foreign import capi unsafe "sodium.h sodium_malloc" c_sodium_malloc :: CSize -> IO (Ptr a)

--

-- | @void sodium_free(void *ptr);@
--
-- <https://libsodium.gitbook.io/doc/memory_management>
foreign import capi unsafe "sodium.h sodium_free" c_sodium_free :: Ptr a -> IO ()

-- | @void sodium_free(void *ptr);@
--
-- <https://libsodium.gitbook.io/doc/memory_management>
foreign import capi unsafe "sodium.h &sodium_free" c_sodium_free_funptr :: FunPtr (Ptr a -> IO ())

-- | @void *sodium_mlock(void * const addr, size_t size);@
--
-- <https://libsodium.gitbook.io/doc/memory_management>
foreign import capi unsafe "sodium.h sodium_mlock" c_sodium_mlock :: Ptr a -> CSize -> IO CInt

-- | @void *sodium_munlock(void * const addr, size_t size);@
--
-- <https://libsodium.gitbook.io/doc/memory_management>
foreign import capi unsafe "sodium.h sodium_munlock" c_sodium_munlock :: Ptr a -> CSize -> IO CInt

-------------------------------------------------------------------------------
-- Hashing: SHA256
-------------------------------------------------------------------------------

-- | @int crypto_hash_sha256(unsigned char *out, const unsigned char *in, unsigned long long inlen);@
--
-- <https://libsodium.gitbook.io/doc/advanced/sha-2_hash_function>
foreign import capi unsafe "sodium.h crypto_hash_sha256"
  c_crypto_hash_sha256 :: SizedPtr CRYPTO_SHA256_BYTES -> Ptr CUChar -> CULLong -> IO Int

-- | @int crypto_hash_sha256_init(crypto_hash_sha256_state *state);@
foreign import capi unsafe "sodium.h crypto_hash_sha256_init"
  c_crypto_hash_sha256_init :: SizedPtr CRYPTO_SHA256_STATE_SIZE -> IO Int

-- | @int crypto_hash_sha256_update(crypto_hash_sha256_state *state, const unsigned char *in, unsigned long long inlen);@
foreign import capi unsafe "sodium.h crypto_hash_sha256_update"
  c_crypto_hash_sha256_update :: SizedPtr CRYPTO_SHA256_STATE_SIZE -> Ptr CUChar -> CULLong -> IO Int

-- | @int crypto_hash_sha256_final(crypto_hash_sha256_state *state, unsigned char *out);@
foreign import capi unsafe "sodium.h crypto_hash_sha256_final"
  c_crypto_hash_sha256_final ::
    SizedPtr CRYPTO_SHA256_STATE_SIZE -> SizedPtr CRYPTO_SHA256_BYTES -> IO Int

-------------------------------------------------------------------------------
-- Hashing: Blake2b
-------------------------------------------------------------------------------

-- | @int crypto_generichash_blake2b(unsigned char *out, size_t outlen, const unsigned char *in, unsigned long long inlen, const unsigned char *key, size_t keylen);@
--
-- <https://libsodium.gitbook.io/doc/hashing/generic_hashing>
foreign import capi unsafe "sodium.h crypto_generichash_blake2b"
  c_crypto_generichash_blake2b ::
    Ptr out ->
    CSize ->
    Ptr CUChar ->
    CULLong ->
    Ptr key ->
    CSize ->
    IO Int

-- | @int crypto_generichash_blake2b_init(crypto_generichash_blake2b_state *state, const unsigned char *key, const size_t keylen, const size_t outlen);@
foreign import capi unsafe "sodium.h crypto_generichash_blake2b_init"
  c_crypto_generichash_blake2b_init ::
    SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr key -> CSize -> CSize -> IO Int

-- | @int crypto_generichash_blake2b_update(crypto_generichash_blake2b_state *state, const unsigned char *in, unsigned long long inlen);@
foreign import capi unsafe "sodium.h crypto_generichash_blake2b_update"
  c_crypto_generichash_blake2b_update ::
    SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr CUChar -> CULLong -> IO Int

-- | @int crypto_generichash_blake2b_final(crypto_generichash_blake2b_state *state, unsigned char *out, const size_t outlen);@
foreign import capi unsafe "sodium.h crypto_generichash_blake2b_final"
  c_crypto_generichash_blake2b_final ::
    SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr out -> CSize -> IO Int

-------------------------------------------------------------------------------
-- Signing: ED25519
-------------------------------------------------------------------------------

-- https://github.com/jedisct1/libsodium/blob/7b67cd1b32915bc957d750e7a15229f2a938ff1a/src/libsodium/include/sodium/crypto_sign_ed25519.h

-- | @int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed);@
foreign import capi unsafe "sodium.h crypto_sign_ed25519_seed_keypair"
  c_crypto_sign_ed25519_seed_keypair ::
    SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES ->
    SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES ->
    SizedPtr CRYPTO_SIGN_ED25519_SEEDBYTES ->
    IO Int

-- | @int crypto_sign_ed25519_sk_to_seed(unsigned char *seed, const unsigned char *sk);@
foreign import capi unsafe "sodium.h crypto_sign_ed25519_sk_to_seed"
  c_crypto_sign_ed25519_sk_to_seed ::
    SizedPtr CRYPTO_SIGN_ED25519_SEEDBYTES ->
    SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES ->
    IO Int

-- | @int crypto_sign_ed25519_detached(unsigned char *sig, unsigned long long *siglen_p, const unsigned char *m, unsigned long long mlen, const unsigned char *sk);@
foreign import capi unsafe "sodium.h crypto_sign_ed25519_detached"
  c_crypto_sign_ed25519_detached ::
    SizedPtr CRYPTO_SIGN_ED25519_BYTES ->
    Ptr CULLong ->
    Ptr CUChar ->
    CULLong ->
    SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES ->
    IO Int

-- | @int crypto_sign_ed25519_verify_detached(const unsigned char *sig, const unsigned char *m, unsigned long long mlen, const unsigned char *pk);@
foreign import capi unsafe "sodium.h crypto_sign_ed25519_verify_detached"
  c_crypto_sign_ed25519_verify_detached ::
    SizedPtr CRYPTO_SIGN_ED25519_BYTES ->
    Ptr CUChar ->
    CULLong ->
    SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES ->
    IO Int

-- | @int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk);@
foreign import capi unsafe "sodium.h crypto_sign_ed25519_sk_to_pk"
  c_crypto_sign_ed25519_sk_to_pk ::
    SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES ->
    SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES ->
    IO Int

-------------------------------------------------------------------------------
-- Helpers
-------------------------------------------------------------------------------

-- | @int sodium_compare(const void * const b1_, const void * const b2_, size_t len);@
--
-- <https://libsodium.gitbook.io/doc/helpers#comparing-large-numbers>
foreign import capi unsafe "sodium.h sodium_compare"
  c_sodium_compare :: Ptr a -> Ptr a -> CSize -> IO Int

-- | @void randombytes_buf(void * const buf, const size_t size);@
foreign import capi unsafe "sodium/randombytes.h randombytes_buf"
  c_sodium_randombytes_buf :: Ptr a -> CSize -> IO ()