{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module BLAKE3.IO
(
hash
, init
, update
, finalize
, finalizeSeek
, Digest(..)
, Key
, key
, initDerive
, Hasher
, modifyHasher
, HASHER_ALIGNMENT
, HASHER_SIZE
, KEY_LEN
, BLOCK_SIZE
, DEFAULT_DIGEST_LEN
, CHUNK_LEN
, MAX_DEPTH
, MAX_SIMD_DEGREE
, c_init
, c_init_keyed
, c_init_derive_key_raw
, c_update
, c_finalize
, c_finalize_seek
)
where
import Data.Foldable
import Data.Proxy
import Data.String
import Data.Word
import Foreign.C.Types
import Foreign.Marshal.Array (copyArray)
import Foreign.Ptr
import Foreign.Storable
import GHC.TypeLits
import Prelude hiding (init)
import qualified Data.ByteArray as BA
import qualified Data.ByteArray.Sized as BAS
import qualified Data.ByteArray.Encoding as BA
newtype Digest (len :: Nat)
= Digest (BAS.SizedByteArray len BA.ScrubbedBytes)
deriving newtype ( Digest len -> Digest len -> Bool
forall (len :: Nat). Digest len -> Digest len -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Digest len -> Digest len -> Bool
$c/= :: forall (len :: Nat). Digest len -> Digest len -> Bool
== :: Digest len -> Digest len -> Bool
$c== :: forall (len :: Nat). Digest len -> Digest len -> Bool
Eq
, Digest len -> Digest len -> Bool
Digest len -> Digest len -> Ordering
Digest len -> Digest len -> Digest len
forall (len :: Nat). Eq (Digest len)
forall (len :: Nat). Digest len -> Digest len -> Bool
forall (len :: Nat). Digest len -> Digest len -> Ordering
forall (len :: Nat). Digest len -> Digest len -> Digest len
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Digest len -> Digest len -> Digest len
$cmin :: forall (len :: Nat). Digest len -> Digest len -> Digest len
max :: Digest len -> Digest len -> Digest len
$cmax :: forall (len :: Nat). Digest len -> Digest len -> Digest len
>= :: Digest len -> Digest len -> Bool
$c>= :: forall (len :: Nat). Digest len -> Digest len -> Bool
> :: Digest len -> Digest len -> Bool
$c> :: forall (len :: Nat). Digest len -> Digest len -> Bool
<= :: Digest len -> Digest len -> Bool
$c<= :: forall (len :: Nat). Digest len -> Digest len -> Bool
< :: Digest len -> Digest len -> Bool
$c< :: forall (len :: Nat). Digest len -> Digest len -> Bool
compare :: Digest len -> Digest len -> Ordering
$ccompare :: forall (len :: Nat). Digest len -> Digest len -> Ordering
Ord
, Digest len -> Int
forall (len :: Nat). KnownNat len => Digest len -> Int
forall (len :: Nat) p. KnownNat len => Digest len -> Ptr p -> IO ()
forall (len :: Nat) p a.
KnownNat len =>
Digest len -> (Ptr p -> IO a) -> IO a
forall p. Digest len -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. Digest len -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: forall p. Digest len -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall (len :: Nat) p. KnownNat len => Digest len -> Ptr p -> IO ()
withByteArray :: forall p a. Digest len -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall (len :: Nat) p a.
KnownNat len =>
Digest len -> (Ptr p -> IO a) -> IO a
length :: Digest len -> Int
$clength :: forall (len :: Nat). KnownNat len => Digest len -> Int
BA.ByteArrayAccess
, BAS.ByteArrayN len )
instance Show (Digest len) where
show :: Digest len -> String
show (Digest SizedByteArray len ScrubbedBytes
x) = forall x. ByteArrayAccess x => x -> String
showBase16 (forall (n :: Nat) ba. SizedByteArray n ba -> ba
BAS.unSizedByteArray SizedByteArray len ScrubbedBytes
x)
instance forall len. KnownNat len => Storable (Digest len) where
sizeOf :: Digest len -> Int
sizeOf Digest len
_ = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @len))
alignment :: Digest len -> Int
alignment Digest len
_ = Int
8
peek :: Ptr (Digest len) -> IO (Digest len)
peek Ptr (Digest len)
ps = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
BAS.alloc forall a b. (a -> b) -> a -> b
$ \Ptr (Digest len)
pd -> forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
copyArray Ptr (Digest len)
pd Ptr (Digest len)
ps Int
1
poke :: Ptr (Digest len) -> Digest len -> IO ()
poke Ptr (Digest len)
pd Digest len
src = forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray Digest len
src forall a b. (a -> b) -> a -> b
$ \Ptr (Digest len)
ps -> forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
copyArray Ptr (Digest len)
pd Ptr (Digest len)
ps Int
1
data Key where
Key :: BA.ByteArrayAccess x => x -> Key
instance Eq Key where
== :: Key -> Key -> Bool
(==) = forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
BA.constEq
{-# INLINE (==) #-}
instance Show Key where
show :: Key -> String
show (Key x
x) = forall x. ByteArrayAccess x => x -> String
showBase16 x
x
instance BA.ByteArrayAccess Key where
length :: Key -> Int
length (Key x
x) = forall ba. ByteArrayAccess ba => ba -> Int
BA.length x
x
withByteArray :: forall p a. Key -> (Ptr p -> IO a) -> IO a
withByteArray (Key x
x) = forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray x
x
instance BAS.ByteArrayN KEY_LEN Key where
allocRet :: forall p a. Proxy KEY_LEN -> (Ptr p -> IO a) -> IO (a, Key)
allocRet Proxy KEY_LEN
_ Ptr p -> IO a
g = do
(a
a, ScrubbedBytes
bs :: BA.ScrubbedBytes) <- forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
BA.allocRet Int
keyLen Ptr p -> IO a
g
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
a, forall x. ByteArrayAccess x => x -> Key
Key ScrubbedBytes
bs)
instance Storable Key where
sizeOf :: Key -> Int
sizeOf Key
_ = Int
keyLen
alignment :: Key -> Int
alignment Key
_ = Int
8
peek :: Ptr Key -> IO Key
peek Ptr Key
ps = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
BAS.alloc forall a b. (a -> b) -> a -> b
$ \Ptr Key
pd -> forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
copyArray Ptr Key
pd Ptr Key
ps Int
1
poke :: Ptr Key -> Key -> IO ()
poke Ptr Key
pd Key
src = forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray Key
src forall a b. (a -> b) -> a -> b
$ \Ptr Key
ps -> forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
copyArray Ptr Key
pd Ptr Key
ps Int
1
key
:: BA.ByteArrayAccess bin
=> bin
-> Maybe Key
key :: forall bin. ByteArrayAccess bin => bin -> Maybe Key
key bin
bin | forall ba. ByteArrayAccess ba => ba -> Int
BA.length bin
bin forall a. Eq a => a -> a -> Bool
/= Int
keyLen = forall a. Maybe a
Nothing
| Bool
otherwise = forall a. a -> Maybe a
Just (forall x. ByteArrayAccess x => x -> Key
Key bin
bin)
showBase16 :: BA.ByteArrayAccess x => x -> String
showBase16 :: forall x. ByteArrayAccess x => x -> String
showBase16 = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Enum a => Int -> a
toEnum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ByteArrayAccess a => a -> [Word8]
BA.unpack @BA.ScrubbedBytes
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
Base -> bin -> bout
BA.convertToBase Base
BA.Base16
hash
:: forall len digest bin
. (BAS.ByteArrayN len digest, BA.ByteArrayAccess bin)
=> Maybe Key
-> [bin]
-> IO digest
hash :: forall (len :: Nat) digest bin.
(ByteArrayN len digest, ByteArrayAccess bin) =>
Maybe Key -> [bin] -> IO digest
hash Maybe Key
yk [bin]
bins = do
(digest
dig, Hasher
_ :: Hasher) <- forall (n :: Nat) c p a.
ByteArrayN n c =>
Proxy n -> (Ptr p -> IO a) -> IO (a, c)
BAS.allocRet forall {k} (t :: k). Proxy t
Proxy forall a b. (a -> b) -> a -> b
$ \Ptr Hasher
ph -> do
Ptr Hasher -> Maybe Key -> IO ()
init Ptr Hasher
ph Maybe Key
yk
forall bin. ByteArrayAccess bin => Ptr Hasher -> [bin] -> IO ()
update Ptr Hasher
ph [bin]
bins
forall (len :: Nat) output.
ByteArrayN len output =>
Ptr Hasher -> IO output
finalize Ptr Hasher
ph
forall (f :: * -> *) a. Applicative f => a -> f a
pure digest
dig
init
:: Ptr Hasher
-> Maybe Key
-> IO ()
init :: Ptr Hasher -> Maybe Key -> IO ()
init Ptr Hasher
ph Maybe Key
Nothing = Ptr Hasher -> IO ()
c_init Ptr Hasher
ph
init Ptr Hasher
ph (Just Key
key0) = forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray Key
key0 forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pkey ->
Ptr Hasher -> Ptr Word8 -> IO ()
c_init_keyed Ptr Hasher
ph Ptr Word8
pkey
initDerive
:: forall context
. BA.ByteArrayAccess context
=> Ptr Hasher
-> context
-> IO ()
initDerive :: forall context.
ByteArrayAccess context =>
Ptr Hasher -> context -> IO ()
initDerive Ptr Hasher
ph context
ctx =
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray context
ctx forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pc ->
Ptr Hasher -> Ptr Word8 -> CSize -> IO ()
c_init_derive_key_raw Ptr Hasher
ph Ptr Word8
pc (forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall ba. ByteArrayAccess ba => ba -> Int
BA.length context
ctx))
update
:: forall bin
. BA.ByteArrayAccess bin
=> Ptr Hasher
-> [bin]
-> IO ()
update :: forall bin. ByteArrayAccess bin => Ptr Hasher -> [bin] -> IO ()
update Ptr Hasher
ph [bin]
bins =
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [bin]
bins forall a b. (a -> b) -> a -> b
$ \bin
bin ->
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray bin
bin forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pbin ->
Ptr Hasher -> Ptr Word8 -> CSize -> IO ()
c_update Ptr Hasher
ph Ptr Word8
pbin (forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall ba. ByteArrayAccess ba => ba -> Int
BA.length bin
bin))
finalize
:: forall len output
. BAS.ByteArrayN len output
=> Ptr Hasher
-> IO output
finalize :: forall (len :: Nat) output.
ByteArrayN len output =>
Ptr Hasher -> IO output
finalize Ptr Hasher
ph =
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
BAS.alloc forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pd ->
Ptr Hasher -> Ptr Word8 -> CSize -> IO ()
c_finalize Ptr Hasher
ph Ptr Word8
pd (forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @len)))
finalizeSeek
:: forall len output
. BAS.ByteArrayN len output
=> Ptr Hasher
-> Word64
-> IO output
finalizeSeek :: forall (len :: Nat) output.
ByteArrayN len output =>
Ptr Hasher -> Word64 -> IO output
finalizeSeek Ptr Hasher
ph Word64
pos =
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
BAS.alloc forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pd ->
Ptr Hasher -> Word64 -> Ptr Word8 -> CSize -> IO ()
c_finalize_seek Ptr Hasher
ph Word64
pos Ptr Word8
pd (forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @len)))
type HASHER_ALIGNMENT = 8
type HASHER_SIZE = 1912
hasherSize :: Int
hasherSize :: Int
hasherSize = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @HASHER_SIZE))
type KEY_LEN = 32
keyLen :: Int
keyLen :: Int
keyLen = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @KEY_LEN))
type DEFAULT_DIGEST_LEN = 32
type BLOCK_SIZE = 64
type CHUNK_LEN = 1024
type MAX_DEPTH = 54
type MAX_SIMD_DEGREE = 16
newtype Hasher = Hasher (BAS.SizedByteArray HASHER_SIZE BA.ScrubbedBytes)
deriving newtype
( Hasher -> Hasher -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Hasher -> Hasher -> Bool
$c/= :: Hasher -> Hasher -> Bool
== :: Hasher -> Hasher -> Bool
$c== :: Hasher -> Hasher -> Bool
Eq
, Hasher -> Int
forall p. Hasher -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. Hasher -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: forall p. Hasher -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall p. Hasher -> Ptr p -> IO ()
withByteArray :: forall p a. Hasher -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall p a. Hasher -> (Ptr p -> IO a) -> IO a
length :: Hasher -> Int
$clength :: Hasher -> Int
BA.ByteArrayAccess
, BAS.ByteArrayN HASHER_SIZE
)
instance Show Hasher where
show :: Hasher -> String
show = forall x. ByteArrayAccess x => x -> String
showBase16
modifyHasher
:: Hasher
-> (Ptr Hasher -> IO a)
-> IO a
modifyHasher :: forall a. Hasher -> (Ptr Hasher -> IO a) -> IO a
modifyHasher = forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray
instance Storable Hasher where
sizeOf :: Hasher -> Int
sizeOf Hasher
_ = Int
hasherSize
alignment :: Hasher -> Int
alignment Hasher
_ = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @HASHER_ALIGNMENT))
peek :: Ptr Hasher -> IO Hasher
peek Ptr Hasher
ps = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
BAS.alloc forall a b. (a -> b) -> a -> b
$ \Ptr Hasher
pd -> forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
copyArray Ptr Hasher
pd Ptr Hasher
ps Int
1
poke :: Ptr Hasher -> Hasher -> IO ()
poke Ptr Hasher
pd Hasher
src = forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
BA.withByteArray Hasher
src forall a b. (a -> b) -> a -> b
$ \Ptr Hasher
ps -> forall a. Storable a => Ptr a -> Ptr a -> Int -> IO ()
copyArray Ptr Hasher
pd Ptr Hasher
ps Int
1
foreign import ccall unsafe
"blake3.h blake3_hasher_init"
c_init
:: Ptr Hasher
-> IO ()
foreign import ccall unsafe
"blake3.h blake3_hasher_init_keyed"
c_init_keyed
:: Ptr Hasher
-> Ptr Word8
-> IO ()
foreign import ccall unsafe
"blake3.h blake3_hasher_init_derive_key_raw"
c_init_derive_key_raw
:: Ptr Hasher
-> Ptr Word8
-> CSize
-> IO ()
foreign import ccall unsafe
"blake3.h blake3_hasher_update"
c_update
:: Ptr Hasher
-> Ptr Word8
-> CSize
-> IO ()
foreign import ccall unsafe
"blake3.h blake3_hasher_finalize"
c_finalize
:: Ptr Hasher
-> Ptr Word8
-> CSize
-> IO ()
foreign import ccall unsafe
"blake3.h blake3_hasher_finalize_seek"
c_finalize_seek
:: Ptr Hasher
-> Word64
-> Ptr Word8
-> CSize
-> IO ()