diff --git a/Bench/Bench.hs b/Bench/Bench.hs
new file mode 100644
--- /dev/null
+++ b/Bench/Bench.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE BangPatterns #-}
+import Criterion.Main
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import qualified Crypto.Hash.MD2 as MD2
+import qualified Crypto.Hash.MD4 as MD4
+import qualified Crypto.Hash.MD5 as MD5
+import qualified Crypto.Hash.SHA1 as SHA1
+import qualified Crypto.Hash.SHA224 as SHA224
+import qualified Crypto.Hash.SHA256 as SHA256
+import qualified Crypto.Hash.SHA384 as SHA384
+import qualified Crypto.Hash.SHA512 as SHA512
+import qualified Crypto.Hash.SHA512t as SHA512t
+import qualified Crypto.Hash.SHA3 as SHA3
+import qualified Crypto.Hash.RIPEMD160 as RIPEMD160
+import qualified Crypto.Hash.Tiger as Tiger
+import qualified Crypto.Hash.Skein256 as Skein256
+import qualified Crypto.Hash.Skein512 as Skein512
+import qualified Crypto.Hash.Whirlpool as Whirlpool
+
+hashmany (i,u,f) = f . foldl u i
+
+allHashs =
+    [ ("MD2",MD2.hash, hashmany (MD2.init,MD2.update,MD2.finalize))
+    , ("MD4",MD4.hash, hashmany (MD4.init,MD4.update,MD4.finalize))
+    , ("MD5",MD5.hash, hashmany (MD5.init,MD5.update,MD5.finalize))
+    , ("SHA1",SHA1.hash, hashmany (SHA1.init,SHA1.update,SHA1.finalize))
+    , ("SHA2-224",SHA224.hash, hashmany (SHA224.init,SHA224.update,SHA224.finalize))
+    , ("SHA2-256",SHA256.hash, hashmany (SHA256.init,SHA256.update,SHA256.finalize))
+    , ("SHA2-384",SHA384.hash, hashmany (SHA384.init,SHA384.update,SHA384.finalize))
+    , ("SHA2-512",SHA512.hash, hashmany (SHA512.init,SHA512.update,SHA512.finalize))
+    , ("SHA2-512t-512",SHA512t.hash 512, hashmany (SHA512t.init 512,SHA512t.update,SHA512t.finalize))
+    , ("SHA3-224",SHA3.hash 224, hashmany (SHA3.init 224,SHA3.update,SHA3.finalize))
+    , ("SHA3-256",SHA3.hash 256, hashmany (SHA3.init 256,SHA3.update,SHA3.finalize))
+    , ("SHA3-384",SHA3.hash 384, hashmany (SHA3.init 384,SHA3.update,SHA3.finalize))
+    , ("SHA3-512",SHA3.hash 512, hashmany (SHA3.init 512,SHA3.update,SHA3.finalize))
+    , ("RIPEMD160",RIPEMD160.hash, hashmany (RIPEMD160.init,RIPEMD160.update,RIPEMD160.finalize))
+    , ("Tiger",Tiger.hash, hashmany (Tiger.init,Tiger.update,Tiger.finalize))
+    , ("Skein256-256",Skein256.hash 256, hashmany (Skein256.init 256,Skein256.update,Skein256.finalize))
+    , ("Skein512-512",Skein512.hash 512, hashmany (Skein512.init 512,Skein512.update,Skein512.finalize))
+    , ("Whirlpool",Whirlpool.hash, hashmany (Whirlpool.init,Whirlpool.update,Whirlpool.finalize))
+    ]
+
+benchHash :: a -> (a -> B.ByteString) -> Pure
+benchHash bs f = whnf f bs
+
+withHashesFilter out f = map f $ filter (\(n,_,_) -> not (n `elem` out)) allHashs
+withHashes f = map f allHashs
+
+main = do
+    let !bs32     = B.replicate 32 0
+        !bs256    = B.replicate 256 0
+        !bs4096   = B.replicate 4096 0
+        !bs1M     = B.replicate (1*1024*1024) 0
+    let !lbs64x256 = (map (const (B.replicate 64 0)) [0..3])
+        !lbs64x4096 = (map (const (B.replicate 64 0)) [0..63])
+    defaultMain
+        [ bgroup "hash-32b" (withHashes (\(name, f,_) -> bench name $ benchHash bs32 f))
+        , bgroup "hash-256b" (withHashes (\(name, f,_) -> bench name $ benchHash bs256 f))
+        , bgroup "hash-4Kb" (withHashes (\(name, f,_) -> bench name $ benchHash bs4096 f))
+        , bgroup "hash-1Mb" (withHashesFilter ["MD2"] (\(name, f,_) -> bench name $ benchHash bs1M f))
+        , bgroup "iuf-64x256" (withHashes (\(name, _,f) -> bench name $ benchHash lbs64x256 f))
+        , bgroup "iuf-64x4096" (withHashes (\(name, _,f) -> bench name $ benchHash lbs64x4096 f))
+        ]
diff --git a/Bench/BenchAPI.hs b/Bench/BenchAPI.hs
new file mode 100644
--- /dev/null
+++ b/Bench/BenchAPI.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE BangPatterns #-}
+import Criterion.Main
+import Data.Byteable
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import qualified Crypto.Hash.SHA1 as SHA1
+import qualified Crypto.Hash.SHA512 as SHA512
+import qualified Crypto.Hash.SHA3 as SHA3
+import Crypto.Hash
+
+sha1F = ( "sha1"
+        , SHA1.hash
+        , SHA1.finalize . SHA1.update SHA1.init
+        , toBytes . (hash :: B.ByteString -> Digest SHA1)
+        )
+
+sha512F = ( "sha512"
+        , SHA512.hash
+        , SHA512.finalize . SHA512.update SHA512.init
+        , toBytes . (hash :: B.ByteString -> Digest SHA512)
+        )
+
+main = do
+    let !bs32     = B.replicate 32 0
+        !bs256    = B.replicate 256 0
+        !bs4096   = B.replicate 4096 0
+        !bs1M     = B.replicate (1*1024*1024) 0
+    let !lbs64x256 = (map (const (B.replicate 64 0)) [0..3])
+        !lbs64x4096 = (map (const (B.replicate 64 0)) [0..63])
+
+    let (fname, fHash, fIncr, fAPI) = sha512F
+    let benchName ty z = fname ++ "." ++ ty ++ " " ++ show z
+    defaultMain
+        [ bgroup "digest hex"
+            [ bench "hex" $ whnf digestToHexByteString (hashsha1 B.empty)
+            ]
+        , bcompare
+            [ bench (benchName "hash" 0) $ whnf fHash B.empty
+            , bench (benchName "incr" 0) $ whnf fIncr B.empty
+            , bench (benchName "api" 0)  $ whnf fAPI B.empty
+            ]
+        , bcompare
+            [ bench (benchName "hash" 32) $ whnf SHA1.hash bs32
+            , bench (benchName "incr" 32) $ whnf fIncr bs32
+            , bench (benchName "api" 32)  $ whnf fAPI bs32
+            ]
+        , bcompare
+            [ bench (benchName "hash" 256) $ whnf SHA1.hash bs256
+            , bench (benchName "incr" 256) $ whnf fIncr bs256
+            , bench (benchName "api" 256)  $ whnf fAPI bs256
+            ]
+        , bcompare
+            [ bench (benchName "hash" 4096) $ whnf SHA1.hash bs4096
+            , bench (benchName "incr" 4096) $ whnf fIncr bs4096
+            , bench (benchName "api" 4096)  $ whnf fAPI bs4096
+            ]
+        ]
+    where hashsha1 = hash :: B.ByteString -> Digest SHA1
diff --git a/Bench/BenchHMAC.hs b/Bench/BenchHMAC.hs
new file mode 100644
--- /dev/null
+++ b/Bench/BenchHMAC.hs
@@ -0,0 +1,12 @@
+
+import Criterion.Main
+import Crypto.Hash
+import qualified Data.ByteString as B
+import Data.Byteable
+
+main = do
+    let b32 = B.replicate 32 0
+    defaultMain
+        [ bench "hmac-md5" $ whnf (toBytes . hmacAlg MD5 b32) b32
+        , bench "hmac-sha1" $ whnf (toBytes . hmacAlg SHA1 b32) b32
+        ]
diff --git a/Crypto/Hash.hs b/Crypto/Hash.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Hash.hs
@@ -0,0 +1,228 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PackageImports #-}
+-- |
+-- Module      : Crypto.Hash
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- Generalized cryptographic hash interface, that you can use with cryptographic hash
+-- algorithm that belong to the HashAlgorithm type class.
+--
+-- > import Crypto.Hash
+-- >
+-- > sha1 :: ByteString -> Digest SHA1
+-- > sha1 = hash
+-- >
+-- > hexSha3_512 :: ByteString -> String
+-- > hexSha3_512 bs = show (hash bs :: Digest SHA3_512)
+--
+module Crypto.Hash
+    (
+    -- * Types
+      HashAlgorithm(..)
+    , HashFunctionBS
+    , HashFunctionLBS
+    , Context
+    , Digest
+    -- * Functions
+    , digestToByteString
+    , digestToHexByteString
+    , hash
+    , hashlazy
+    , hashUpdate
+    , hashInitAlg
+    -- * hash algorithms
+    , H.MD2(..)
+    , H.MD4(..)
+    , H.MD5(..)
+    , H.SHA1(..)
+    , H.SHA224(..)
+    , H.SHA256(..)
+    , H.SHA384(..)
+    , H.SHA512(..)
+    , H.RIPEMD160(..)
+    , H.Tiger(..)
+    , H.SHA3_224(..)
+    , H.SHA3_256(..)
+    , H.SHA3_384(..)
+    , H.SHA3_512(..)
+    , H.Skein256_224(..)
+    , H.Skein256_256(..)
+    , H.Skein512_224(..)
+    , H.Skein512_256(..)
+    , H.Skein512_384(..)
+    , H.Skein512_512(..)
+    , H.Whirlpool(..)
+    -- * MAC algorithms
+    , HMAC(..)
+    , hmac
+    , hmacAlg
+    ) where
+
+import Crypto.Hash.Types
+import Data.ByteString (ByteString)
+import Data.Byteable
+import Data.Bits (xor)
+import qualified Data.ByteString as B
+import qualified Data.ByteArray.Encoding as B
+import qualified Data.ByteString.Lazy as L
+
+import qualified "cryptonite" Crypto.Hash as H
+
+-- | Alias to a single pass hash function that operate on a strict bytestring
+type HashFunctionBS a = ByteString -> Digest a
+
+-- | Alias to a single pass hash function that operate on a lazy bytestring
+type HashFunctionLBS a = L.ByteString -> Digest a
+
+-- | run hashUpdates on one single bytestring and return the updated context.
+hashUpdate :: HashAlgorithm a => Context a -> ByteString -> Context a
+hashUpdate ctx b = hashUpdates ctx [b]
+
+-- | Hash a strict bytestring into a digest.
+hash :: HashAlgorithm a => ByteString -> Digest a
+hash bs = hashFinalize $ hashUpdate hashInit bs
+
+-- | Hash a lazy bytestring into a digest.
+hashlazy :: HashAlgorithm a => L.ByteString -> Digest a
+hashlazy lbs = hashFinalize $ hashUpdates hashInit (L.toChunks lbs)
+
+-- | Return the hexadecimal (base16) bytestring of the digest
+digestToHexByteString :: Digest a -> ByteString
+digestToHexByteString = B.convertToBase B.Base16 . toBytes
+
+-- | Class representing hashing algorithms.
+--
+-- The hash algorithm is built over 3 primitives:
+--
+-- * init     : create a new hashing context
+--
+-- * updates  : update the hashing context with some strict bytestrings
+--              and return the new context
+--
+-- * finalize : finalize the context into a digest
+--
+class HashAlgorithm a where
+    -- | Block size in bytes the hash algorithm operates on
+    hashBlockSize :: Context a -> Int
+
+    -- | Initialize a new context for this hash algorithm
+    hashInit     :: Context a
+
+    -- | Update the context with a list of strict bytestring,
+    -- and return a new context with the updates.
+    hashUpdates  :: Context a -> [ByteString] -> Context a
+
+    -- | Finalize a context and return a digest.
+    hashFinalize :: Context a -> Digest a
+
+    -- | Try to convert a binary digest bytestring to a digest.
+    digestFromByteString :: ByteString -> Maybe (Digest a)
+
+
+#define DEFINE_INSTANCE(NAME, MODULENAME, BLOCKSIZE) \
+instance HashAlgorithm H.NAME where \
+    { hashInit = Context $ H.hashInit \
+    ; hashBlockSize ~(Context _) = BLOCKSIZE \
+    ; hashUpdates (Context c) bs = Context $ H.hashUpdates c bs \
+    ; hashFinalize (Context c) = Digest $ H.hashFinalize c \
+    ; digestFromByteString bs = Digest `fmap` H.digestFromByteString bs \
+    };
+
+#define DEFINE_INSTANCE_LEN(NAME, MODULENAME, LEN, BLOCKSIZE) \
+instance HashAlgorithm H.NAME where \
+    { hashInit = Context $ H.hashInit \
+    ; hashBlockSize ~(Context _) = BLOCKSIZE \
+    ; hashUpdates (Context c) bs = Context $ H.hashUpdates c bs \
+    ; hashFinalize (Context c) = Digest $ H.hashFinalize c \
+    ; digestFromByteString bs = Digest `fmap` H.digestFromByteString bs \
+    };
+
+-- | MD2 cryptographic hash
+DEFINE_INSTANCE(MD2, MD2, 16)
+-- | MD4 cryptographic hash
+DEFINE_INSTANCE(MD4, MD4, 64)
+-- | MD5 cryptographic hash
+DEFINE_INSTANCE(MD5, MD5, 64)
+-- | SHA1 cryptographic hash
+DEFINE_INSTANCE(SHA1, SHA1, 64)
+-- | SHA224 cryptographic hash
+DEFINE_INSTANCE(SHA224, SHA224, 64)
+-- | SHA256 cryptographic hash
+DEFINE_INSTANCE(SHA256, SHA256, 64)
+-- | SHA384 cryptographic hash
+DEFINE_INSTANCE(SHA384, SHA384, 128)
+-- | SHA512 cryptographic hash
+DEFINE_INSTANCE(SHA512, SHA512, 128)
+
+-- | RIPEMD160 cryptographic hash
+DEFINE_INSTANCE(RIPEMD160, RIPEMD160, 64)
+-- | Whirlpool cryptographic hash
+DEFINE_INSTANCE(Whirlpool, Whirlpool, 64)
+-- | Tiger cryptographic hash
+DEFINE_INSTANCE(Tiger, Tiger, 64)
+
+-- | SHA3 (224 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(SHA3_224, SHA3, 224, 144)
+-- | SHA3 (256 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(SHA3_256, SHA3, 256, 136)
+-- | SHA3 (384 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(SHA3_384, SHA3, 384, 104)
+-- | SHA3 (512 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(SHA3_512, SHA3, 512, 72)
+
+-- | Skein256 (224 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(Skein256_224, Skein256, 224, 32)
+-- | Skein256 (256 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(Skein256_256, Skein256, 256, 32)
+
+-- | Skein512 (224 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(Skein512_224, Skein512, 224, 64)
+-- | Skein512 (256 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(Skein512_256, Skein512, 256, 64)
+-- | Skein512 (384 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(Skein512_384, Skein512, 384, 64)
+-- | Skein512 (512 bits version) cryptographic hash
+DEFINE_INSTANCE_LEN(Skein512_512, Skein512, 512, 64)
+
+-- | Initialize a new context for a specified hash algorithm
+hashInitAlg :: HashAlgorithm alg => alg -> Context alg
+hashInitAlg _ = hashInit
+
+-- | Represent an HMAC that is a phantom type with the hash used to produce the mac.
+--
+-- The Eq instance is constant time.
+newtype HMAC a = HMAC { hmacGetDigest :: Digest a }
+
+instance Byteable (HMAC a) where
+    toBytes (HMAC b) = toBytes b
+
+instance Eq (HMAC a) where
+    (HMAC b1) == (HMAC b2) = constEqBytes (toBytes b1) (toBytes b2)
+
+-- | compute a MAC using the supplied hashing function
+hmac :: HashAlgorithm a
+     => ByteString       -- ^ Secret key
+     -> ByteString       -- ^ Message to MAC
+     -> HMAC a
+hmac secret msg = doHMAC hashInit
+  where doHMAC :: HashAlgorithm a => Context a -> HMAC a
+        doHMAC ctxInit = HMAC $ hashF $ B.append opad (toBytes $ hashF $ B.append ipad msg)
+          where opad = B.map (xor 0x5c) k'
+                ipad = B.map (xor 0x36) k'
+
+                k'  = B.append kt pad
+                kt  = if B.length secret > fromIntegral blockSize then toBytes (hashF secret) else secret
+                pad = B.replicate (fromIntegral blockSize - B.length kt) 0
+                hashF = hashFinalize . hashUpdate ctxInit
+                blockSize = hashBlockSize ctxInit
+
+-- | compute a HMAC using a specified algorithm
+hmacAlg :: HashAlgorithm a
+        => a           -- ^ the hash algorithm the actual value is unused.
+        -> ByteString  -- ^ Secret key
+        -> ByteString  -- ^ Message to MAC
+        -> HMAC a
+hmacAlg _ secret msg = hmac secret msg
diff --git a/Crypto/Hash/Internal.hs b/Crypto/Hash/Internal.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Hash/Internal.hs
@@ -0,0 +1,38 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PackageImports #-}
+
+-- |
+-- Module      : Crypto.Hash.Internal
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+module Crypto.Hash.Internal
+    ( unsafeDoIO
+    , digestToByteString
+    , digestToByteStringWitness
+    ) where
+
+import System.IO.Unsafe
+import Data.ByteArray (convert)
+import "cryptonite" Crypto.Hash
+import Data.ByteString (ByteString)
+
+-- | perform io for hashes that do allocation and ffi.
+-- unsafeDupablePerformIO is used when possible as the
+-- computation is pure and the output is directly linked
+-- to the input. we also do not modify anything after it has
+-- been returned to the user.
+unsafeDoIO :: IO a -> a
+#if __GLASGOW_HASKELL__ > 704
+unsafeDoIO = unsafeDupablePerformIO
+#else
+unsafeDoIO = unsafePerformIO
+#endif
+
+digestToByteString :: HashAlgorithm h => Digest h -> ByteString
+digestToByteString = convert
+
+digestToByteStringWitness :: HashAlgorithm h => h -> Digest h -> ByteString
+digestToByteStringWitness _ = convert
+
diff --git a/Crypto/Hash/MD2.hs b/Crypto/Hash/MD2.hs
--- a/Crypto/Hash/MD2.hs
+++ b/Crypto/Hash/MD2.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.MD2
@@ -10,111 +10,50 @@
 -- A module containing MD2 bindings
 --
 module Crypto.Hash.MD2
-	( Ctx(..)
-	, MD2
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx MD2 where
-	outputLength    = Tagged (16 * 8)
-	blockLength     = Tagged (16 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize MD2 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data MD2 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 16
-sizeCtx = 96
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "md2.h md2_init"
-	c_md2_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_md2_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_md2_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | MD2 Context
+newtype Ctx = Ctx (H.Context H.MD2)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_md2_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.MD2 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.MD2 $ H.hashlazy l
diff --git a/Crypto/Hash/MD4.hs b/Crypto/Hash/MD4.hs
--- a/Crypto/Hash/MD4.hs
+++ b/Crypto/Hash/MD4.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.MD4
@@ -10,111 +10,50 @@
 -- A module containing MD4 bindings
 --
 module Crypto.Hash.MD4
-	( Ctx(..)
-	, MD4
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx MD4 where
-	outputLength    = Tagged (16 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize MD4 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data MD4 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 16
-sizeCtx = 96
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "md4.h md4_init"
-	c_md4_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_md4_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_md4_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | MD4 Context
+newtype Ctx = Ctx (H.Context H.MD4)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_md4_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.MD4 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.MD4 $ H.hashlazy l
diff --git a/Crypto/Hash/MD5.hs b/Crypto/Hash/MD5.hs
--- a/Crypto/Hash/MD5.hs
+++ b/Crypto/Hash/MD5.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.MD5
@@ -10,111 +10,50 @@
 -- A module containing MD5 bindings
 --
 module Crypto.Hash.MD5
-	( Ctx(..)
-	, MD5
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx MD5 where
-	outputLength    = Tagged (16 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize MD5 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data MD5 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 16
-sizeCtx = 96
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "md5.h md5_init"
-	c_md5_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_md5_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_md5_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | MD5 Context
+newtype Ctx = Ctx (H.Context H.MD5)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_md5_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.MD5 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.MD5 $ H.hashlazy l
diff --git a/Crypto/Hash/RIPEMD160.hs b/Crypto/Hash/RIPEMD160.hs
--- a/Crypto/Hash/RIPEMD160.hs
+++ b/Crypto/Hash/RIPEMD160.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.RIPEMD160
@@ -10,111 +10,50 @@
 -- A module containing RIPEMD160 bindings
 --
 module Crypto.Hash.RIPEMD160
-	( Ctx(..)
-	, RIPEMD160
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx RIPEMD160 where
-	outputLength    = Tagged (20 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize RIPEMD160 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data RIPEMD160 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 20
-sizeCtx = 128
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "ripemd.h ripemd160_init"
-	c_ripemd160_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_ripemd160_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_ripemd160_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | RIPEMD160 Context
+newtype Ctx = Ctx (H.Context H.RIPEMD160)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_ripemd160_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.RIPEMD160 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.RIPEMD160 $ H.hashlazy l
diff --git a/Crypto/Hash/SHA1.hs b/Crypto/Hash/SHA1.hs
--- a/Crypto/Hash/SHA1.hs
+++ b/Crypto/Hash/SHA1.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.SHA1
@@ -10,111 +10,50 @@
 -- A module containing SHA1 bindings
 --
 module Crypto.Hash.SHA1
-	( Ctx(..)
-	, SHA1
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx SHA1 where
-	outputLength    = Tagged (20 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize SHA1 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data SHA1 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 20
-sizeCtx = 96
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "sha1.h sha1_init"
-	c_sha1_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_sha1_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_sha1_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | SHA1 Context
+newtype Ctx = Ctx (H.Context H.SHA1)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha1_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.SHA1 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.SHA1 $ H.hashlazy l
diff --git a/Crypto/Hash/SHA224.hs b/Crypto/Hash/SHA224.hs
--- a/Crypto/Hash/SHA224.hs
+++ b/Crypto/Hash/SHA224.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.SHA224
@@ -10,111 +10,50 @@
 -- A module containing SHA224 bindings
 --
 module Crypto.Hash.SHA224
-	( Ctx(..)
-	, SHA224
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx SHA224 where
-	outputLength    = Tagged (28 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize SHA224 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data SHA224 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 28
-sizeCtx = 192
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "sha256.h sha224_init"
-	c_sha224_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_sha224_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_sha224_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | SHA224 Context
+newtype Ctx = Ctx (H.Context H.SHA224)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha224_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.SHA224 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.SHA224 $ H.hashlazy l
diff --git a/Crypto/Hash/SHA256.hs b/Crypto/Hash/SHA256.hs
--- a/Crypto/Hash/SHA256.hs
+++ b/Crypto/Hash/SHA256.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.SHA256
@@ -10,111 +10,50 @@
 -- A module containing SHA256 bindings
 --
 module Crypto.Hash.SHA256
-	( Ctx(..)
-	, SHA256
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx SHA256 where
-	outputLength    = Tagged (32 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize SHA256 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data SHA256 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 32
-sizeCtx = 192
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "sha256.h sha256_init"
-	c_sha256_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_sha256_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_sha256_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | SHA256 Context
+newtype Ctx = Ctx (H.Context H.SHA256)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha256_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.SHA256 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.SHA256 $ H.hashlazy l
diff --git a/Crypto/Hash/SHA3.hs b/Crypto/Hash/SHA3.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Hash/SHA3.hs
@@ -0,0 +1,142 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+-- |
+-- Module      : Crypto.Hash.SHA3
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing SHA3 bindings
+--
+-- WARNING: this implementation is not SHA3 as standardize, but
+-- SHA3 as submitted before standardisation. also known at the Keccak.
+--
+-- A matching implementation is available as Keccak in cryptonite
+-- for people that are using the pre-standard SHA3.
+--
+-- do not use.
+--
+module Crypto.Hash.SHA3
+{-# WARNING "this implementation is not SHA3 as standardized, but SHA3 as submitted before standardisation (Keccak)" #-}
+    ( Ctx(..)
+
+    -- * Incremental hashing Functions
+    , init     -- :: Int -> Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
+
+    -- * Single Pass hashing
+    , hash     -- :: Int -> ByteString -> ByteString
+    , hashlazy -- :: Int -> ByteString -> ByteString
+    ) where
+
+import Prelude hiding (init)
+import Foreign.Ptr
+import Foreign.ForeignPtr (withForeignPtr)
+import Foreign.Storable
+import Foreign.Marshal.Alloc
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
+import Data.ByteString.Internal (create, toForeignPtr)
+import Data.Word
+import Crypto.Hash.Internal (unsafeDoIO)
+
+-- | SHA3 Context
+newtype Ctx = Ctx ByteString
+
+{-# INLINE sizeCtx #-}
+sizeCtx :: Int
+sizeCtx = 360
+
+{- return the number of bytes of output for the digest -}
+peekHashlen :: Ptr Ctx -> IO Int
+peekHashlen ptr = peek iptr >>= \v -> return $! fromIntegral v
+    where iptr :: Ptr Word32
+          iptr = castPtr ptr
+
+{-# RULES "hash" forall b i. finalize (update (init i) b) = hash i b #-}
+{-# RULES "hash.list1" forall b i. finalize (updates (init i) [b]) = hash i b #-}
+{-# RULES "hashmany" forall b i. finalize (foldl update (init i) b) = hashlazy i (L.fromChunks b) #-}
+{-# RULES "hashlazy" forall b i. finalize (foldl update (init i) $ L.toChunks b) = hashlazy i b #-}
+
+{-# INLINE withByteStringPtr #-}
+withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a
+withByteStringPtr b f =
+    withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
+    where (fptr, off, _) = toForeignPtr b
+
+{-# INLINE memcopy64 #-}
+memcopy64 :: Ptr Word64 -> Ptr Word64 -> IO ()
+memcopy64 dst src = mapM_ peekAndPoke [0..(45-1)]
+    where peekAndPoke i = peekElemOff src i >>= pokeElemOff dst i
+
+withCtxCopy :: Ctx -> (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxCopy (Ctx ctxB) f = Ctx `fmap` createCtx
+    where createCtx = create sizeCtx $ \dstPtr ->
+                      withByteStringPtr ctxB $ \srcPtr -> do
+                          memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+                          f (castPtr dstPtr)
+
+withCtxThrow :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+withCtxThrow (Ctx ctxB) f =
+    allocaBytes sizeCtx $ \dstPtr ->
+    withByteStringPtr ctxB $ \srcPtr -> do
+        memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+        f (castPtr dstPtr)
+
+withCtxNew :: (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxNew f = Ctx `fmap` create sizeCtx (f . castPtr)
+
+withCtxNewThrow :: (Ptr Ctx -> IO a) -> IO a
+withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr)
+
+foreign import ccall unsafe "sha3.h cryptohash_sha3_init"
+    c_sha3_init :: Ptr Ctx -> Word32 -> IO ()
+
+foreign import ccall "sha3.h cryptohash_sha3_update"
+    c_sha3_update :: Ptr Ctx -> Ptr Word8 -> Word32 -> IO ()
+
+foreign import ccall unsafe "sha3.h cryptohash_sha3_finalize"
+    c_sha3_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()
+
+updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
+updateInternalIO ptr d =
+    unsafeUseAsCStringLen d (\(cs, len) -> c_sha3_update ptr (castPtr cs) (fromIntegral len))
+
+finalizeInternalIO :: Ptr Ctx -> IO ByteString
+finalizeInternalIO ptr =
+    peekHashlen ptr >>= \digestSize -> create digestSize (c_sha3_finalize ptr)
+
+{-# NOINLINE init #-}
+-- | init a context
+init :: Int -> Ctx
+init hashlen = unsafeDoIO $ withCtxNew $ \ptr -> c_sha3_init ptr (fromIntegral hashlen)
+
+{-# NOINLINE update #-}
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+
+{-# NOINLINE updates #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+
+{-# NOINLINE finalize #-}
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
+
+{-# NOINLINE hash #-}
+-- | hash a strict bytestring into a digest bytestring
+hash :: Int -> ByteString -> ByteString
+hash hashlen d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
+    c_sha3_init ptr (fromIntegral hashlen) >> updateInternalIO ptr d >> finalizeInternalIO ptr
+
+{-# NOINLINE hashlazy #-}
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: Int -> L.ByteString -> ByteString
+hashlazy hashlen l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
+    c_sha3_init ptr (fromIntegral hashlen) >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/SHA384.hs b/Crypto/Hash/SHA384.hs
--- a/Crypto/Hash/SHA384.hs
+++ b/Crypto/Hash/SHA384.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.SHA384
@@ -10,111 +10,50 @@
 -- A module containing SHA384 bindings
 --
 module Crypto.Hash.SHA384
-	( Ctx(..)
-	, SHA384
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx SHA384 where
-	outputLength    = Tagged (48 * 8)
-	blockLength     = Tagged (128 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize SHA384 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data SHA384 = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 48
-sizeCtx = 256
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "sha512.h sha384_init"
-	c_sha384_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_sha384_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_sha384_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | SHA384 Context
+newtype Ctx = Ctx (H.Context H.SHA384)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha384_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# 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
+hash d = digestToByteStringWitness H.SHA384 $ H.hash d
 
-{-# 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
+hashlazy l = digestToByteStringWitness H.SHA384 $ H.hashlazy l
diff --git a/Crypto/Hash/SHA512.hs b/Crypto/Hash/SHA512.hs
--- a/Crypto/Hash/SHA512.hs
+++ b/Crypto/Hash/SHA512.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
 
 -- |
 -- Module      : Crypto.Hash.SHA512
@@ -10,120 +10,133 @@
 -- A module containing SHA512 bindings
 --
 module Crypto.Hash.SHA512
-	( Ctx(..)
-	, SHA512
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, init_t   -- :: Int -> Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , init_t   -- :: Int -> Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 Foreign.Ptr
+import Foreign.ForeignPtr (withForeignPtr)
+import Foreign.Storable
+import Foreign.Marshal.Alloc
 import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString as B
 import Data.ByteString (ByteString)
-import Data.ByteString.Unsafe (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
+import Data.ByteString.Internal (create, toForeignPtr)
+import Data.Word
+import Crypto.Hash.Internal (unsafeDoIO)
 
-#ifdef HAVE_CRYPTOAPI
+-- | SHA512 Context
+newtype Ctx = Ctx ByteString
 
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
+{-# INLINE digestSize #-}
+digestSize :: Int
+digestSize = 64
 
-instance C.Hash Ctx SHA512 where
-	outputLength    = Tagged (64 * 8)
-	blockLength     = Tagged (128 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
+{-# INLINE sizeCtx #-}
+sizeCtx :: Int
+sizeCtx = 256
 
-instance Serialize SHA512 where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
+{-# RULES "digestSize" B.length (finalize init) = digestSize #-}
+{-# RULES "hash" forall b. finalize (update init b) = hash b #-}
+{-# RULES "hash.list1" forall b. finalize (updates init [b]) = hash b #-}
+{-# RULES "hashmany" forall b. finalize (foldl update init b) = hashlazy (L.fromChunks b) #-}
+{-# RULES "hashlazy" forall b. finalize (foldl update init $ L.toChunks b) = hashlazy b #-}
 
-#endif
+{-# INLINE withByteStringPtr #-}
+withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a
+withByteStringPtr b f =
+    withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
+    where (fptr, off, _) = toForeignPtr b
 
-data Ctx = Ctx !ByteString
-data SHA512 = Digest !ByteString
-	deriving (Eq,Ord,Show)
+{-# INLINE memcopy64 #-}
+memcopy64 :: Ptr Word64 -> Ptr Word64 -> IO ()
+memcopy64 dst src = mapM_ peekAndPoke [0..(32-1)]
+    where peekAndPoke i = peekElemOff src i >>= pokeElemOff dst i
 
-digestSize, sizeCtx :: Int
-digestSize = 64
-sizeCtx = 256
+withCtxCopy :: Ctx -> (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxCopy (Ctx ctxB) f = Ctx `fmap` createCtx
+    where createCtx = create sizeCtx $ \dstPtr ->
+                      withByteStringPtr ctxB $ \srcPtr -> do
+                          memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+                          f (castPtr dstPtr)
 
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
+withCtxThrow :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+withCtxThrow (Ctx ctxB) f =
+    allocaBytes sizeCtx $ \dstPtr ->
+    withByteStringPtr ctxB $ \srcPtr -> do
+        memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+        f (castPtr dstPtr)
 
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
+withCtxNew :: (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxNew f = Ctx `fmap` create sizeCtx (f . castPtr)
 
-foreign import ccall unsafe "sha512.h sha512_init"
-	c_sha512_init :: Ptr Ctx -> IO ()
+withCtxNewThrow :: (Ptr Ctx -> IO a) -> IO a
+withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr)
 
-foreign import ccall unsafe "sha512.h sha512_init_t"
-	c_sha512_init_t :: Ptr Ctx -> Int -> IO ()
+foreign import ccall unsafe "sha512.h cryptohash_sha512_init"
+    c_sha512_init :: Ptr Ctx -> IO ()
 
-foreign import ccall "sha512.h sha512_update"
-	c_sha512_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+foreign import ccall "sha512.h cryptohash_sha512_update"
+    c_sha512_update :: Ptr Ctx -> Ptr Word8 -> Word32 -> IO ()
 
-foreign import ccall unsafe "sha512.h sha512_finalize"
-	c_sha512_finalize :: Ptr Ctx -> CString -> IO ()
+foreign import ccall unsafe "sha512.h cryptohash_sha512_finalize"
+    c_sha512_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()
 
-allocInternal :: (Ptr Ctx -> IO a) -> IO a
-allocInternal = alloca
+foreign import ccall unsafe "sha512.h cryptohash_sha512_init_t"
+    c_sha512_init_t :: Ptr Ctx -> Int -> IO ()
 
-allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
-allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+{-# NOINLINE init_t #-}
+-- | init a context using FIPS 180-4 for truncated SHA512
+init_t :: Int -> Ctx
+init_t t = unsafeDoIO $ withCtxNew $ \ptr -> c_sha512_init_t ptr t
 
 updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
 updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_sha512_update ptr cs (fromIntegral len))
+    unsafeUseAsCStringLen d (\(cs, len) -> c_sha512_update ptr (castPtr cs) (fromIntegral len))
 
 finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_sha512_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+finalizeInternalIO ptr = create digestSize (c_sha512_finalize ptr)
 
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha512_init ptr >> peek ptr)
-
-{-# NOINLINE init_t #-}
--- | init a context using FIPS 180-4 for truncated SHA512
-init_t :: Int -> Ctx
-init_t t = unsafePerformIO $ allocInternal $ \ptr -> do (c_sha512_init_t ptr t >> peek ptr)
+init = unsafeDoIO $ withCtxNew $ c_sha512_init
 
 {-# 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
+update ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
 
+{-# NOINLINE updates #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+
 {-# NOINLINE finalize #-}
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# 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
+hash d = unsafeDoIO $ withCtxNewThrow $ \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
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
+    c_sha512_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/SHA512t.hs b/Crypto/Hash/SHA512t.hs
--- a/Crypto/Hash/SHA512t.hs
+++ b/Crypto/Hash/SHA512t.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
-
 -- |
 -- Module      : Crypto.Hash.SHA512t
 -- License     : BSD-style
@@ -10,18 +8,17 @@
 -- A module containing SHA512/t
 --
 module Crypto.Hash.SHA512t
-	( Ctx(..)
-	--, SHA512t
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * Single Pass hashing
+    , hash     -- :: ByteString -> ByteString
+    , hashlazy -- :: ByteString -> ByteString
+    ) where
 
 import Prelude hiding (init)
 import Data.List (foldl')
@@ -31,6 +28,7 @@
 
 import qualified Crypto.Hash.SHA512 as SHA512
 
+-- | SHA512 Context with variable size output
 data Ctx = Ctx !Int !SHA512.Ctx
 
 -- | init a context
diff --git a/Crypto/Hash/Skein256.hs b/Crypto/Hash/Skein256.hs
--- a/Crypto/Hash/Skein256.hs
+++ b/Crypto/Hash/Skein256.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
 
 -- |
 -- Module      : Crypto.Hash.Skein256
@@ -10,118 +10,125 @@
 -- A module containing Skein256 bindings
 --
 module Crypto.Hash.Skein256
-	( Ctx(..)
-	, Skein256
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Int -> Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Int -> Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: Int -> ByteString -> ByteString
-	, hashlazy -- :: Int -> ByteString -> ByteString
-	) where
+    -- * Single Pass hashing
+    , hash     -- :: Int -> ByteString -> ByteString
+    , hashlazy -- :: Int -> ByteString -> ByteString
+    ) where
 
 import Prelude hiding (init)
-import Foreign
-import Foreign.C.String
-import Foreign.C.Types
-import qualified Data.ByteString as B
+import Foreign.Ptr
+import Foreign.ForeignPtr (withForeignPtr)
+import Foreign.Storable
+import Foreign.Marshal.Alloc
 import qualified Data.ByteString.Lazy as L
 import Data.ByteString (ByteString)
-import Data.ByteString.Unsafe (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
+import Data.ByteString.Internal (create, toForeignPtr)
+import Data.Word
+import Crypto.Hash.Internal (unsafeDoIO)
 
-instance C.Hash Ctx Skein256 where
-	outputLength    = Tagged (32 * 8)
-	blockLength     = Tagged (32 * 8)
-	initialCtx      = init (32 * 8)
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
+-- | Skein256 Context
+newtype Ctx = Ctx ByteString
 
-instance Serialize Skein256 where
-	get            = liftM Digest (getByteString 32)
-	put (Digest d) = putByteString d
+{-# INLINE sizeCtx #-}
+sizeCtx :: Int
+sizeCtx = 96
 
-#endif
+{- return the number of bytes of output for the digest -}
+peekHashlen :: Ptr Ctx -> IO Int
+peekHashlen ptr = peek iptr >>= \v -> return $! fromIntegral v
+    where iptr :: Ptr Word32
+          iptr = castPtr ptr
 
-data Ctx = Ctx !ByteString
-data Skein256 = Digest !ByteString
-	deriving (Eq,Ord,Show)
+{-# RULES "hash" forall b i. finalize (update (init i) b) = hash i b #-}
+{-# RULES "hash.list1" forall b i. finalize (updates (init i) [b]) = hash i b #-}
+{-# RULES "hashmany" forall b i. finalize (foldl update (init i) b) = hashlazy i (L.fromChunks b) #-}
+{-# RULES "hashlazy" forall b i. finalize (foldl update (init i) $ L.toChunks b) = hashlazy i b #-}
 
-sizeCtx :: Int
-sizeCtx = 100
+{-# INLINE withByteStringPtr #-}
+withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a
+withByteStringPtr b f =
+    withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
+    where (fptr, off, _) = toForeignPtr b
 
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
+{-# INLINE memcopy64 #-}
+memcopy64 :: Ptr Word64 -> Ptr Word64 -> IO ()
+memcopy64 dst src = mapM_ peekAndPoke [0..(12-1)]
+    where peekAndPoke i = peekElemOff src i >>= pokeElemOff dst i
 
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
+withCtxCopy :: Ctx -> (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxCopy (Ctx ctxB) f = Ctx `fmap` createCtx
+    where createCtx = create sizeCtx $ \dstPtr ->
+                      withByteStringPtr ctxB $ \srcPtr -> do
+                          memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+                          f (castPtr dstPtr)
 
-poke_hashlen :: Ptr Ctx -> IO Int
-poke_hashlen ptr = do
-	let iptr = castPtr ptr :: Ptr CUInt
-	a <- peek iptr
-	return $ fromIntegral a
+withCtxThrow :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+withCtxThrow (Ctx ctxB) f =
+    allocaBytes sizeCtx $ \dstPtr ->
+    withByteStringPtr ctxB $ \srcPtr -> do
+        memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+        f (castPtr dstPtr)
 
-foreign import ccall unsafe "skein256.h skein256_init"
-	c_skein256_init :: Ptr Ctx -> CUInt -> IO ()
+withCtxNew :: (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxNew f = Ctx `fmap` create sizeCtx (f . castPtr)
 
-foreign import ccall "skein256.h skein256_update"
-	c_skein256_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+withCtxNewThrow :: (Ptr Ctx -> IO a) -> IO a
+withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr)
 
-foreign import ccall unsafe "skein256.h skein256_finalize"
-	c_skein256_finalize :: Ptr Ctx -> CString -> IO ()
+foreign import ccall unsafe "skein256.h cryptohash_skein256_init"
+    c_skein256_init :: Ptr Ctx -> Word32 -> IO ()
 
-allocInternal :: (Ptr Ctx -> IO a) -> IO a
-allocInternal = alloca
+foreign import ccall "skein256.h cryptohash_skein256_update"
+    c_skein256_update :: Ptr Ctx -> Ptr Word8 -> Word32 -> IO ()
 
-allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
-allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+foreign import ccall unsafe "skein256.h cryptohash_skein256_finalize"
+    c_skein256_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()
 
 updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
 updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_skein256_update ptr cs (fromIntegral len))
+    unsafeUseAsCStringLen d (\(cs, len) -> c_skein256_update ptr (castPtr cs) (fromIntegral len))
 
 finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr = do
-	digestSize <- fmap (\x -> (x + 7) `shiftR` 3) $ poke_hashlen ptr
-	allocaBytes digestSize (\cs -> c_skein256_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+finalizeInternalIO ptr =
+    peekHashlen ptr >>= \digestSize -> create digestSize (c_skein256_finalize ptr)
 
 {-# NOINLINE init #-}
 -- | init a context
 init :: Int -> Ctx
-init hashlen = unsafePerformIO $ allocInternal $ \ptr -> do (c_skein256_init ptr (fromIntegral hashlen) >> peek ptr)
+init hashlen = unsafeDoIO $ withCtxNew $ \ptr -> c_skein256_init ptr (fromIntegral hashlen)
 
 {-# 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
+update ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
 
+{-# NOINLINE updates #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+
 {-# NOINLINE finalize #-}
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: Int -> ByteString -> ByteString
-hash hashlen d = unsafePerformIO $ allocInternal $ \ptr -> do
-	c_skein256_init ptr (fromIntegral hashlen) >> updateInternalIO ptr d >> finalizeInternalIO ptr
+hash hashlen d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
+    c_skein256_init ptr (fromIntegral hashlen) >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: Int -> L.ByteString -> ByteString
-hashlazy hashlen l = unsafePerformIO $ allocInternal $ \ptr -> do
-	c_skein256_init ptr (fromIntegral hashlen) >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
+hashlazy hashlen l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
+    c_skein256_init ptr (fromIntegral hashlen) >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/Skein512.hs b/Crypto/Hash/Skein512.hs
--- a/Crypto/Hash/Skein512.hs
+++ b/Crypto/Hash/Skein512.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
 
 -- |
 -- Module      : Crypto.Hash.Skein512
@@ -10,118 +10,125 @@
 -- A module containing Skein512 bindings
 --
 module Crypto.Hash.Skein512
-	( Ctx(..)
-	, Skein512
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Int -> Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Int -> Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: Int -> ByteString -> ByteString
-	, hashlazy -- :: Int -> ByteString -> ByteString
-	) where
+    -- * Single Pass hashing
+    , hash     -- :: Int -> ByteString -> ByteString
+    , hashlazy -- :: Int -> ByteString -> ByteString
+    ) where
 
 import Prelude hiding (init)
-import Foreign
-import Foreign.C.String
-import Foreign.C.Types
-import qualified Data.ByteString as B
+import Foreign.Ptr
+import Foreign.ForeignPtr (withForeignPtr)
+import Foreign.Storable
+import Foreign.Marshal.Alloc
 import qualified Data.ByteString.Lazy as L
 import Data.ByteString (ByteString)
-import Data.ByteString.Unsafe (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
+import Data.ByteString.Internal (create, toForeignPtr)
+import Data.Word
+import Crypto.Hash.Internal (unsafeDoIO)
 
-instance C.Hash Ctx Skein512 where
-	outputLength    = Tagged (64 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init (64 * 8)
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
+-- | Skein512 Context
+newtype Ctx = Ctx ByteString
 
-instance Serialize Skein512 where
-	get            = liftM Digest (getByteString 64)
-	put (Digest d) = putByteString d
+{-# INLINE sizeCtx #-}
+sizeCtx :: Int
+sizeCtx = 160
 
-#endif
+{- return the number of bytes of output for the digest -}
+peekHashlen :: Ptr Ctx -> IO Int
+peekHashlen ptr = peek iptr >>= \v -> return $! fromIntegral v
+    where iptr :: Ptr Word32
+          iptr = castPtr ptr
 
-data Ctx = Ctx !ByteString
-data Skein512 = Digest !ByteString
-	deriving (Eq,Ord,Show)
+{-# RULES "hash" forall b i. finalize (update (init i) b) = hash i b #-}
+{-# RULES "hash.list1" forall b i. finalize (updates (init i) [b]) = hash i b #-}
+{-# RULES "hashmany" forall b i. finalize (foldl update (init i) b) = hashlazy i (L.fromChunks b) #-}
+{-# RULES "hashlazy" forall b i. finalize (foldl update (init i) $ L.toChunks b) = hashlazy i b #-}
 
-sizeCtx :: Int
-sizeCtx = 160
+{-# INLINE withByteStringPtr #-}
+withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a
+withByteStringPtr b f =
+    withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
+    where (fptr, off, _) = toForeignPtr b
 
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
+{-# INLINE memcopy64 #-}
+memcopy64 :: Ptr Word64 -> Ptr Word64 -> IO ()
+memcopy64 dst src = mapM_ peekAndPoke [0..(20-1)]
+    where peekAndPoke i = peekElemOff src i >>= pokeElemOff dst i
 
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
+withCtxCopy :: Ctx -> (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxCopy (Ctx ctxB) f = Ctx `fmap` createCtx
+    where createCtx = create sizeCtx $ \dstPtr ->
+                      withByteStringPtr ctxB $ \srcPtr -> do
+                          memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+                          f (castPtr dstPtr)
 
-poke_hashlen :: Ptr Ctx -> IO Int
-poke_hashlen ptr = do
-	let iptr = castPtr ptr :: Ptr CUInt
-	a <- peek iptr
-	return $ fromIntegral a
+withCtxThrow :: Ctx -> (Ptr Ctx -> IO a) -> IO a
+withCtxThrow (Ctx ctxB) f =
+    allocaBytes sizeCtx $ \dstPtr ->
+    withByteStringPtr ctxB $ \srcPtr -> do
+        memcopy64 (castPtr dstPtr) (castPtr srcPtr)
+        f (castPtr dstPtr)
 
-foreign import ccall unsafe "skein512.h skein512_init"
-	c_skein512_init :: Ptr Ctx -> CUInt -> IO ()
+withCtxNew :: (Ptr Ctx -> IO ()) -> IO Ctx
+withCtxNew f = Ctx `fmap` create sizeCtx (f . castPtr)
 
-foreign import ccall "skein512.h skein512_update"
-	c_skein512_update :: Ptr Ctx -> CString -> Word32 -> IO ()
+withCtxNewThrow :: (Ptr Ctx -> IO a) -> IO a
+withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr)
 
-foreign import ccall unsafe "skein512.h skein512_finalize"
-	c_skein512_finalize :: Ptr Ctx -> CString -> IO ()
+foreign import ccall unsafe "skein512.h cryptohash_skein512_init"
+    c_skein512_init :: Ptr Ctx -> Word32 -> IO ()
 
-allocInternal :: (Ptr Ctx -> IO a) -> IO a
-allocInternal = alloca
+foreign import ccall "skein512.h cryptohash_skein512_update"
+    c_skein512_update :: Ptr Ctx -> Ptr Word8 -> Word32 -> IO ()
 
-allocInternalFrom :: Ctx -> (Ptr Ctx -> IO a) -> IO a
-allocInternalFrom ctx f = allocInternal $ \ptr -> (poke ptr ctx >> f ptr)
+foreign import ccall unsafe "skein512.h cryptohash_skein512_finalize"
+    c_skein512_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()
 
 updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
 updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_skein512_update ptr cs (fromIntegral len))
+    unsafeUseAsCStringLen d (\(cs, len) -> c_skein512_update ptr (castPtr cs) (fromIntegral len))
 
 finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr = do
-	digestSize <- fmap (\x -> (x + 7) `shiftR` 3) $ poke_hashlen ptr
-	allocaBytes digestSize (\cs -> c_skein512_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+finalizeInternalIO ptr =
+    peekHashlen ptr >>= \digestSize -> create digestSize (c_skein512_finalize ptr)
 
 {-# NOINLINE init #-}
 -- | init a context
 init :: Int -> Ctx
-init hashlen = unsafePerformIO $ allocInternal $ \ptr -> do (c_skein512_init ptr (fromIntegral hashlen) >> peek ptr)
+init hashlen = unsafeDoIO $ withCtxNew $ \ptr -> c_skein512_init ptr (fromIntegral hashlen)
 
 {-# 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
+update ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
 
+{-# NOINLINE updates #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+
 {-# NOINLINE finalize #-}
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: Int -> ByteString -> ByteString
-hash hashlen d = unsafePerformIO $ allocInternal $ \ptr -> do
-	c_skein512_init ptr (fromIntegral hashlen) >> updateInternalIO ptr d >> finalizeInternalIO ptr
+hash hashlen d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
+    c_skein512_init ptr (fromIntegral hashlen) >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: Int -> L.ByteString -> ByteString
-hashlazy hashlen l = unsafePerformIO $ allocInternal $ \ptr -> do
-	c_skein512_init ptr (fromIntegral hashlen) >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
+hashlazy hashlen l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
+    c_skein512_init ptr (fromIntegral hashlen) >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/Tiger.hs b/Crypto/Hash/Tiger.hs
--- a/Crypto/Hash/Tiger.hs
+++ b/Crypto/Hash/Tiger.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
+{-# LANGUAGE PackageImports #-}
 
 -- |
 -- Module      : Crypto.Hash.Tiger
@@ -10,111 +10,50 @@
 -- A module containing Tiger bindings
 --
 module Crypto.Hash.Tiger
-	( Ctx(..)
-	, Tiger
+    ( Ctx(..)
 
-	-- * Incremental hashing Functions
-	, init     -- :: Ctx
-	, update   -- :: Ctx -> ByteString -> Ctx
-	, finalize -- :: Ctx -> ByteString
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
 
-	-- * Single Pass hashing
-	, hash     -- :: ByteString -> ByteString
-	, hashlazy -- :: ByteString -> ByteString
-	) where
+    -- * 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 (unsafeUseAsCString, unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, memcpy)
-
-#ifdef HAVE_CRYPTOAPI
-
-import Control.Monad (liftM)
-import Data.Serialize (Serialize(..))
-import Data.Serialize.Get (getByteString)
-import Data.Serialize.Put (putByteString)
-import Data.Tagged (Tagged(..))
-import qualified Crypto.Classes as C (Hash(..))
-
-instance C.Hash Ctx Tiger where
-	outputLength    = Tagged (24 * 8)
-	blockLength     = Tagged (64 * 8)
-	initialCtx      = init
-	updateCtx       = update
-	finalize ctx bs = Digest . finalize $ update ctx bs
-
-instance Serialize Tiger where
-	get            = liftM Digest (getByteString digestSize)
-	put (Digest d) = putByteString d
-
-#endif
-
-data Ctx = Ctx !ByteString
-data Tiger = Digest !ByteString
-	deriving (Eq,Ord,Show)
-
-digestSize, sizeCtx :: Int
-digestSize = 24
-sizeCtx = 96
-
-instance Storable Ctx where
-	sizeOf _    = sizeCtx
-	alignment _ = 16
-	poke ptr (Ctx b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeCtx))
-
-	peek ptr = create sizeCtx (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeCtx)) >>= return . Ctx
-
-foreign import ccall unsafe "tiger.h tiger_init"
-	c_tiger_init :: Ptr Ctx -> IO ()
-
-foreign import ccall "tiger.h tiger_update"
-	c_tiger_update :: Ptr Ctx -> CString -> Word32 -> IO ()
-
-foreign import ccall unsafe "tiger.h tiger_finalize"
-	c_tiger_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)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
 
-updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
-updateInternalIO ptr d =
-	unsafeUseAsCStringLen d (\(cs, len) -> c_tiger_update ptr cs (fromIntegral len))
+import qualified "cryptonite" Crypto.Hash as H
 
-finalizeInternalIO :: Ptr Ctx -> IO ByteString
-finalizeInternalIO ptr =
-	allocaBytes digestSize (\cs -> c_tiger_finalize ptr cs >> B.packCStringLen (cs, digestSize))
+-- | Tiger Context
+newtype Ctx = Ctx (H.Context H.Tiger)
 
-{-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafePerformIO $ allocInternal $ \ptr -> do (c_tiger_init ptr >> peek ptr)
+init = Ctx H.hashInit
 
-{-# 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
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
 
-{-# NOINLINE finalize #-}
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
 -- | finalize the context into a digest bytestring
 finalize :: Ctx -> ByteString
-finalize ctx = unsafePerformIO $ allocInternalFrom ctx $ \ptr -> do finalizeInternalIO ptr
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
 
-{-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafePerformIO $ allocInternal $ \ptr -> do
-	c_tiger_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+hash d = digestToByteStringWitness H.Tiger $ H.hash d
 
-{-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafePerformIO $ allocInternal $ \ptr -> do
-	c_tiger_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
+hashlazy l = digestToByteStringWitness H.Tiger $ H.hashlazy l
diff --git a/Crypto/Hash/Types.hs b/Crypto/Hash/Types.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Hash/Types.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE PackageImports #-}
+-- |
+-- Module      : Crypto.Hash.Types
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- Crypto hash types definitions
+--
+module Crypto.Hash.Types
+    ( Context(..)
+    , Digest(..)
+    -- * deprecated
+    , contextToByteString
+    , digestToByteString
+    )
+    where
+
+import Data.ByteString (ByteString)
+import Data.Byteable
+import qualified Data.ByteArray as B (convert)
+import qualified "cryptonite" Crypto.Hash as H
+
+-- | Represent a context for a given hash algorithm.
+newtype Context a = Context (H.Context a)
+
+instance Byteable (Context a) where
+    toBytes (Context ctx) = B.convert ctx
+
+--- | return the binary bytestring. deprecated use toBytes.
+contextToByteString :: Context a -> ByteString
+contextToByteString = toBytes
+
+-- | Represent a digest for a given hash algorithm.
+newtype Digest a = Digest (H.Digest a)
+    deriving (Eq,Ord)
+
+instance Byteable (Digest a) where
+    toBytes (Digest dig) = B.convert dig
+
+-- | return the binary bytestring. deprecated use toBytes.
+{-# DEPRECATED digestToByteString "use toBytes from byteable:Data.Byteable" #-}
+digestToByteString :: Digest a -> ByteString
+digestToByteString = toBytes
+
+instance Show (Digest a) where
+    show (Digest dig) = show dig
diff --git a/Crypto/Hash/Whirlpool.hs b/Crypto/Hash/Whirlpool.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Hash/Whirlpool.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE PackageImports #-}
+
+-- |
+-- Module      : Crypto.Hash.Whirlpool
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- A module containing Whirlpool bindings
+--
+module Crypto.Hash.Whirlpool
+    ( Ctx(..)
+
+    -- * Incremental hashing Functions
+    , init     -- :: Ctx
+    , update   -- :: Ctx -> ByteString -> Ctx
+    , updates  -- :: Ctx -> [ByteString] -> Ctx
+    , finalize -- :: Ctx -> ByteString
+
+    -- * Single Pass hashing
+    , hash     -- :: ByteString -> ByteString
+    , hashlazy -- :: ByteString -> ByteString
+    ) where
+
+import Prelude hiding (init)
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
+import Crypto.Hash.Internal (digestToByteString, digestToByteStringWitness)
+
+import qualified "cryptonite" Crypto.Hash as H
+
+-- | Whirlpool Context
+newtype Ctx = Ctx (H.Context H.Whirlpool)
+
+-- | init a context
+init :: Ctx
+init = Ctx H.hashInit
+
+-- | update a context with a bytestring
+update :: Ctx -> ByteString -> Ctx
+update (Ctx ctx) d = Ctx $ H.hashUpdate ctx d
+
+-- | updates a context with multiples bytestring
+updates :: Ctx -> [ByteString] -> Ctx
+updates (Ctx ctx) d =
+    Ctx $ H.hashUpdates ctx d
+
+-- | finalize the context into a digest bytestring
+finalize :: Ctx -> ByteString
+finalize (Ctx ctx) = digestToByteString $ H.hashFinalize ctx
+
+-- | hash a strict bytestring into a digest bytestring
+hash :: ByteString -> ByteString
+hash d = digestToByteStringWitness H.Whirlpool $ H.hash d
+
+-- | hash a lazy bytestring into a digest bytestring
+hashlazy :: L.ByteString -> ByteString
+hashlazy l = digestToByteStringWitness H.Whirlpool $ H.hashlazy l
diff --git a/Crypto/MAC.hs b/Crypto/MAC.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/MAC.hs
@@ -0,0 +1,75 @@
+-- |
+-- Module      : Crypto.MAC
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- Crypto hash generic MAC (Message Authentification Code) module
+--
+{-# LANGUAGE BangPatterns #-}
+module Crypto.MAC
+    (
+    -- * MAC algorithms
+      HMAC(..)
+    , hmac
+    , hmacAlg
+    -- ** Incremental MAC algorithms
+    , HMACContext
+    , hmacInit
+    , hmacInitAlg
+    , hmacUpdate
+    , hmacFinalize
+    ) where
+
+import Crypto.Hash
+import Data.ByteString (ByteString)
+import Data.Byteable
+import Data.Bits (xor)
+import qualified Data.ByteString as B
+
+-- -------------------------------------------------------------------------- --
+-- Incremental HMAC
+
+-- | Represent an ongoing HMAC state, that can be appended with 'hmacUpdate'
+-- and finalize to an HMAC with 'hmacFinalize'
+data HMACContext hashalg = HMACContext !(Context hashalg) !(Context hashalg)
+
+-- | Initialize a new incremental HMAC context
+hmacInit :: HashAlgorithm a
+         => ByteString -- ^ Secret key
+         -> HMACContext a
+hmacInit secret = HMACContext octx ictx
+    where ctxInit = hashInit
+          ictx = hashUpdates ctxInit [ipad]
+          octx = hashUpdates ctxInit [opad]
+          ipad = B.map (xor 0x36) k'
+          opad = B.map (xor 0x5c) k'
+
+          k'  = B.append kt pad
+          kt  = if B.length secret > fromIntegral blockSize then toBytes (hashF secret) else secret
+          pad = B.replicate (fromIntegral blockSize - B.length kt) 0
+          hashF = hashFinalize . hashUpdate ctxInit
+          blockSize = hashBlockSize ctxInit
+
+-- | Initialize a new incremental HMAC context with a given hash algorithm.
+hmacInitAlg :: HashAlgorithm a
+            => a           -- ^ the hash algorithm the actual value is unused.
+            -> ByteString  -- ^ Secret key
+            -> HMACContext a
+hmacInitAlg _ secret = hmacInit secret
+
+-- | Incrementally update a HMAC context
+hmacUpdate :: HashAlgorithm a
+           => HMACContext a
+           -> ByteString -- ^ Message to Mac
+           -> HMACContext a
+hmacUpdate (HMACContext octx ictx) msg =
+    HMACContext octx (hashUpdate ictx msg)
+
+-- | Finalize a HMAC context and return the HMAC.
+hmacFinalize :: HashAlgorithm a
+             => HMACContext a
+             -> HMAC a
+hmacFinalize (HMACContext octx ictx) =
+    HMAC $ hashFinalize $ hashUpdates octx [toBytes $ hashFinalize ictx]
diff --git a/Crypto/MAC/HMAC.hs b/Crypto/MAC/HMAC.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/MAC/HMAC.hs
@@ -0,0 +1,34 @@
+-- |
+-- Module      : Crypto.MAC.HMAC
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- provide the HMAC (Hash based Message Authentification Code) base algorithm.
+-- <http://en.wikipedia.org/wiki/HMAC>
+--
+module Crypto.MAC.HMAC
+    ( hmac
+    ) where
+
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Data.Bits (xor)
+
+-- | compute a MAC using the supplied hashing function
+--
+-- An incremental API can be found in the module "Crypto.Hash".
+--
+hmac :: (ByteString -> ByteString) -- ^ hash function
+     -> Int -- ^ block size
+     -> ByteString -- ^ secret
+     -> ByteString -- ^ message
+     -> ByteString
+hmac hashF blockSize secret msg = hashF $ B.append opad (hashF $ B.append ipad msg)
+    where opad = B.map (xor 0x5c) k'
+          ipad = B.map (xor 0x36) k'
+
+          k'  = B.append kt pad
+          kt  = if B.length secret > fromIntegral blockSize then hashF secret else secret
+          pad = B.replicate (fromIntegral blockSize - B.length kt) 0
diff --git a/Crypto/MAC/SHA3.hs b/Crypto/MAC/SHA3.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/MAC/SHA3.hs
@@ -0,0 +1,81 @@
+-- |
+-- Module      : Crypto.MAC.SHA3
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- provide a simple SHA3 MAC mechanism with
+--
+-- > mac = hash(key|message)
+--
+module Crypto.MAC.SHA3
+    ( MAC512(..)
+    , MAC384(..)
+    , MAC256(..)
+    , MAC224(..)
+    , mac512
+    , mac384
+    , mac256
+    , mac224
+    ) where
+
+import Data.Byteable
+import Data.ByteString (ByteString)
+import Crypto.Hash
+
+-- | SHA3_512 MAC
+data MAC512 = MAC512 { getDigest512 :: Digest SHA3_512 }
+
+instance Byteable MAC512 where
+    toBytes (MAC512 b) = toBytes b
+instance Eq MAC512 where
+    (MAC512 b1) == (MAC512 b2) = constEqBytes (toBytes b1) (toBytes b2)
+
+-- | SHA3_384 MAC
+data MAC384 = MAC384 { getDigest384 :: Digest SHA3_384 }
+
+instance Byteable MAC384 where
+    toBytes (MAC384 b) = toBytes b
+instance Eq MAC384 where
+    (MAC384 b1) == (MAC384 b2) = constEqBytes (toBytes b1) (toBytes b2)
+
+-- | SHA3_256 MAC
+data MAC256 = MAC256 { getDigest256 :: Digest SHA3_256 }
+
+instance Byteable MAC256 where
+    toBytes (MAC256 b) = toBytes b
+instance Eq MAC256 where
+    (MAC256 b1) == (MAC256 b2) = constEqBytes (toBytes b1) (toBytes b2)
+
+-- | SHA3_224 MAC
+data MAC224 = MAC224 { getDigest224 :: Digest SHA3_224 }
+
+instance Byteable MAC224 where
+    toBytes (MAC224 b) = toBytes b
+instance Eq MAC224 where
+    (MAC224 b1) == (MAC224 b2) = constEqBytes (toBytes b1) (toBytes b2)
+
+-- | compute a MAC using a simple SHA3_512 key|msg
+mac512 :: ByteString -- ^ secret
+       -> ByteString -- ^ message
+       -> MAC512
+mac512 secret msg = MAC512 $ hashFinalize $ hashUpdates hashInit [secret,msg]
+
+-- | compute a MAC using a simple SHA3_384 key|msg
+mac384 :: ByteString -- ^ secret
+       -> ByteString -- ^ message
+       -> MAC384
+mac384 secret msg = MAC384 $ hashFinalize $ hashUpdates hashInit [secret,msg]
+
+-- | compute a MAC using a simple SHA3_256 key|msg
+mac256 :: ByteString -- ^ secret
+       -> ByteString -- ^ message
+       -> MAC256
+mac256 secret msg = MAC256 $ hashFinalize $ hashUpdates hashInit [secret,msg]
+
+-- | compute a MAC using a simple SHA3_224 key|msg
+mac224 :: ByteString -- ^ secret
+       -> ByteString -- ^ message
+       -> MAC224
+mac224 secret msg = MAC224 $ hashFinalize $ hashUpdates hashInit [secret,msg]
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010 Vincent Hanquez <vincent@snarc.org>
+Copyright (c) 2010-2014 Vincent Hanquez <vincent@snarc.org>
 
 All rights reserved.
 
diff --git a/README b/README
deleted file mode 100644
--- a/README
+++ /dev/null
@@ -1,22 +0,0 @@
-hs-cryptohash provides lots of different secure digest algorithms.
-
-All different cryptohashes contains the exact same API, for ease of
-switching between different hashes; this API is separated two folds:
-the incremental API and the one-pass API.
-
-= Incremental API
-
-The incremental API permits the user to compute the digest incrementally,
-with the overhead of having to box and unbox the context in and out
-the computing function.
-
-this API is made of: init, update and finalize; this is similar
-to how a digest algorithm works in other languages.
-
-= One Pass API
-
-The one pass API permits a single shot computation that doesn't have
-the overhead of boxing and unboxing at each step.
-
-this API is made of: hash and hashlazy. hash works on a strict bytestring,
-whereas hashlazy works on a lazy bytestring.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,98 @@
+:warning: this library is now deprecated in favor of `cryptonite`, which is
+a superset of this, and also have more functionality. For new projects,
+you should *not* use this library anymore, and preferably you should
+convert old projects to `cryptonite` too.
+
+:warning: the SHA3 implementation available in Crypto.Hash.SHA3 is
+not SHA3 as standardized by NIST, but Keccak as submitted for the SHA3 contest.
+A matching implementation is available as Keccak in `cryptonite`, although I would
+recommend not to use unless you happens to really really need your digest value
+to be compatible. On the other hand, the centralized `Crypto.Hash` export
+a proper SHA3 implementation (as standardized by NIST)
+
+CryptoHash
+==========
+
+`hs-cryptohash` provides many different secure digest algorithms, also
+called cryptographic hash functions or, simply, cryptohashes. The package
+exports common hash functions, as well as some more exotic ones, and
+provides a single API for them all.
+
+The general performance is comparable to the most optimised implementations
+available.
+
+Here is the complete list of supported algorithms:
+
+* MD2, MD4, MD5 
+* RIPEMD160
+* SHA1
+* SHA-2 family: 224, 256, 384, 512 and the newer 512t
+* SHA-3 (aka Keccak)
+* Skein: 256, 512
+* Tiger
+* Whirlpool
+
+You can easily import any hash with the following:
+
+    import qualified Crypto.Hash.<HASH> as <Hash>
+
+We recommend using `import qualified` because the APIs are similar and
+many of the modules reuse the same names. However, if you are ony using
+one module, there is no need to qualify the names.
+
+Incremental API
+---------------
+
+it's based on 4 different functions, similar to the lowlevel operations
+of a typical hash:
+
+* init: create a new hash context
+* update: update non-destructively a new hash context with a strict bytestring
+* updates: same as update, except that it takes a list of strict bytestring
+* finalize: finalize the context and returns a digest bytestring.
+
+all those operations are completely pure, and instead of changing the
+context as usual in others language, it re-allocates a new context each time.
+
+One Pass API
+------------
+
+The one pass API use the incremental API under the hood, but expose
+common operations to create digests out of a bytestring and lazy bytestring.
+
+* hash: create a digest (init+update+finalize) from a strict bytestring
+* hashlazy: create a digest (init+update+finalize) from a lazy bytestring
+
+More Type safety
+----------------
+
+A more type safe API is also available from Crypto.Hash. The API provides
+all the supported hashes in the same namespace, through unified functions.
+
+It introduces 2 new types, the Context type and the Digest type.
+Both those types are parametrized with the HashAlgorithm used.
+
+The API is very similar to each single hash module, except the types are
+slightly different.
+
+    import Crypto.Hash
+
+    -- use the incremental API to hash the byte [1,2,3] with SHA1
+    -- and print the hexadecimal digest.
+    example1 = do
+        let ctx = hashInit
+            ctx' = hashUpdates ctx [ Data.ByteString.pack [1,2,3] ]
+            dgt  = hashFinalize ctx' :: Digest SHA1
+        putStrLn $ show dgt
+
+    -- use the one-pass API to hash the byte 1,2,3 with SHA3_512
+    -- and print the hexadecimal digest.
+    example2 = do
+        let dgt  = hash (Data.ByteString.pack [1,2,3]) :: Digest SHA3_512
+        putStrLn $ show dgt
+
+Performance
+-----------
+
+Cryptohash uses C implementations to provide maximum performance.
+see the cbits directory for more information
diff --git a/Tests.hs b/Tests.hs
deleted file mode 100644
--- a/Tests.hs
+++ /dev/null
@@ -1,174 +0,0 @@
-import Test.HUnit
-import Data.Char
-import Data.Bits
-import Data.Word
-import qualified Data.ByteString as B
-import qualified Crypto.Hash.MD2 as MD2
-import qualified Crypto.Hash.MD4 as MD4
-import qualified Crypto.Hash.MD5 as MD5
-import qualified Crypto.Hash.SHA1 as SHA1
-import qualified Crypto.Hash.SHA224 as SHA224
-import qualified Crypto.Hash.SHA256 as SHA256
-import qualified Crypto.Hash.SHA384 as SHA384
-import qualified Crypto.Hash.SHA512 as SHA512
-import qualified Crypto.Hash.SHA512t as SHA512t
-import qualified Crypto.Hash.RIPEMD160 as RIPEMD160
-import qualified Crypto.Hash.Tiger as Tiger
-import qualified Crypto.Hash.Skein256 as Skein256
-import qualified Crypto.Hash.Skein512 as Skein512
-
-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 }
-sha512_224Hash = HashFct { fctHash = SHA512t.hash 224, fctInc = hashinc (SHA512t.init 224) SHA512t.update SHA512t.finalize }
-sha512_256Hash = HashFct { fctHash = SHA512t.hash 256, fctInc = hashinc (SHA512t.init 256) SHA512t.update SHA512t.finalize }
-
-ripemd160Hash = HashFct { fctHash = RIPEMD160.hash, fctInc = hashinc RIPEMD160.init RIPEMD160.update RIPEMD160.finalize }
-tigerHash = HashFct { fctHash = Tiger.hash, fctInc = hashinc Tiger.init Tiger.update Tiger.finalize }
-
-skein256Hash x = HashFct { fctHash = Skein256.hash x, fctInc = hashinc (Skein256.init x) Skein256.update Skein256.finalize }
-skein512Hash x = HashFct { fctHash = Skein512.hash x, fctInc = hashinc (Skein512.init x) Skein512.update Skein512.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" ]),
-
-	("SHA512/224", sha512_224Hash, [
-		"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",
-		"944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37",
-		"2b9d6565a7e40f780ba8ab7c8dcf41e3ed3b77997f4c55aa987eede5" ]),
-	("SHA512/256", sha512_256Hash, [
-		"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
-		"dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d",
-		"cc8d255a7f2f38fd50388fd1f65ea7910835c5c1e73da46fba01ea50d5dd76fb" ]),
-	("RIPEMD160", ripemd160Hash, [
-		"9c1185a5c5e9fc54612808977ee8f548b2258d31",
-		"37f332f68db77bd9d7edd4969571ad671cf9dd3b",
-		"132072df690933835eb8b6ad0b77e7b6f14acad7" ]),
-	("Tiger", tigerHash, [
-		"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3",
-		"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075",
-		"a8f04b0f7201a0d728101c9d26525b31764a3493fcd8458f" ])
-	, ("Skein256-160", skein256Hash 160, [
-		"2ab89f14cfb3a5cb4655379386c42df7a45ccaf7",
-		"c86ef8411dc1deb008a3c175091691b74643631e",
-		"2775e79484bc087b58eb78d977c143a3029471be" ])
-	, ("Skein256-256", skein256Hash 256, [
-		"0b04103b828cddaebcf592ac845ecafd5887f61230a755406d38d85376e1ae08",
-		"a7e63c4dc73d0cb77184e319ebb6f69b73bfc8b945c1b371fafd01223a2ade1c",
-		"2174ca46353601a53826b430b52e76fca51bb0419f7a20ac7ffd53c4c448fa51" ])
-	, ("Skein512-160", skein512Hash 160, [
-		"b034bcc065b01b0c486159b3dba3e03aa52fdd70",
-		"9709e7d913bc3eee240e1f302840a0da9d9acc48",
-		"fb2cc0959e884d66927346552df8b51d2d98690c" ])
-	, ("Skein512-384", skein512Hash 384, [
-		"2c3fe10673f4d6904f27585fc3df455a678bc12d7d39d6be4b37f47b80a43889181103bc727a7db4b4e2d2dec1ded86a",
-		"19d373842a6dd304454d6673cb3a8b7871f139477ac28900de739a31789f6e2846d3b641b2e8386f65061efe602d7cac",
-		"bbc4e1089364dd69b0847a06bff6ce19889fed18bf57c901402c74e22ba763bf0dacb9b1d24efc78d969170fd434dad7" ])
-	, ("Skein512-512", skein512Hash 512, [
-		"5af68a4912e0a6187a004947a9d2a37d7a1f0873f0bdd9dc64838ece60da5535c2a55d039bd58e178948996b7a8336486ed969c894be658e47d595a5a9b86a8b",
-		"e38e8ec4814aa2ca485c8ace47c929691ec6acabf2d2795006306267210728d5576d6b7d361bbf99fb1e843d9027b340f828ad074315a5d4b71361de34c511c0",
-		"cd90f50e10e7fe59e263c3796b92795a78fcf561f0fea07b04faeb4e602edb4d6d9f927cc0b5f2b0671e7c7e5fc42ca8875222bcfd42936c542d8f2312fd3615" ])
-	, ("Skein512-896", skein512Hash 896, [
-		"bcc274c53cfa75284f8dcf71e28d19bf52f0e218c241cc1c23e2da043bf61c383899c67fdcbb7511de1831a9113720125127876df2bd0cd57d99ef303baf209c00998bc7d3749f6845d9eaf32ac629de84ac3b494efa29a68cb93d65fd25a2dcef515484b78381eede4af762a1d2f188",
-		"7ad8b71b5bdcaff6f785c9b80b2b1f5fe56030f3ead98965d1ebd20ae75388c2e94097b32a01b7d11a32cef60ea9268170db51726cddf9ee62c3f33e3f84f8ec470053affb564952da6a9cb5e8a4baba8e72b9612ea95863c99b7e59a461288459990ef063fe0b066f8f24fb3794e708",
-		"14b22fe85d5b22f8aa921f32bab0e2cca9d88971dd6f7624506c6662faec9c7429be5bc54be37734c52f10cd866612d0e364023e1db888579b6d9462530807ade129d308adb09eb3308ad8c8731aedb1559f6cefd7d4d9761627f727a79a149788fb267439004d5f7a8dad69a6046d8b" ])
-	]
-
-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/Tests/KAT.hs b/Tests/KAT.hs
new file mode 100644
--- /dev/null
+++ b/Tests/KAT.hs
@@ -0,0 +1,264 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
+import Data.Char
+import Data.Bits
+import Data.Word
+import Data.ByteString (ByteString)
+import Data.Byteable
+import Data.Foldable (foldl')
+import Data.Monoid (mconcat)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as BC
+import qualified Crypto.Hash.MD2 as MD2
+import qualified Crypto.Hash.MD4 as MD4
+import qualified Crypto.Hash.MD5 as MD5
+import qualified Crypto.Hash.SHA1 as SHA1
+import qualified Crypto.Hash.SHA224 as SHA224
+import qualified Crypto.Hash.SHA256 as SHA256
+import qualified Crypto.Hash.SHA384 as SHA384
+import qualified Crypto.Hash.SHA512 as SHA512
+import qualified Crypto.Hash.SHA512t as SHA512t
+import qualified Crypto.Hash.RIPEMD160 as RIPEMD160
+import qualified Crypto.Hash.Tiger as Tiger
+import qualified Crypto.Hash.Skein256 as Skein256
+import qualified Crypto.Hash.Skein512 as Skein512
+import qualified Crypto.Hash.Whirlpool as Whirlpool
+import Crypto.Hash
+import Crypto.MAC
+
+import Test.Tasty
+import Test.Tasty.QuickCheck
+import Test.Tasty.HUnit
+
+v0,v1,v2 :: ByteString
+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 ]
+
+instance Arbitrary ByteString where
+    arbitrary = B.pack `fmap` arbitrary
+
+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 }
+sha512_224Hash = HashFct { fctHash = SHA512t.hash 224, fctInc = hashinc (SHA512t.init 224) SHA512t.update SHA512t.finalize }
+sha512_256Hash = HashFct { fctHash = SHA512t.hash 256, fctInc = hashinc (SHA512t.init 256) SHA512t.update SHA512t.finalize }
+
+ripemd160Hash = HashFct { fctHash = RIPEMD160.hash, fctInc = hashinc RIPEMD160.init RIPEMD160.update RIPEMD160.finalize }
+tigerHash = HashFct { fctHash = Tiger.hash, fctInc = hashinc Tiger.init Tiger.update Tiger.finalize }
+
+skein256Hash x = HashFct { fctHash = Skein256.hash x, fctInc = hashinc (Skein256.init x) Skein256.update Skein256.finalize }
+skein512Hash x = HashFct { fctHash = Skein512.hash x, fctInc = hashinc (Skein512.init x) Skein512.update Skein512.finalize }
+
+whirlpoolHash = HashFct { fctHash = Whirlpool.hash, fctInc = hashinc Whirlpool.init Whirlpool.update Whirlpool.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" ]),
+
+    ("SHA512/224", sha512_224Hash, [
+        "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",
+        "944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37",
+        "2b9d6565a7e40f780ba8ab7c8dcf41e3ed3b77997f4c55aa987eede5" ]),
+    ("SHA512/256", sha512_256Hash, [
+        "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
+        "dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d",
+        "cc8d255a7f2f38fd50388fd1f65ea7910835c5c1e73da46fba01ea50d5dd76fb" ]),
+    ("RIPEMD160", ripemd160Hash, [
+        "9c1185a5c5e9fc54612808977ee8f548b2258d31",
+        "37f332f68db77bd9d7edd4969571ad671cf9dd3b",
+        "132072df690933835eb8b6ad0b77e7b6f14acad7" ]),
+    ("Tiger", tigerHash, [
+        "3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3",
+        "6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075",
+        "a8f04b0f7201a0d728101c9d26525b31764a3493fcd8458f" ])
+    , ("Skein256-160", skein256Hash 160, [
+        "ff800bed6d2044ee9d604a674e3fda50d9b24a72",
+        "3265703c166aa3e0d7da070b9cf1b1a5953f0a77",
+        "17b29aa1424b3ec022505bd215ff73fd2e6d1e5a" ])
+    , ("Skein256-256", skein256Hash 256, [
+        "c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba",
+        "c0fbd7d779b20f0a4614a66697f9e41859eaf382f14bf857e8cdb210adb9b3fe",
+        "fb2f2f2deed0e1dd7ee2b91cee34e2d1c22072e1f5eaee288c35a0723eb653cd" ])
+    , ("Skein512-160", skein512Hash 160, [
+        "49daf1ccebb3544bc93cb5019ba91b0eea8876ee",
+        "826325ee55a6dd18c3b2dbbc9c10420f5475975e",
+        "7544ec7a35712ec953f02b0d0c86641cae4eb6e5" ])
+    , ("Skein512-384", skein512Hash 384, [
+        "dd5aaf4589dc227bd1eb7bc68771f5baeaa3586ef6c7680167a023ec8ce26980f06c4082c488b4ac9ef313f8cbe70808",
+        "f814c107f3465e7c54048a5503547deddc377264f05c706b0d19db4847b354855ee52ab6a785c238c9e710d848542041",
+        "e06520eeadc1d0a44fee1d2492547499c1e58526387c8b9c53905e5edb79f9840575cbf844e21b1ad1ea126dd8a8ca6f" ])
+    , ("Skein512-512", skein512Hash 512, [
+        "bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af41fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a",
+        "94c2ae036dba8783d0b3f7d6cc111ff810702f5c77707999be7e1c9486ff238a7044de734293147359b4ac7e1d09cd247c351d69826b78dcddd951f0ef912713",
+        "7f81113575e4b4d3441940e87aca331e6d63d103fe5107f29cd877af0d0f5e0ea34164258c60da5190189d0872e63a96596d2ef25e709099842da71d64111e0f" ])
+    , ("Skein512-896", skein512Hash 896, [
+        "b95175236c83a459ce7ec6c12b761a838b22d750e765b3fdaa892201b2aa714bc3d1d887dd64028bbf177c1dd11baa09c6c4ddb598fd07d6a8c131a09fc5b958e2999a8006754b25abe3bf8492b7eabec70e52e04e5ac867df2393c573f16eee3244554f1d2b724f2c0437c62007f770",
+        "3265708553e7d146e5c7bcbc97b3e9e9f5b53a5e4af53612bdd6454da4fa7b13d413184fe34ed57b6574be10e389d0ec4b1d2b1dd2c80e0257d5a76b2cd86a19a27b1bcb3cc24d911b5dc5ee74d19ad558fd85b5f024e99f56d1d3199f1f9f88ed85fab9f945f11cf9fc00e94e3ca4c7",
+        "3d23d3db9be719bbd2119f8402a28f38d8225faa79d5b68b80738c64a82004aafc7a840cd6dd9bced6644fa894a3d8d7d2ee89525fd1956a2db052c4c2f8d2111c91ef46b0997540d42bcf384826af1a5ef6510077f52d0574cf2b46f1b6a5dad07ed40f3d21a13ca2d079fa602ff02d" ])
+    , ("Whirlpool", whirlpoolHash, [
+        "19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3",
+        "b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35",
+        "dce81fc695cfea3d7e1446509238daf89f24cc61896f2d265927daa70f2108f8902f0dfd68be085d5abb9fcd2e482c1dc24f2fabf81f40b73495cad44d7360d3"])
+    ]
+
+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 :: Int -> ByteString -> [ByteString]
+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) = testGroup name $ concatMap maketest (zip3 [0..] vectors results)
+    where
+        runtest :: ByteString -> String
+        runtest v = runhash hash v
+
+        runtestinc :: Int -> ByteString -> String
+        runtestinc i v = runhashinc hash $ splitB i v
+
+        maketest (i, v, r) =
+            [ testCase (show i ++ " one-pass") (r @=? runtest v)
+            , testCase (show i ++ " inc 1") (r @=? runtestinc 1 v)
+            , testCase (show i ++ " inc 2") (r @=? runtestinc 2 v)
+            , testCase (show i ++ " inc 3") (r @=? runtestinc 3 v)
+            , testCase (show i ++ " inc 4") (r @=? runtestinc 4 v)
+            , testCase (show i ++ " inc 5") (r @=? runtestinc 5 v)
+            , testCase (show i ++ " inc 9") (r @=? runtestinc 9 v)
+            , testCase (show i ++ " inc 16") (r @=? runtestinc 16 v)
+            ]
+
+katTests :: [TestTree]
+katTests = map makeTestAlg results
+
+apiTests :: [TestTree]
+apiTests =
+    [ testCase "sha1 api" (runhash sha1Hash B.empty @=? show (hash B.empty :: Digest SHA1))
+    , testCase "sha256 api" (runhash sha256Hash B.empty @=? show (hash B.empty :: Digest SHA256))
+    , testCase "sha512 api" (runhash sha512Hash B.empty @=? show (hash B.empty :: Digest SHA512))
+    ]
+
+
+data MACVector = MACVector { macKey :: ByteString
+                           , macSecret :: ByteString
+                           , macResult :: ByteString
+                           }
+
+md5MACVectors =
+    [ MACVector B.empty B.empty "\x74\xe6\xf7\x29\x8a\x9c\x2d\x16\x89\x35\xf5\x8c\x00\x1b\xad\x88"
+    , MACVector "key"   v1      "\x80\x07\x07\x13\x46\x3e\x77\x49\xb9\x0c\x2d\xc2\x49\x11\xe2\x75"
+    ]
+
+sha1MACVectors =
+    [ MACVector B.empty B.empty "\xfb\xdb\x1d\x1b\x18\xaa\x6c\x08\x32\x4b\x7d\x64\xb7\x1f\xb7\x63\x70\x69\x0e\x1d"
+    , MACVector "key"   v1      "\xde\x7c\x9b\x85\xb8\xb7\x8a\xa6\xbc\x8a\x7a\x36\xf7\x0a\x90\x70\x1c\x9d\xb4\xd9"
+    ]
+
+sha256MACVectors =
+    [ MACVector B.empty B.empty "\xb6\x13\x67\x9a\x08\x14\xd9\xec\x77\x2f\x95\xd7\x78\xc3\x5f\xc5\xff\x16\x97\xc4\x93\x71\x56\x53\xc6\xc7\x12\x14\x42\x92\xc5\xad"
+    , MACVector "key"   v1      "\xf7\xbc\x83\xf4\x30\x53\x84\x24\xb1\x32\x98\xe6\xaa\x6f\xb1\x43\xef\x4d\x59\xa1\x49\x46\x17\x59\x97\x47\x9d\xbc\x2d\x1a\x3c\xd8"
+    ]
+
+macTests :: [TestTree]
+macTests =
+    [ testGroup "hmac-md5" $ map (toMACTest MD5) $ zip [0..] md5MACVectors
+    , testGroup "hmac-sha1" $ map (toMACTest SHA1) $ zip [0..] sha1MACVectors
+    , testGroup "hmac-sha256" $ map (toMACTest SHA256) $ zip [0..] sha256MACVectors
+    ]
+    where toMACTest hashAlg (i, macVector) =
+            testCase (show i) (macResult macVector @=? toBytes (hmacAlg hashAlg (macKey macVector) (macSecret macVector)))
+
+macIncrementalTests :: [TestTree]
+macIncrementalTests =
+    [ testGroup "hmac-md5" $ map (toMACTest MD5) $ zip [0..] md5MACVectors
+    , testGroup "hmac-sha1" $ map (toMACTest SHA1) $ zip [0..] sha1MACVectors
+    , testGroup "hmac-sha256" $ map (toMACTest SHA256) $ zip [0..] sha256MACVectors
+
+    , testProperty "hmac-md5" $ prop_inc0 MD5
+    , testProperty "hmac-md5" $ prop_inc1 MD5
+    , testProperty "hmac-sha1" $ prop_inc0 SHA1
+    , testProperty "hmac-sha1" $ prop_inc1 SHA1
+    , testProperty "hmac-sha256" $ prop_inc0 SHA256
+    , testProperty "hmac-sha256" $ prop_inc1 SHA256
+    ]
+    where toMACTest hashAlg (i, macVector) =
+            testCase (show i) (macResult macVector @=? toBytes (hmacFinalize $ hmacUpdate initCtx (macSecret macVector)))
+              where initCtx = hmacInitAlg hashAlg (macKey macVector)
+
+          prop_inc0 :: HashAlgorithm a => a -> ByteString -> ByteString -> Bool
+          prop_inc0 hashAlg secret msg = hmacFinalize (hmacUpdate initCtx msg) == hmacAlg hashAlg secret msg
+              where initCtx = hmacInitAlg hashAlg secret
+
+          prop_inc1 :: HashAlgorithm a => a -> ByteString -> [ByteString] -> Bool
+          prop_inc1 hashAlg secret msgs = hmacFinalize (foldl' hmacUpdate initCtx msgs) == hmacAlg hashAlg secret (mconcat msgs)
+              where initCtx = hmacInitAlg hashAlg secret
+
+main = defaultMain $ testGroup "cryptohash"
+    [ testGroup "KATs" katTests
+    , testGroup "API" apiTests
+    , testGroup "MACs" macTests
+    , testGroup "Incremental MACs" macIncrementalTests
+    ]
diff --git a/cbits/bitfn.h b/cbits/bitfn.h
--- a/cbits/bitfn.h
+++ b/cbits/bitfn.h
@@ -161,7 +161,7 @@
 #ifdef __MINGW32__
   # define LITTLE_ENDIAN 1234
   # define BYTE_ORDER    LITTLE_ENDIAN
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
   # include <sys/endian.h>
 #elif defined(__OpenBSD__) || defined(__SVR4)
   # include <sys/types.h>
@@ -169,6 +169,14 @@
   # include <machine/endian.h>
 #elif defined( BSD ) && ( BSD >= 199103 )
   # include <machine/endian.h>
+#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ )
+  # define LITTLE_ENDIAN 1234
+  # define BYTE_ORDER    LITTLE_ENDIAN
+#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ )
+  # define BIG_ENDIAN 1234
+  # define BYTE_ORDER    BIG_ENDIAN
+#elif defined( _AIX )
+  # include <sys/machine.h>
 #else
   # include <endian.h>
 #endif
diff --git a/cbits/md2.c b/cbits/md2.c
deleted file mode 100644
--- a/cbits/md2.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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/md2.h b/cbits/md2.h
deleted file mode 100644
--- a/cbits/md2.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-#ifndef CRYPTOHASH_MD2_H
-#define CRYPTOHASH_MD2_H
-
-#include <stdint.h>
-
-struct md2_ctx
-{
-	uint64_t sz;
-	uint8_t  buf[16];
-	uint8_t  h[16];
-	uint8_t  cksum[16];
-};
-
-#define MD2_DIGEST_SIZE		16
-#define MD2_CTX_SIZE		sizeof(struct md2_ctx)
-
-void md2_init(struct md2_ctx *ctx);
-void md2_update(struct md2_ctx *ctx, uint8_t *data, uint32_t len);
-void md2_finalize(struct md2_ctx *ctx, uint8_t *out);
-
-#endif
diff --git a/cbits/md4.c b/cbits/md4.c
deleted file mode 100644
--- a/cbits/md4.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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/md4.h b/cbits/md4.h
deleted file mode 100644
--- a/cbits/md4.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-#ifndef CRYPTOHASH_MD4_H
-#define CRYPTOHASH_MD4_H
-
-#include <stdint.h>
-
-struct md4_ctx
-{
-	uint64_t sz;
-	uint8_t  buf[64];
-	uint32_t h[4];
-};
-
-#define MD4_DIGEST_SIZE		16
-#define MD4_CTX_SIZE		sizeof(struct md4_ctx)
-
-void md4_init(struct md4_ctx *ctx);
-void md4_update(struct md4_ctx *ctx, uint8_t *data, uint32_t len);
-void md4_finalize(struct md4_ctx *ctx, uint8_t *out);
-
-#endif
diff --git a/cbits/md5.c b/cbits/md5.c
deleted file mode 100644
--- a/cbits/md5.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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/md5.h b/cbits/md5.h
deleted file mode 100644
--- a/cbits/md5.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-#ifndef CRYPTOHASH_MD5_H
-#define CRYPTOHASH_MD5_H
-
-#include <stdint.h>
-
-struct md5_ctx
-{
-	uint64_t sz;
-	uint8_t  buf[64];
-	uint32_t h[4];
-};
-
-#define MD5_DIGEST_SIZE		16
-#define MD5_CTX_SIZE		sizeof(struct md5_ctx)
-
-void md5_init(struct md5_ctx *ctx);
-void md5_update(struct md5_ctx *ctx, uint8_t *data, uint32_t len);
-void md5_finalize(struct md5_ctx *ctx, uint8_t *out);
-
-#endif
diff --git a/cbits/ripemd.c b/cbits/ripemd.c
deleted file mode 100644
--- a/cbits/ripemd.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * 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/ripemd.h b/cbits/ripemd.h
deleted file mode 100644
--- a/cbits/ripemd.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-#ifndef CRYPTOHASH_RIPEMD_H
-#define CRYPTOHASH_RIPEMD_H
-
-#include <stdint.h>
-
-struct ripemd160_ctx
-{
-	uint64_t sz;
-	uint8_t  buf[64];
-	uint32_t h[5];
-};
-
-#define RIPEMD160_DIGEST_SIZE	20
-#define RIPEMD160_CTX_SIZE	sizeof(struct ripemd160_ctx)
-
-void ripemd160_init(struct ripemd160_ctx *ctx);
-void ripemd160_update(struct ripemd160_ctx *ctx, uint8_t *data, uint32_t len);
-void ripemd160_finalize(struct ripemd160_ctx *ctx, uint8_t *out);
-
-#endif
diff --git a/cbits/sha1.c b/cbits/sha1.c
deleted file mode 100644
--- a/cbits/sha1.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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)
-
-#define M(i)  (w[i & 0x0f] = rol32(w[i & 0x0f] ^ w[(i - 14) & 0x0f] \
-              ^ w[(i - 8) & 0x0f] ^ w[(i - 3) & 0x0f], 1))
-
-static inline void sha1_do_chunk(struct sha1_ctx *ctx, uint32_t *buf)
-{
-	uint32_t a, b, c, d, e;
-	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
-
-	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/sha1.h b/cbits/sha1.h
deleted file mode 100644
--- a/cbits/sha1.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-#ifndef CRYPTOHASH_SHA1_H
-#define CRYPTOHASH_SHA1_H
-
-#include <stdint.h>
-
-struct sha1_ctx
-{
-	uint64_t sz;
-	uint8_t  buf[64];
-	uint32_t h[5];
-};
-
-#define SHA1_DIGEST_SIZE	20
-#define SHA1_CTX_SIZE 		(sizeof(struct sha1_ctx))
-
-void sha1_init(struct sha1_ctx *ctx);
-void sha1_update(struct sha1_ctx *ctx, uint8_t *data, uint32_t len);
-void sha1_finalize(struct sha1_ctx *ctx, uint8_t *out);
-
-#endif
diff --git a/cbits/sha256.c b/cbits/sha256.c
deleted file mode 100644
--- a/cbits/sha256.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * 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/sha256.h b/cbits/sha256.h
deleted file mode 100644
--- a/cbits/sha256.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef CRYPTOHASH_SHA256_H
-#define CRYPTOHASH_SHA256_H
-
-#include <stdint.h>
-
-struct sha256_ctx
-{
-	uint64_t sz;
-	uint8_t  buf[128];
-	uint32_t h[8];
-};
-
-#define sha224_ctx 		sha256_ctx
-
-#define SHA224_DIGEST_SIZE	28
-#define SHA224_CTX_SIZE		sizeof(struct sha224_ctx)
-
-#define SHA256_DIGEST_SIZE	32
-#define SHA256_CTX_SIZE		sizeof(struct sha256_ctx)
-
-void sha224_init(struct sha224_ctx *ctx);
-void sha224_update(struct sha224_ctx *ctx, uint8_t *data, uint32_t len);
-void sha224_finalize(struct sha224_ctx *ctx, uint8_t *out);
-
-void sha256_init(struct sha256_ctx *ctx);
-void sha256_update(struct sha256_ctx *ctx, uint8_t *data, uint32_t len);
-void sha256_finalize(struct sha256_ctx *ctx, uint8_t *out);
-
-#endif
diff --git a/cbits/sha3.c b/cbits/sha3.c
new file mode 100644
--- /dev/null
+++ b/cbits/sha3.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 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 <stdint.h>
+#include <string.h>
+#include "bitfn.h"
+#include "sha3.h"
+
+#define KECCAK_NB_ROUNDS 24
+
+/* rounds constants */
+static const uint64_t keccak_rndc[24] =
+{
+	0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
+	0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
+	0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
+	0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
+	0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
+	0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
+	0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
+	0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL,
+};
+
+/* triangular numbers constants */
+static const int keccak_rotc[24] =
+	{ 1,3,6,10,15,21,28,36,45,55,2,14,27,41,56,8,25,43,62,18,39,61,20,44 };
+
+static const int keccak_piln[24] =
+	{ 10,7,11,17,18,3,5,16,8,21,24,4,15,23,19,13,12,2,20,14,22,9,6,1 };
+
+static inline void sha3_do_chunk(uint64_t state[25], uint64_t buf[], int bufsz)
+{
+	int i, j, r;
+	uint64_t tmp, bc[5];
+
+	/* merge buf with state */
+	for (i = 0; i < bufsz; i++)
+		state[i] ^= le64_to_cpu(buf[i]);
+
+	/* run keccak rounds */
+	for (r = 0; r < KECCAK_NB_ROUNDS; r++) {
+		/* compute the parity of each columns */
+		for (i = 0; i < 5; i++)
+			bc[i] = state[i] ^ state[i+5] ^ state[i+10] ^ state[i+15] ^ state[i+20];
+
+		for (i = 0; i < 5; i++) {
+			tmp = bc[(i + 4) % 5] ^ rol64(bc[(i + 1) % 5], 1);
+			for (j = 0; j < 25; j += 5)
+				state[j + i] ^= tmp;
+		}
+
+		/* rho pi */
+		tmp = state[1];
+		for (i = 0; i < 24; i++) {
+			j = keccak_piln[i];
+			bc[0] = state[j];
+			state[j] = rol64(tmp, keccak_rotc[i]);
+			tmp = bc[0];
+		}
+
+		/* bitwise combine along rows using a = a xor (not b and c) */
+		for (j = 0; j < 25; j += 5) {
+			for (i = 0; i < 5; i++)
+				bc[i] = state[j + i];
+			#define andn(b,c) (~(b) & (c))
+			state[j + 0] ^= andn(bc[1], bc[2]);
+			state[j + 1] ^= andn(bc[2], bc[3]);
+			state[j + 2] ^= andn(bc[3], bc[4]);
+			state[j + 3] ^= andn(bc[4], bc[0]);
+			state[j + 4] ^= andn(bc[0], bc[1]);
+			#undef andn
+		}
+
+		/* xor the round constant */
+		state[0] ^= keccak_rndc[r];
+	}
+}
+
+void cryptohash_sha3_init(struct sha3_ctx *ctx, uint32_t hashlen)
+{
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->hashlen = hashlen / 8;
+	ctx->bufsz = 200 - 2 * ctx->hashlen;
+}
+
+void cryptohash_sha3_update(struct sha3_ctx *ctx, uint8_t *data, uint32_t len)
+{
+	uint32_t to_fill;
+
+	to_fill = ctx->bufsz - ctx->bufindex;
+
+	if (ctx->bufindex == ctx->bufsz) {
+		sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);
+		ctx->bufindex = 0;
+	}
+
+	/* process partial buffer if there's enough data to make a block */
+	if (ctx->bufindex && len >= to_fill) {
+		memcpy(ctx->buf + ctx->bufindex, data, to_fill);
+		sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);
+		len -= to_fill;
+		data += to_fill;
+		ctx->bufindex = 0;
+	}
+
+	/* process as much ctx->bufsz-block */
+	for (; len >= ctx->bufsz; len -= ctx->bufsz, data += ctx->bufsz)
+		sha3_do_chunk(ctx->state, (uint64_t *) data, ctx->bufsz / 8);
+
+	/* append data into buf */
+	if (len) {
+		memcpy(ctx->buf + ctx->bufindex, data, len);
+		ctx->bufindex += len;
+	}
+}
+
+void cryptohash_sha3_finalize(struct sha3_ctx *ctx, uint8_t *out)
+{
+	uint64_t w[25];
+
+	/* process full buffer if needed */
+	if (ctx->bufindex == ctx->bufsz) {
+		sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);
+		ctx->bufindex = 0;
+	}
+
+	/* add the 10*1 padding */
+	ctx->buf[ctx->bufindex++] = 1;
+	memset(ctx->buf + ctx->bufindex, 0, ctx->bufsz - ctx->bufindex);
+	ctx->buf[ctx->bufsz - 1] |= 0x80;
+
+	/* process */
+	sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);
+
+	/* output */
+	cpu_to_le64_array(w, ctx->state, 25);
+	memcpy(out, w, ctx->hashlen);
+}
diff --git a/cbits/sha3.h b/cbits/sha3.h
new file mode 100644
--- /dev/null
+++ b/cbits/sha3.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+#ifndef CRYPTOHASH_SHA3_H
+#define CRYPTOHASH_SHA3_H
+
+#include <stdint.h>
+
+struct sha3_ctx
+{
+	uint32_t hashlen; /* in bytes */
+	uint32_t bufindex;
+	uint64_t state[25];
+	uint32_t bufsz;
+	uint32_t _padding;
+	uint8_t  buf[144]; /* minimum SHA3-224, otherwise buffer need increases */
+};
+
+#define SHA3_CTX_SIZE		sizeof(struct sha3_ctx)
+
+void cryptohash_sha3_init(struct sha3_ctx *ctx, uint32_t hashlen);
+void cryptohash_sha3_update(struct sha3_ctx *ctx, uint8_t *data, uint32_t len);
+void cryptohash_sha3_finalize(struct sha3_ctx *ctx, uint8_t *out);
+
+#endif
diff --git a/cbits/sha512.c b/cbits/sha512.c
--- a/cbits/sha512.c
+++ b/cbits/sha512.c
@@ -26,7 +26,7 @@
 #include "bitfn.h"
 #include "sha512.h"
 
-void sha384_init(struct sha512_ctx *ctx)
+void cryptohash_sha384_init(struct sha512_ctx *ctx)
 {
 	memset(ctx, 0, sizeof(*ctx));
 
@@ -40,7 +40,7 @@
 	ctx->h[7] = 0x47b5481dbefa4fa4ULL;
 }
 
-void sha512_init(struct sha512_ctx *ctx)
+void cryptohash_sha512_init(struct sha512_ctx *ctx)
 {
 	memset(ctx, 0, sizeof(*ctx));
 
@@ -127,12 +127,12 @@
 	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)
+void cryptohash_sha384_update(struct sha384_ctx *ctx, uint8_t *data, uint32_t len)
 {
-	return sha512_update(ctx, data, len);
+	return cryptohash_sha512_update(ctx, data, len);
 }
 
-void sha512_update(struct sha512_ctx *ctx, uint8_t *data, uint32_t len)
+void cryptohash_sha512_update(struct sha512_ctx *ctx, uint8_t *data, uint32_t len)
 {
 	unsigned int index, to_fill;
 
@@ -162,15 +162,15 @@
 		memcpy(ctx->buf + index, data, len);
 }
 
-void sha384_finalize(struct sha384_ctx *ctx, uint8_t *out)
+void cryptohash_sha384_finalize(struct sha384_ctx *ctx, uint8_t *out)
 {
 	uint8_t intermediate[SHA512_DIGEST_SIZE];
 
-	sha512_finalize(ctx, intermediate);
+	cryptohash_sha512_finalize(ctx, intermediate);
 	memcpy(out, intermediate, SHA384_DIGEST_SIZE);
 }
 
-void sha512_finalize(struct sha512_ctx *ctx, uint8_t *out)
+void cryptohash_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out)
 {
 	static uint8_t padding[128] = { 0x80, };
 	uint32_t i, index, padlen;
@@ -184,10 +184,10 @@
 	/* pad out to 56 */
 	index = (unsigned int) (ctx->sz[0] & 0x7f);
 	padlen = (index < 112) ? (112 - index) : ((128 + 112) - index);
-	sha512_update(ctx, padding, padlen);
+	cryptohash_sha512_update(ctx, padding, padlen);
 
 	/* append length */
-	sha512_update(ctx, (uint8_t *) bits, sizeof(bits));
+	cryptohash_sha512_update(ctx, (uint8_t *) bits, sizeof(bits));
 
 	/* store to digest */
 	for (i = 0; i < 8; i++)
@@ -196,7 +196,7 @@
 
 #include <stdio.h>
 
-void sha512_init_t(struct sha512_ctx *ctx, int t)
+void cryptohash_sha512_init_t(struct sha512_ctx *ctx, int t)
 {
 	memset(ctx, 0, sizeof(*ctx));
 	if (t >= 512)
@@ -228,13 +228,13 @@
 		uint8_t out[64];
 		int i;
 
-		sha512_init(ctx);
+		cryptohash_sha512_init(ctx);
 		for (i = 0; i < 8; i++)
 			ctx->h[i] ^= 0xa5a5a5a5a5a5a5a5ULL;
 
 		i = sprintf(buf, "SHA-512/%d", t);
-		sha512_update(ctx, buf, i);
-		sha512_finalize(ctx, out);
+		cryptohash_sha512_update(ctx, (uint8_t *) buf, i);
+		cryptohash_sha512_finalize(ctx, out);
 
 		/* re-init the context, otherwise len is changed */
 		memset(ctx, 0, sizeof(*ctx));
diff --git a/cbits/sha512.h b/cbits/sha512.h
--- a/cbits/sha512.h
+++ b/cbits/sha512.h
@@ -35,20 +35,20 @@
 
 #define sha384_ctx sha512_ctx
 
-#define SHA384_DIGEST_SIZE	64
+#define SHA384_DIGEST_SIZE	48
 #define SHA384_CTX_SIZE		sizeof(struct sha384_ctx)
 
 #define SHA512_DIGEST_SIZE	64
 #define SHA512_CTX_SIZE		sizeof(struct sha512_ctx)
 
-void sha384_init(struct sha384_ctx *ctx);
-void sha384_update(struct sha384_ctx *ctx, uint8_t *data, uint32_t len);
-void sha384_finalize(struct sha384_ctx *ctx, uint8_t *out);
+void cryptohash_sha384_init(struct sha384_ctx *ctx);
+void cryptohash_sha384_update(struct sha384_ctx *ctx, uint8_t *data, uint32_t len);
+void cryptohash_sha384_finalize(struct sha384_ctx *ctx, uint8_t *out);
 
-void sha512_init(struct sha512_ctx *ctx);
-void sha512_update(struct sha512_ctx *ctx, uint8_t *data, uint32_t len);
-void sha512_finalize(struct sha512_ctx *ctx, uint8_t *out);
+void cryptohash_sha512_init(struct sha512_ctx *ctx);
+void cryptohash_sha512_update(struct sha512_ctx *ctx, uint8_t *data, uint32_t len);
+void cryptohash_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out);
 
-void sha512_init_t(struct sha512_ctx *ctx, int t);
+void cryptohash_sha512_init_t(struct sha512_ctx *ctx, int t);
 
 #endif
diff --git a/cbits/skein256.c b/cbits/skein256.c
--- a/cbits/skein256.c
+++ b/cbits/skein256.c
@@ -42,7 +42,7 @@
 	uint64_t ts[3];
 	uint64_t ks[4+1];
 
-	ks[4] = 0x5555555555555555ULL;
+	ks[4] = 0x1bd11bdaa9fc1a22ULL;
 	ks[0] = ctx->h[0]; ks[4] ^= ctx->h[0];
 	ks[1] = ctx->h[1]; ks[4] ^= ctx->h[1];
 	ks[2] = ctx->h[2]; ks[4] ^= ctx->h[2];
@@ -103,12 +103,12 @@
         ctx->h[3] = x[3] ^ cpu_to_le64(buf[3]);
 }
 
-void skein256_init(struct skein256_ctx *ctx, uint32_t hashlen)
+void cryptohash_skein256_init(struct skein256_ctx *ctx, uint32_t hashlen)
 {
 	uint64_t buf[4];
 	memset(ctx, 0, sizeof(*ctx));
 
-	ctx->hashlen = hashlen;
+	ctx->hashlen = (hashlen + 7) >> 3;
 	SET_TYPE(ctx, FLAG_FIRST | FLAG_FINAL | FLAG_TYPE(TYPE_CFG));
 	
 	memset(buf, '\0', sizeof(buf));
@@ -120,10 +120,13 @@
 	SET_TYPE(ctx, FLAG_FIRST | FLAG_TYPE(TYPE_MSG));
 }
 
-void skein256_update(struct skein256_ctx *ctx, uint8_t *data, uint32_t len)
+void cryptohash_skein256_update(struct skein256_ctx *ctx, uint8_t *data, uint32_t len)
 {
 	uint32_t to_fill;
 
+	if (!len)
+		return;
+
 	to_fill = 32 - ctx->bufindex;
 
 	if (ctx->bufindex == 32) {
@@ -131,8 +134,9 @@
 		ctx->bufindex = 0;
 	}
 
-	/* process partial buffer if there's enough data to make a block */
-	if (ctx->bufindex && len >= to_fill) {
+	/* process partial buffer if there's enough data to make a block
+	 * and there's without doubt further blocks */
+	if (ctx->bufindex && len > to_fill) {
 		memcpy(ctx->buf + ctx->bufindex, data, to_fill);
 		skein256_do_chunk(ctx, (uint64_t *) ctx->buf, 32);
 		len -= to_fill;
@@ -151,7 +155,7 @@
 	}
 }
 
-void skein256_finalize(struct skein256_ctx *ctx, uint8_t *out)
+void cryptohash_skein256_finalize(struct skein256_ctx *ctx, uint8_t *out)
 {
 	uint32_t outsize;
 	uint64_t *p = (uint64_t *) out;
@@ -167,13 +171,14 @@
 	memset(ctx->buf, '\0', 32);
 
 	/* make sure we have a 8 bit rounded value */
-	outsize = (ctx->hashlen + 7) >> 3;
+	outsize = ctx->hashlen;
 
 	/* backup h[0--4] */
 	for (j = 0; j < 4; j++)
 		x[j] = ctx->h[j];
 	/* threefish in counter mode, 0 for 1st 64 bytes, 1 for 2nd 64 bytes, .. */
 	for (i = 0; i*32 < outsize; i++) {
+		uint64_t w[4];
 		*((uint64_t *) ctx->buf) = cpu_to_le64(i);
 		SET_TYPE(ctx, FLAG_FIRST | FLAG_FINAL | FLAG_TYPE(TYPE_OUT));
 		skein256_do_chunk(ctx, (uint64_t *) ctx->buf, sizeof(uint64_t));
@@ -181,8 +186,8 @@
 		n = outsize - i * 32;
 		if (n >= 32) n = 32;
 
-		/* FIXME should be little endian array copy ? */
-		memcpy(out + i*32, ctx->h, n);
+		cpu_to_le64_array(w, ctx->h, 4);
+		memcpy(out + i*32, w, n);
 
 		/* restore h[0--4] */
 		for (j = 0; j < 4; j++)
diff --git a/cbits/skein256.h b/cbits/skein256.h
--- a/cbits/skein256.h
+++ b/cbits/skein256.h
@@ -38,8 +38,8 @@
 
 #define SKEIN256_CTX_SIZE		sizeof(struct skein256_ctx)
 
-void skein256_init(struct skein256_ctx *ctx, uint32_t hashlen);
-void skein256_update(struct skein256_ctx *ctx, uint8_t *data, uint32_t len);
-void skein256_finalize(struct skein256_ctx *ctx, uint8_t *out);
+void cryptohash_skein256_init(struct skein256_ctx *ctx, uint32_t hashlen);
+void cryptohash_skein256_update(struct skein256_ctx *ctx, uint8_t *data, uint32_t len);
+void cryptohash_skein256_finalize(struct skein256_ctx *ctx, uint8_t *out);
 
 #endif
diff --git a/cbits/skein512.c b/cbits/skein512.c
--- a/cbits/skein512.c
+++ b/cbits/skein512.c
@@ -42,7 +42,7 @@
 	uint64_t ts[3];
 	uint64_t ks[8+1];
 
-	ks[8] = 0x5555555555555555ULL;
+	ks[8] = 0x1bd11bdaa9fc1a22ULL;
 	ks[0] = ctx->h[0]; ks[8] ^= ctx->h[0];
 	ks[1] = ctx->h[1]; ks[8] ^= ctx->h[1];
 	ks[2] = ctx->h[2]; ks[8] ^= ctx->h[2];
@@ -121,12 +121,12 @@
         ctx->h[7] = x[7] ^ cpu_to_le64(buf[7]);
 }
 
-void skein512_init(struct skein512_ctx *ctx, uint32_t hashlen)
+void cryptohash_skein512_init(struct skein512_ctx *ctx, uint32_t hashlen)
 {
 	uint64_t buf[8];
 	memset(ctx, 0, sizeof(*ctx));
 
-	ctx->hashlen = hashlen;
+	ctx->hashlen = (hashlen + 7) >> 3;
 	SET_TYPE(ctx, FLAG_FIRST | FLAG_FINAL | FLAG_TYPE(TYPE_CFG));
 	
 	memset(buf, '\0', sizeof(buf));
@@ -138,10 +138,13 @@
 	SET_TYPE(ctx, FLAG_FIRST | FLAG_TYPE(TYPE_MSG));
 }
 
-void skein512_update(struct skein512_ctx *ctx, uint8_t *data, uint32_t len)
+void cryptohash_skein512_update(struct skein512_ctx *ctx, uint8_t *data, uint32_t len)
 {
 	uint32_t to_fill;
 
+	if (!len)
+		return;
+
 	to_fill = 64 - ctx->bufindex;
 
 	if (ctx->bufindex == 64) {
@@ -149,8 +152,9 @@
 		ctx->bufindex = 0;
 	}
 
-	/* process partial buffer if there's enough data to make a block */
-	if (ctx->bufindex && len >= to_fill) {
+	/* process partial buffer if there's enough data to make a block
+	 * and there's without doubt further blocks */
+	if (ctx->bufindex && len > to_fill) {
 		memcpy(ctx->buf + ctx->bufindex, data, to_fill);
 		skein512_do_chunk(ctx, (uint64_t *) ctx->buf, 64);
 		len -= to_fill;
@@ -169,7 +173,7 @@
 	}
 }
 
-void skein512_finalize(struct skein512_ctx *ctx, uint8_t *out)
+void cryptohash_skein512_finalize(struct skein512_ctx *ctx, uint8_t *out)
 {
 	uint32_t outsize;
 	uint64_t *p = (uint64_t *) out;
@@ -185,13 +189,14 @@
 	memset(ctx->buf, '\0', 64);
 
 	/* make sure we have a 8 bit rounded value */
-	outsize = (ctx->hashlen + 7) >> 3;
+	outsize = ctx->hashlen;
 
 	/* backup h[0--7] */
 	for (j = 0; j < 8; j++)
 		x[j] = ctx->h[j];
 	/* threefish in counter mode, 0 for 1st 64 bytes, 1 for 2nd 64 bytes, .. */
 	for (i = 0; i*64 < outsize; i++) {
+		uint64_t w[8];
 		*((uint64_t *) ctx->buf) = cpu_to_le64(i);
 		SET_TYPE(ctx, FLAG_FIRST | FLAG_FINAL | FLAG_TYPE(TYPE_OUT));
 		skein512_do_chunk(ctx, (uint64_t *) ctx->buf, sizeof(uint64_t));
@@ -199,8 +204,8 @@
 		n = outsize - i * 64;
 		if (n >= 64) n = 64;
 
-		/* FIXME should be little endian array copy ? */
-		memcpy(out + i*64, ctx->h, n);
+		cpu_to_le64_array(w, ctx->h, 8);
+		memcpy(out + i*64, w, n);
 
 		/* restore h[0--7] */
 		for (j = 0; j < 8; j++)
diff --git a/cbits/skein512.h b/cbits/skein512.h
--- a/cbits/skein512.h
+++ b/cbits/skein512.h
@@ -28,7 +28,7 @@
 
 struct skein512_ctx
 {
-	uint32_t hashlen; /* in bits, typically 384, 512 */
+	uint32_t hashlen; /* in bytes, typically 384/8, 512/8 */
 	uint32_t bufindex;
 	uint8_t  buf[64];
 	uint64_t h[8];
@@ -38,8 +38,8 @@
 
 #define SKEIN512_CTX_SIZE		sizeof(struct skein512_ctx)
 
-void skein512_init(struct skein512_ctx *ctx, uint32_t hashlen);
-void skein512_update(struct skein512_ctx *ctx, uint8_t *data, uint32_t len);
-void skein512_finalize(struct skein512_ctx *ctx, uint8_t *out);
+void cryptohash_skein512_init(struct skein512_ctx *ctx, uint32_t hashlen);
+void cryptohash_skein512_update(struct skein512_ctx *ctx, uint8_t *data, uint32_t len);
+void cryptohash_skein512_finalize(struct skein512_ctx *ctx, uint8_t *out);
 
 #endif
diff --git a/cbits/tiger.c b/cbits/tiger.c
deleted file mode 100644
--- a/cbits/tiger.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * 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 "tiger.h"
-#include "bitfn.h"
-
-static const uint64_t t1[256] = {
-	0x02aab17cf7e90c5eULL,0xac424b03e243a8ecULL,0x72cd5be30dd5fcd3ULL,0x6d019b93f6f97f3aULL,
-	0xcd9978ffd21f9193ULL,0x7573a1c9708029e2ULL,0xb164326b922a83c3ULL,0x46883eee04915870ULL,
-	0xeaace3057103ece6ULL,0xc54169b808a3535cULL,0x4ce754918ddec47cULL,0x0aa2f4dfdc0df40cULL,
-	0x10b76f18a74dbefaULL,0xc6ccb6235ad1ab6aULL,0x13726121572fe2ffULL,0x1a488c6f199d921eULL,
-	0x4bc9f9f4da0007caULL,0x26f5e6f6e85241c7ULL,0x859079dbea5947b6ULL,0x4f1885c5c99e8c92ULL,
-	0xd78e761ea96f864bULL,0x8e36428c52b5c17dULL,0x69cf6827373063c1ULL,0xb607c93d9bb4c56eULL,
-	0x7d820e760e76b5eaULL,0x645c9cc6f07fdc42ULL,0xbf38a078243342e0ULL,0x5f6b343c9d2e7d04ULL,
-	0xf2c28aeb600b0ec6ULL,0x6c0ed85f7254bcacULL,0x71592281a4db4fe5ULL,0x1967fa69ce0fed9fULL,
-	0xfd5293f8b96545dbULL,0xc879e9d7f2a7600bULL,0x860248920193194eULL,0xa4f9533b2d9cc0b3ULL,
-	0x9053836c15957613ULL,0xdb6dcf8afc357bf1ULL,0x18beea7a7a370f57ULL,0x037117ca50b99066ULL,
-	0x6ab30a9774424a35ULL,0xf4e92f02e325249bULL,0x7739db07061ccae1ULL,0xd8f3b49ceca42a05ULL,
-	0xbd56be3f51382f73ULL,0x45faed5843b0bb28ULL,0x1c813d5c11bf1f83ULL,0x8af0e4b6d75fa169ULL,
-	0x33ee18a487ad9999ULL,0x3c26e8eab1c94410ULL,0xb510102bc0a822f9ULL,0x141eef310ce6123bULL,
-	0xfc65b90059ddb154ULL,0xe0158640c5e0e607ULL,0x884e079826c3a3cfULL,0x930d0d9523c535fdULL,
-	0x35638d754e9a2b00ULL,0x4085fccf40469dd5ULL,0xc4b17ad28be23a4cULL,0xcab2f0fc6a3e6a2eULL,
-	0x2860971a6b943fcdULL,0x3dde6ee212e30446ULL,0x6222f32ae01765aeULL,0x5d550bb5478308feULL,
-	0xa9efa98da0eda22aULL,0xc351a71686c40da7ULL,0x1105586d9c867c84ULL,0xdcffee85fda22853ULL,
-	0xccfbd0262c5eef76ULL,0xbaf294cb8990d201ULL,0xe69464f52afad975ULL,0x94b013afdf133e14ULL,
-	0x06a7d1a32823c958ULL,0x6f95fe5130f61119ULL,0xd92ab34e462c06c0ULL,0xed7bde33887c71d2ULL,
-	0x79746d6e6518393eULL,0x5ba419385d713329ULL,0x7c1ba6b948a97564ULL,0x31987c197bfdac67ULL,
-	0xde6c23c44b053d02ULL,0x581c49fed002d64dULL,0xdd474d6338261571ULL,0xaa4546c3e473d062ULL,
-	0x928fce349455f860ULL,0x48161bbacaab94d9ULL,0x63912430770e6f68ULL,0x6ec8a5e602c6641cULL,
-	0x87282515337ddd2bULL,0x2cda6b42034b701bULL,0xb03d37c181cb096dULL,0xe108438266c71c6fULL,
-	0x2b3180c7eb51b255ULL,0xdf92b82f96c08bbcULL,0x5c68c8c0a632f3baULL,0x5504cc861c3d0556ULL,
-	0xabbfa4e55fb26b8fULL,0x41848b0ab3baceb4ULL,0xb334a273aa445d32ULL,0xbca696f0a85ad881ULL,
-	0x24f6ec65b528d56cULL,0x0ce1512e90f4524aULL,0x4e9dd79d5506d35aULL,0x258905fac6ce9779ULL,
-	0x2019295b3e109b33ULL,0xf8a9478b73a054ccULL,0x2924f2f934417eb0ULL,0x3993357d536d1bc4ULL,
-	0x38a81ac21db6ff8bULL,0x47c4fbf17d6016bfULL,0x1e0faadd7667e3f5ULL,0x7abcff62938beb96ULL,
-	0xa78dad948fc179c9ULL,0x8f1f98b72911e50dULL,0x61e48eae27121a91ULL,0x4d62f7ad31859808ULL,
-	0xeceba345ef5ceaebULL,0xf5ceb25ebc9684ceULL,0xf633e20cb7f76221ULL,0xa32cdf06ab8293e4ULL,
-	0x985a202ca5ee2ca4ULL,0xcf0b8447cc8a8fb1ULL,0x9f765244979859a3ULL,0xa8d516b1a1240017ULL,
-	0x0bd7ba3ebb5dc726ULL,0xe54bca55b86adb39ULL,0x1d7a3afd6c478063ULL,0x519ec608e7669eddULL,
-	0x0e5715a2d149aa23ULL,0x177d4571848ff194ULL,0xeeb55f3241014c22ULL,0x0f5e5ca13a6e2ec2ULL,
-	0x8029927b75f5c361ULL,0xad139fabc3d6e436ULL,0x0d5df1a94ccf402fULL,0x3e8bd948bea5dfc8ULL,
-	0xa5a0d357bd3ff77eULL,0xa2d12e251f74f645ULL,0x66fd9e525e81a082ULL,0x2e0c90ce7f687a49ULL,
-	0xc2e8bcbeba973bc5ULL,0x000001bce509745fULL,0x423777bbe6dab3d6ULL,0xd1661c7eaef06eb5ULL,
-	0xa1781f354daacfd8ULL,0x2d11284a2b16affcULL,0xf1fc4f67fa891d1fULL,0x73ecc25dcb920adaULL,
-	0xae610c22c2a12651ULL,0x96e0a810d356b78aULL,0x5a9a381f2fe7870fULL,0xd5ad62ede94e5530ULL,
-	0xd225e5e8368d1427ULL,0x65977b70c7af4631ULL,0x99f889b2de39d74fULL,0x233f30bf54e1d143ULL,
-	0x9a9675d3d9a63c97ULL,0x5470554ff334f9a8ULL,0x166acb744a4f5688ULL,0x70c74caab2e4aeadULL,
-	0xf0d091646f294d12ULL,0x57b82a89684031d1ULL,0xefd95a5a61be0b6bULL,0x2fbd12e969f2f29aULL,
-	0x9bd37013feff9fe8ULL,0x3f9b0404d6085a06ULL,0x4940c1f3166cfe15ULL,0x09542c4dcdf3defbULL,
-	0xb4c5218385cd5ce3ULL,0xc935b7dc4462a641ULL,0x3417f8a68ed3b63fULL,0xb80959295b215b40ULL,
-	0xf99cdaef3b8c8572ULL,0x018c0614f8fcb95dULL,0x1b14accd1a3acdf3ULL,0x84d471f200bb732dULL,
-	0xc1a3110e95e8da16ULL,0x430a7220bf1a82b8ULL,0xb77e090d39df210eULL,0x5ef4bd9f3cd05e9dULL,
-	0x9d4ff6da7e57a444ULL,0xda1d60e183d4a5f8ULL,0xb287c38417998e47ULL,0xfe3edc121bb31886ULL,
-	0xc7fe3ccc980ccbefULL,0xe46fb590189bfd03ULL,0x3732fd469a4c57dcULL,0x7ef700a07cf1ad65ULL,
-	0x59c64468a31d8859ULL,0x762fb0b4d45b61f6ULL,0x155baed099047718ULL,0x68755e4c3d50baa6ULL,
-	0xe9214e7f22d8b4dfULL,0x2addbf532eac95f4ULL,0x32ae3909b4bd0109ULL,0x834df537b08e3450ULL,
-	0xfa209da84220728dULL,0x9e691d9b9efe23f7ULL,0x0446d288c4ae8d7fULL,0x7b4cc524e169785bULL,
-	0x21d87f0135ca1385ULL,0xcebb400f137b8aa5ULL,0x272e2b66580796beULL,0x3612264125c2b0deULL,
-	0x057702bdad1efbb2ULL,0xd4babb8eacf84be9ULL,0x91583139641bc67bULL,0x8bdc2de08036e024ULL,
-	0x603c8156f49f68edULL,0xf7d236f7dbef5111ULL,0x9727c4598ad21e80ULL,0xa08a0896670a5fd7ULL,
-	0xcb4a8f4309eba9cbULL,0x81af564b0f7036a1ULL,0xc0b99aa778199abdULL,0x959f1ec83fc8e952ULL,
-	0x8c505077794a81b9ULL,0x3acaaf8f056338f0ULL,0x07b43f50627a6778ULL,0x4a44ab49f5eccc77ULL,
-	0x3bc3d6e4b679ee98ULL,0x9cc0d4d1cf14108cULL,0x4406c00b206bc8a0ULL,0x82a18854c8d72d89ULL,
-	0x67e366b35c3c432cULL,0xb923dd61102b37f2ULL,0x56ab2779d884271dULL,0xbe83e1b0ff1525afULL,
-	0xfb7c65d4217e49a9ULL,0x6bdbe0e76d48e7d4ULL,0x08df828745d9179eULL,0x22ea6a9add53bd34ULL,
-	0xe36e141c5622200aULL,0x7f805d1b8cb750eeULL,0xafe5c7a59f58e837ULL,0xe27f996a4fb1c23cULL,
-	0xd3867dfb0775f0d0ULL,0xd0e673de6e88891aULL,0x123aeb9eafb86c25ULL,0x30f1d5d5c145b895ULL,
-	0xbb434a2dee7269e7ULL,0x78cb67ecf931fa38ULL,0xf33b0372323bbf9cULL,0x52d66336fb279c74ULL,
-	0x505f33ac0afb4eaaULL,0xe8a5cd99a2cce187ULL,0x534974801e2d30bbULL,0x8d2d5711d5876d90ULL,
-	0x1f1a412891bc038eULL,0xd6e2e71d82e56648ULL,0x74036c3a497732b7ULL,0x89b67ed96361f5abULL,
-	0xffed95d8f1ea02a2ULL,0xe72b3bd61464d43dULL,0xa6300f170bdc4820ULL,0xebc18760ed78a77aULL,
-};
-
-static const uint64_t t2[256] =
-{
-	0xe6a6be5a05a12138ULL,0xb5a122a5b4f87c98ULL,0x563c6089140b6990ULL,0x4c46cb2e391f5dd5ULL,
-	0xd932addbc9b79434ULL,0x08ea70e42015aff5ULL,0xd765a6673e478cf1ULL,0xc4fb757eab278d99ULL,
-	0xdf11c6862d6e0692ULL,0xddeb84f10d7f3b16ULL,0x6f2ef604a665ea04ULL,0x4a8e0f0ff0e0dfb3ULL,
-	0xa5edeef83dbcba51ULL,0xfc4f0a2a0ea4371eULL,0xe83e1da85cb38429ULL,0xdc8ff882ba1b1ce2ULL,
-	0xcd45505e8353e80dULL,0x18d19a00d4db0717ULL,0x34a0cfeda5f38101ULL,0x0be77e518887caf2ULL,
-	0x1e341438b3c45136ULL,0xe05797f49089ccf9ULL,0xffd23f9df2591d14ULL,0x543dda228595c5cdULL,
-	0x661f81fd99052a33ULL,0x8736e641db0f7b76ULL,0x15227725418e5307ULL,0xe25f7f46162eb2faULL,
-	0x48a8b2126c13d9feULL,0xafdc541792e76eeaULL,0x03d912bfc6d1898fULL,0x31b1aafa1b83f51bULL,
-	0xf1ac2796e42ab7d9ULL,0x40a3a7d7fcd2ebacULL,0x1056136d0afbbcc5ULL,0x7889e1dd9a6d0c85ULL,
-	0xd33525782a7974aaULL,0xa7e25d09078ac09bULL,0xbd4138b3eac6edd0ULL,0x920abfbe71eb9e70ULL,
-	0xa2a5d0f54fc2625cULL,0xc054e36b0b1290a3ULL,0xf6dd59ff62fe932bULL,0x3537354511a8ac7dULL,
-	0xca845e9172fadcd4ULL,0x84f82b60329d20dcULL,0x79c62ce1cd672f18ULL,0x8b09a2add124642cULL,
-	0xd0c1e96a19d9e726ULL,0x5a786a9b4ba9500cULL,0x0e020336634c43f3ULL,0xc17b474aeb66d822ULL,
-	0x6a731ae3ec9baac2ULL,0x8226667ae0840258ULL,0x67d4567691caeca5ULL,0x1d94155c4875adb5ULL,
-	0x6d00fd985b813fdfULL,0x51286efcb774cd06ULL,0x5e8834471fa744afULL,0xf72ca0aee761ae2eULL,
-	0xbe40e4cdaee8e09aULL,0xe9970bbb5118f665ULL,0x726e4beb33df1964ULL,0x703b000729199762ULL,
-	0x4631d816f5ef30a7ULL,0xb880b5b51504a6beULL,0x641793c37ed84b6cULL,0x7b21ed77f6e97d96ULL,
-	0x776306312ef96b73ULL,0xae528948e86ff3f4ULL,0x53dbd7f286a3f8f8ULL,0x16cadce74cfc1063ULL,
-	0x005c19bdfa52c6ddULL,0x68868f5d64d46ad3ULL,0x3a9d512ccf1e186aULL,0x367e62c2385660aeULL,
-	0xe359e7ea77dcb1d7ULL,0x526c0773749abe6eULL,0x735ae5f9d09f734bULL,0x493fc7cc8a558ba8ULL,
-	0xb0b9c1533041ab45ULL,0x321958ba470a59bdULL,0x852db00b5f46c393ULL,0x91209b2bd336b0e5ULL,
-	0x6e604f7d659ef19fULL,0xb99a8ae2782ccb24ULL,0xccf52ab6c814c4c7ULL,0x4727d9afbe11727bULL,
-	0x7e950d0c0121b34dULL,0x756f435670ad471fULL,0xf5add442615a6849ULL,0x4e87e09980b9957aULL,
-	0x2acfa1df50aee355ULL,0xd898263afd2fd556ULL,0xc8f4924dd80c8fd6ULL,0xcf99ca3d754a173aULL,
-	0xfe477bacaf91bf3cULL,0xed5371f6d690c12dULL,0x831a5c285e687094ULL,0xc5d3c90a3708a0a4ULL,
-	0x0f7f903717d06580ULL,0x19f9bb13b8fdf27fULL,0xb1bd6f1b4d502843ULL,0x1c761ba38fff4012ULL,
-	0x0d1530c4e2e21f3bULL,0x8943ce69a7372c8aULL,0xe5184e11feb5ce66ULL,0x618bdb80bd736621ULL,
-	0x7d29bad68b574d0bULL,0x81bb613e25e6fe5bULL,0x071c9c10bc07913fULL,0xc7beeb7909ac2d97ULL,
-	0xc3e58d353bc5d757ULL,0xeb017892f38f61e8ULL,0xd4effb9c9b1cc21aULL,0x99727d26f494f7abULL,
-	0xa3e063a2956b3e03ULL,0x9d4a8b9a4aa09c30ULL,0x3f6ab7d500090fb4ULL,0x9cc0f2a057268ac0ULL,
-	0x3dee9d2dedbf42d1ULL,0x330f49c87960a972ULL,0xc6b2720287421b41ULL,0x0ac59ec07c00369cULL,
-	0xef4eac49cb353425ULL,0xf450244eef0129d8ULL,0x8acc46e5caf4deb6ULL,0x2ffeab63989263f7ULL,
-	0x8f7cb9fe5d7a4578ULL,0x5bd8f7644e634635ULL,0x427a7315bf2dc900ULL,0x17d0c4aa2125261cULL,
-	0x3992486c93518e50ULL,0xb4cbfee0a2d7d4c3ULL,0x7c75d6202c5ddd8dULL,0xdbc295d8e35b6c61ULL,
-	0x60b369d302032b19ULL,0xce42685fdce44132ULL,0x06f3ddb9ddf65610ULL,0x8ea4d21db5e148f0ULL,
-	0x20b0fce62fcd496fULL,0x2c1b912358b0ee31ULL,0xb28317b818f5a308ULL,0xa89c1e189ca6d2cfULL,
-	0x0c6b18576aaadbc8ULL,0xb65deaa91299fae3ULL,0xfb2b794b7f1027e7ULL,0x04e4317f443b5bebULL,
-	0x4b852d325939d0a6ULL,0xd5ae6beefb207ffcULL,0x309682b281c7d374ULL,0xbae309a194c3b475ULL,
-	0x8cc3f97b13b49f05ULL,0x98a9422ff8293967ULL,0x244b16b01076ff7cULL,0xf8bf571c663d67eeULL,
-	0x1f0d6758eee30da1ULL,0xc9b611d97adeb9b7ULL,0xb7afd5887b6c57a2ULL,0x6290ae846b984fe1ULL,
-	0x94df4cdeacc1a5fdULL,0x058a5bd1c5483affULL,0x63166cc142ba3c37ULL,0x8db8526eb2f76f40ULL,
-	0xe10880036f0d6d4eULL,0x9e0523c9971d311dULL,0x45ec2824cc7cd691ULL,0x575b8359e62382c9ULL,
-	0xfa9e400dc4889995ULL,0xd1823ecb45721568ULL,0xdafd983b8206082fULL,0xaa7d29082386a8cbULL,
-	0x269fcd4403b87588ULL,0x1b91f5f728bdd1e0ULL,0xe4669f39040201f6ULL,0x7a1d7c218cf04adeULL,
-	0x65623c29d79ce5ceULL,0x2368449096c00bb1ULL,0xab9bf1879da503baULL,0xbc23ecb1a458058eULL,
-	0x9a58df01bb401eccULL,0xa070e868a85f143dULL,0x4ff188307df2239eULL,0x14d565b41a641183ULL,
-	0xee13337452701602ULL,0x950e3dcf3f285e09ULL,0x59930254b9c80953ULL,0x3bf299408930da6dULL,
-	0xa955943f53691387ULL,0xa15edecaa9cb8784ULL,0x29142127352be9a0ULL,0x76f0371fff4e7afbULL,
-	0x0239f450274f2228ULL,0xbb073af01d5e868bULL,0xbfc80571c10e96c1ULL,0xd267088568222e23ULL,
-	0x9671a3d48e80b5b0ULL,0x55b5d38ae193bb81ULL,0x693ae2d0a18b04b8ULL,0x5c48b4ecadd5335fULL,
-	0xfd743b194916a1caULL,0x2577018134be98c4ULL,0xe77987e83c54a4adULL,0x28e11014da33e1b9ULL,
-	0x270cc59e226aa213ULL,0x71495f756d1a5f60ULL,0x9be853fb60afef77ULL,0xadc786a7f7443dbfULL,
-	0x0904456173b29a82ULL,0x58bc7a66c232bd5eULL,0xf306558c673ac8b2ULL,0x41f639c6b6c9772aULL,
-	0x216defe99fda35daULL,0x11640cc71c7be615ULL,0x93c43694565c5527ULL,0xea038e6246777839ULL,
-	0xf9abf3ce5a3e2469ULL,0x741e768d0fd312d2ULL,0x0144b883ced652c6ULL,0xc20b5a5ba33f8552ULL,
-	0x1ae69633c3435a9dULL,0x97a28ca4088cfdecULL,0x8824a43c1e96f420ULL,0x37612fa66eeea746ULL,
-	0x6b4cb165f9cf0e5aULL,0x43aa1c06a0abfb4aULL,0x7f4dc26ff162796bULL,0x6cbacc8e54ed9b0fULL,
-	0xa6b7ffefd2bb253eULL,0x2e25bc95b0a29d4fULL,0x86d6a58bdef1388cULL,0xded74ac576b6f054ULL,
-	0x8030bdbc2b45805dULL,0x3c81af70e94d9289ULL,0x3eff6dda9e3100dbULL,0xb38dc39fdfcc8847ULL,
-	0x123885528d17b87eULL,0xf2da0ed240b1b642ULL,0x44cefadcd54bf9a9ULL,0x1312200e433c7ee6ULL,
-	0x9ffcc84f3a78c748ULL,0xf0cd1f72248576bbULL,0xec6974053638cfe4ULL,0x2ba7b67c0cec4e4cULL,
-	0xac2f4df3e5ce32edULL,0xcb33d14326ea4c11ULL,0xa4e9044cc77e58bcULL,0x5f513293d934fcefULL,
-	0x5dc9645506e55444ULL,0x50de418f317de40aULL,0x388cb31a69dde259ULL,0x2db4a83455820a86ULL,
-	0x9010a91e84711ae9ULL,0x4df7f0b7b1498371ULL,0xd62a2eabc0977179ULL,0x22fac097aa8d5c0eULL,
-}; 
-
-static const uint64_t t3[256]= {
-	0xf49fcc2ff1daf39bULL,0x487fd5c66ff29281ULL,0xe8a30667fcdca83fULL,0x2c9b4be3d2fcce63ULL,
-	0xda3ff74b93fbbbc2ULL,0x2fa165d2fe70ba66ULL,0xa103e279970e93d4ULL,0xbecdec77b0e45e71ULL,
-	0xcfb41e723985e497ULL,0xb70aaa025ef75017ULL,0xd42309f03840b8e0ULL,0x8efc1ad035898579ULL,
-	0x96c6920be2b2abc5ULL,0x66af4163375a9172ULL,0x2174abdcca7127fbULL,0xb33ccea64a72ff41ULL,
-	0xf04a4933083066a5ULL,0x8d970acdd7289af5ULL,0x8f96e8e031c8c25eULL,0xf3fec02276875d47ULL,
-	0xec7bf310056190ddULL,0xf5adb0aebb0f1491ULL,0x9b50f8850fd58892ULL,0x4975488358b74de8ULL,
-	0xa3354ff691531c61ULL,0x0702bbe481d2c6eeULL,0x89fb24057deded98ULL,0xac3075138596e902ULL,
-	0x1d2d3580172772edULL,0xeb738fc28e6bc30dULL,0x5854ef8f63044326ULL,0x9e5c52325add3bbeULL,
-	0x90aa53cf325c4623ULL,0xc1d24d51349dd067ULL,0x2051cfeea69ea624ULL,0x13220f0a862e7e4fULL,
-	0xce39399404e04864ULL,0xd9c42ca47086fcb7ULL,0x685ad2238a03e7ccULL,0x066484b2ab2ff1dbULL,
-	0xfe9d5d70efbf79ecULL,0x5b13b9dd9c481854ULL,0x15f0d475ed1509adULL,0x0bebcd060ec79851ULL,
-	0xd58c6791183ab7f8ULL,0xd1187c5052f3eee4ULL,0xc95d1192e54e82ffULL,0x86eea14cb9ac6ca2ULL,
-	0x3485beb153677d5dULL,0xdd191d781f8c492aULL,0xf60866baa784ebf9ULL,0x518f643ba2d08c74ULL,
-	0x8852e956e1087c22ULL,0xa768cb8dc410ae8dULL,0x38047726bfec8e1aULL,0xa67738b4cd3b45aaULL,
-	0xad16691cec0dde19ULL,0xc6d4319380462e07ULL,0xc5a5876d0ba61938ULL,0x16b9fa1fa58fd840ULL,
-	0x188ab1173ca74f18ULL,0xabda2f98c99c021fULL,0x3e0580ab134ae816ULL,0x5f3b05b773645abbULL,
-	0x2501a2be5575f2f6ULL,0x1b2f74004e7e8ba9ULL,0x1cd7580371e8d953ULL,0x7f6ed89562764e30ULL,
-	0xb15926ff596f003dULL,0x9f65293da8c5d6b9ULL,0x6ecef04dd690f84cULL,0x4782275fff33af88ULL,
-	0xe41433083f820801ULL,0xfd0dfe409a1af9b5ULL,0x4325a3342cdb396bULL,0x8ae77e62b301b252ULL,
-	0xc36f9e9f6655615aULL,0x85455a2d92d32c09ULL,0xf2c7dea949477485ULL,0x63cfb4c133a39ebaULL,
-	0x83b040cc6ebc5462ULL,0x3b9454c8fdb326b0ULL,0x56f56a9e87ffd78cULL,0x2dc2940d99f42bc6ULL,
-	0x98f7df096b096e2dULL,0x19a6e01e3ad852bfULL,0x42a99ccbdbd4b40bULL,0xa59998af45e9c559ULL,
-	0x366295e807d93186ULL,0x6b48181bfaa1f773ULL,0x1fec57e2157a0a1dULL,0x4667446af6201ad5ULL,
-	0xe615ebcacfb0f075ULL,0xb8f31f4f68290778ULL,0x22713ed6ce22d11eULL,0x3057c1a72ec3c93bULL,
-	0xcb46acc37c3f1f2fULL,0xdbb893fd02aaf50eULL,0x331fd92e600b9fcfULL,0xa498f96148ea3ad6ULL,
-	0xa8d8426e8b6a83eaULL,0xa089b274b7735cdcULL,0x87f6b3731e524a11ULL,0x118808e5cbc96749ULL,
-	0x9906e4c7b19bd394ULL,0xafed7f7e9b24a20cULL,0x6509eadeeb3644a7ULL,0x6c1ef1d3e8ef0edeULL,
-	0xb9c97d43e9798fb4ULL,0xa2f2d784740c28a3ULL,0x7b8496476197566fULL,0x7a5be3e6b65f069dULL,
-	0xf96330ed78be6f10ULL,0xeee60de77a076a15ULL,0x2b4bee4aa08b9bd0ULL,0x6a56a63ec7b8894eULL,
-	0x02121359ba34fef4ULL,0x4cbf99f8283703fcULL,0x398071350caf30c8ULL,0xd0a77a89f017687aULL,
-	0xf1c1a9eb9e423569ULL,0x8c7976282dee8199ULL,0x5d1737a5dd1f7abdULL,0x4f53433c09a9fa80ULL,
-	0xfa8b0c53df7ca1d9ULL,0x3fd9dcbc886ccb77ULL,0xc040917ca91b4720ULL,0x7dd00142f9d1dcdfULL,
-	0x8476fc1d4f387b58ULL,0x23f8e7c5f3316503ULL,0x032a2244e7e37339ULL,0x5c87a5d750f5a74bULL,
-	0x082b4cc43698992eULL,0xdf917becb858f63cULL,0x3270b8fc5bf86ddaULL,0x10ae72bb29b5dd76ULL,
-	0x576ac94e7700362bULL,0x1ad112dac61efb8fULL,0x691bc30ec5faa427ULL,0xff246311cc327143ULL,
-	0x3142368e30e53206ULL,0x71380e31e02ca396ULL,0x958d5c960aad76f1ULL,0xf8d6f430c16da536ULL,
-	0xc8ffd13f1be7e1d2ULL,0x7578ae66004ddbe1ULL,0x05833f01067be646ULL,0xbb34b5ad3bfe586dULL,
-	0x095f34c9a12b97f0ULL,0x247ab64525d60ca8ULL,0xdcdbc6f3017477d1ULL,0x4a2e14d4decad24dULL,
-	0xbdb5e6d9be0a1eebULL,0x2a7e70f7794301abULL,0xdef42d8a270540fdULL,0x01078ec0a34c22c1ULL,
-	0xe5de511af4c16387ULL,0x7ebb3a52bd9a330aULL,0x77697857aa7d6435ULL,0x004e831603ae4c32ULL,
-	0xe7a21020ad78e312ULL,0x9d41a70c6ab420f2ULL,0x28e06c18ea1141e6ULL,0xd2b28cbd984f6b28ULL,
-	0x26b75f6c446e9d83ULL,0xba47568c4d418d7fULL,0xd80badbfe6183d8eULL,0x0e206d7f5f166044ULL,
-	0xe258a43911cbca3eULL,0x723a1746b21dc0bcULL,0xc7caa854f5d7cdd3ULL,0x7cac32883d261d9cULL,
-	0x7690c26423ba942cULL,0x17e55524478042b8ULL,0xe0be477656a2389fULL,0x4d289b5e67ab2da0ULL,
-	0x44862b9c8fbbfd31ULL,0xb47cc8049d141365ULL,0x822c1b362b91c793ULL,0x4eb14655fb13dfd8ULL,
-	0x1ecbba0714e2a97bULL,0x6143459d5cde5f14ULL,0x53a8fbf1d5f0ac89ULL,0x97ea04d81c5e5b00ULL,
-	0x622181a8d4fdb3f3ULL,0xe9bcd341572a1208ULL,0x1411258643cce58aULL,0x9144c5fea4c6e0a4ULL,
-	0x0d33d06565cf620fULL,0x54a48d489f219ca1ULL,0xc43e5eac6d63c821ULL,0xa9728b3a72770dafULL,
-	0xd7934e7b20df87efULL,0xe35503b61a3e86e5ULL,0xcae321fbc819d504ULL,0x129a50b3ac60bfa6ULL,
-	0xcd5e68ea7e9fb6c3ULL,0xb01c90199483b1c7ULL,0x3de93cd5c295376cULL,0xaed52edf2ab9ad13ULL,
-	0x2e60f512c0a07884ULL,0xbc3d86a3e36210c9ULL,0x35269d9b163951ceULL,0x0c7d6e2ad0cdb5faULL,
-	0x59e86297d87f5733ULL,0x298ef221898db0e7ULL,0x55000029d1a5aa7eULL,0x8bc08ae1b5061b45ULL,
-	0xc2c31c2b6c92703aULL,0x94cc596baf25ef42ULL,0x0a1d73db22540456ULL,0x04b6a0f9d9c4179aULL,
-	0xeffdafa2ae3d3c60ULL,0xf7c8075bb49496c4ULL,0x9cc5c7141d1cd4e3ULL,0x78bd1638218e5534ULL,
-	0xb2f11568f850246aULL,0xedfabcfa9502bc29ULL,0x796ce5f2da23051bULL,0xaae128b0dc93537cULL,
-	0x3a493da0ee4b29aeULL,0xb5df6b2c416895d7ULL,0xfcabbd25122d7f37ULL,0x70810b58105dc4b1ULL,
-	0xe10fdd37f7882a90ULL,0x524dcab5518a3f5cULL,0x3c9e85878451255bULL,0x4029828119bd34e2ULL,
-	0x74a05b6f5d3ceccbULL,0xb610021542e13ecaULL,0x0ff979d12f59e2acULL,0x6037da27e4f9cc50ULL,
-	0x5e92975a0df1847dULL,0xd66de190d3e623feULL,0x5032d6b87b568048ULL,0x9a36b7ce8235216eULL,
-	0x80272a7a24f64b4aULL,0x93efed8b8c6916f7ULL,0x37ddbff44cce1555ULL,0x4b95db5d4b99bd25ULL,
-	0x92d3fda169812fc0ULL,0xfb1a4a9a90660bb6ULL,0x730c196946a4b9b2ULL,0x81e289aa7f49da68ULL,
-	0x64669a0f83b1a05fULL,0x27b3ff7d9644f48bULL,0xcc6b615c8db675b3ULL,0x674f20b9bcebbe95ULL,
-	0x6f31238275655982ULL,0x5ae488713e45cf05ULL,0xbf619f9954c21157ULL,0xeabac46040a8eae9ULL,
-	0x454c6fe9f2c0c1cdULL,0x419cf6496412691cULL,0xd3dc3bef265b0f70ULL,0x6d0e60f5c3578a9eULL,
-};
-
-static const uint64_t t4[256]=
-{
-	0x5b0e608526323c55ULL,0x1a46c1a9fa1b59f5ULL, 0xa9e245a17c4c8ffaULL,0x65ca5159db2955d7ULL,
-	0x05db0a76ce35afc2ULL,0x81eac77ea9113d45ULL, 0x528ef88ab6ac0a0dULL,0xa09ea253597be3ffULL,
-	0x430ddfb3ac48cd56ULL,0xc4b3a67af45ce46fULL, 0x4ececfd8fbe2d05eULL,0x3ef56f10b39935f0ULL,
-	0x0b22d6829cd619c6ULL,0x17fd460a74df2069ULL, 0x6cf8cc8e8510ed40ULL,0xd6c824bf3a6ecaa7ULL,
-	0x61243d581a817049ULL,0x048bacb6bbc163a2ULL, 0xd9a38ac27d44cc32ULL,0x7fddff5baaf410abULL,
-	0xad6d495aa804824bULL,0xe1a6a74f2d8c9f94ULL, 0xd4f7851235dee8e3ULL,0xfd4b7f886540d893ULL,
-	0x247c20042aa4bfdaULL,0x096ea1c517d1327cULL, 0xd56966b4361a6685ULL,0x277da5c31221057dULL,
-	0x94d59893a43acff7ULL,0x64f0c51ccdc02281ULL, 0x3d33bcc4ff6189dbULL,0xe005cb184ce66af1ULL,
-	0xff5ccd1d1db99beaULL,0xb0b854a7fe42980fULL, 0x7bd46a6a718d4b9fULL,0xd10fa8cc22a5fd8cULL,
-	0xd31484952be4bd31ULL,0xc7fa975fcb243847ULL, 0x4886ed1e5846c407ULL,0x28cddb791eb70b04ULL,
-	0xc2b00be2f573417fULL,0x5c9590452180f877ULL, 0x7a6bddfff370eb00ULL,0xce509e38d6d9d6a4ULL,
-	0xebeb0f00647fa702ULL,0x1dcc06cf76606f06ULL, 0xe4d9f28ba286ff0aULL,0xd85a305dc918c262ULL,
-	0x475b1d8732225f54ULL,0x2d4fb51668ccb5feULL, 0xa679b9d9d72bba20ULL,0x53841c0d912d43a5ULL,
-	0x3b7eaa48bf12a4e8ULL,0x781e0e47f22f1ddfULL, 0xeff20ce60ab50973ULL,0x20d261d19dffb742ULL,
-	0x16a12b03062a2e39ULL,0x1960eb2239650495ULL, 0x251c16fed50eb8b8ULL,0x9ac0c330f826016eULL,
-	0xed152665953e7671ULL,0x02d63194a6369570ULL, 0x5074f08394b1c987ULL,0x70ba598c90b25ce1ULL,
-	0x794a15810b9742f6ULL,0x0d5925e9fcaf8c6cULL, 0x3067716cd868744eULL,0x910ab077e8d7731bULL,
-	0x6a61bbdb5ac42f61ULL,0x93513efbf0851567ULL, 0xf494724b9e83e9d5ULL,0xe887e1985c09648dULL,
-	0x34b1d3c675370cfdULL,0xdc35e433bc0d255dULL, 0xd0aab84234131be0ULL,0x08042a50b48b7eafULL,
-	0x9997c4ee44a3ab35ULL,0x829a7b49201799d0ULL, 0x263b8307b7c54441ULL,0x752f95f4fd6a6ca6ULL,
-	0x927217402c08c6e5ULL,0x2a8ab754a795d9eeULL, 0xa442f7552f72943dULL,0x2c31334e19781208ULL,
-	0x4fa98d7ceaee6291ULL,0x55c3862f665db309ULL, 0xbd0610175d53b1f3ULL,0x46fe6cb840413f27ULL,
-	0x3fe03792df0cfa59ULL,0xcfe700372eb85e8fULL, 0xa7be29e7adbce118ULL,0xe544ee5cde8431ddULL,
-	0x8a781b1b41f1873eULL,0xa5c94c78a0d2f0e7ULL, 0x39412e2877b60728ULL,0xa1265ef3afc9a62cULL,
-	0xbcc2770c6a2506c5ULL,0x3ab66dd5dce1ce12ULL, 0xe65499d04a675b37ULL,0x7d8f523481bfd216ULL,
-	0x0f6f64fcec15f389ULL,0x74efbe618b5b13c8ULL, 0xacdc82b714273e1dULL,0xdd40bfe003199d17ULL,
-	0x37e99257e7e061f8ULL,0xfa52626904775aaaULL, 0x8bbbf63a463d56f9ULL,0xf0013f1543a26e64ULL,
-	0xa8307e9f879ec898ULL,0xcc4c27a4150177ccULL, 0x1b432f2cca1d3348ULL,0xde1d1f8f9f6fa013ULL,
-	0x606602a047a7ddd6ULL,0xd237ab64cc1cb2c7ULL, 0x9b938e7225fcd1d3ULL,0xec4e03708e0ff476ULL,
-	0xfeb2fbda3d03c12dULL,0xae0bced2ee43889aULL, 0x22cb8923ebfb4f43ULL,0x69360d013cf7396dULL,
-	0x855e3602d2d4e022ULL,0x073805bad01f784cULL, 0x33e17a133852f546ULL,0xdf4874058ac7b638ULL,
-	0xba92b29c678aa14aULL,0x0ce89fc76cfaadcdULL, 0x5f9d4e0908339e34ULL,0xf1afe9291f5923b9ULL,
-	0x6e3480f60f4a265fULL,0xeebf3a2ab29b841cULL, 0xe21938a88f91b4adULL,0x57dfeff845c6d3c3ULL,
-	0x2f006b0bf62caaf2ULL,0x62f479ef6f75ee78ULL, 0x11a55ad41c8916a9ULL,0xf229d29084fed453ULL,
-	0x42f1c27b16b000e6ULL,0x2b1f76749823c074ULL, 0x4b76eca3c2745360ULL,0x8c98f463b91691bdULL,
-	0x14bcc93cf1ade66aULL,0x8885213e6d458397ULL, 0x8e177df0274d4711ULL,0xb49b73b5503f2951ULL,
-	0x10168168c3f96b6bULL,0x0e3d963b63cab0aeULL, 0x8dfc4b5655a1db14ULL,0xf789f1356e14de5cULL,
-	0x683e68af4e51dac1ULL,0xc9a84f9d8d4b0fd9ULL, 0x3691e03f52a0f9d1ULL,0x5ed86e46e1878e80ULL,
-	0x3c711a0e99d07150ULL,0x5a0865b20c4e9310ULL, 0x56fbfc1fe4f0682eULL,0xea8d5de3105edf9bULL,
-	0x71abfdb12379187aULL,0x2eb99de1bee77b9cULL, 0x21ecc0ea33cf4523ULL,0x59a4d7521805c7a1ULL,
-	0x3896f5eb56ae7c72ULL,0xaa638f3db18f75dcULL, 0x9f39358dabe9808eULL,0xb7defa91c00b72acULL,
-	0x6b5541fd62492d92ULL,0x6dc6dee8f92e4d5bULL, 0x353f57abc4beea7eULL,0x735769d6da5690ceULL,
-	0x0a234aa642391484ULL,0xf6f9508028f80d9dULL, 0xb8e319a27ab3f215ULL,0x31ad9c1151341a4dULL,
-	0x773c22a57bef5805ULL,0x45c7561a07968633ULL, 0xf913da9e249dbe36ULL,0xda652d9b78a64c68ULL,
-	0x4c27a97f3bc334efULL,0x76621220e66b17f4ULL, 0x967743899acd7d0bULL,0xf3ee5bcae0ed6782ULL,
-	0x409f753600c879fcULL,0x06d09a39b5926db6ULL, 0x6f83aeb0317ac588ULL,0x01e6ca4a86381f21ULL,
-	0x66ff3462d19f3025ULL,0x72207c24ddfd3bfbULL, 0x4af6b6d3e2ece2ebULL,0x9c994dbec7ea08deULL,
-	0x49ace597b09a8bc4ULL,0xb38c4766cf0797baULL, 0x131b9373c57c2a75ULL,0xb1822cce61931e58ULL,
-	0x9d7555b909ba1c0cULL,0x127fafdd937d11d2ULL, 0x29da3badc66d92e4ULL,0xa2c1d57154c2ecbcULL,
-	0x58c5134d82f6fe24ULL,0x1c3ae3515b62274fULL, 0xe907c82e01cb8126ULL,0xf8ed091913e37fcbULL,
-	0x3249d8f9c80046c9ULL,0x80cf9bede388fb63ULL, 0x1881539a116cf19eULL,0x5103f3f76bd52457ULL,
-	0x15b7e6f5ae47f7a8ULL,0xdbd7c6ded47e9ccfULL, 0x44e55c410228bb1aULL,0xb647d4255edb4e99ULL,
-	0x5d11882bb8aafc30ULL,0xf5098bbb29d3212aULL, 0x8fb5ea14e90296b3ULL,0x677b942157dd025aULL,
-	0xfb58e7c0a390acb5ULL,0x89d3674c83bd4a01ULL, 0x9e2da4df4bf3b93bULL,0xfcc41e328cab4829ULL,
-	0x03f38c96ba582c52ULL,0xcad1bdbd7fd85db2ULL, 0xbbb442c16082ae83ULL,0xb95fe86ba5da9ab0ULL,
-	0xb22e04673771a93fULL,0x845358c9493152d8ULL, 0xbe2a488697b4541eULL,0x95a2dc2dd38e6966ULL,
-	0xc02c11ac923c852bULL,0x2388b1990df2a87bULL, 0x7c8008fa1b4f37beULL,0x1f70d0c84d54e503ULL,
-	0x5490adec7ece57d4ULL,0x002b3c27d9063a3aULL, 0x7eaea3848030a2bfULL,0xc602326ded2003c0ULL,
-	0x83a7287d69a94086ULL,0xc57a5fcb30f57a8aULL, 0xb56844e479ebe779ULL,0xa373b40f05dcbce9ULL,
-	0xd71a786e88570ee2ULL,0x879cbacdbde8f6a0ULL, 0x976ad1bcc164a32fULL,0xab21e25e9666d78bULL,
-	0x901063aae5e5c33cULL,0x9818b34448698d90ULL, 0xe36487ae3e1e8abbULL,0xafbdf931893bdcb4ULL,
-	0x6345a0dc5fbbd519ULL,0x8628fe269b9465caULL, 0x1e5d01603f9c51ecULL,0x4de44006a15049b7ULL,
-	0xbf6c70e5f776cbb1ULL,0x411218f2ef552bedULL, 0xcb0c0708705a36a3ULL,0xe74d14754f986044ULL,
-	0xcd56d9430ea8280eULL,0xc12591d7535f5065ULL, 0xc83223f1720aef96ULL,0xc3a0396f7363a51fULL,
-}; 
-
-void tiger_init(struct tiger_ctx *ctx)
-{
-	memset(ctx, 0, sizeof(*ctx));
-
-	ctx->h[0] = 0x0123456789abcdefULL;
-	ctx->h[1] = 0xfedcba9876543210ULL;
-	ctx->h[2] = 0xf096a5b4c3b2e187ULL;
-}
-
-static inline void tiger_do_chunk(struct tiger_ctx *ctx, uint64_t *buf)
-{
-	uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
-	uint64_t a,b,c;
-	a = ctx->h[0];
-	b = ctx->h[1];
-	c = ctx->h[2];
-
-	x0 = cpu_to_le64(buf[0]); x1 = cpu_to_le64(buf[1]); x2 = cpu_to_le64(buf[2]); x3 = cpu_to_le64(buf[3]);
-	x4 = cpu_to_le64(buf[4]); x5 = cpu_to_le64(buf[5]); x6 = cpu_to_le64(buf[6]); x7 = cpu_to_le64(buf[7]);
-
-#define BYTEOF(c, n) ((uint8_t) (c >> ((n * 8))))
-
-#define ROUND(a,b,c,x,mul)                                                          \
-	c ^= x;                                                                     \
-	a -= t1[BYTEOF(c,0)] ^ t2[BYTEOF(c,2)] ^ t3[BYTEOF(c,4)] ^ t4[BYTEOF(c,6)]; \
-	b += t4[BYTEOF(c,1)] ^ t3[BYTEOF(c,3)] ^ t2[BYTEOF(c,5)] ^ t1[BYTEOF(c,7)]; \
-	b *= mul;
-
-#define PASS(a,b,c,mul)	     \
-	ROUND(a,b,c,x0,mul); \
-	ROUND(b,c,a,x1,mul); \
-	ROUND(c,a,b,x2,mul); \
-	ROUND(a,b,c,x3,mul); \
-	ROUND(b,c,a,x4,mul); \
-	ROUND(c,a,b,x5,mul); \
-	ROUND(a,b,c,x6,mul); \
-	ROUND(b,c,a,x7,mul)
-
-#define SCHEDULE()                        \
-	x0 -= x7 ^ 0xa5a5a5a5a5a5a5a5ULL; \
-	x1 ^= x0;                         \
-	x2 += x1;                         \
-	x3 -= x2 ^ ((~x1)<<19);           \
-	x4 ^= x3;                         \
-	x5 += x4;                         \
-	x6 -= x5 ^ ((~x4)>>23);           \
-	x7 ^= x6;                         \
-	x0 += x7;                         \
-	x1 -= x0 ^ ((~x7)<<19);           \
-	x2 ^= x1;                         \
-	x3 += x2;                         \
-	x4 -= x3 ^ ((~x2)>>23);           \
-	x5 ^= x4;                         \
-	x6 += x5;                         \
-	x7 -= x6 ^ 0x0123456789abcdefULL
-
-	PASS(a,b,c,5);
-	SCHEDULE();
-	PASS(c,a,b,7);
-	SCHEDULE();
-	PASS(b,c,a,9);
-
-	ctx->h[0] ^= a;
-	ctx->h[1] = b - ctx->h[1];
-	ctx->h[2] += c;
-}
-
-void tiger_update(struct tiger_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);
-		tiger_do_chunk(ctx, (uint64_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)
-		tiger_do_chunk(ctx, (uint64_t *) data);
-
-	/* append data into buf */
-	if (len)
-		memcpy(ctx->buf + index, data, len);
-}
-
-void tiger_finalize(struct tiger_ctx *ctx, uint8_t *out)
-{
-	static uint8_t padding[64] = { 0x01, };
-	uint64_t bits;
-	uint32_t index, padlen;
-	uint64_t *p = (uint64_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);
-	tiger_update(ctx, padding, padlen);
-
-	/* append length */
-	tiger_update(ctx, (uint8_t *) &bits, sizeof(bits));
-
-	/* output hash */
-	p[0] = cpu_to_le64(ctx->h[0]);
-	p[1] = cpu_to_le64(ctx->h[1]);
-	p[2] = cpu_to_le64(ctx->h[2]);
-}
diff --git a/cbits/tiger.h b/cbits/tiger.h
deleted file mode 100644
--- a/cbits/tiger.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-#ifndef CRYPTOHASH_TIGER_H
-#define CRYPTOHASH_TIGER_H
-
-#include <stdint.h>
-
-struct tiger_ctx
-{
-	uint64_t sz;
-	uint8_t  buf[64];
-	uint64_t h[3];
-};
-
-#define TIGER_DIGEST_SIZE	24
-#define TIGER_CTX_SIZE 		(sizeof(struct tiger_ctx))
-
-void tiger_init(struct tiger_ctx *ctx);
-void tiger_update(struct tiger_ctx *ctx, uint8_t *data, uint32_t len);
-void tiger_finalize(struct tiger_ctx *ctx, uint8_t *out);
-
-#endif
diff --git a/cryptohash.cabal b/cryptohash.cabal
--- a/cryptohash.cabal
+++ b/cryptohash.cabal
@@ -1,11 +1,36 @@
 Name:                cryptohash
-Version:             0.7.2
+Version:             0.11.9
 Description:
+    DEPRECATED: this library is still fully functional, but please use cryptonite for new projects
+    and convert old one to use cryptonite. This is where things are at nowadays.
+    .
     A collection of crypto hashes, with a practical incremental and one-pass, pure APIs,
-    with performance close to the fastest implementations available in others languages.
+    with performance close to the fastest implementations available in other languages.
     .
     The implementations are made in C with a haskell FFI wrapper that hide the C implementation.
-
+    .
+    Simple examples using the unified API:
+    .
+    > import Crypto.Hash
+    >
+    > sha1 :: ByteString -> Digest SHA1
+    > sha1 = hash
+    >
+    > hexSha3_512 :: ByteString -> String
+    > hexSha3_512 bs = show (hash bs :: Digest SHA3_512)
+    .
+    Simple examples using the module API:
+    .
+    > import qualified Crypto.Hash.SHA1 as SHA1
+    >
+    > main = putStrLn $ show $ SHA1.hash (Data.ByteString.pack [0..255])
+    .
+    > import qualified Crypto.Hash.SHA3 as SHA3
+    >
+    > main = putStrLn $ show $ digest
+    >   where digest = SHA3.finalize ctx
+    >         ctx    = foldl' SHA3.update iCtx (map Data.ByteString.pack [ [1,2,3], [4,5,6] ]
+    >         iCtx   = SHA3.init 224
 License:             BSD3
 License-file:        LICENSE
 Copyright:           Vincent Hanquez <vincent@snarc.org>
@@ -14,36 +39,29 @@
 Synopsis:            collection of crypto hashes, fast, pure and practical
 Category:            Data, Cryptography
 Build-Type:          Simple
-Cabal-Version:       >=1.6
+Cabal-Version:       >=1.8
 Homepage:            http://github.com/vincenthz/hs-cryptohash
-data-files:          README
 
 extra-source-files:
-  cbits/bitfn.h cbits/md2.h cbits/md4.h cbits/md5.h
-  cbits/ripemd.h cbits/sha1.h cbits/sha256.h cbits/sha512.h
+  cbits/bitfn.h cbits/sha512.h cbits/sha3.h
   cbits/skein.h cbits/skein256.h cbits/skein512.h
-  cbits/tiger.h
-
-Flag test
-  Description:       Build unit test
-  Default:           False
-
-Flag cryptoapi
-  Description:       Defines crypto-api instances
-  Default:           True
+  README.md
 
 Library
-  Build-Depends:     base >= 4 && < 6, bytestring
-  if flag(cryptoapi)
-    Build-depends:   crypto-api >= 0.5, tagged >= 0.1, cereal >= 0.2
-    cpp-options:     -DHAVE_CRYPTOAPI
+  Build-Depends:     base >= 4 && < 6, bytestring, byteable, cryptonite >= 0.13, memory, ghc-prim
+  if impl(ghc >= 7.2.1)
+    Extensions:      Trustworthy
   Extensions:        ForeignFunctionInterface
-  Exposed-modules:   Crypto.Hash.SHA1
+  Exposed-modules:   Crypto.Hash
+                     Crypto.Hash.Types
+                     Crypto.MAC
+                     Crypto.Hash.SHA1
                      Crypto.Hash.SHA224
                      Crypto.Hash.SHA256
                      Crypto.Hash.SHA384
                      Crypto.Hash.SHA512
                      Crypto.Hash.SHA512t
+                     Crypto.Hash.SHA3
                      Crypto.Hash.MD2
                      Crypto.Hash.MD4
                      Crypto.Hash.MD5
@@ -51,40 +69,50 @@
                      Crypto.Hash.Skein256
                      Crypto.Hash.Skein512
                      Crypto.Hash.Tiger
-  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
+                     Crypto.Hash.Whirlpool
+                     Crypto.MAC.HMAC
+                     Crypto.MAC.SHA3
+  Other-modules:     Crypto.Hash.Internal
+  ghc-options:       -Wall -optc-O3 -fno-cse -fwarn-tabs
+  C-sources:         cbits/sha512.c
+                     cbits/sha3.c
                      cbits/skein256.c
                      cbits/skein512.c
-                     cbits/tiger.c
   Include-Dirs:      cbits
+  if (arch(i386) || arch(x86_64))
+    cpp-options: -DARCH_X86
 
-Executable           Tests
-  Main-Is:           Tests.hs
-  Extensions:        ForeignFunctionInterface
-  C-sources:         cbits/sha1.c
-                     cbits/sha256.c
-                     cbits/sha512.c
-                     cbits/md2.c
-                     cbits/md4.c
-                     cbits/md5.c
-                     cbits/ripemd.c
-                     cbits/skein256.c
-                     cbits/skein512.c
-                     cbits/tiger.c
-  if flag(test)
-    Buildable:       True
-    Build-depends:   base >= 4, HUnit, bytestring
-  else
-    Buildable:       False
-  if flag(cryptoapi)
-    Build-depends:   crypto-api >= 0.5, tagged >= 0.1, cereal >= 0.2
-    cpp-options:     -DHAVE_CRYPTOAPI
+Test-Suite test-kat
+  type:              exitcode-stdio-1.0
+  hs-source-dirs:    Tests
+  Main-Is:           KAT.hs
+  Build-depends:     base >= 4 && < 5
+                   , bytestring
+                   , byteable
+                   , HUnit
+                   , QuickCheck >= 2
+                   , tasty
+                   , tasty-quickcheck
+                   , tasty-hunit
+                   , cryptohash
+
+Benchmark bench-hashes
+  Main-Is:           Bench.hs
+  hs-source-dirs:    Bench
+  type:              exitcode-stdio-1.0
+  Build-depends:     base >= 4, bytestring, criterion, cryptohash
+
+Benchmark bench-hmac
+  Main-Is:           BenchHMAC.hs
+  hs-source-dirs:    Bench
+  type:              exitcode-stdio-1.0
+  Build-depends:     base >= 4, bytestring, criterion, cryptohash, byteable
+
+Benchmark bench-api
+  Main-Is:           BenchAPI.hs
+  hs-source-dirs:    Bench
+  type:              exitcode-stdio-1.0
+  Build-depends:     base >= 4, bytestring, criterion, cryptohash, byteable
 
 source-repository head
   type:     git
