{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Sel.Hashing.SHA256
(
Hash
, hashByteString
, hashText
, Multipart
, withMultipart
, updateMultipart
, hashToBinary
, hashToHexText
, hashToHexByteString
) where
import Control.Monad (void)
import Data.ByteString (StrictByteString)
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Internal as BS
import qualified Data.ByteString.Unsafe as BS
import Data.Text (Text)
import Data.Text.Display (Display (..))
import qualified Data.Text.Encoding as Text
import qualified Data.Text.Internal.Builder as Builder
import Foreign (ForeignPtr, Ptr, Storable)
import qualified Foreign
import Foreign.C (CChar, CSize, CUChar, CULLong)
import LibSodium.Bindings.SHA2
( CryptoHashSHA256State
, cryptoHashSHA256
, cryptoHashSHA256Bytes
, cryptoHashSHA256Final
, cryptoHashSHA256Init
, cryptoHashSHA256StateBytes
, cryptoHashSHA256Update
)
import System.IO.Unsafe (unsafeDupablePerformIO)
import Control.Monad.IO.Class (MonadIO (liftIO))
import qualified Data.Base16.Types as Base16
import Data.Kind (Type)
import Sel.Internal
newtype Hash = Hash (ForeignPtr CUChar)
instance Eq Hash where
(Hash ForeignPtr CUChar
h1) == :: Hash -> Hash -> Bool
== (Hash ForeignPtr CUChar
h2) =
IO Bool -> Bool
forall a. IO a -> a
unsafeDupablePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$
ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Bool
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Bool
foreignPtrEq ForeignPtr CUChar
h1 ForeignPtr CUChar
h2 CSize
cryptoHashSHA256Bytes
instance Ord Hash where
compare :: Hash -> Hash -> Ordering
compare (Hash ForeignPtr CUChar
h1) (Hash ForeignPtr CUChar
h2) =
IO Ordering -> Ordering
forall a. IO a -> a
unsafeDupablePerformIO (IO Ordering -> Ordering) -> IO Ordering -> Ordering
forall a b. (a -> b) -> a -> b
$
ForeignPtr CUChar -> ForeignPtr CUChar -> CSize -> IO Ordering
forall a. ForeignPtr a -> ForeignPtr a -> CSize -> IO Ordering
foreignPtrOrd ForeignPtr CUChar
h1 ForeignPtr CUChar
h2 CSize
cryptoHashSHA256Bytes
instance Storable Hash where
sizeOf :: Hash -> Int
sizeOf :: Hash -> Int
sizeOf Hash
_ = CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoHashSHA256Bytes
alignment :: Hash -> Int
alignment :: Hash -> Int
alignment Hash
_ = Int
32
poke :: Ptr Hash -> Hash -> IO ()
poke :: Ptr Hash -> Hash -> IO ()
poke Ptr Hash
ptr (Hash ForeignPtr CUChar
hashForeignPtr) =
ForeignPtr CUChar -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
hashForeignPtr ((Ptr CUChar -> IO ()) -> IO ()) -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
hashPtr ->
Ptr CUChar -> Ptr CUChar -> Int -> IO ()
forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyArray (Ptr Hash -> Ptr CUChar
forall a b. Ptr a -> Ptr b
Foreign.castPtr Ptr Hash
ptr) Ptr CUChar
hashPtr (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoHashSHA256Bytes)
peek :: Ptr Hash -> IO Hash
peek :: Ptr Hash -> IO Hash
peek Ptr Hash
ptr = do
ForeignPtr CUChar
hashfPtr <- Int -> IO (ForeignPtr CUChar)
forall a. Int -> IO (ForeignPtr a)
Foreign.mallocForeignPtrBytes (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoHashSHA256Bytes)
ForeignPtr CUChar -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
hashfPtr ((Ptr CUChar -> IO ()) -> IO ()) -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
hashPtr ->
Ptr CUChar -> Ptr CUChar -> Int -> IO ()
forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
Foreign.copyArray Ptr CUChar
hashPtr (Ptr Hash -> Ptr CUChar
forall a b. Ptr a -> Ptr b
Foreign.castPtr Ptr Hash
ptr) (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoHashSHA256Bytes)
Hash -> IO Hash
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Hash -> IO Hash) -> Hash -> IO Hash
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> Hash
Hash ForeignPtr CUChar
hashfPtr
instance Display Hash where
displayBuilder :: Hash -> Builder
displayBuilder = Text -> Builder
Builder.fromText (Text -> Builder) -> (Hash -> Text) -> Hash -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> Text
hashToHexText
instance Show Hash where
show :: Hash -> String
show = ByteString -> String
BS.unpackChars (ByteString -> String) -> (Hash -> ByteString) -> Hash -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> ByteString
hashToHexByteString
hashByteString :: StrictByteString -> IO Hash
hashByteString :: ByteString -> IO Hash
hashByteString ByteString
bytestring =
ByteString -> (CStringLen -> IO Hash) -> IO Hash
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.unsafeUseAsCStringLen ByteString
bytestring ((CStringLen -> IO Hash) -> IO Hash)
-> (CStringLen -> IO Hash) -> IO Hash
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
cString, Int
cStringLen) -> do
ForeignPtr CUChar
hashForeignPtr <- Int -> IO (ForeignPtr CUChar)
forall a. Int -> IO (ForeignPtr a)
Foreign.mallocForeignPtrBytes (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoHashSHA256Bytes)
ForeignPtr CUChar -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
hashForeignPtr ((Ptr CUChar -> IO ()) -> IO ()) -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CUChar
hashPtr ->
IO CInt -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$
Ptr CUChar -> Ptr CUChar -> CULLong -> IO CInt
cryptoHashSHA256
Ptr CUChar
hashPtr
(Ptr CChar -> Ptr CUChar
forall a b. Ptr a -> Ptr b
Foreign.castPtr Ptr CChar
cString :: Ptr CUChar)
(forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @CULLong Int
cStringLen)
Hash -> IO Hash
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Hash -> IO Hash) -> Hash -> IO Hash
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> Hash
Hash ForeignPtr CUChar
hashForeignPtr
hashText :: Text -> IO Hash
hashText :: Text -> IO Hash
hashText Text
text = ByteString -> IO Hash
hashByteString (Text -> ByteString
Text.encodeUtf8 Text
text)
hashToHexText :: Hash -> Text
hashToHexText :: Hash -> Text
hashToHexText = Base16 Text -> Text
forall a. Base16 a -> a
Base16.extractBase16 (Base16 Text -> Text) -> (Hash -> Base16 Text) -> Hash -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base16 Text
Base16.encodeBase16 (ByteString -> Base16 Text)
-> (Hash -> ByteString) -> Hash -> Base16 Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> ByteString
hashToBinary
hashToHexByteString :: Hash -> StrictByteString
hashToHexByteString :: Hash -> ByteString
hashToHexByteString = Base16 ByteString -> ByteString
forall a. Base16 a -> a
Base16.extractBase16 (Base16 ByteString -> ByteString)
-> (Hash -> Base16 ByteString) -> Hash -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base16 ByteString
Base16.encodeBase16' (ByteString -> Base16 ByteString)
-> (Hash -> ByteString) -> Hash -> Base16 ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> ByteString
hashToBinary
hashToBinary :: Hash -> StrictByteString
hashToBinary :: Hash -> ByteString
hashToBinary (Hash ForeignPtr CUChar
fPtr) =
ForeignPtr Word8 -> Int -> Int -> ByteString
BS.fromForeignPtr
(ForeignPtr CUChar -> ForeignPtr Word8
forall a b. ForeignPtr a -> ForeignPtr b
Foreign.castForeignPtr ForeignPtr CUChar
fPtr)
Int
0
(forall a b. (Integral a, Num b) => a -> b
fromIntegral @CSize @Int CSize
cryptoHashSHA256Bytes)
newtype Multipart s = Multipart (Ptr CryptoHashSHA256State)
type role Multipart nominal
withMultipart
:: forall (a :: Type) (m :: Type -> Type)
. MonadIO m
=> (forall s. Multipart s -> m a)
-> m Hash
withMultipart :: forall a (m :: * -> *).
MonadIO m =>
(forall s. Multipart s -> m a) -> m Hash
withMultipart forall s. Multipart s -> m a
actions = do
CSize -> (Ptr CryptoHashSHA256State -> m Hash) -> m Hash
forall a b (m :: * -> *).
MonadIO m =>
CSize -> (Ptr a -> m b) -> m b
allocateWith CSize
cryptoHashSHA256StateBytes ((Ptr CryptoHashSHA256State -> m Hash) -> m Hash)
-> (Ptr CryptoHashSHA256State -> m Hash) -> m Hash
forall a b. (a -> b) -> a -> b
$ \Ptr CryptoHashSHA256State
statePtr -> do
m CInt -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m CInt -> m ()) -> m CInt -> m ()
forall a b. (a -> b) -> a -> b
$ IO CInt -> m CInt
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO CInt -> m CInt) -> IO CInt -> m CInt
forall a b. (a -> b) -> a -> b
$ Ptr CryptoHashSHA256State -> IO CInt
cryptoHashSHA256Init Ptr CryptoHashSHA256State
statePtr
let part :: Multipart s
part = Ptr CryptoHashSHA256State -> Multipart s
forall s. Ptr CryptoHashSHA256State -> Multipart s
Multipart Ptr CryptoHashSHA256State
statePtr
Multipart Any -> m a
forall s. Multipart s -> m a
actions Multipart Any
forall {s}. Multipart s
part
IO Hash -> m Hash
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Multipart Any -> IO Hash
forall s. Multipart s -> IO Hash
finaliseMultipart Multipart Any
forall {s}. Multipart s
part)
finaliseMultipart :: Multipart s -> IO Hash
finaliseMultipart :: forall s. Multipart s -> IO Hash
finaliseMultipart (Multipart Ptr CryptoHashSHA256State
statePtr) = do
ForeignPtr CUChar
hashForeignPtr <- Int -> IO (ForeignPtr CUChar)
forall a. Int -> IO (ForeignPtr a)
Foreign.mallocForeignPtrBytes (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
cryptoHashSHA256Bytes)
ForeignPtr CUChar -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr CUChar
hashForeignPtr ((Ptr CUChar -> IO ()) -> IO ()) -> (Ptr CUChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(Ptr CUChar
hashPtr :: Ptr CUChar) ->
IO CInt -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$
Ptr CryptoHashSHA256State -> Ptr CUChar -> IO CInt
cryptoHashSHA256Final
Ptr CryptoHashSHA256State
statePtr
Ptr CUChar
hashPtr
Hash -> IO Hash
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Hash -> IO Hash) -> Hash -> IO Hash
forall a b. (a -> b) -> a -> b
$ ForeignPtr CUChar -> Hash
Hash ForeignPtr CUChar
hashForeignPtr
updateMultipart :: Multipart s -> StrictByteString -> IO ()
updateMultipart :: forall s. Multipart s -> ByteString -> IO ()
updateMultipart (Multipart Ptr CryptoHashSHA256State
statePtr) ByteString
message = do
ByteString -> (CStringLen -> IO ()) -> IO ()
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.unsafeUseAsCStringLen ByteString
message ((CStringLen -> IO ()) -> IO ()) -> (CStringLen -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
cString, Int
cStringLen) -> do
let messagePtr :: Ptr CUChar
messagePtr = forall a b. Ptr a -> Ptr b
Foreign.castPtr @CChar @CUChar Ptr CChar
cString
let messageLen :: CULLong
messageLen = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @CULLong Int
cStringLen
IO CInt -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$
Ptr CryptoHashSHA256State -> Ptr CUChar -> CULLong -> IO CInt
cryptoHashSHA256Update
Ptr CryptoHashSHA256State
statePtr
Ptr CUChar
messagePtr
CULLong
messageLen