diff --git a/Data/CryptoHash/MD2.hs b/Data/CryptoHash/MD2.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/MD2.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.MD2
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing MD2 bindings
+--
+module Data.CryptoHash.MD2 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 16
+sizeCtx = 96
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "md2.h md2_init"
+	c_md2_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "md2.h md2_update"
+	c_md2_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "md2.h md2_finalize"
+	c_md2_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_md2_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_md2_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_md2_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_md2_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_md2_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/MD4.hs b/Data/CryptoHash/MD4.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/MD4.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.MD4
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing MD4 bindings
+--
+module Data.CryptoHash.MD4 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 16
+sizeCtx = 96
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "md4.h md4_init"
+	c_md4_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "md4.h md4_update"
+	c_md4_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "md4.h md4_finalize"
+	c_md4_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_md4_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_md4_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_md4_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_md4_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_md4_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/MD5.hs b/Data/CryptoHash/MD5.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/MD5.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.MD5
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing MD5 bindings
+--
+module Data.CryptoHash.MD5 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 16
+sizeCtx = 96
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "md5.h md5_init"
+	c_md5_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "md5.h md5_update"
+	c_md5_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "md5.h md5_finalize"
+	c_md5_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_md5_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_md5_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_md5_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_md5_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_md5_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/RIPEMD160.hs b/Data/CryptoHash/RIPEMD160.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/RIPEMD160.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.RIPEMD160
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing RIPEMD160 bindings
+--
+module Data.CryptoHash.RIPEMD160 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 20
+sizeCtx = 128
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "ripemd.h ripemd160_init"
+	c_ripemd160_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "ripemd.h ripemd160_update"
+	c_ripemd160_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "ripemd.h ripemd160_finalize"
+	c_ripemd160_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_ripemd160_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_ripemd160_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_ripemd160_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_ripemd160_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_ripemd160_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/SHA1.hs b/Data/CryptoHash/SHA1.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/SHA1.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.SHA1
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing SHA1 bindings
+--
+module Data.CryptoHash.SHA1 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 20
+sizeCtx = 96
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "sha1.h sha1_init"
+	c_sha1_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "sha1.h sha1_update"
+	c_sha1_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "sha1.h sha1_finalize"
+	c_sha1_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_sha1_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_sha1_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha1_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha1_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha1_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/SHA224.hs b/Data/CryptoHash/SHA224.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/SHA224.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.SHA224
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing SHA224 bindings
+--
+module Data.CryptoHash.SHA224 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 28
+sizeCtx = 192
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "sha256.h sha224_init"
+	c_sha224_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "sha256.h sha224_update"
+	c_sha224_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "sha256.h sha224_finalize"
+	c_sha224_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_sha224_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_sha224_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha224_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha224_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha224_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/SHA256.hs b/Data/CryptoHash/SHA256.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/SHA256.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.SHA256
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing SHA256 bindings
+--
+module Data.CryptoHash.SHA256 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 32
+sizeCtx = 192
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "sha256.h sha256_init"
+	c_sha256_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "sha256.h sha256_update"
+	c_sha256_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "sha256.h sha256_finalize"
+	c_sha256_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_sha256_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_sha256_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha256_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha256_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha256_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/SHA384.hs b/Data/CryptoHash/SHA384.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/SHA384.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.SHA384
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing SHA384 bindings
+--
+module Data.CryptoHash.SHA384 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 48
+sizeCtx = 256
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "sha512.h sha384_init"
+	c_sha384_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "sha512.h sha384_update"
+	c_sha384_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "sha512.h sha384_finalize"
+	c_sha384_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_sha384_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_sha384_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha384_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha384_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha384_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Data/CryptoHash/SHA512.hs b/Data/CryptoHash/SHA512.hs
new file mode 100644
--- /dev/null
+++ b/Data/CryptoHash/SHA512.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+-- Module      : Data.CryptoHash.SHA512
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing SHA512 bindings
+--
+module Data.CryptoHash.SHA512 (
+	Ctx(..),
+
+	-- * Incremental hashing Functions
+	init,      -- :: Ctx
+	update,    -- :: Ctx -> ByteString -> Ctx
+	finalize,  -- :: Ctx -> ByteString
+
+	-- * Single Pass hashing
+	hash,      -- :: ByteString -> ByteString
+	hashlazy   -- :: ByteString -> ByteString
+	) where
+
+import Prelude hiding (init)
+import Foreign
+import Foreign.C.String
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen, unsafeIndex)
+import Data.ByteString.Internal (create)
+
+data Ctx = Ctx ByteString
+
+digestSize :: Int
+sizeCtx :: Int
+
+digestSize = 64
+sizeCtx = 256
+
+instance Storable Ctx where
+	sizeOf _    = sizeCtx
+	alignment _ = 16
+	poke ptr (Ctx b) = mapM_ (\i -> poke (ptr `plusPtr` i) (unsafeIndex b i)) [0..(sizeCtx-1)]
+
+	peek ptr = do
+		b <- create sizeCtx (\bptr -> mapM_ (\i -> do
+			f <- peek (ptr `plusPtr` i) :: IO Word8
+			poke (bptr `plusPtr` i) f
+			) [0..(sizeCtx-1)])
+		return $ Ctx $! b
+
+foreign import ccall unsafe "sha512.h sha512_init"
+	c_sha512_init :: Ptr Ctx -> IO ()
+
+foreign import ccall unsafe "sha512.h sha512_update"
+	c_sha512_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+
+foreign import ccall unsafe "sha512.h sha512_finalize"
+	c_sha512_finalize :: Ptr Ctx -> CString -> IO ()
+
+allocInternal :: (Ptr Ctx -> IO a) -> IO a
+allocInternal = alloca
+
+allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+	unsafeUseAsCStringLen d (\(cs, len) -> c_sha512_update ptr cs (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+	allocaBytes digestSize (\cs -> c_sha512_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Ctx
+init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha512_init ptr >> peek ptr)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do updateInternalIO ptr d >> peek ptr
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha512_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
+	c_sha512_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2010 Vincent Hanquez <vincent@snarc.org>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Tests.hs b/Tests.hs
new file mode 100644
--- /dev/null
+++ b/Tests.hs
@@ -0,0 +1,123 @@
+import Test.HUnit
+import Data.Char
+import Data.Bits
+import Data.Word
+import qualified Data.ByteString as B
+import qualified Data.CryptoHash.MD2 as MD2
+import qualified Data.CryptoHash.MD4 as MD4
+import qualified Data.CryptoHash.MD5 as MD5
+import qualified Data.CryptoHash.SHA1 as SHA1
+import qualified Data.CryptoHash.SHA224 as SHA224
+import qualified Data.CryptoHash.SHA256 as SHA256
+import qualified Data.CryptoHash.SHA384 as SHA384
+import qualified Data.CryptoHash.SHA512 as SHA512
+import qualified Data.CryptoHash.RIPEMD160 as RIPEMD160
+
+v0 = ""
+v1 = "The quick brown fox jumps over the lazy dog"
+v2 = "The quick brown fox jumps over the lazy cog"
+vectors = [ v0, v1, v2 ]
+
+data HashFct = HashFct
+	{ fctHash   :: (B.ByteString -> B.ByteString)
+	, fctInc    :: ([B.ByteString] -> B.ByteString) }
+
+hashinc i u f = f . foldl u i
+
+md2Hash    = HashFct { fctHash = MD2.hash, fctInc = hashinc MD2.init MD2.update MD2.finalize }
+md4Hash    = HashFct { fctHash = MD4.hash, fctInc = hashinc MD4.init MD4.update MD4.finalize }
+md5Hash    = HashFct { fctHash = MD5.hash, fctInc = hashinc MD5.init MD5.update MD5.finalize }
+sha1Hash   = HashFct { fctHash = SHA1.hash, fctInc = hashinc SHA1.init SHA1.update SHA1.finalize }
+sha224Hash = HashFct { fctHash = SHA224.hash, fctInc = hashinc SHA224.init SHA224.update SHA224.finalize }
+sha256Hash = HashFct { fctHash = SHA256.hash, fctInc = hashinc SHA256.init SHA256.update SHA256.finalize }
+sha384Hash = HashFct { fctHash = SHA384.hash, fctInc = hashinc SHA384.init SHA384.update SHA384.finalize }
+sha512Hash = HashFct { fctHash = SHA512.hash, fctInc = hashinc SHA512.init SHA512.update SHA512.finalize }
+ripemd160Hash = HashFct { fctHash = RIPEMD160.hash, fctInc = hashinc RIPEMD160.init RIPEMD160.update RIPEMD160.finalize }
+
+results :: [ (String, HashFct, [String]) ]
+results = [
+	("MD2", md2Hash, [
+		"8350e5a3e24c153df2275c9f80692773",
+		"03d85a0d629d2c442e987525319fc471",
+		"6b890c9292668cdbbfda00a4ebf31f05" ]),
+	("MD4", md4Hash, [
+		"31d6cfe0d16ae931b73c59d7e0c089c0",
+		"1bee69a46ba811185c194762abaeae90",
+		"b86e130ce7028da59e672d56ad0113df" ]),
+	("MD5", md5Hash, [
+		"d41d8cd98f00b204e9800998ecf8427e",
+		"9e107d9d372bb6826bd81d3542a419d6",
+		"1055d3e698d289f2af8663725127bd4b" ]),
+	("SHA1", sha1Hash, [
+		"da39a3ee5e6b4b0d3255bfef95601890afd80709",
+		"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
+		"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3" ]),
+	("SHA224", sha224Hash, [
+		"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
+		"730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525",
+		"fee755f44a55f20fb3362cdc3c493615b3cb574ed95ce610ee5b1e9b" ]),
+	("SHA256", sha256Hash, [
+		"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+		"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
+		"e4c4d8f3bf76b692de791a173e05321150f7a345b46484fe427f6acc7ecc81be" ]),
+	("SHA384", sha384Hash, [
+		"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
+		"ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1",
+		"098cea620b0978caa5f0befba6ddcf22764bea977e1c70b3483edfdf1de25f4b40d6cea3cadf00f809d422feb1f0161b" ]),
+	("SHA512", sha512Hash, [
+		"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
+		"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
+		"3eeee1d0e11733ef152a6c29503b3ae20c4f1f3cda4cb26f1bc1a41f91c7fe4ab3bd86494049e201c4bd5155f31ecb7a3c8606843c4cc8dfcab7da11c8ae5045" ]),
+	("RIPEMD160", ripemd160Hash, [
+		"9c1185a5c5e9fc54612808977ee8f548b2258d31",
+		"37f332f68db77bd9d7edd4969571ad671cf9dd3b",
+		"132072df690933835eb8b6ad0b77e7b6f14acad7" ])
+	]
+
+hexalise s =
+        concatMap (\c -> [ hex $ c `div` 16, hex $ c `mod` 16 ]) s
+        where hex i
+                | i >= 0 && i <= 9   = fromIntegral (ord '0') + i
+                | i >= 10 && i <= 15 = fromIntegral (ord 'a') + i - 10
+                | otherwise          = 0
+
+hexaliseB :: B.ByteString -> B.ByteString
+hexaliseB = B.pack . hexalise . B.unpack
+
+splitB l b =
+	if B.length b > l
+		then
+			let (b1, b2) = B.splitAt l b in
+			b1 : splitB l b2
+		else	
+			[ b ]
+
+showHash :: B.ByteString -> String
+showHash = map (toEnum.fromEnum) . hexalise . B.unpack
+
+runhash hash v = showHash $ (fctHash hash) $ v
+runhashinc hash v = showHash $ (fctInc hash) $ v
+
+makeTestAlg (name, hash, results) = concatMap maketest $ zip3 [0..] vectors results
+	where
+		testname i = name ++ " " ++ show i
+		runtest v = runhash hash $ B.pack $ map (toEnum.fromEnum) v
+
+		runtestinc i v = runhashinc hash $ splitB i $ B.pack $ map (toEnum.fromEnum) v
+
+		maketest (i, v, r) =
+			[ testname i ~: testname i ~: r ~=? (runtest v),
+			  testname i ~: testname i ~: r ~=? (runtestinc 1 v),
+			  testname i ~: testname i ~: r ~=? (runtestinc 2 v),
+			  testname i ~: testname i ~: r ~=? (runtestinc 3 v),
+			  testname i ~: testname i ~: r ~=? (runtestinc 4 v),
+			  testname i ~: testname i ~: r ~=? (runtestinc 5 v),
+			  testname i ~: testname i ~: r ~=? (runtestinc 9 v),
+			  testname i ~: testname i ~: r ~=? (runtestinc 16 v) ]
+
+mapTests :: [Test]
+mapTests = concatMap makeTestAlg results
+
+tests = TestList mapTests
+
+main = runTestTT tests
diff --git a/cbits/md2.c b/cbits/md2.c
new file mode 100644
--- /dev/null
+++ b/cbits/md2.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2006-2010 Vincent Hanquez <vincent@snarc.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "bitfn.h"
+#include "md2.h"
+
+void md2_init(struct md2_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->sz = 0ULL;
+}
+
+static uint8_t S_table[]  = {
+	0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 
+	0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 
+	0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 
+	0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, 
+	0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
+	0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 
+	0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, 
+	0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 
+	0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, 
+	0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, 
+	0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 
+	0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, 
+	0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 
+	0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 
+	0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 
+	0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
+};
+
+static uint8_t *padding_table[] = {
+	"",
+	"\x1",
+	"\x2\x2",
+	"\x3\x3\x3",
+	"\x4\x4\x4\x4",
+	"\x5\x5\x5\x5\x5",
+	"\x6\x6\x6\x6\x6\x6",
+	"\x7\x7\x7\x7\x7\x7\x7",
+	"\x8\x8\x8\x8\x8\x8\x8\x8",
+	"\x9\x9\x9\x9\x9\x9\x9\x9\x9",
+	"\xa\xa\xa\xa\xa\xa\xa\xa\xa\xa",
+	"\xb\xb\xb\xb\xb\xb\xb\xb\xb\xb\xb",
+	"\xc\xc\xc\xc\xc\xc\xc\xc\xc\xc\xc\xc",
+	"\xd\xd\xd\xd\xd\xd\xd\xd\xd\xd\xd\xd\xd",
+	"\xe\xe\xe\xe\xe\xe\xe\xe\xe\xe\xe\xe\xe\xe",
+	"\xf\xf\xf\xf\xf\xf\xf\xf\xf\xf\xf\xf\xf\xf\xf",
+	"\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10"
+};
+
+static void md2_do_chunk(struct md2_ctx *ctx, uint8_t *buf)
+{
+	uint8_t i, j, t;
+	uint8_t x[48];
+
+	memcpy(x, ctx->h, 16);
+	memcpy(x+16, buf, 16);
+
+	for (i = 0; i < 16; i++)
+		x[i+32] = ctx->h[i] ^ buf[i];
+
+	for (t = i = 0; i < 18; i++) {
+		for (j = 0; j < 48; j++)
+			t = x[j] ^= S_table[t];
+		t = (t + i) & 0xff;
+	}
+
+	memcpy (ctx->h, x, 16);
+
+	t = ctx->cksum[15];
+	for (i = 0; i < 16; i++)
+		t = ctx->cksum[i] ^= S_table[buf[i] ^ t];
+}
+
+void md2_update(struct md2_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	uint32_t index, to_fill;
+
+	index = (uint32_t) (ctx->sz & 0xf);
+	to_fill = 16 - index;
+
+	ctx->sz += len;
+
+	if (index && len >= to_fill) {
+		memcpy(ctx->buf + index, data, to_fill);
+		md2_do_chunk(ctx, ctx->buf);
+		len -= to_fill;
+		data += to_fill;
+		index = 0;
+	}
+
+	/* process as much 16-block as possible */
+	for (; len >= 16; len -= 16, data += 16)
+		md2_do_chunk(ctx, data);
+
+	/* append data into buf */
+	if (len)
+		memcpy(ctx->buf + index, data, len);
+}
+
+void md2_finalize(struct md2_ctx *ctx, uint8_t *out)
+{
+	uint32_t index, padlen;
+
+	index = ctx->sz & 0xf;
+	padlen = 16 - index;
+
+	md2_update(ctx, padding_table[padlen], padlen);
+	md2_update(ctx, ctx->cksum, 16);
+	memcpy(out, ctx->h, 16);
+}
diff --git a/cbits/md4.c b/cbits/md4.c
new file mode 100644
--- /dev/null
+++ b/cbits/md4.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "bitfn.h"
+#include "md4.h"
+
+void md4_init(struct md4_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->sz = 0ULL;
+	ctx->h[0] = 0x67452301;
+	ctx->h[1] = 0xefcdab89;
+	ctx->h[2] = 0x98badcfe;
+	ctx->h[3] = 0x10325476;
+}
+
+#define f1(x, y, z)	((x & y) | ((~x) & z))
+#define f2(x, y, z)	((x & y) | (x & z) | (y & z))
+#define f3(x, y, z)	(x ^ y ^ z)
+
+#define K1 	0x00000000
+#define K2 	0x5A827999
+#define K3 	0x6ED9EBA1
+#define R(a,b,c,d,f,k,s,i) (a = rol32(a + f(b,c,d) + w[i] + k, s))
+
+static void md4_do_chunk(struct md4_ctx *ctx, uint32_t *buf)
+{
+	uint32_t a, b, c, d;
+#ifdef ARCH_IS_BIG_ENDIAN
+	uint32_t w[16];
+	cpu_to_le32_array(w, (uint32_t *) buf, 16);
+#else
+	uint32_t *w = buf;
+#endif
+
+	a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];
+
+	R(a, b, c, d, f1, K1, 3, 0);
+	R(d, a, b, c, f1, K1, 7, 1);
+	R(c, d, a, b, f1, K1, 11, 2);
+	R(b, c, d, a, f1, K1, 19, 3);
+	R(a, b, c, d, f1, K1, 3, 4);
+	R(d, a, b, c, f1, K1, 7, 5);
+	R(c, d, a, b, f1, K1, 11, 6);
+	R(b, c, d, a, f1, K1, 19, 7);
+	R(a, b, c, d, f1, K1, 3, 8);
+	R(d, a, b, c, f1, K1, 7, 9);
+	R(c, d, a, b, f1, K1, 11, 10);
+	R(b, c, d, a, f1, K1, 19, 11);
+	R(a, b, c, d, f1, K1, 3, 12);
+	R(d, a, b, c, f1, K1, 7, 13);
+	R(c, d, a, b, f1, K1, 11, 14);
+	R(b, c, d, a, f1, K1, 19, 15);
+
+	R(a, b, c, d, f2, K2, 3, 0);
+	R(d, a, b, c, f2, K2, 5, 4);
+	R(c, d, a, b, f2, K2, 9, 8);
+	R(b, c, d, a, f2, K2, 13, 12);
+	R(a, b, c, d, f2, K2, 3, 1);
+	R(d, a, b, c, f2, K2, 5, 5);
+	R(c, d, a, b, f2, K2, 9, 9);
+	R(b, c, d, a, f2, K2, 13, 13);
+	R(a, b, c, d, f2, K2, 3, 2);
+	R(d, a, b, c, f2, K2, 5, 6);
+	R(c, d, a, b, f2, K2, 9, 10);
+	R(b, c, d, a, f2, K2, 13, 14);
+	R(a, b, c, d, f2, K2, 3, 3);
+	R(d, a, b, c, f2, K2, 5, 7);
+	R(c, d, a, b, f2, K2, 9, 11);
+	R(b, c, d, a, f2, K2, 13, 15);
+
+	R(a, b, c, d, f3, K3, 3, 0);
+	R(d, a, b, c, f3, K3, 9, 8);
+	R(c, d, a, b, f3, K3, 11, 4);
+	R(b, c, d, a, f3, K3, 15, 12);
+	R(a, b, c, d, f3, K3, 3, 2);
+	R(d, a, b, c, f3, K3, 9, 10);
+	R(c, d, a, b, f3, K3, 11, 6);
+	R(b, c, d, a, f3, K3, 15, 14);
+	R(a, b, c, d, f3, K3, 3, 1);
+	R(d, a, b, c, f3, K3, 9, 9);
+	R(c, d, a, b, f3, K3, 11, 5);
+	R(b, c, d, a, f3, K3, 15, 13);
+	R(a, b, c, d, f3, K3, 3, 3);
+	R(d, a, b, c, f3, K3, 9, 11);
+	R(c, d, a, b, f3, K3, 11, 7);
+	R(b, c, d, a, f3, K3, 15, 15);
+
+	ctx->h[0] += a; ctx->h[1] += b; ctx->h[2] += c; ctx->h[3] += d;
+}
+
+void md4_update(struct md4_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	uint32_t index, to_fill;
+
+	index = (uint32_t) (ctx->sz & 0x3f);
+	to_fill = 64 - index;
+
+	ctx->sz += len;
+
+	if (index && len >= to_fill) {
+		memcpy(ctx->buf + index, data, to_fill);
+		md4_do_chunk(ctx, (uint32_t *) ctx->buf);
+		len -= to_fill;
+		data += to_fill;
+		index = 0;
+	}
+
+	/* process as much 64-block as possible */
+	for (; len >= 64; len -= 64, data += 64)
+		md4_do_chunk(ctx, (uint32_t *) data);
+
+	/* append data into buf */
+	if (len)
+		memcpy(ctx->buf + index, data, len);
+}
+
+void md4_finalize(struct md4_ctx *ctx, uint8_t *out)
+{
+	static uint8_t padding[64] = { 0x80, };
+	uint64_t bits;
+	uint32_t index, padlen;
+
+	/* add padding and update data with it */
+	bits = cpu_to_le64(ctx->sz << 3);
+
+	/* pad out to 56 */
+	index = (uint32_t) (ctx->sz & 0x3f);
+	padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+	md4_update(ctx, padding, padlen);
+
+	/* append length */
+	md4_update(ctx, (uint8_t *) &bits, sizeof(bits));
+
+	/* output hash */
+	le32_to_cpu_array((uint32_t *) out, ctx->h, 4);
+}
diff --git a/cbits/md5.c b/cbits/md5.c
new file mode 100644
--- /dev/null
+++ b/cbits/md5.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "bitfn.h"
+#include "md5.h"
+
+void md5_init(struct md5_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->sz = 0ULL;
+	ctx->h[0] = 0x67452301;
+	ctx->h[1] = 0xefcdab89;
+	ctx->h[2] = 0x98badcfe;
+	ctx->h[3] = 0x10325476;
+}
+
+#define f1(x, y, z)	(z ^ (x & (y ^ z)))
+#define f2(x, y, z)	f1(z, x, y)
+#define f3(x, y, z)	(x ^ y ^ z)
+#define f4(x, y, z)	(y ^ (x | ~z))
+#define R(f, a, b, c, d, i, k, s) a += f(b, c, d) + w[i] + k; a = rol32(a, s); a += b
+
+static void md5_do_chunk(struct md5_ctx *ctx, uint32_t *buf)
+{
+	uint32_t a, b, c, d;
+#ifdef ARCH_IS_BIG_ENDIAN
+	uint32_t w[16];
+	cpu_to_le32_array(w, buf, 16);
+#else
+	uint32_t *w = buf;
+#endif
+	a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];
+
+	R(f1, a, b, c, d, 0, 0xd76aa478, 7);
+	R(f1, d, a, b, c, 1, 0xe8c7b756, 12);
+	R(f1, c, d, a, b, 2, 0x242070db, 17);
+	R(f1, b, c, d, a, 3, 0xc1bdceee, 22);
+	R(f1, a, b, c, d, 4, 0xf57c0faf, 7);
+	R(f1, d, a, b, c, 5, 0x4787c62a, 12);
+	R(f1, c, d, a, b, 6, 0xa8304613, 17);
+	R(f1, b, c, d, a, 7, 0xfd469501, 22);
+	R(f1, a, b, c, d, 8, 0x698098d8, 7);
+	R(f1, d, a, b, c, 9, 0x8b44f7af, 12);
+	R(f1, c, d, a, b, 10, 0xffff5bb1, 17);
+	R(f1, b, c, d, a, 11, 0x895cd7be, 22);
+	R(f1, a, b, c, d, 12, 0x6b901122, 7);
+	R(f1, d, a, b, c, 13, 0xfd987193, 12);
+	R(f1, c, d, a, b, 14, 0xa679438e, 17);
+	R(f1, b, c, d, a, 15, 0x49b40821, 22);
+
+	R(f2, a, b, c, d, 1, 0xf61e2562, 5);
+	R(f2, d, a, b, c, 6, 0xc040b340, 9);
+	R(f2, c, d, a, b, 11, 0x265e5a51, 14);
+	R(f2, b, c, d, a, 0, 0xe9b6c7aa, 20);
+	R(f2, a, b, c, d, 5, 0xd62f105d, 5);
+	R(f2, d, a, b, c, 10, 0x02441453, 9);
+	R(f2, c, d, a, b, 15, 0xd8a1e681, 14);
+	R(f2, b, c, d, a, 4, 0xe7d3fbc8, 20);
+	R(f2, a, b, c, d, 9, 0x21e1cde6, 5);
+	R(f2, d, a, b, c, 14, 0xc33707d6, 9);
+	R(f2, c, d, a, b, 3, 0xf4d50d87, 14);
+	R(f2, b, c, d, a, 8, 0x455a14ed, 20);
+	R(f2, a, b, c, d, 13, 0xa9e3e905, 5);
+	R(f2, d, a, b, c, 2, 0xfcefa3f8, 9);
+	R(f2, c, d, a, b, 7, 0x676f02d9, 14);
+	R(f2, b, c, d, a, 12, 0x8d2a4c8a, 20);
+
+	R(f3, a, b, c, d, 5, 0xfffa3942, 4);
+	R(f3, d, a, b, c, 8, 0x8771f681, 11);
+	R(f3, c, d, a, b, 11, 0x6d9d6122, 16);
+	R(f3, b, c, d, a, 14, 0xfde5380c, 23);
+	R(f3, a, b, c, d, 1, 0xa4beea44, 4);
+	R(f3, d, a, b, c, 4, 0x4bdecfa9, 11);
+	R(f3, c, d, a, b, 7, 0xf6bb4b60, 16);
+	R(f3, b, c, d, a, 10, 0xbebfbc70, 23);
+	R(f3, a, b, c, d, 13, 0x289b7ec6, 4);
+	R(f3, d, a, b, c, 0, 0xeaa127fa, 11);
+	R(f3, c, d, a, b, 3, 0xd4ef3085, 16);
+	R(f3, b, c, d, a, 6, 0x04881d05, 23);
+	R(f3, a, b, c, d, 9, 0xd9d4d039, 4);
+	R(f3, d, a, b, c, 12, 0xe6db99e5, 11);
+	R(f3, c, d, a, b, 15, 0x1fa27cf8, 16);
+	R(f3, b, c, d, a, 2, 0xc4ac5665, 23);
+
+	R(f4, a, b, c, d, 0, 0xf4292244, 6);
+	R(f4, d, a, b, c, 7, 0x432aff97, 10);
+	R(f4, c, d, a, b, 14, 0xab9423a7, 15);
+	R(f4, b, c, d, a, 5, 0xfc93a039, 21);
+	R(f4, a, b, c, d, 12, 0x655b59c3, 6);
+	R(f4, d, a, b, c, 3, 0x8f0ccc92, 10);
+	R(f4, c, d, a, b, 10, 0xffeff47d, 15);
+	R(f4, b, c, d, a, 1, 0x85845dd1, 21);
+	R(f4, a, b, c, d, 8, 0x6fa87e4f, 6);
+	R(f4, d, a, b, c, 15, 0xfe2ce6e0, 10);
+	R(f4, c, d, a, b, 6, 0xa3014314, 15);
+	R(f4, b, c, d, a, 13, 0x4e0811a1, 21);
+	R(f4, a, b, c, d, 4, 0xf7537e82, 6);
+	R(f4, d, a, b, c, 11, 0xbd3af235, 10);
+	R(f4, c, d, a, b, 2, 0x2ad7d2bb, 15);
+	R(f4, b, c, d, a, 9, 0xeb86d391, 21);
+
+	ctx->h[0] += a; ctx->h[1] += b; ctx->h[2] += c; ctx->h[3] += d;
+}
+
+void md5_update(struct md5_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	uint32_t index, to_fill;
+
+	index = (uint32_t) (ctx->sz & 0x3f);
+	to_fill = 64 - index;
+
+	ctx->sz += len;
+
+	if (index && len >= to_fill) {
+		memcpy(ctx->buf + index, data, to_fill);
+		md5_do_chunk(ctx, (uint32_t *) ctx->buf);
+		len -= to_fill;
+		data += to_fill;
+		index = 0;
+	}
+
+	/* process as much 64-block as possible */
+	for (; len >= 64; len -= 64, data += 64)
+		md5_do_chunk(ctx, (uint32_t *) data);
+
+	/* append data into buf */
+	if (len)
+		memcpy(ctx->buf + index, data, len);
+}
+
+void md5_finalize(struct md5_ctx *ctx, uint8_t *out)
+{
+	static uint8_t padding[64] = { 0x80, };
+	uint64_t bits;
+	uint32_t index, padlen;
+	uint32_t *p = (uint32_t *) out;
+
+	/* add padding and update data with it */
+	bits = cpu_to_le64(ctx->sz << 3);
+
+	/* pad out to 56 */
+	index = (uint32_t) (ctx->sz & 0x3f);
+	padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+	md5_update(ctx, padding, padlen);
+
+	/* append length */
+	md5_update(ctx, (uint8_t *) &bits, sizeof(bits));
+
+	/* output hash */
+	p[0] = cpu_to_le32(ctx->h[0]);
+	p[1] = cpu_to_le32(ctx->h[1]);
+	p[2] = cpu_to_le32(ctx->h[2]);
+	p[3] = cpu_to_le32(ctx->h[3]);
+}
diff --git a/cbits/ripemd.c b/cbits/ripemd.c
new file mode 100644
--- /dev/null
+++ b/cbits/ripemd.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ripemd.h"
+#include "bitfn.h"
+#include <string.h>
+
+void ripemd160_init(struct ripemd160_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->h[0] = 0x67452301;
+	ctx->h[1] = 0xefcdab89;
+	ctx->h[2] = 0x98badcfe;
+	ctx->h[3] = 0x10325476;
+	ctx->h[4] = 0xc3d2e1f0;
+}
+
+#define K1  0x00000000
+#define K2  0x5a827999
+#define K3  0x6ed9eba1
+#define K4  0x8f1bbcdc
+#define K5  0xa953fd4e
+#define K6  0x50a28be6
+#define K7  0x5c4dd124
+#define K8  0x6d703ef3
+#define K9  0x7a6d76e9
+
+#define f1(x, y, z) (x ^ y ^ z)
+#define f2(x, y, z) (z ^ (x & (y ^ z)))
+#define f3(x, y, z) ((x | ~y) ^ z)
+#define f4(x, y, z) (y ^ (z & (x ^ y)))
+#define f5(x, y, z) (x ^ (y | ~z))
+
+#define R(a, b, c, d, e, f, k, i, s)	\
+	a += f(b, c, d) + w[i] + k; a = rol32(a, s) + e; c = rol32(c, 10)
+
+static void ripemd160_do_chunk(struct ripemd160_ctx *ctx, uint32_t *buf)
+{
+	uint32_t a1, b1, c1, d1, e1, a2, b2, c2, d2, e2;
+#ifdef ARCH_IS_BIG_ENDIAN
+	uint32_t w[16];
+	cpu_to_le32_array(w, buf, 16);
+#else
+	uint32_t *w = buf;
+#endif
+
+	a1 = ctx->h[0]; b1 = ctx->h[1]; c1 = ctx->h[2]; d1 = ctx->h[3]; e1 = ctx->h[4];
+	a2 = ctx->h[0]; b2 = ctx->h[1]; c2 = ctx->h[2]; d2 = ctx->h[3]; e2 = ctx->h[4];
+
+	/* 5 passes on first state copy */
+	R(a1, b1, c1, d1, e1, f1, K1, 0, 11);
+	R(e1, a1, b1, c1, d1, f1, K1, 1, 14);
+	R(d1, e1, a1, b1, c1, f1, K1, 2, 15);
+	R(c1, d1, e1, a1, b1, f1, K1, 3, 12);
+	R(b1, c1, d1, e1, a1, f1, K1, 4, 5);
+	R(a1, b1, c1, d1, e1, f1, K1, 5, 8);
+	R(e1, a1, b1, c1, d1, f1, K1, 6, 7);
+	R(d1, e1, a1, b1, c1, f1, K1, 7, 9);
+	R(c1, d1, e1, a1, b1, f1, K1, 8, 11);
+	R(b1, c1, d1, e1, a1, f1, K1, 9, 13);
+	R(a1, b1, c1, d1, e1, f1, K1, 10, 14);
+	R(e1, a1, b1, c1, d1, f1, K1, 11, 15);
+	R(d1, e1, a1, b1, c1, f1, K1, 12, 6);
+	R(c1, d1, e1, a1, b1, f1, K1, 13, 7);
+	R(b1, c1, d1, e1, a1, f1, K1, 14, 9);
+	R(a1, b1, c1, d1, e1, f1, K1, 15, 8);
+	
+	R(e1, a1, b1, c1, d1, f2, K2, 7, 7);
+	R(d1, e1, a1, b1, c1, f2, K2, 4, 6);
+	R(c1, d1, e1, a1, b1, f2, K2, 13, 8);
+	R(b1, c1, d1, e1, a1, f2, K2, 1, 13);
+	R(a1, b1, c1, d1, e1, f2, K2, 10, 11);
+	R(e1, a1, b1, c1, d1, f2, K2, 6, 9);
+	R(d1, e1, a1, b1, c1, f2, K2, 15, 7);
+	R(c1, d1, e1, a1, b1, f2, K2, 3, 15);
+	R(b1, c1, d1, e1, a1, f2, K2, 12, 7);
+	R(a1, b1, c1, d1, e1, f2, K2, 0, 12);
+	R(e1, a1, b1, c1, d1, f2, K2, 9, 15);
+	R(d1, e1, a1, b1, c1, f2, K2, 5, 9);
+	R(c1, d1, e1, a1, b1, f2, K2, 2, 11);
+	R(b1, c1, d1, e1, a1, f2, K2, 14, 7);
+	R(a1, b1, c1, d1, e1, f2, K2, 11, 13);
+	R(e1, a1, b1, c1, d1, f2, K2, 8, 12);
+
+	R(d1, e1, a1, b1, c1, f3, K3, 3, 11);
+	R(c1, d1, e1, a1, b1, f3, K3, 10, 13);
+	R(b1, c1, d1, e1, a1, f3, K3, 14, 6);
+	R(a1, b1, c1, d1, e1, f3, K3, 4, 7);
+	R(e1, a1, b1, c1, d1, f3, K3, 9, 14);
+	R(d1, e1, a1, b1, c1, f3, K3, 15, 9);
+	R(c1, d1, e1, a1, b1, f3, K3, 8, 13);
+	R(b1, c1, d1, e1, a1, f3, K3, 1, 15);
+	R(a1, b1, c1, d1, e1, f3, K3, 2, 14);
+	R(e1, a1, b1, c1, d1, f3, K3, 7, 8);
+	R(d1, e1, a1, b1, c1, f3, K3, 0, 13);
+	R(c1, d1, e1, a1, b1, f3, K3, 6, 6);
+	R(b1, c1, d1, e1, a1, f3, K3, 13, 5);
+	R(a1, b1, c1, d1, e1, f3, K3, 11, 12);
+	R(e1, a1, b1, c1, d1, f3, K3, 5, 7);
+	R(d1, e1, a1, b1, c1, f3, K3, 12, 5);
+
+	R(c1, d1, e1, a1, b1, f4, K4, 1, 11);
+	R(b1, c1, d1, e1, a1, f4, K4, 9, 12);
+	R(a1, b1, c1, d1, e1, f4, K4, 11, 14);
+	R(e1, a1, b1, c1, d1, f4, K4, 10, 15);
+	R(d1, e1, a1, b1, c1, f4, K4, 0, 14);
+	R(c1, d1, e1, a1, b1, f4, K4, 8, 15);
+	R(b1, c1, d1, e1, a1, f4, K4, 12, 9);
+	R(a1, b1, c1, d1, e1, f4, K4, 4, 8);
+	R(e1, a1, b1, c1, d1, f4, K4, 13, 9);
+	R(d1, e1, a1, b1, c1, f4, K4, 3, 14);
+	R(c1, d1, e1, a1, b1, f4, K4, 7, 5);
+	R(b1, c1, d1, e1, a1, f4, K4, 15, 6);
+	R(a1, b1, c1, d1, e1, f4, K4, 14, 8);
+	R(e1, a1, b1, c1, d1, f4, K4, 5, 6);
+	R(d1, e1, a1, b1, c1, f4, K4, 6, 5);
+	R(c1, d1, e1, a1, b1, f4, K4, 2, 12);
+
+	R(b1, c1, d1, e1, a1, f5, K5, 4, 9);
+	R(a1, b1, c1, d1, e1, f5, K5, 0, 15);
+	R(e1, a1, b1, c1, d1, f5, K5, 5, 5);
+	R(d1, e1, a1, b1, c1, f5, K5, 9, 11);
+	R(c1, d1, e1, a1, b1, f5, K5, 7, 6);
+	R(b1, c1, d1, e1, a1, f5, K5, 12, 8);
+	R(a1, b1, c1, d1, e1, f5, K5, 2, 13);
+	R(e1, a1, b1, c1, d1, f5, K5, 10, 12);
+	R(d1, e1, a1, b1, c1, f5, K5, 14, 5);
+	R(c1, d1, e1, a1, b1, f5, K5, 1, 12);
+	R(b1, c1, d1, e1, a1, f5, K5, 3, 13);
+	R(a1, b1, c1, d1, e1, f5, K5, 8, 14);
+	R(e1, a1, b1, c1, d1, f5, K5, 11, 11);
+	R(d1, e1, a1, b1, c1, f5, K5, 6, 8);
+	R(c1, d1, e1, a1, b1, f5, K5, 15, 5);
+	R(b1, c1, d1, e1, a1, f5, K5, 13, 6);
+
+	/* 5 passes on second state copy */
+	R(a2, b2, c2, d2, e2, f5, K6, 5, 8);
+	R(e2, a2, b2, c2, d2, f5, K6, 14, 9);
+	R(d2, e2, a2, b2, c2, f5, K6, 7, 9);
+	R(c2, d2, e2, a2, b2, f5, K6, 0, 11);
+	R(b2, c2, d2, e2, a2, f5, K6, 9, 13);
+	R(a2, b2, c2, d2, e2, f5, K6, 2, 15);
+	R(e2, a2, b2, c2, d2, f5, K6, 11, 15);
+	R(d2, e2, a2, b2, c2, f5, K6, 4, 5);
+	R(c2, d2, e2, a2, b2, f5, K6, 13, 7);
+	R(b2, c2, d2, e2, a2, f5, K6, 6, 7);
+	R(a2, b2, c2, d2, e2, f5, K6, 15, 8);
+	R(e2, a2, b2, c2, d2, f5, K6, 8, 11);
+	R(d2, e2, a2, b2, c2, f5, K6, 1, 14);
+	R(c2, d2, e2, a2, b2, f5, K6, 10, 14);
+	R(b2, c2, d2, e2, a2, f5, K6, 3, 12);
+	R(a2, b2, c2, d2, e2, f5, K6, 12, 6);
+
+	R(e2, a2, b2, c2, d2, f4, K7, 6, 9);
+	R(d2, e2, a2, b2, c2, f4, K7, 11, 13);
+	R(c2, d2, e2, a2, b2, f4, K7, 3, 15);
+	R(b2, c2, d2, e2, a2, f4, K7, 7, 7);
+	R(a2, b2, c2, d2, e2, f4, K7, 0, 12);
+	R(e2, a2, b2, c2, d2, f4, K7, 13, 8);
+	R(d2, e2, a2, b2, c2, f4, K7, 5, 9);
+	R(c2, d2, e2, a2, b2, f4, K7, 10, 11);
+	R(b2, c2, d2, e2, a2, f4, K7, 14, 7);
+	R(a2, b2, c2, d2, e2, f4, K7, 15, 7);
+	R(e2, a2, b2, c2, d2, f4, K7, 8, 12);
+	R(d2, e2, a2, b2, c2, f4, K7, 12, 7);
+	R(c2, d2, e2, a2, b2, f4, K7, 4, 6);
+	R(b2, c2, d2, e2, a2, f4, K7, 9, 15);
+	R(a2, b2, c2, d2, e2, f4, K7, 1, 13);
+	R(e2, a2, b2, c2, d2, f4, K7, 2, 11);
+
+	R(d2, e2, a2, b2, c2, f3, K8, 15, 9);
+	R(c2, d2, e2, a2, b2, f3, K8, 5, 7);
+	R(b2, c2, d2, e2, a2, f3, K8, 1, 15);
+	R(a2, b2, c2, d2, e2, f3, K8, 3, 11);
+	R(e2, a2, b2, c2, d2, f3, K8, 7, 8);
+	R(d2, e2, a2, b2, c2, f3, K8, 14, 6);
+	R(c2, d2, e2, a2, b2, f3, K8, 6, 6);
+	R(b2, c2, d2, e2, a2, f3, K8, 9, 14);
+	R(a2, b2, c2, d2, e2, f3, K8, 11, 12);
+	R(e2, a2, b2, c2, d2, f3, K8, 8, 13);
+	R(d2, e2, a2, b2, c2, f3, K8, 12, 5);
+	R(c2, d2, e2, a2, b2, f3, K8, 2, 14);
+	R(b2, c2, d2, e2, a2, f3, K8, 10, 13);
+	R(a2, b2, c2, d2, e2, f3, K8, 0, 13);
+	R(e2, a2, b2, c2, d2, f3, K8, 4, 7);
+	R(d2, e2, a2, b2, c2, f3, K8, 13, 5);
+
+	R(c2, d2, e2, a2, b2, f2, K9, 8, 15);
+	R(b2, c2, d2, e2, a2, f2, K9, 6, 5);
+	R(a2, b2, c2, d2, e2, f2, K9, 4, 8);
+	R(e2, a2, b2, c2, d2, f2, K9, 1, 11);
+	R(d2, e2, a2, b2, c2, f2, K9, 3, 14);
+	R(c2, d2, e2, a2, b2, f2, K9, 11, 14);
+	R(b2, c2, d2, e2, a2, f2, K9, 15, 6);
+	R(a2, b2, c2, d2, e2, f2, K9, 0, 14);
+	R(e2, a2, b2, c2, d2, f2, K9, 5, 6);
+	R(d2, e2, a2, b2, c2, f2, K9, 12, 9);
+	R(c2, d2, e2, a2, b2, f2, K9, 2, 12);
+	R(b2, c2, d2, e2, a2, f2, K9, 13, 9);
+	R(a2, b2, c2, d2, e2, f2, K9, 9, 12);
+	R(e2, a2, b2, c2, d2, f2, K9, 7, 5);
+	R(d2, e2, a2, b2, c2, f2, K9, 10, 15);
+	R(c2, d2, e2, a2, b2, f2, K9, 14, 8);
+
+	R(b2, c2, d2, e2, a2, f1, K1, 12, 8);
+	R(a2, b2, c2, d2, e2, f1, K1, 15, 5);
+	R(e2, a2, b2, c2, d2, f1, K1, 10, 12);
+	R(d2, e2, a2, b2, c2, f1, K1, 4, 9);
+	R(c2, d2, e2, a2, b2, f1, K1, 1, 12);
+	R(b2, c2, d2, e2, a2, f1, K1, 5, 5);
+	R(a2, b2, c2, d2, e2, f1, K1, 8, 14);
+	R(e2, a2, b2, c2, d2, f1, K1, 7, 6);
+	R(d2, e2, a2, b2, c2, f1, K1, 6, 8);
+	R(c2, d2, e2, a2, b2, f1, K1, 2, 13);
+	R(b2, c2, d2, e2, a2, f1, K1, 13, 6);
+	R(a2, b2, c2, d2, e2, f1, K1, 14, 5);
+	R(e2, a2, b2, c2, d2, f1, K1, 0, 15);
+	R(d2, e2, a2, b2, c2, f1, K1, 3, 13);
+	R(c2, d2, e2, a2, b2, f1, K1, 9, 11);
+	R(b2, c2, d2, e2, a2, f1, K1, 11, 11);
+
+	d2 += c1 + ctx->h[1];
+	ctx->h[1] = ctx->h[2] + d1 + e2;
+	ctx->h[2] = ctx->h[3] + e1 + a2;
+	ctx->h[3] = ctx->h[4] + a1 + b2;
+	ctx->h[4] = ctx->h[0] + b1 + c2;
+	ctx->h[0] = d2;
+}
+
+void ripemd160_update(struct ripemd160_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	uint32_t index, to_fill;
+
+	index = (uint32_t) (ctx->sz & 0x3f);
+	to_fill = 64 - index;
+
+	ctx->sz += len;
+	if (index && len >= to_fill) {
+		memcpy(ctx->buf + index, data, to_fill);
+		ripemd160_do_chunk(ctx, (uint32_t *) ctx->buf);
+		len -= to_fill;
+		data += to_fill;
+		index = 0;
+	}
+
+	for (; len >= 64; len -= 64, data += 64)
+		ripemd160_do_chunk(ctx, (uint32_t *) data);
+
+	if (len)
+		memcpy(ctx->buf + index, data, len);
+}
+
+void ripemd160_finalize(struct ripemd160_ctx *ctx, uint8_t *out)
+{
+	static uint8_t padding[64] = { 0x80, };
+	uint64_t bits;
+	uint32_t index, padlen;
+	uint32_t *p = (uint32_t *) out;
+
+	/* add padding and update data with it */
+	bits = cpu_to_le64(ctx->sz << 3);
+
+	/* pad out to 56 */
+	index = (uint32_t) (ctx->sz & 0x3f);
+	padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+	ripemd160_update(ctx, padding, padlen);
+
+	/* append length */
+	ripemd160_update(ctx, (uint8_t *) &bits, sizeof(bits));
+
+	/* output digest */
+	p[0] = cpu_to_le32(ctx->h[0]);
+	p[1] = cpu_to_le32(ctx->h[1]);
+	p[2] = cpu_to_le32(ctx->h[2]);
+	p[3] = cpu_to_le32(ctx->h[3]);
+	p[4] = cpu_to_le32(ctx->h[4]);
+}
diff --git a/cbits/sha1.c b/cbits/sha1.c
new file mode 100644
--- /dev/null
+++ b/cbits/sha1.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include "sha1.h"
+#include "bitfn.h"
+
+void sha1_init(struct sha1_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->h[0] = 0x67452301;
+	ctx->h[1] = 0xefcdab89;
+	ctx->h[2] = 0x98badcfe;
+	ctx->h[3] = 0x10325476;
+	ctx->h[4] = 0xc3d2e1f0;
+}
+
+#define f1(x, y, z)   (z ^ (x & (y ^ z)))
+#define f2(x, y, z)   (x ^ y ^ z)
+#define f3(x, y, z)   ((x & y) + (z & (x ^ y)))
+#define f4(x, y, z)   f2(x, y, z)
+
+#define K1  0x5a827999
+#define K2  0x6ed9eba1
+#define K3  0x8f1bbcdc
+#define K4  0xca62c1d6
+
+#define R(a, b, c, d, e, f, k, w)  \
+	e += rol32(a, 5) + f(b, c, d) + k + w; b = rol32(b, 30)
+
+#if (defined(__arm__))
+#define M(i)  (w[i])
+#else
+#define M(i)  (w[i & 0x0f] = rol32(w[i & 0x0f] ^ w[(i - 14) & 0x0f] \
+              ^ w[(i - 8) & 0x0f] ^ w[(i - 3) & 0x0f], 1))
+#endif
+
+static inline void sha1_do_chunk(struct sha1_ctx *ctx, uint32_t *buf)
+{
+	uint32_t a, b, c, d, e;
+#if (defined(__arm__))
+	uint32_t i;
+	uint32_t w[80];
+	for (i = 0; i < 16; i++)
+		w[i] = be32_to_cpu(buf[i]);
+	for (; i < 80; i++)
+		w[i] = rol32(w[i & 0x0f] ^ w[(i - 14) & 0x0f] ^
+		             w[(i - 8) % 0x0f] ^ w[(i - 3) & 0x0f], 1);
+#else
+	uint32_t w[16];
+#define CPY(i)	w[i] = be32_to_cpu(buf[i])
+	CPY(0); CPY(1); CPY(2); CPY(3); CPY(4); CPY(5); CPY(6); CPY(7);
+	CPY(8); CPY(9); CPY(10); CPY(11); CPY(12); CPY(13); CPY(14); CPY(15);
+#undef CPY
+#endif
+
+	a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3]; e = ctx->h[4];
+
+	R(a, b, c, d, e, f1, K1, w[0]);
+	R(e, a, b, c, d, f1, K1, w[1]);
+	R(d, e, a, b, c, f1, K1, w[2]);
+	R(c, d, e, a, b, f1, K1, w[3]);
+	R(b, c, d, e, a, f1, K1, w[4]);
+	R(a, b, c, d, e, f1, K1, w[5]);
+	R(e, a, b, c, d, f1, K1, w[6]);
+	R(d, e, a, b, c, f1, K1, w[7]);
+	R(c, d, e, a, b, f1, K1, w[8]);
+	R(b, c, d, e, a, f1, K1, w[9]);
+	R(a, b, c, d, e, f1, K1, w[10]);
+	R(e, a, b, c, d, f1, K1, w[11]);
+	R(d, e, a, b, c, f1, K1, w[12]);
+	R(c, d, e, a, b, f1, K1, w[13]);
+	R(b, c, d, e, a, f1, K1, w[14]);
+	R(a, b, c, d, e, f1, K1, w[15]);
+	R(e, a, b, c, d, f1, K1, M(16));
+	R(d, e, a, b, c, f1, K1, M(17));
+	R(c, d, e, a, b, f1, K1, M(18));
+	R(b, c, d, e, a, f1, K1, M(19));
+
+	R(a, b, c, d, e, f2, K2, M(20));
+	R(e, a, b, c, d, f2, K2, M(21));
+	R(d, e, a, b, c, f2, K2, M(22));
+	R(c, d, e, a, b, f2, K2, M(23));
+	R(b, c, d, e, a, f2, K2, M(24));
+	R(a, b, c, d, e, f2, K2, M(25));
+	R(e, a, b, c, d, f2, K2, M(26));
+	R(d, e, a, b, c, f2, K2, M(27));
+	R(c, d, e, a, b, f2, K2, M(28));
+	R(b, c, d, e, a, f2, K2, M(29));
+	R(a, b, c, d, e, f2, K2, M(30));
+	R(e, a, b, c, d, f2, K2, M(31));
+	R(d, e, a, b, c, f2, K2, M(32));
+	R(c, d, e, a, b, f2, K2, M(33));
+	R(b, c, d, e, a, f2, K2, M(34));
+	R(a, b, c, d, e, f2, K2, M(35));
+	R(e, a, b, c, d, f2, K2, M(36));
+	R(d, e, a, b, c, f2, K2, M(37));
+	R(c, d, e, a, b, f2, K2, M(38));
+	R(b, c, d, e, a, f2, K2, M(39));
+
+	R(a, b, c, d, e, f3, K3, M(40));
+	R(e, a, b, c, d, f3, K3, M(41));
+	R(d, e, a, b, c, f3, K3, M(42));
+	R(c, d, e, a, b, f3, K3, M(43));
+	R(b, c, d, e, a, f3, K3, M(44));
+	R(a, b, c, d, e, f3, K3, M(45));
+	R(e, a, b, c, d, f3, K3, M(46));
+	R(d, e, a, b, c, f3, K3, M(47));
+	R(c, d, e, a, b, f3, K3, M(48));
+	R(b, c, d, e, a, f3, K3, M(49));
+	R(a, b, c, d, e, f3, K3, M(50));
+	R(e, a, b, c, d, f3, K3, M(51));
+	R(d, e, a, b, c, f3, K3, M(52));
+	R(c, d, e, a, b, f3, K3, M(53));
+	R(b, c, d, e, a, f3, K3, M(54));
+	R(a, b, c, d, e, f3, K3, M(55));
+	R(e, a, b, c, d, f3, K3, M(56));
+	R(d, e, a, b, c, f3, K3, M(57));
+	R(c, d, e, a, b, f3, K3, M(58));
+	R(b, c, d, e, a, f3, K3, M(59));
+
+	R(a, b, c, d, e, f4, K4, M(60));
+	R(e, a, b, c, d, f4, K4, M(61));
+	R(d, e, a, b, c, f4, K4, M(62));
+	R(c, d, e, a, b, f4, K4, M(63));
+	R(b, c, d, e, a, f4, K4, M(64));
+	R(a, b, c, d, e, f4, K4, M(65));
+	R(e, a, b, c, d, f4, K4, M(66));
+	R(d, e, a, b, c, f4, K4, M(67));
+	R(c, d, e, a, b, f4, K4, M(68));
+	R(b, c, d, e, a, f4, K4, M(69));
+	R(a, b, c, d, e, f4, K4, M(70));
+	R(e, a, b, c, d, f4, K4, M(71));
+	R(d, e, a, b, c, f4, K4, M(72));
+	R(c, d, e, a, b, f4, K4, M(73));
+	R(b, c, d, e, a, f4, K4, M(74));
+	R(a, b, c, d, e, f4, K4, M(75));
+	R(e, a, b, c, d, f4, K4, M(76));
+	R(d, e, a, b, c, f4, K4, M(77));
+	R(c, d, e, a, b, f4, K4, M(78));
+	R(b, c, d, e, a, f4, K4, M(79));
+
+	ctx->h[0] += a;
+	ctx->h[1] += b;
+	ctx->h[2] += c;
+	ctx->h[3] += d;
+	ctx->h[4] += e;
+}
+
+void sha1_update(struct sha1_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	uint32_t index, to_fill;
+
+	index = (uint32_t) (ctx->sz & 0x3f);
+	to_fill = 64 - index;
+
+	ctx->sz += len;
+
+	/* process partial buffer if there's enough data to make a block */
+	if (index && len >= to_fill) {
+		memcpy(ctx->buf + index, data, to_fill);
+		sha1_do_chunk(ctx, (uint32_t *) ctx->buf);
+		len -= to_fill;
+		data += to_fill;
+		index = 0;
+	}
+
+	/* process as much 64-block as possible */
+	for (; len >= 64; len -= 64, data += 64)
+		sha1_do_chunk(ctx, (uint32_t *) data);
+
+	/* append data into buf */
+	if (len)
+		memcpy(ctx->buf + index, data, len);
+}
+
+void sha1_finalize(struct sha1_ctx *ctx, uint8_t *out)
+{
+	static uint8_t padding[64] = { 0x80, };
+	uint64_t bits;
+	uint32_t index, padlen;
+	uint32_t *p = (uint32_t *) out;
+
+	/* add padding and update data with it */
+	bits = cpu_to_be64(ctx->sz << 3);
+
+	/* pad out to 56 */
+	index = (uint32_t) (ctx->sz & 0x3f);
+	padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+	sha1_update(ctx, padding, padlen);
+
+	/* append length */
+	sha1_update(ctx, (uint8_t *) &bits, sizeof(bits));
+
+	/* output hash */
+	p[0] = cpu_to_be32(ctx->h[0]);
+	p[1] = cpu_to_be32(ctx->h[1]);
+	p[2] = cpu_to_be32(ctx->h[2]);
+	p[3] = cpu_to_be32(ctx->h[3]);
+	p[4] = cpu_to_be32(ctx->h[4]);
+}
diff --git a/cbits/sha256.c b/cbits/sha256.c
new file mode 100644
--- /dev/null
+++ b/cbits/sha256.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include "sha256.h"
+#include "bitfn.h"
+
+void sha224_init(struct sha224_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->h[0] = 0xc1059ed8;
+	ctx->h[1] = 0x367cd507;
+	ctx->h[2] = 0x3070dd17;
+	ctx->h[3] = 0xf70e5939;
+	ctx->h[4] = 0xffc00b31;
+	ctx->h[5] = 0x68581511;
+	ctx->h[6] = 0x64f98fa7;
+	ctx->h[7] = 0xbefa4fa4;
+}
+
+void sha256_init(struct sha256_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->h[0] = 0x6a09e667;
+	ctx->h[1] = 0xbb67ae85;
+	ctx->h[2] = 0x3c6ef372;
+	ctx->h[3] = 0xa54ff53a;
+	ctx->h[4] = 0x510e527f;
+	ctx->h[5] = 0x9b05688c;
+	ctx->h[6] = 0x1f83d9ab;
+	ctx->h[7] = 0x5be0cd19;
+}
+
+/* 232 times the cube root of the first 64 primes 2..311 */
+static const uint32_t k[] = {
+	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+	0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+	0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+	0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+	0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+	0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+#define e0(x)       (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22))
+#define e1(x)       (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25))
+#define s0(x)       (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3))
+#define s1(x)       (ror32(x,17) ^ ror32(x,19) ^ (x >> 10))
+
+static void sha256_do_chunk(struct sha256_ctx *ctx, uint32_t buf[])
+{
+	uint32_t a, b, c, d, e, f, g, h, t1, t2;
+	int i;
+	uint32_t w[64];
+
+	cpu_to_be32_array(w, buf, 16);
+	for (i = 16; i < 64; i++)
+		w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];
+
+	a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];
+	e = ctx->h[4]; f = ctx->h[5]; g = ctx->h[6]; h = ctx->h[7];
+
+#define R(a, b, c, d, e, f, g, h, k, w)			\
+	t1 = h + e1(e) + (g ^ (e & (f ^ g))) + k + w; 	\
+	t2 = e0(a) + ((a & b) | (c & (a | b)));		\
+	d += t1;					\
+	h = t1 + t2;
+
+	for (i = 0; i < 64; i += 8) {
+		R(a, b, c, d, e, f, g, h, k[i + 0], w[i + 0]);
+		R(h, a, b, c, d, e, f, g, k[i + 1], w[i + 1]);
+		R(g, h, a, b, c, d, e, f, k[i + 2], w[i + 2]);
+		R(f, g, h, a, b, c, d, e, k[i + 3], w[i + 3]);
+		R(e, f, g, h, a, b, c, d, k[i + 4], w[i + 4]);
+		R(d, e, f, g, h, a, b, c, k[i + 5], w[i + 5]);
+		R(c, d, e, f, g, h, a, b, k[i + 6], w[i + 6]);
+		R(b, c, d, e, f, g, h, a, k[i + 7], w[i + 7]);
+	}
+
+#undef R
+
+	ctx->h[0] += a; ctx->h[1] += b; ctx->h[2] += c; ctx->h[3] += d;
+	ctx->h[4] += e; ctx->h[5] += f; ctx->h[6] += g; ctx->h[7] += h;
+}
+
+void sha224_update(struct sha224_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	return sha256_update(ctx, data, len);
+}
+
+void sha256_update(struct sha256_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	uint32_t index, to_fill;
+
+	/* check for partial buffer */
+	index = (uint32_t) (ctx->sz & 0x3f);
+	to_fill = 64 - index;
+
+	ctx->sz += len;
+
+	/* process partial buffer if there's enough data to make a block */
+	if (index && len >= to_fill) {
+		memcpy(ctx->buf + index, data, to_fill);
+		sha256_do_chunk(ctx, (uint32_t *) ctx->buf);
+		len -= to_fill;
+		data += to_fill;
+		index = 0;
+	}
+
+	/* process as much 64-block as possible */
+	for (; len >= 64; len -= 64, data += 64)
+		sha256_do_chunk(ctx, (uint32_t *) data);
+
+	/* append data into buf */
+	if (len)
+		memcpy(ctx->buf + index, data, len);
+}
+
+void sha224_finalize(struct sha224_ctx *ctx, uint8_t *out)
+{
+	uint8_t intermediate[SHA256_DIGEST_SIZE];
+
+	sha256_finalize(ctx, intermediate);
+	memcpy(out, intermediate, SHA224_DIGEST_SIZE);
+}
+
+void sha256_finalize(struct sha256_ctx *ctx, uint8_t *out)
+{
+	static uint8_t padding[64] = { 0x80, };
+	uint64_t bits;
+	uint32_t i, index, padlen;
+	uint32_t *p = (uint32_t *) out;
+
+	/* cpu -> big endian */
+	bits = cpu_to_be64(ctx->sz << 3);
+
+	/* pad out to 56 */
+	index = (uint32_t) (ctx->sz & 0x3f);
+	padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+	sha256_update(ctx, padding, padlen);
+
+	/* append length */
+	sha256_update(ctx, (uint8_t *) &bits, sizeof(bits));
+
+	/* store to digest */
+	for (i = 0; i < 8; i++)
+		p[i] = cpu_to_be32(ctx->h[i]);
+}
diff --git a/cbits/sha512.c b/cbits/sha512.c
new file mode 100644
--- /dev/null
+++ b/cbits/sha512.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include "bitfn.h"
+#include "sha512.h"
+
+void sha384_init(struct sha512_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->h[0] = 0xcbbb9d5dc1059ed8ULL;
+	ctx->h[1] = 0x629a292a367cd507ULL;
+	ctx->h[2] = 0x9159015a3070dd17ULL;
+	ctx->h[3] = 0x152fecd8f70e5939ULL;
+	ctx->h[4] = 0x67332667ffc00b31ULL;
+	ctx->h[5] = 0x8eb44a8768581511ULL;
+	ctx->h[6] = 0xdb0c2e0d64f98fa7ULL;
+	ctx->h[7] = 0x47b5481dbefa4fa4ULL;
+}
+
+void sha512_init(struct sha512_ctx *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->h[0] = 0x6a09e667f3bcc908ULL;
+	ctx->h[1] = 0xbb67ae8584caa73bULL;
+	ctx->h[2] = 0x3c6ef372fe94f82bULL;
+	ctx->h[3] = 0xa54ff53a5f1d36f1ULL;
+	ctx->h[4] = 0x510e527fade682d1ULL;
+	ctx->h[5] = 0x9b05688c2b3e6c1fULL;
+	ctx->h[6] = 0x1f83d9abfb41bd6bULL;
+	ctx->h[7] = 0x5be0cd19137e2179ULL;
+}
+
+/* 232 times the cube root of the first 64 primes 2..311 */
+static const uint64_t k[] = {
+	0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+	0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+	0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+	0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+	0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+	0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+	0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+	0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+	0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+	0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+	0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+	0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+	0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+	0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+	0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+	0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+	0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+	0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+	0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+	0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+	0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+	0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+	0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+	0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+	0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+	0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+	0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
+};
+
+#define e0(x)       (ror64(x, 28) ^ ror64(x, 34) ^ ror64(x, 39))
+#define e1(x)       (ror64(x, 14) ^ ror64(x, 18) ^ ror64(x, 41))
+#define s0(x)       (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7))
+#define s1(x)       (ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6))
+
+static void sha512_do_chunk(struct sha512_ctx *ctx, uint64_t *buf)
+{
+	uint64_t a, b, c, d, e, f, g, h, t1, t2;
+	int i;
+	uint64_t w[80];
+
+	cpu_to_be64_array(w, buf, 16);
+
+	for (i = 16; i < 80; i++)
+		w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];
+
+	a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];
+	e = ctx->h[4]; f = ctx->h[5]; g = ctx->h[6]; h = ctx->h[7];
+
+#define R(a, b, c, d, e, f, g, h, k, w)			\
+	t1 = h + e1(e) + (g ^ (e & (f ^ g))) + k + w;	\
+	t2 = e0(a) + ((a & b) | (c & (a | b)));		\
+	d += t1;					\
+	h = t1 + t2
+
+	for (i = 0; i < 80; i += 8) {
+		R(a, b, c, d, e, f, g, h, k[i + 0], w[i + 0]);
+		R(h, a, b, c, d, e, f, g, k[i + 1], w[i + 1]);
+		R(g, h, a, b, c, d, e, f, k[i + 2], w[i + 2]);
+		R(f, g, h, a, b, c, d, e, k[i + 3], w[i + 3]);
+		R(e, f, g, h, a, b, c, d, k[i + 4], w[i + 4]);
+		R(d, e, f, g, h, a, b, c, k[i + 5], w[i + 5]);
+		R(c, d, e, f, g, h, a, b, k[i + 6], w[i + 6]);
+		R(b, c, d, e, f, g, h, a, k[i + 7], w[i + 7]);
+	}
+
+#undef R
+
+	ctx->h[0] += a; ctx->h[1] += b; ctx->h[2] += c; ctx->h[3] += d;
+	ctx->h[4] += e; ctx->h[5] += f; ctx->h[6] += g; ctx->h[7] += h;
+}
+
+void sha384_update(struct sha384_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	return sha512_update(ctx, data, len);
+}
+
+void sha512_update(struct sha512_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	unsigned int index, to_fill;
+
+	/* check for partial buffer */
+	index = (unsigned int) (ctx->sz[0] & 0x7f);
+	to_fill = 128 - index;
+
+	ctx->sz[0] += len;
+	if (ctx->sz[0] < len)
+		ctx->sz[1]++;
+
+	/* process partial buffer if there's enough data to make a block */
+	if (index && len >= to_fill) {
+		memcpy(ctx->buf + index, data, to_fill);
+		sha512_do_chunk(ctx, (uint64_t *) ctx->buf);
+		len -= to_fill;
+		data += to_fill;
+		index = 0;
+	}
+
+	/* process as much 128-block as possible */
+	for (; len >= 128; len -= 128, data += 128)
+		sha512_do_chunk(ctx, (uint64_t *) data);
+
+	/* append data into buf */
+	if (len)
+		memcpy(ctx->buf + index, data, len);
+}
+
+void sha384_finalize(struct sha384_ctx *ctx, uint8_t *out)
+{
+	uint8_t intermediate[SHA512_DIGEST_SIZE];
+
+	sha512_finalize(ctx, intermediate);
+	memcpy(out, intermediate, SHA384_DIGEST_SIZE);
+}
+
+void sha512_finalize(struct sha512_ctx *ctx, uint8_t *out)
+{
+	static uint8_t padding[128] = { 0x80, };
+	uint32_t i, index, padlen;
+	uint64_t bits[2];
+	uint64_t *p = (uint64_t *) out;
+
+	/* cpu -> big endian */
+	bits[0] = cpu_to_be64((ctx->sz[1] << 3 | ctx->sz[0] >> 61));
+	bits[1] = cpu_to_be64((ctx->sz[0] << 3));
+
+	/* pad out to 56 */
+	index = (unsigned int) (ctx->sz[0] & 0x7f);
+	padlen = (index < 112) ? (112 - index) : ((128 + 112) - index);
+	sha512_update(ctx, padding, padlen);
+
+	/* append length */
+	sha512_update(ctx, (uint8_t *) bits, sizeof(bits));
+
+	/* store to digest */
+	for (i = 0; i < 8; i++)
+		p[i] = cpu_to_be64(ctx->h[i]);
+}
diff --git a/cryptohash.cabal b/cryptohash.cabal
new file mode 100644
--- /dev/null
+++ b/cryptohash.cabal
@@ -0,0 +1,53 @@
+Name:                cryptohash
+Version:             0.4
+Description:         Efficient crypto hash computation
+License:             BSD3
+License-file:        LICENSE
+Author:              Vincent Hanquez
+Maintainer:          vincent@snarc.org
+Synopsis:            crypto hashes fast and pratical
+Category:            Data, Cryptography
+Build-Type:          Simple
+Cabal-Version:       >=1.2
+
+Flag unittest
+  Description:       Build unit test
+  Default:           False
+
+Library
+  Build-Depends:     base >= 3 && < 5, bytestring
+  Extensions:        ForeignFunctionInterface
+  Exposed-modules:   Data.CryptoHash.SHA1
+                     Data.CryptoHash.SHA224
+                     Data.CryptoHash.SHA256
+                     Data.CryptoHash.SHA384
+                     Data.CryptoHash.SHA512
+                     Data.CryptoHash.MD2
+                     Data.CryptoHash.MD4
+                     Data.CryptoHash.MD5
+                     Data.CryptoHash.RIPEMD160
+  ghc-options:       -Wall -O2 -optc-O3 -fno-cse
+  C-sources:         cbits/sha1.c
+                     cbits/sha256.c
+                     cbits/sha512.c
+                     cbits/md2.c
+                     cbits/md4.c
+                     cbits/md5.c
+                     cbits/ripemd.c
+  Include-Dirs:      cbits
+
+Executable           Tests
+  Main-Is:           Tests.hs
+  Extensions:        ForeignFunctionInterface
+  Build-depends:     base >= 3 && < 5, HUnit, bytestring
+  C-sources:         cbits/sha1.c
+                     cbits/sha256.c
+                     cbits/sha512.c
+                     cbits/md2.c
+                     cbits/md4.c
+                     cbits/md5.c
+                     cbits/ripemd.c
+  if flag(unittest)
+    Buildable:       True
+  else
+    Buildable:       False
