blake3-0.1: lib/BLAKE3.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
-- | Haskell bindings to the [official BLAKE3 hashing
-- implementation in C](https://github.com/BLAKE3-team/BLAKE3).
--
-- The original C implementation is released into the public domain with CC0 1.0.
-- Alternatively, it is licensed under the Apache License 2.0, copyright of Jack
-- O'Connor and Samuel Neves. See its [LICENSE](https://github.com/BLAKE3-team/BLAKE3/blob/88dcee7005be962a81516f7863e70009d9caa2c9/LICENSE)
-- for details.
--
-- This Haskell library is the copyright of Renzo Carbonara,
-- licensed under the terms of
-- the [Apache License 2.0](https://github.com/k0001/hs-blake3/blob/master/blake3/LICENSE).
module BLAKE3
( -- * Hashing
hash
, BIO.Digest
-- * Keyed hashing
, hashKeyed
, BIO.Key
, BIO.key
-- * Key derivation
, derive
, BIO.Context
, BIO.context
-- * Incremental hashing
, BIO.Hasher
, hasher
, hasherKeyed
, update
, finalize
-- * Constants
, BIO.KEY_LEN
, BIO.BLOCK_SIZE
, BIO.DEFAULT_DIGEST_LEN
)
where
import qualified Data.ByteArray as BA
import GHC.TypeLits
import System.IO.Unsafe (unsafeDupablePerformIO)
import qualified BLAKE3.IO as BIO
--------------------------------------------------------------------------------
-- | BLAKE3 hashing.
--
-- For incremental hashing, see 'hasher', 'update' and 'finalize':
--
-- @
-- 'hash' = 'finalize' '.' 'update' 'hasher'
-- @
hash
:: forall len bin
. (KnownNat len, BA.ByteArrayAccess bin)
=> [bin] -- ^ Data to hash.
-> BIO.Digest len -- ^ Default digest length is 'BIO.DEFAULT_DIGEST_LEN'.
hash bins = unsafeDupablePerformIO $ do
fmap fst $ BIO.allocRetHasher $ \ph -> do
BIO.init ph
BIO.update ph bins
BIO.finalize ph
{-# NOINLINE hash #-}
-- | BLAKE3 hashing with a 'BIO.Key'.
--
-- For incremental hashing, see 'hasherKeyed', 'update' and 'finalize':
--
-- @
-- 'hashKeyed' key = 'finalize' '.' 'update' ('hasherKeyed' key)
-- @
hashKeyed
:: forall len bin
. (KnownNat len, BA.ByteArrayAccess bin)
=> BIO.Key
-> [bin] -- ^ Data to hash.
-> BIO.Digest len -- ^ Default digest length is 'BIO.DEFAULT_DIGEST_LEN'.
hashKeyed key0 bins = unsafeDupablePerformIO $ do
fmap fst $ BIO.allocRetHasher $ \ph -> do
BIO.initKeyed ph key0
BIO.update ph bins
BIO.finalize ph
{-# NOINLINE hashKeyed #-}
-- | BLAKE3 key derivation.
derive
:: forall len ikm
. (KnownNat len, BA.ByteArrayAccess ikm)
=> BIO.Context
-> [ikm] -- ^ Input key material.
-> BIO.Digest len -- ^ Default digest length is 'BIO.DEFAULT_DIGEST_LEN'.
derive ctx ikms = unsafeDupablePerformIO $
fmap fst $ BIO.allocRetHasher $ \ph -> do
BIO.initDerive ph ctx
BIO.update ph ikms
BIO.finalize ph
{-# NOINLINE derive #-}
-- | Initial 'BIO.Hasher' for incremental hashing.
hasher :: BIO.Hasher -- ^
hasher = unsafeDupablePerformIO $
fmap snd $ BIO.allocRetHasher BIO.init
{-# NOINLINE hasher #-}
-- | Initial 'BIO.Hasher' for incremental /keyed/ hashing.
hasherKeyed :: BIO.Key -> BIO.Hasher -- ^
hasherKeyed key0 = unsafeDupablePerformIO $
fmap snd $ BIO.allocRetHasher $ \ph ->
BIO.initKeyed ph key0
{-# NOINLINE hasherKeyed #-}
-- | Update 'BIO.Hasher' with new data.
update
:: forall bin
. BA.ByteArrayAccess bin
=> BIO.Hasher
-> [bin]
-> BIO.Hasher
update h0 bins = unsafeDupablePerformIO $ do
h1 <- BIO.copyHasher h0
BIO.withHasherInternal h1 $ \ph1 -> do
BIO.update ph1 bins
pure h1
{-# NOINLINE update #-}
-- | Update 'BIO.Hasher' with new data.
finalize
:: forall len
. KnownNat len
=> BIO.Hasher
-> BIO.Digest len
finalize h0 = unsafeDupablePerformIO $ do
h1 <- BIO.copyHasher h0
BIO.withHasherInternal h1 $ \ph1 ->
BIO.finalize ph1
{-# NOINLINE finalize #-}