{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}

-- | Implementation of the SHA256 hashing algorithm.
module Cardano.Crypto.Hash.SHA256
  ( SHA256
  )
where

import Control.Monad (unless)
import Cardano.Crypto.Libsodium.C (c_crypto_hash_sha256)
import Cardano.Foreign (SizedPtr(SizedPtr))
import Cardano.Crypto.Hash.Class (HashAlgorithm, SizeHash, hashAlgorithmName, digest)

import Foreign.Ptr (castPtr)
import Foreign.C.Error (errnoToIOError, getErrno)
import Data.Proxy (Proxy(..))
import GHC.TypeLits (natVal)
import GHC.IO.Exception (ioException)

import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as BI


data SHA256

instance HashAlgorithm SHA256 where
  type SizeHash SHA256 = 32
  hashAlgorithmName :: proxy SHA256 -> String
hashAlgorithmName proxy SHA256
_ = String
"sha256"
  digest :: proxy SHA256 -> ByteString -> ByteString
digest proxy SHA256
_ = ByteString -> ByteString
sha256_libsodium

sha256_libsodium :: B.ByteString -> B.ByteString
sha256_libsodium :: ByteString -> ByteString
sha256_libsodium ByteString
input =
  Int -> (Ptr Word8 -> IO ()) -> ByteString
BI.unsafeCreate Int
expected_size ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
outptr ->
    ByteString -> (CStringLen -> IO ()) -> IO ()
forall a. ByteString -> (CStringLen -> IO a) -> IO a
B.useAsCStringLen ByteString
input ((CStringLen -> IO ()) -> IO ()) -> (CStringLen -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
inptr, Int
inputlen) -> do
      Int
res <- SizedPtr CRYPTO_SHA256_BYTES -> Ptr CUChar -> CULLong -> IO Int
c_crypto_hash_sha256 (Ptr Void -> SizedPtr CRYPTO_SHA256_BYTES
forall (n :: Nat). Ptr Void -> SizedPtr n
SizedPtr (Ptr Word8 -> Ptr Void
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
outptr)) (Ptr CChar -> Ptr CUChar
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
inptr) (Int -> CULLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
inputlen)
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
res Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
          Errno
errno <- IO Errno
getErrno
          IOException -> IO ()
forall a. IOException -> IO a
ioException (IOException -> IO ()) -> IOException -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> Errno -> Maybe Handle -> Maybe String -> IOException
errnoToIOError String
"digest @SHA256: c_crypto_hash_sha256" Errno
errno Maybe Handle
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing

  where
    expected_size :: Int
expected_size = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy CRYPTO_SHA256_BYTES -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy (SizeHash SHA256)
forall k (t :: k). Proxy t
Proxy::Proxy (SizeHash SHA256)))