-- SPDX-FileCopyrightText: 2020 Serokell
--
-- SPDX-License-Identifier: MPL-2.0

-- | Internals of @crypto_hash@.
module NaCl.Hash.Internal
  ( HashSha256
  , sha256

  , HashSha512
  , sha512
  ) where

import Prelude hiding (length)

import Data.ByteArray (ByteArray, ByteArrayAccess, length, withByteArray)
import Data.ByteArray.Sized (SizedByteArray, allocRet)
import Data.Proxy (Proxy (Proxy))

import qualified Libsodium as Na


-- | Hash returned by 'sha256'.
--
-- This type is parametrised by the actual data type that contains
-- bytes. This can be, for example, a @ByteString@.
type HashSha256 a = SizedByteArray Na.CRYPTO_HASH_SHA256_BYTES a

-- | Hash a message using SHA-256.
sha256
  ::  ( ByteArrayAccess pt
      , ByteArray hashBytes
      )
  => pt  -- ^ Message to hash
  -> IO (HashSha256 hashBytes)
sha256 :: pt -> IO (HashSha256 hashBytes)
sha256 pt
msg = do
    (CInt
_ret, HashSha256 hashBytes
ct) <-
      Proxy CRYPTO_HASH_SHA256_BYTES
-> (Ptr CUChar -> IO CInt) -> IO (CInt, HashSha256 hashBytes)
forall (n :: Nat) c p a.
ByteArrayN n c =>
Proxy n -> (Ptr p -> IO a) -> IO (a, c)
allocRet (Proxy CRYPTO_HASH_SHA256_BYTES
forall k (t :: k). Proxy t
Proxy :: Proxy Na.CRYPTO_HASH_SHA256_BYTES) ((Ptr CUChar -> IO CInt) -> IO (CInt, HashSha256 hashBytes))
-> (Ptr CUChar -> IO CInt) -> IO (CInt, HashSha256 hashBytes)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
hashPtr ->
      pt -> (Ptr CUChar -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray pt
msg ((Ptr CUChar -> IO CInt) -> IO CInt)
-> (Ptr CUChar -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
msgPtr -> do
        Ptr CUChar -> Ptr CUChar -> (Any ::: CULLong) -> IO CInt
forall k1 k2 k3 (out :: k1) (in_ :: k2) (inlen :: k3).
Ptr CUChar -> Ptr CUChar -> (Any ::: CULLong) -> IO CInt
Na.crypto_hash_sha256 Ptr CUChar
hashPtr
          Ptr CUChar
msgPtr (Int -> Any ::: CULLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Any ::: CULLong) -> Int -> Any ::: CULLong
forall a b. (a -> b) -> a -> b
$ pt -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length pt
msg)
    -- _ret can be only 0, so we don’t check it
    HashSha256 hashBytes -> IO (HashSha256 hashBytes)
forall (f :: * -> *) a. Applicative f => a -> f a
pure HashSha256 hashBytes
ct


-- | Hash returned by 'sha512'.
--
-- This type is parametrised by the actual data type that contains
-- bytes. This can be, for example, a @ByteString@.
type HashSha512 a = SizedByteArray Na.CRYPTO_HASH_SHA512_BYTES a

-- | Hash a message using SHA-512.
sha512
  ::  ( ByteArrayAccess pt
      , ByteArray hashBytes
      )
  => pt  -- ^ Message to hash
  -> IO (HashSha512 hashBytes)
sha512 :: pt -> IO (HashSha512 hashBytes)
sha512 pt
msg = do
    (CInt
_ret, HashSha512 hashBytes
ct) <-
      Proxy CRYPTO_HASH_SHA512_BYTES
-> (Ptr CUChar -> IO CInt) -> IO (CInt, HashSha512 hashBytes)
forall (n :: Nat) c p a.
ByteArrayN n c =>
Proxy n -> (Ptr p -> IO a) -> IO (a, c)
allocRet (Proxy CRYPTO_HASH_SHA512_BYTES
forall k (t :: k). Proxy t
Proxy :: Proxy Na.CRYPTO_HASH_SHA512_BYTES) ((Ptr CUChar -> IO CInt) -> IO (CInt, HashSha512 hashBytes))
-> (Ptr CUChar -> IO CInt) -> IO (CInt, HashSha512 hashBytes)
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
hashPtr ->
      pt -> (Ptr CUChar -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray pt
msg ((Ptr CUChar -> IO CInt) -> IO CInt)
-> (Ptr CUChar -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
msgPtr -> do
        Ptr CUChar -> Ptr CUChar -> (Any ::: CULLong) -> IO CInt
forall k1 k2 k3 (out :: k1) (in_ :: k2) (inlen :: k3).
Ptr CUChar -> Ptr CUChar -> (Any ::: CULLong) -> IO CInt
Na.crypto_hash_sha512 Ptr CUChar
hashPtr
          Ptr CUChar
msgPtr (Int -> Any ::: CULLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Any ::: CULLong) -> Int -> Any ::: CULLong
forall a b. (a -> b) -> a -> b
$ pt -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length pt
msg)
    -- _ret can be only 0, so we don’t check it
    HashSha512 hashBytes -> IO (HashSha512 hashBytes)
forall (f :: * -> *) a. Applicative f => a -> f a
pure HashSha512 hashBytes
ct