git-annex-10.20260624: Utility/Hash/Botan.hs
{- Convenience wrapper around botan's hashing.
-
- Copyright 2026 Joey Hess <id@joeyh.name>
-
- License: BSD-2-clause
-}
{-# LANGUAGE BangPatterns #-}
module Utility.Hash.Botan (
sha1,
sha1_hasher,
sha1s,
sha2_224,
sha2_224_hasher,
sha2_256,
sha2_256_hasher,
sha2_384,
sha2_384_hasher,
sha2_512,
sha2_512_hasher,
sha3_224,
sha3_224_hasher,
sha3_256,
sha3_256_hasher,
sha3_384,
sha3_384_hasher,
sha3_512,
sha3_512_hasher,
skein512,
skein512_hasher,
blake2b_160,
blake2b_160_hasher,
blake2b_224,
blake2b_224_hasher,
blake2b_256,
blake2b_256_hasher,
blake2b_384,
blake2b_384_hasher,
blake2b_512,
blake2b_512_hasher,
md5,
md5_hasher,
md5s,
) where
import qualified Botan.Low.Hash as Botan
import Control.Monad
import System.IO.Unsafe (unsafePerformIO)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as S
import Data.IORef
import Utility.Hash.Types
import Utility.Hash.Incremental
sha1 :: L.ByteString -> HashDigest
sha1 = hashLazy Botan.SHA1
sha1_hasher :: IO IncrementalHasher
sha1_hasher = mkIncrementalHasher Botan.SHA1
sha1s :: S.ByteString -> HashDigest
sha1s = hashStrict Botan.SHA1
sha2_224 :: L.ByteString -> HashDigest
sha2_224 = hashLazy Botan.SHA224
sha2_224_hasher :: IO IncrementalHasher
sha2_224_hasher = mkIncrementalHasher Botan.SHA224
sha2_256 :: L.ByteString -> HashDigest
sha2_256 = hashLazy Botan.SHA256
sha2_256_hasher :: IO IncrementalHasher
sha2_256_hasher = mkIncrementalHasher Botan.SHA256
sha2_384 :: L.ByteString -> HashDigest
sha2_384 = hashLazy Botan.SHA384
sha2_384_hasher :: IO IncrementalHasher
sha2_384_hasher = mkIncrementalHasher Botan.SHA384
sha2_512 :: L.ByteString -> HashDigest
sha2_512 = hashLazy Botan.SHA512
sha2_512_hasher :: IO IncrementalHasher
sha2_512_hasher = mkIncrementalHasher Botan.SHA512
sha3_224 :: L.ByteString -> HashDigest
sha3_224 = hashLazy (Botan.sha3 (224 :: Int))
sha3_224_hasher :: IO IncrementalHasher
sha3_224_hasher = mkIncrementalHasher (Botan.sha3 (224 :: Int))
sha3_256 :: L.ByteString -> HashDigest
sha3_256 = hashLazy (Botan.sha3 (256 :: Int))
sha3_256_hasher :: IO IncrementalHasher
sha3_256_hasher = mkIncrementalHasher (Botan.sha3 (256 :: Int))
sha3_384 :: L.ByteString -> HashDigest
sha3_384 = hashLazy (Botan.sha3 (384 :: Int))
sha3_384_hasher :: IO IncrementalHasher
sha3_384_hasher = mkIncrementalHasher (Botan.sha3 (384 :: Int))
sha3_512 :: L.ByteString -> HashDigest
sha3_512 = hashLazy (Botan.sha3 (512 :: Int))
sha3_512_hasher :: IO IncrementalHasher
sha3_512_hasher = mkIncrementalHasher (Botan.sha3 (512 :: Int))
skein512 :: L.ByteString -> HashDigest
skein512 = hashLazy Botan.Skein512
skein512_hasher :: IO IncrementalHasher
skein512_hasher = mkIncrementalHasher Botan.Skein512
blake2b_160 :: L.ByteString -> HashDigest
blake2b_160 = hashLazy (Botan.blake2b (160 :: Int))
blake2b_160_hasher :: IO IncrementalHasher
blake2b_160_hasher = mkIncrementalHasher (Botan.blake2b (160 :: Int))
blake2b_224 :: L.ByteString -> HashDigest
blake2b_224 = hashLazy (Botan.blake2b (224 :: Int))
blake2b_224_hasher :: IO IncrementalHasher
blake2b_224_hasher = mkIncrementalHasher (Botan.blake2b (224 :: Int))
blake2b_256 :: L.ByteString -> HashDigest
blake2b_256 = hashLazy (Botan.blake2b (256 :: Int))
blake2b_256_hasher :: IO IncrementalHasher
blake2b_256_hasher = mkIncrementalHasher (Botan.blake2b (256 :: Int))
blake2b_384 :: L.ByteString -> HashDigest
blake2b_384 = hashLazy (Botan.blake2b (384 :: Int))
blake2b_384_hasher :: IO IncrementalHasher
blake2b_384_hasher = mkIncrementalHasher (Botan.blake2b (384 :: Int))
blake2b_512 :: L.ByteString -> HashDigest
blake2b_512 = hashLazy (Botan.blake2b (512 :: Int))
blake2b_512_hasher :: IO IncrementalHasher
blake2b_512_hasher = mkIncrementalHasher (Botan.blake2b (512 :: Int))
md5 :: L.ByteString -> HashDigest
md5 = hashLazy Botan.MD5
md5_hasher :: IO IncrementalHasher
md5_hasher = mkIncrementalHasher Botan.MD5
md5s :: S.ByteString -> HashDigest
md5s = hashStrict Botan.MD5
hashLazy :: Botan.HashName -> L.ByteString -> HashDigest
hashLazy h b = unsafePerformIO $ do
hasher <- Botan.hashInit h
forM_ (L.toChunks b) (Botan.hashUpdate hasher)
HashDigest <$> Botan.hashFinal hasher
hashStrict :: Botan.HashName -> S.ByteString -> HashDigest
hashStrict h b = unsafePerformIO $ do
hasher <- Botan.hashInit h
Botan.hashUpdate hasher b
HashDigest <$> Botan.hashFinal hasher
mkIncrementalHasher :: Botan.HashName -> IO IncrementalHasher
mkIncrementalHasher h = do
hasher <- Botan.hashInit h
v <- newIORef (Just 0)
return $ IncrementalHasher
{ updateIncrementalHasher = \b -> do
readIORef v >>= \case
Just n -> do
let !n' = n + fromIntegral (S.length b)
writeIORef v (Just n')
Botan.hashUpdate hasher b
Nothing -> return ()
, finalizeIncrementalHasher = do
readIORef v >>= \case
Just _ -> Just . HashDigest
<$> Botan.hashFinal hasher
Nothing -> return Nothing
, unableIncrementalHasher = writeIORef v Nothing
, positionIncrementalHasher = readIORef v
}