large-hashable-0.1.0.0: benchmark/Data/LargeHashable/Benchmarks/CryptoHash.hs
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE MagicHash #-}
module Data.LargeHashable.Benchmarks.CryptoHash where
-- keep imports in alphabetic order (in Emacs, use "M-x sort-lines")
import Data.Bits
import Data.Byteable
import Data.List (foldl')
import Data.Word
import qualified Crypto.Hash as H
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Char8 as BSC
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
data HashAlgorithm
= MD5
| SHA256
| SHA512
deriving (Eq, Show)
data HashCtx = forall h . H.HashAlgorithm h => HashCtx !(H.Context h)
newtype Hash = Hash { unHash :: BS.ByteString }
deriving (Eq)
instance Show Hash where
show (Hash bs) =
BSC.unpack (Base16.encode bs)
hashMd5 :: LargeHashable h => h -> Hash
hashMd5 h =
let ctx = hashInit MD5
in hashFinish (hashUpdate ctx h)
hashInit :: HashAlgorithm -> HashCtx
hashInit alg =
case alg of
MD5 -> HashCtx (H.hashInit :: H.Context H.MD5)
SHA256 -> HashCtx (H.hashInit :: H.Context H.SHA256)
SHA512 -> HashCtx (H.hashInit :: H.Context H.SHA512)
hashFinish :: HashCtx -> Hash
hashFinish (HashCtx x) = Hash (toBytes $ H.hashFinalize x)
updateFromBuilder :: HashCtx -> B.Builder -> HashCtx
updateFromBuilder (HashCtx ctx) builder =
HashCtx (H.hashUpdates ctx (BSL.toChunks (B.toLazyByteString builder)))
class LargeHashable a where
hashUpdate :: HashCtx -> a -> HashCtx
instance LargeHashable BS.ByteString where
hashUpdate (HashCtx x) bs = HashCtx (H.hashUpdate x bs)
instance LargeHashable Int where
hashUpdate (HashCtx ctx) i =
-- we can make this faster by accessing the machine represenation of an int
let w = (fromIntegral (toInteger i)) :: Word64
in HashCtx (H.hashUpdate ctx (BS.pack [(fromIntegral (shiftR w 56) :: Word8)
,(fromIntegral (shiftR w 48) :: Word8)
,(fromIntegral (shiftR w 40) :: Word8)
,(fromIntegral (shiftR w 32) :: Word8)
,(fromIntegral (shiftR w 24) :: Word8)
,(fromIntegral (shiftR w 16) :: Word8)
,(fromIntegral (shiftR w 8) :: Word8)
,(fromIntegral (w) :: Word8)]))
instance LargeHashable T.Text where
hashUpdate (HashCtx ctx) t = HashCtx (H.hashUpdate ctx (T.encodeUtf8 t))
instance LargeHashable a => LargeHashable [a] where
hashUpdate ctx l =
foldl' hashUpdate ctx l