diff --git a/Data/SecureMem.hs b/Data/SecureMem.hs
new file mode 100644
--- /dev/null
+++ b/Data/SecureMem.hs
@@ -0,0 +1,190 @@
+-- |
+-- Module      : Data.SecureMem
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : Stable
+-- Portability : GHC
+--
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE MagicHash #-}
+module Data.SecureMem
+    ( SecureMem
+    , secureMemGetSize
+    , ToSecureMem(..)
+    -- * Allocation and early termination
+    , allocateSecureMem
+    , createSecureMem
+    , unsafeCreateSecureMem
+    , finalizeSecureMem
+    -- * Pointers manipulation
+    , withSecureMemPtr
+    , withSecureMemPtrSz
+    -- * convertion
+    , secureMemFromByteString
+    ) where
+
+import Foreign.C.Types
+import Foreign.ForeignPtr (withForeignPtr, finalizeForeignPtr)
+import Foreign.Ptr
+import GHC.Types (Int(..))
+import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents(..), mallocForeignPtrBytes, addForeignPtrConcFinalizer)
+import GHC.Prim (sizeofMutableByteArray#)
+import GHC.Ptr (Ptr(..))
+import Data.Word (Word8)
+import Data.Monoid
+import Control.Applicative ((<$>))
+import Data.ByteString (ByteString)
+import Data.Byteable
+import qualified Data.ByteString.Internal as B
+
+-- | SecureMem is a memory chunk which have the properties of:
+--
+-- * Being scrubbed after its goes out of scope.
+-- * A Show instance that doesn't actually show any content
+-- * A Eq instance that is constant time
+newtype SecureMem = SecureMem (ForeignPtr Word8)
+
+-- | Return the size of the memory allocated by this secure mem.
+secureMemGetSize :: SecureMem -> Int
+secureMemGetSize (SecureMem (ForeignPtr _ fpc)) =
+    case fpc of
+        MallocPtr mba _ -> I# (sizeofMutableByteArray# mba)
+        _               -> error "cannot happen"
+
+instance Show SecureMem where
+    show _ = "<secure-mem>"
+
+instance Byteable SecureMem where
+    toBytes = secureMemToByteString
+
+instance Eq SecureMem where
+    sm1 == sm2 = sz1 == sz2 && B.inlinePerformIO meq
+        where meq = withSecureMemPtr sm1 $ \ptr1 ->
+                    withSecureMemPtr sm2 $ \ptr2 ->
+                    feq ptr1 ptr2
+              !sz1 = secureMemGetSize sm1
+              !sz2 = secureMemGetSize sm2
+              feq | sz1 == 8   = compareEq8
+                  | sz1 == 16  = compareEq16
+                  | sz1 == 24  = compareEq24
+                  | sz1 == 32  = compareEq32
+                  | sz1 == 64  = compareEq64
+                  | sz1 == 128 = compareEq128
+                  | sz1 == 256 = compareEq256
+                  | otherwise  = compareEq (fromIntegral sz1)
+
+instance Monoid SecureMem where
+    mempty        = unsafeCreateSecureMem 0 (\_ -> return ())
+    mappend s1 s2 = unsafeCreateSecureMem (sz1+sz2) $ \dst -> do
+                        withSecureMemPtr s1 $ \sp1 -> B.memcpy dst sp1 (fromIntegral sz1)
+                        withSecureMemPtr s2 $ \sp2 -> B.memcpy (dst `plusPtr` sz1) sp2 (fromIntegral sz2)
+                    where 
+                          !sz1 = secureMemGetSize s1
+                          !sz2 = secureMemGetSize s2
+
+type Finalizer = Ptr Word8 -> IO ()
+type FinalizerWithSize = CInt -> Ptr Word8 -> IO ()
+
+-- | Types that can be converted to a secure mem object.
+class ToSecureMem a where
+    toSecureMem :: a -> SecureMem
+
+instance ToSecureMem SecureMem where
+    toSecureMem a = a
+instance ToSecureMem ByteString where
+    toSecureMem bs = secureMemFromByteString bs
+
+-- | Generic eq function
+foreign import ccall "compare_eq"    compareEq    :: CInt -> Ptr Word8 -> Ptr Word8 -> IO Bool
+
+-- | Specialized eq functions which are much faster
+foreign import ccall "compare_eq8"   compareEq8   :: Ptr Word8 -> Ptr Word8 -> IO Bool
+foreign import ccall "compare_eq16"  compareEq16  :: Ptr Word8 -> Ptr Word8 -> IO Bool
+foreign import ccall "compare_eq24"  compareEq24  :: Ptr Word8 -> Ptr Word8 -> IO Bool
+foreign import ccall "compare_eq32"  compareEq32  :: Ptr Word8 -> Ptr Word8 -> IO Bool
+foreign import ccall "compare_eq64"  compareEq64  :: Ptr Word8 -> Ptr Word8 -> IO Bool
+foreign import ccall "compare_eq128" compareEq128 :: Ptr Word8 -> Ptr Word8 -> IO Bool
+foreign import ccall "compare_eq256" compareEq256 :: Ptr Word8 -> Ptr Word8 -> IO Bool
+
+-- | Scruber finalizers
+foreign import ccall "finalizer_scrub8" finalizerScrub8     :: Finalizer
+foreign import ccall "finalizer_scrub16" finalizerScrub16   :: Finalizer
+foreign import ccall "finalizer_scrub24" finalizerScrub24   :: Finalizer
+foreign import ccall "finalizer_scrub32" finalizerScrub32   :: Finalizer
+foreign import ccall "finalizer_scrub64" finalizerScrub64   :: Finalizer
+foreign import ccall "finalizer_scrub128" finalizerScrub128 :: Finalizer
+foreign import ccall "finalizer_scrub256" finalizerScrub256 :: Finalizer
+foreign import ccall "finalizer_scrubvar" finalizerScrubVar :: FinalizerWithSize
+
+szToScruber :: Int -> Ptr Word8 -> IO ()
+szToScruber 0   = \_ -> return ()
+szToScruber 8   = finalizerScrub8
+szToScruber 16  = finalizerScrub16
+szToScruber 24  = finalizerScrub24
+szToScruber 32  = finalizerScrub32
+szToScruber 64  = finalizerScrub64
+szToScruber 128 = finalizerScrub128
+szToScruber 256 = finalizerScrub256
+szToScruber n   = finalizerScrubVar (fromIntegral n)
+
+-- | Allocate a foreign ptr which will be scrubed before memory free.
+-- the memory is allocated on the haskell heap
+allocateScrubedForeignPtr :: Int -> IO (ForeignPtr a)
+allocateScrubedForeignPtr sz = do
+    fptr@(ForeignPtr addr _) <- mallocForeignPtrBytes sz
+    addForeignPtrConcFinalizer fptr (scruber (Ptr addr))
+    return fptr
+    where !scruber = szToScruber sz
+
+-- | Allocate a new SecureMem
+--
+-- The memory is allocated on the haskell heap, and will be scrubed
+-- before being released.
+allocateSecureMem :: Int -> IO SecureMem
+allocateSecureMem sz = SecureMem <$> allocateScrubedForeignPtr sz
+
+-- | Create a new secure mem and running an initializer function
+createSecureMem :: Int -> (Ptr Word8 -> IO ()) -> IO SecureMem
+createSecureMem sz f = do
+    sm <- allocateSecureMem sz
+    withSecureMemPtr sm f
+    return sm
+
+-- | Create a new secure mem using inline perform IO to create a pure
+-- result.
+unsafeCreateSecureMem :: Int -> (Ptr Word8 -> IO ()) -> SecureMem
+unsafeCreateSecureMem sz f = B.inlinePerformIO (createSecureMem sz f)
+
+-- | This is a way to look at the pointer living inside a foreign object. This
+-- function takes a function which is applied to that pointer. The resulting IO
+-- action is then executed
+--
+-- this is similary to withForeignPtr for a ForeignPtr
+withSecureMemPtr :: SecureMem -> (Ptr Word8 -> IO b) -> IO b
+withSecureMemPtr (SecureMem fptr) f = withForeignPtr fptr f
+
+-- | similar to withSecureMem but also include the size of the pointed memory.
+withSecureMemPtrSz :: SecureMem -> (Int -> Ptr Word8 -> IO b) -> IO b
+withSecureMemPtrSz sm@(SecureMem fptr) f = withForeignPtr fptr (f (secureMemGetSize sm))
+
+-- | Finalize a SecureMem early
+finalizeSecureMem :: SecureMem -> IO ()
+finalizeSecureMem (SecureMem fptr) = finalizeForeignPtr fptr
+
+-- | Create a bytestring from a Secure Mem
+secureMemToByteString :: SecureMem -> ByteString
+secureMemToByteString sm =
+    B.unsafeCreate sz $ \dst ->
+    withSecureMemPtr sm $ \src ->
+    B.memcpy dst src (fromIntegral sz)
+    where !sz = secureMemGetSize sm
+
+-- | Create a SecureMem from a bytestring
+secureMemFromByteString :: ByteString -> SecureMem
+secureMemFromByteString b = B.inlinePerformIO $ do
+    sm <- allocateSecureMem len 
+    withSecureMemPtr sm $ \dst -> withBytestringPtr $ \src -> B.memcpy dst src (fromIntegral len)
+    return sm
+    where (fp, off, !len) = B.toForeignPtr b
+          withBytestringPtr f = withForeignPtr fp $ \p -> f (p `plusPtr` off)
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2013 Vincent Hanquez <vincent@snarc.org>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+securemem
+=======
+
+Documentation: [securemem on hackage](http://hackage.haskell.org/package/securemem)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cbits/utils.c b/cbits/utils.c
new file mode 100644
--- /dev/null
+++ b/cbits/utils.c
@@ -0,0 +1,133 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SCRUBVAR 0xa5a5a5a5a5a5a5a5ULL
+
+void finalizer_scrub8(void *ptr)
+{
+	uint64_t *sz_ptr = (uint64_t *) ptr;
+	sz_ptr[0] = SCRUBVAR;
+}
+
+void finalizer_scrub16(void *ptr)
+{
+	uint64_t *sz_ptr = (uint64_t *) ptr;
+	sz_ptr[0] = SCRUBVAR;
+	sz_ptr[1] = SCRUBVAR;
+}
+
+void finalizer_scrub24(void *ptr)
+{
+	uint64_t *sz_ptr = (uint64_t *) ptr;
+	sz_ptr[0] = SCRUBVAR;
+	sz_ptr[1] = SCRUBVAR;
+	sz_ptr[2] = SCRUBVAR;
+}
+
+void finalizer_scrub32(void *ptr)
+{
+	uint64_t *sz_ptr = (uint64_t *) ptr;
+	sz_ptr[0] = SCRUBVAR;
+	sz_ptr[1] = SCRUBVAR;
+	sz_ptr[2] = SCRUBVAR;
+	sz_ptr[3] = SCRUBVAR;
+}
+
+void finalizer_scrub64(void *ptr)
+{
+	uint64_t *sz_ptr = (uint64_t *) ptr;
+	sz_ptr[0] = SCRUBVAR;
+	sz_ptr[1] = SCRUBVAR;
+	sz_ptr[2] = SCRUBVAR;
+	sz_ptr[3] = SCRUBVAR;
+	sz_ptr[4] = SCRUBVAR;
+	sz_ptr[5] = SCRUBVAR;
+	sz_ptr[6] = SCRUBVAR;
+	sz_ptr[7] = SCRUBVAR;
+}
+
+void finalizer_scrub128(void *ptr)
+{
+	uint64_t *sz_ptr = (uint64_t *) ptr;
+	int i;
+
+	for (i = 0; i < 16; i++)
+		sz_ptr[i] = SCRUBVAR;
+}
+
+void finalizer_scrub256(void *ptr)
+{
+	uint64_t *sz_ptr = (uint64_t *) ptr;
+	int i;
+
+	for (i = 0; i < 32; i++)
+		sz_ptr[i] = SCRUBVAR;
+}
+
+void finalizer_scrubvar(uint32_t sz, void *ptr)
+{
+	memset(ptr, 0xa5, sz);
+}
+
+int constant_memeq16(uint8_t *p1, uint8_t *p2)
+{
+}
+
+int compare_eq(uint32_t size, uint8_t *p1, uint8_t *p2)
+{
+	uint32_t i;
+	int acc = 1;
+
+	for (i = 0; i < size / 8; i++)
+		acc &= (p1[i] == p2[i]);
+	return acc;
+}
+
+#define COMPARE_LOOP(n) \
+	uint64_t *sp1, *sp2; \
+	int i, acc; \
+	sp1 = (uint64_t *) p1; sp2 = (uint64_t *) p2; \
+	acc = 1; \
+	for (i = 0; i < n; i++) \
+		acc &= (sp1[i] == sp2[i]); \
+	return acc; \
+
+int compare_eq8(uint8_t *p1, uint8_t *p2)
+{
+	uint64_t *sp1, *sp2;
+	sp1 = (uint64_t *) p1; sp2 = (uint64_t *) p2;
+	return (p1[0] == p2[0]);
+}
+
+int compare_eq16(uint8_t *p1, uint8_t *p2)
+{
+	uint64_t *sp1, *sp2;
+	sp1 = (uint64_t *) p1; sp2 = (uint64_t *) p2;
+	return ((p1[0] == p2[0]) & (p1[1] == p2[1])) == 1;
+}
+
+int compare_eq24(uint8_t *p1, uint8_t *p2)
+{
+	COMPARE_LOOP(3);
+}
+
+int compare_eq32(uint8_t *p1, uint8_t *p2)
+{
+	COMPARE_LOOP(4);
+}
+
+int compare_eq64(uint8_t *p1, uint8_t *p2)
+{
+	COMPARE_LOOP(8);
+}
+
+int compare_eq128(uint8_t *p1, uint8_t *p2)
+{
+	COMPARE_LOOP(16);
+}
+
+int compare_eq256(uint8_t *p1, uint8_t *p2)
+{
+	COMPARE_LOOP(32);
+}
diff --git a/securemem.cabal b/securemem.cabal
new file mode 100644
--- /dev/null
+++ b/securemem.cabal
@@ -0,0 +1,30 @@
+Name:                securemem
+Version:             0.1.0
+Synopsis:            abstraction to an auto scrubbing and const time eq, memory chunk.
+Description:
+    SecureMem is similar to ByteString, except that it provides a memory chunk that
+    will be auto-scrubbed after it run out of scope.
+License:             BSD3
+License-file:        LICENSE
+Copyright:           Vincent Hanquez <vincent@snarc.org>
+Author:              Vincent Hanquez <vincent@snarc.org>
+Maintainer:          vincent@snarc.org
+Category:            Data
+Stability:           experimental
+Build-Type:          Simple
+Homepage:            http://github.com/vincenthz/hs-securemem
+Cabal-Version:       >=1.8
+data-files:          README.md
+
+Library
+  Exposed-modules:   Data.SecureMem
+  Build-depends:     base >= 4 && < 5
+                   , bytestring
+                   , byteable
+                   , ghc-prim
+  C-sources:         cbits/utils.c
+  ghc-options:       -Wall -fwarn-tabs
+
+source-repository head
+  type: git
+  location: git://github.com/vincenthz/hs-securemem
