LslPlus-0.1.4: src/Language/Lsl/Internal/SHA1.hs
module Language.Lsl.Internal.SHA1(hashStoI,hashStoHex) where
import Text.Printf
import Codec.Binary.UTF8.String
import Data.Array(Array,array,(!))
import Data.Bits(Bits,(.|.),(.&.),xor,rotateL,shiftR,shiftL,complement)
import Data.List(foldl')
import Data.Word(Word8,Word32)
hashStoI = digestToInteger . hash . encode
hash = foldl' (\ buf block -> addDigest buf (processMessageBlock buf block)) ss . blocks512
hashStoHex :: String -> String
hashStoHex s = printf "%040X" (hashStoI s)
data Digest = Digest { eA :: !Word32,
eB :: !Word32,
eC :: !Word32,
eD :: !Word32,
eE :: !Word32 }
deriving (Eq, Show)
addDigest (Digest a1 b1 c1 d1 e1) (Digest a2 b2 c2 d2 e2) = Digest (a1+a2) (b1+b2) (c1+c2) (d1+d2) (e1+e2)
digestToInteger :: Digest -> Integer
digestToInteger (Digest a b c d e) = let n = fromIntegral e +
(fromIntegral d `shiftL` 32) +
(fromIntegral c `shiftL` 64) +
(fromIntegral b `shiftL` 96) +
(fromIntegral a `shiftL` 128)
in n
ks :: Array Int Word32
ks = array (0,79) $ zip [0..] $ concatMap (replicate 20) [0x5a827999,0x6ed9eba1,0x8f1bbcdc,0xca62c1d6]
fs :: Array Int (Word32 -> Word32 -> Word32 -> Word32)
fs = array (0,79) $ zip [0..] $ concatMap (replicate 20) [ \ x y z -> (x .&. y) .|. ((complement x) .&. z),
\ x y z -> x `xor` y `xor` z,
\ x y z -> (x .&. y) .|. (x .&. z) .|. (y .&. z),
\ x y z -> x `xor` y `xor` z ]
processMessageBlock i words =
let foo' n i [] = i
foo' n i (w:ws) =
let i' = (Digest ((eA i `rotateL` 5) + ((fs ! n) (eB i) (eC i) (eD i)) + eE i + w + (ks ! n)) (eA i) (eB i `rotateL` 30) (eC i) (eD i))
in foo' (n + 1) i' ws
in foo' 0 i (compute80Ws words)
compute80Ws :: [Word32] -> [Word32]
compute80Ws xs =
let foo i (q:qs) rs
| i < 16 = q : foo (i + 1) qs (q:rs)
| otherwise =
let v = (rs !! 2 `xor` rs !! 7 `xor` rs !! 13`xor` rs !! 15) `rotateL` 1
in v : foo (i + 1) qs (v:rs)
in take 80 $ foo 0 (xs ++ repeat 0) []
ss :: Digest
ss = Digest 0x67452301 0xefcdab89 0x98badcfe 0x10325476 0xc3d2e1f0
getByte v i = fromIntegral $ (v `shiftR` (i*8)) .&. 0x0ff
padMessage :: [Word8] -> [Word8]
padMessage msg =
let f :: Int -> [Word8] -> [Word8]
f n [] = 0x80:((replicate (64 - ((n + 9) `mod` 64)) 0) ++ map (getByte (8*n)) [7,6..0])
f n (b:bs) = b : (f (n+1) bs)
in f 0 msg
bytesToWord :: [Word8] -> Word32
bytesToWord = go 0
where go acc [] = acc
go acc (b:bs) = go ((acc `shiftL` 8) .|. fromIntegral b) bs
chunk _ [] = []
chunk n l = take n l : chunk n (drop n l)
blocks512 :: [Word8] -> [[Word32]]
blocks512 = (map (map bytesToWord . chunk 4)) . chunk 64 . padMessage