[Fencommits] fenserve: refactor SHA1.hs to use Data.ByteString; still doesn't fix the speed problem :-/

Benja Fallenstein benja.fallenstein at gmail.com
Sat Mar 31 20:18:29 EEST 2007


Sat Mar 31 20:18:16 EEST 2007  Benja Fallenstein <benja.fallenstein at gmail.com>
  * refactor SHA1.hs to use Data.ByteString; still doesn't fix the speed problem :-/
diff -rN -u old-fenserve/SHA1.hs new-fenserve/SHA1.hs
--- old-fenserve/SHA1.hs	2007-03-31 20:18:29.000000000 +0300
+++ new-fenserve/SHA1.hs	2007-03-31 20:18:29.000000000 +0300
@@ -51,52 +51,53 @@
   * Converted to use [Word8] instead of String
 
 Benja Fallenstein, 2007-03-31:
-  * Refactored to use Data.Array.ST
+  * Refactored to use Data.ByteString and Data.Array.ST
   * Changed from .lhs to .hs
 =============================================================================
 -}
 
-module SHA1 (sha1, sha1_size) where
+module SHA1 (sha1) where
 
-import Control.Monad.ST
+import Control.Monad.ST.Strict
 
 import Data.Array.ST
-import Data.Char
 import Data.Bits
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Data.Char
 import Data.Word
 
 type ABCDE = (Word32, Word32, Word32, Word32, Word32)
 type XYZ = (Word32, Word32, Word32)
 type Rotation = Int
 
-sha1 :: [Word8] -> String
+sha1 :: ByteString -> String
 sha1 s = s5
  where s1_2 = sha1_step_1_2_pad_length s
        abcde = sha1_step_3_init
        abcde' = sha1_step_4_main abcde s1_2
        s5 = sha1_step_5_display abcde'
 
+{-
 sha1_size :: (Integral a) => a -> [Word8] -> String
 sha1_size l s = s5
  where s1_2 = s ++ sha1_step_1_2_work (fromIntegral ((toInteger l) `mod` (2^64))) []
        abcde = sha1_step_3_init
        abcde' = sha1_step_4_main abcde s1_2
        s5 = sha1_step_5_display abcde'
+-}
 
-sha1_step_1_2_pad_length :: [Word8] -> [Word8]
-sha1_step_1_2_pad_length s = sha1_step_1_2_work 0 s
-
-sha1_step_1_2_work :: Integer -> [Word8] -> [Word8]
-sha1_step_1_2_work c64 [] = padding ++ len
- where padding = 128:replicate' (shiftR (fromIntegral $ (440 - c64) `mod` 512) 3) 0
-       len = map fromIntegral $ size_split 8 c64
-sha1_step_1_2_work c64 (c:cs) = c:sha1_step_1_2_work ((c64 + 8) `mod` (2^64)) cs
+sha1_step_1_2_pad_length :: ByteString -> ByteString
+sha1_step_1_2_pad_length bytes = B.append bytes (B.pack (padding ++ lenBytes)) where
+    padding = 128:replicate' (shiftR (fromIntegral $ (440-len) `mod` 512) 3) 0
+    lenBytes = map fromIntegral $ size_split 8 len
+    len = fromInteger ((toInteger $ 8 * B.length bytes) `mod` (2^64))
 
 replicate' :: Word16 -> a -> [a]
 replicate' 0 _ = []
 replicate' n x = x:replicate' (n-1) x
 
-size_split :: Int -> Integer -> [Int]
+size_split :: Int -> Int -> [Int]
 size_split 0 _ = []
 size_split p n = size_split (p-1) n' ++ [fromIntegral d]
  where (n', d) = divMod n 256
@@ -104,16 +105,19 @@
 sha1_step_3_init :: ABCDE
 sha1_step_3_init = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0)
 
-sha1_step_4_main :: ABCDE -> [Word8] -> ABCDE
+sha1_step_4_main :: ABCDE -> ByteString -> ABCDE
 sha1_step_4_main abcde s = runST st where
-    st = newArray (0,79) 0 >>= sha1_step_4_work abcde s
+    st = newArray (0,79) 0 >>= sha1_step_4_work abcde s 0
 
 type Arr s = STUArray s Int Word32
 
-sha1_step_4_work :: ABCDE -> [Word8] -> Arr s -> ST s ABCDE
-sha1_step_4_work abcde [] arr = return abcde
-sha1_step_4_work abcde0 s arr = do
-   s' <- sha1_ws 0 s arr
+abcseq :: ABCDE -> a -> a
+abcseq (a,b,c,d,e) x = a `seq` b `seq` c `seq` d `seq` e `seq` x
+
+sha1_step_4_work :: ABCDE -> ByteString -> Int -> Arr s -> ST s ABCDE
+sha1_step_4_work abcde s offs arr | offs >= B.length s = return abcde
+sha1_step_4_work abcde0 s offs arr = abcde0 `abcseq` do
+   sha1_ws 0 s offs arr
    sha1_add_ws 16 arr
    let f1 (x, y, z) = (x .&. y) .|. ((complement x) .&. z)
        f2 (x, y, z) = x `xor` y `xor` z
@@ -125,16 +129,18 @@
    let (a,  b,  c,  d,  e ) = abcde0
        (a', b', c', d', e') = abcde4
        abcde5 = (a + a', b + b', c + c', d + d', e + e')
-   sha1_step_4_work abcde5 s' arr
+   sha1_step_4_work abcde5 s (offs+64) arr
 
 doit :: (XYZ -> Word32) -> Word32 -> ABCDE -> Word32 -> ABCDE
 doit f k (a, b, c, d, e) w = (a', a, rotL b 30, c, d)
  where a' = rotL a 5 + f(b, c, d) + e + w + k
 
-sha1_ws :: Int -> [Word8] -> Arr s -> ST s [Word8]
-sha1_ws 16 s arr = return s
-sha1_ws n (b1:b2:b3:b4:s) arr = do writeArray arr n w; sha1_ws (n+1) s arr
- where w = f b1 24 + f b2 16 + f b3 8 + f b4 0; f x = shiftL (fromIntegral x)
+sha1_ws :: Int -> ByteString -> Int -> Arr s -> ST s ByteString
+sha1_ws 16 s offs arr = return s
+sha1_ws n s offs arr = do 
+    let bs = map (\i -> B.index s (n+offs+i)) [0..3]
+        w = sum $ zipWith shiftL (map fromIntegral bs) [24, 16, 8, 0]
+    writeArray arr n w;  sha1_ws (n+1) s offs arr
 
 sha1_add_ws :: Int -> Arr s -> ST s ()
 sha1_add_ws 80 arr = return ()
@@ -142,10 +148,11 @@
                        writeArray arr n $ rotL (foldr1 xor w1234) 1 
                        sha1_add_ws (n+1) arr
 
-fold_arr :: (a -> Word32 -> a) -> a -> Arr s -> (Int,Int) -> ST s a
+fold_arr :: (ABCDE -> Word32 -> ABCDE) -> ABCDE -> Arr s -> (Int,Int) -> 
+            ST s ABCDE
 fold_arr f x arr (i,j) | i > j = return x
-                       | otherwise = do val <- readArray arr i
-                                        fold_arr f (f x val) arr (i+1,j)
+                       | otherwise = do
+    val <- readArray arr i;   x `abcseq` fold_arr f (f x val) arr (i+1,j)
 
 sha1_step_5_display :: ABCDE -> String
 sha1_step_5_display (a, b, c, d, e)




More information about the Fencommits mailing list