{-# LANGUAGE MagicHash, BangPatterns #-} -- | -- Module : Crypto.Hash.Utils -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unknown -- -- Crypto hash utility for hexadecimal -- module Crypto.Hash.Utils ( toHex ) where import Data.ByteString (ByteString) import qualified Data.ByteString.Internal as B import GHC.Prim import GHC.Types import GHC.Word import Foreign.ForeignPtr (withForeignPtr) import Foreign.Ptr (plusPtr, castPtr) import Foreign.Storable (poke, peek) import Crypto.Hash.Utils.Cpu import Data.Bits (testBit) -- | Convert a bytestring to the hexadecimal equivalent -- using 0123456789abcdef as digit toHex :: ByteString -> ByteString toHex (B.PS fp off len) = B.unsafeCreate (len*2) $ \d -> withForeignPtr fp $ \s -> start d (s `plusPtr` off) where start db sb | use32Hex && (len `testBit` 0) == False = loop32 db sb | otherwise = loop8 db sb where end = sb `plusPtr` len -- write the hex output using 32 bits write. loop32 d s | s == end = return () | otherwise = do b1 <- fromIntegral `fmap` (peek s :: IO Word8) b2 <- fromIntegral `fmap` (peek (s `plusPtr` 1) :: IO Word8) poke (castPtr d) (to32 b1 b2) loop32 (d `plusPtr` 4) (s `plusPtr` 2) -- write the hex output 8 bits, 2 at a time loop8 d s | s == end = return () | otherwise = do b <- fromIntegral `fmap` (peek s :: IO Word8) poke d (r tableHi b) poke (d `plusPtr` 1) (r tableLo b) loop8 (d `plusPtr` 2) (s `plusPtr` 1) -- little endian version to32 (I# i1) (I# i2) = W32# (or# (or# (or# hi2 lo2) hi1) lo1) where hi2 = uncheckedShiftL# (indexWord8OffAddr# tableLo i2) 24# lo2 = uncheckedShiftL# (indexWord8OffAddr# tableHi i2) 16# hi1 = uncheckedShiftL# (indexWord8OffAddr# tableLo i1) 8# lo1 = indexWord8OffAddr# tableHi i1 r :: Addr# -> Int -> Word8 r table (I# index) = W8# (indexWord8OffAddr# table index) !tableLo = "0123456789abcdef0123456789abcdef\ \0123456789abcdef0123456789abcdef\ \0123456789abcdef0123456789abcdef\ \0123456789abcdef0123456789abcdef\ \0123456789abcdef0123456789abcdef\ \0123456789abcdef0123456789abcdef\ \0123456789abcdef0123456789abcdef\ \0123456789abcdef0123456789abcdef"# !tableHi = "00000000000000001111111111111111\ \22222222222222223333333333333333\ \44444444444444445555555555555555\ \66666666666666667777777777777777\ \88888888888888889999999999999999\ \aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb\ \ccccccccccccccccdddddddddddddddd\ \eeeeeeeeeeeeeeeeffffffffffffffff"#