This repository has been archived by the owner on Sep 20, 2023. It is now read-only.
/
Utils.hs
77 lines (72 loc) · 3.32 KB
/
Utils.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
{-# LANGUAGE MagicHash, BangPatterns #-}
-- |
-- Module : Crypto.Hash.Utils
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- 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"#