{-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -- | Haskell bindings to the fast [official BLAKE3 hashing -- implementation in assembly and C](https://github.com/BLAKE3-team/BLAKE3). -- With support for AVX-512, AVX2 and SSE 4.1. -- -- The original assembly and 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] -- ^ New data to hash. -> BIO.Hasher update h0 bins = unsafeDupablePerformIO $ do h1 <- BIO.copyHasher h0 BIO.withHasherInternal h1 $ \ph1 -> do BIO.update ph1 bins pure h1 {-# NOINLINE update #-} -- | Finish hashing and obtain a 'BIO.Digest' of the specified @len@gth. 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 #-}