module HashByteString ( hashByteString ) where import Control.Monad import Control.Monad.Instances import Data.Bits import Data.ByteString (ByteString) import qualified Data.ByteString as ByteString import Data.Int import Data.Word data Mixer = MkMixer !Word32 !Word32 !Word32 !Int rotXor :: Word32 -> Int -> Word32 rotXor !n !m = (n `shiftL` m) `xor` (n `shiftR` (32 - m)) mix :: Mixer -> Mixer mix (MkMixer a0 b0 c0 n) = MkMixer a4 b4 c4 n where mix' !m !n !p !q = ((m - n) `xor` (n `rotXor` p), n + q) (!a1, !c1) = mix' a0 c0 4 b0 (!b1, !a2) = mix' b0 a1 6 c1 (!c2, !b2) = mix' c1 b1 8 a2 (!a3, !c3) = mix' a2 c2 16 b2 (!b3, !a4) = mix' b2 a3 19 c3 (!c4, !b4) = mix' c3 b3 4 a4 final :: Mixer -> Word32 final (MkMixer a0 b0 c0 _) = final' c2 b2 24 where final' !m !n !p = (m `xor` n) - (n `rotXor` p) !c1 = final' c0 b0 14 !a1 = final' a0 c1 11 !b1 = final' b0 a1 25 !c2 = final' c1 b1 16 !a2 = final' a1 c2 4 !b2 = final' b1 a2 14 lsl :: Word8 -> Int -> Word32 lsl !w !n = (fromIntegral w) `shiftL` n mixer :: (Mixer -> Mixer) -> Mixer -> Word8 -> Mixer mixer !_ (MkMixer a b c 0) !w = MkMixer (a + (w `lsl` 24)) b c 1 mixer !_ (MkMixer a b c 1) !w = MkMixer (a + (w `lsl` 16)) b c 2 mixer !_ (MkMixer a b c 2) !w = MkMixer (a + (w `lsl` 8)) b c 3 mixer !_ (MkMixer a b c 3) !w = MkMixer (a + (fromIntegral w)) b c 4 mixer !_ (MkMixer a b c 4) !w = MkMixer a (b + (w `lsl` 24)) c 5 mixer !_ (MkMixer a b c 5) !w = MkMixer a (b + (w `lsl` 16)) c 6 mixer !_ (MkMixer a b c 6) !w = MkMixer a (b + (w `lsl` 8)) c 7 mixer !_ (MkMixer a b c 7) !w = MkMixer a (b + (fromIntegral w)) c 8 mixer !_ (MkMixer a b c 8) !w = MkMixer a b (c + (w `lsl` 24)) 9 mixer !_ (MkMixer a b c 9) !w = MkMixer a b (c + (w `lsl` 16)) 10 mixer !_ (MkMixer a b c 10) !w = MkMixer a b (c + (w `lsl` 8)) 11 mixer !f (MkMixer a b c 11) !w = f $ MkMixer a b (c + (fromIntegral w)) 0 hashByteString :: ByteString -> Int32 hashByteString s | len == 0 = fromIntegral a0 | otherwise = fromIntegral $ final m2 where !len = ByteString.length s !rem = len `mod` 12 !i | rem == 0 = len - 12 | otherwise = len - rem (!s', !s'') = ByteString.splitAt i s !a0 = 0xdeadbeef + (fromIntegral len) m1 = ByteString.foldl' (mixer mix) (MkMixer a0 a0 a0 0) s' m2 = ByteString.foldl' (mixer id) m1 s''