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,24 @@
+{-# LANGUAGE CPP #-}
+
+-- |
+-- Module      : Crypto.Hash.Internal
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+module Crypto.Hash.Internal where
+
+import System.IO.Unsafe
+
+-- | 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
+
diff --git a/Crypto/Hash/MD2.hs b/Crypto/Hash/MD2.hs
--- a/Crypto/Hash/MD2.hs
+++ b/Crypto/Hash/MD2.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_md2_init
+init = unsafeDoIO $ withCtxNew $ c_md2_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_md2_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_md2_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/MD4.hs b/Crypto/Hash/MD4.hs
--- a/Crypto/Hash/MD4.hs
+++ b/Crypto/Hash/MD4.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_md4_init
+init = unsafeDoIO $ withCtxNew $ c_md4_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_md4_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_md4_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/MD5.hs b/Crypto/Hash/MD5.hs
--- a/Crypto/Hash/MD5.hs
+++ b/Crypto/Hash/MD5.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_md5_init
+init = unsafeDoIO $ withCtxNew $ c_md5_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_md5_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_md5_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/RIPEMD160.hs b/Crypto/Hash/RIPEMD160.hs
--- a/Crypto/Hash/RIPEMD160.hs
+++ b/Crypto/Hash/RIPEMD160.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_ripemd160_init
+init = unsafeDoIO $ withCtxNew $ c_ripemd160_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_ripemd160_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_ripemd160_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/SHA1.hs b/Crypto/Hash/SHA1.hs
--- a/Crypto/Hash/SHA1.hs
+++ b/Crypto/Hash/SHA1.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_sha1_init
+init = unsafeDoIO $ withCtxNew $ c_sha1_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha1_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha1_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/SHA224.hs b/Crypto/Hash/SHA224.hs
--- a/Crypto/Hash/SHA224.hs
+++ b/Crypto/Hash/SHA224.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_sha224_init
+init = unsafeDoIO $ withCtxNew $ c_sha224_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha224_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha224_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/SHA256.hs b/Crypto/Hash/SHA256.hs
--- a/Crypto/Hash/SHA256.hs
+++ b/Crypto/Hash/SHA256.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_sha256_init
+init = unsafeDoIO $ withCtxNew $ c_sha256_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha256_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha256_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/SHA3.hs b/Crypto/Hash/SHA3.hs
--- a/Crypto/Hash/SHA3.hs
+++ b/Crypto/Hash/SHA3.hs
@@ -34,7 +34,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -129,31 +129,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Int -> Ctx
-init hashlen = unsafeDupablePerformIO $ withCtxNew $ \ptr -> c_sha3_init ptr (fromIntegral hashlen)
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: Int -> ByteString -> ByteString
-hash hashlen d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+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 = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+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
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_sha384_init
+init = unsafeDoIO $ withCtxNew $ c_sha384_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha384_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha384_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/SHA512.hs b/Crypto/Hash/SHA512.hs
--- a/Crypto/Hash/SHA512.hs
+++ b/Crypto/Hash/SHA512.hs
@@ -36,7 +36,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -125,7 +125,7 @@
 {-# NOINLINE init_t #-}
 -- | init a context using FIPS 180-4 for truncated SHA512
 init_t :: Int -> Ctx
-init_t t = unsafeDupablePerformIO $ withCtxNew $ \ptr -> c_sha512_init_t ptr t
+init_t t = unsafeDoIO $ withCtxNew $ \ptr -> c_sha512_init_t ptr t
 
 updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
 updateInternalIO ptr d =
@@ -137,31 +137,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_sha512_init
+init = unsafeDoIO $ withCtxNew $ c_sha512_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+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 = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_sha512_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/Skein256.hs b/Crypto/Hash/Skein256.hs
--- a/Crypto/Hash/Skein256.hs
+++ b/Crypto/Hash/Skein256.hs
@@ -34,7 +34,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -129,31 +129,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Int -> Ctx
-init hashlen = unsafeDupablePerformIO $ withCtxNew $ \ptr -> c_skein256_init ptr (fromIntegral hashlen)
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: Int -> ByteString -> ByteString
-hash hashlen d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+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 = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+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
@@ -34,7 +34,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -129,31 +129,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Int -> Ctx
-init hashlen = unsafeDupablePerformIO $ withCtxNew $ \ptr -> c_skein512_init ptr (fromIntegral hashlen)
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: Int -> ByteString -> ByteString
-hash hashlen d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+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 = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+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
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_tiger_init
+init = unsafeDoIO $ withCtxNew $ c_tiger_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_tiger_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_tiger_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/Crypto/Hash/Whirlpool.hs b/Crypto/Hash/Whirlpool.hs
--- a/Crypto/Hash/Whirlpool.hs
+++ b/Crypto/Hash/Whirlpool.hs
@@ -35,7 +35,7 @@
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
 import Data.ByteString.Internal (create, toForeignPtr)
 import Data.Word
-import System.IO.Unsafe (unsafeDupablePerformIO)
+import Crypto.Hash.Internal (unsafeDoIO)
 
 #ifdef HAVE_CRYPTOAPI
 
@@ -128,31 +128,31 @@
 {-# NOINLINE init #-}
 -- | init a context
 init :: Ctx
-init = unsafeDupablePerformIO $ withCtxNew $ c_whirlpool_init
+init = unsafeDoIO $ withCtxNew $ c_whirlpool_init
 
 {-# NOINLINE update #-}
 -- | update a context with a bytestring
 update :: Ctx -> ByteString -> Ctx
-update ctx d = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d
+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 = unsafeDupablePerformIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d
+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 = unsafeDupablePerformIO $ withCtxThrow ctx finalizeInternalIO
+finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
 
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring
 hash :: ByteString -> ByteString
-hash d = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_whirlpool_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring
 hashlazy :: L.ByteString -> ByteString
-hashlazy l = unsafeDupablePerformIO $ withCtxNewThrow $ \ptr -> do
+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_whirlpool_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
diff --git a/cryptohash.cabal b/cryptohash.cabal
--- a/cryptohash.cabal
+++ b/cryptohash.cabal
@@ -1,5 +1,5 @@
 Name:                cryptohash
-Version:             0.8.0
+Version:             0.8.1
 Description:
     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.
@@ -77,6 +77,7 @@
                      Crypto.Hash.Whirlpool
                      Crypto.MAC.HMAC
   Other-modules:     Crypto.Hash.Utils
+                     Crypto.Hash.Internal
   ghc-options:       -Wall -O2 -optc-O3 -fno-cse -fwarn-tabs
   C-sources:         cbits/sha1.c
                      cbits/sha256.c
