diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.2
+
+* Fix P256 compilation and exactness, + add tests
+* Add a raw memory number serialization capability (i2osp, os2ip)
+* Improve tests for number serialization
+* Improve tests for ECC arithmetics
+* Add Ord instance for Digest (Nicolas Di Prima)
+* Fix entropy compilation on windows 64 bits.
+
 ## 0.1
 
 * Initial release
diff --git a/Crypto/Error/Types.hs b/Crypto/Error/Types.hs
--- a/Crypto/Error/Types.hs
+++ b/Crypto/Error/Types.hs
@@ -49,6 +49,14 @@
       CryptoPassed a
     | CryptoFailed CryptoError
 
+instance Show a => Show (CryptoFailable a) where
+    show (CryptoPassed a)   = "CryptoPassed " ++ show a
+    show (CryptoFailed err) = "CryptoFailed " ++ show err
+instance Eq a => Eq (CryptoFailable a) where
+    (==) (CryptoPassed a)  (CryptoPassed b)  = a == b
+    (==) (CryptoFailed e1) (CryptoFailed e2) = e1 == e2
+    (==) _                 _                 = False
+
 instance Functor CryptoFailable where
     fmap f (CryptoPassed a) = CryptoPassed (f a)
     fmap _ (CryptoFailed r) = CryptoFailed r
diff --git a/Crypto/Hash/Types.hs b/Crypto/Hash/Types.hs
--- a/Crypto/Hash/Types.hs
+++ b/Crypto/Hash/Types.hs
@@ -51,7 +51,7 @@
 
 -- | Represent a digest for a given hash algorithm.
 newtype Digest a = Digest Bytes
-    deriving (Eq,ByteArrayAccess,NFData)
+    deriving (Eq,Ord,ByteArrayAccess,NFData)
 
 instance Show (Digest a) where
     show (Digest bs) = show (B.convertToBase B.Base16 bs :: Bytes)
diff --git a/Crypto/Number/ModArithmetic.hs b/Crypto/Number/ModArithmetic.hs
--- a/Crypto/Number/ModArithmetic.hs
+++ b/Crypto/Number/ModArithmetic.hs
@@ -47,7 +47,7 @@
         -> Integer -- ^ result
 expSafe b e m
     | odd m     = gmpPowModSecInteger b e m `onGmpUnsupported`
-                  (gmpPowModInteger b e m    `onGmpUnsupported`
+                  (gmpPowModInteger b e m   `onGmpUnsupported`
                   exponentiation b e m)
     | otherwise = gmpPowModInteger b e m    `onGmpUnsupported`
                   exponentiation b e m
diff --git a/Crypto/Number/Serialize.hs b/Crypto/Number/Serialize.hs
--- a/Crypto/Number/Serialize.hs
+++ b/Crypto/Number/Serialize.hs
@@ -12,72 +12,38 @@
     , os2ip
     , i2ospOf
     , i2ospOf_
-    , lengthBytes
     ) where
 
-import           Data.Bits
-import           Data.Word
-import           Foreign.Storable
-import           Foreign.Ptr
-import           Crypto.Number.Compat
+import           Crypto.Number.Basic
 import           Crypto.Internal.Compat (unsafeDoIO)
 import qualified Crypto.Internal.ByteArray as B
-import           Data.Memory.PtrMethods
-
-divMod256 :: Integer -> (Integer, Word8)
-divMod256 n = (n `shiftR` 8, fromIntegral n)
+import qualified Crypto.Number.Serialize.Internal as Internal
 
 -- | os2ip converts a byte string into a positive integer
 os2ip :: B.ByteArrayAccess ba => ba -> Integer
-os2ip bs = unsafeDoIO $ B.withByteArray bs (loop 0 0)
-  where
-        len = B.length bs
-
-        loop :: Integer -> Int -> Ptr Word8 -> IO Integer
-        loop !acc i p
-            | i == len  = return acc
-            | otherwise = do
-                w <- peekByteOff p i :: IO Word8
-                loop ((acc `shiftL` 8) .|. fromIntegral w) (i+1) p
+os2ip bs = unsafeDoIO $ B.withByteArray bs (\p -> Internal.os2ip p (B.length bs))
 
 -- | i2osp converts a positive integer into a byte string
 --
 -- first byte is MSB (most significant byte), last byte is the LSB (least significant byte)
 i2osp :: B.ByteArray ba => Integer -> ba
-i2osp 0 = B.allocAndFreeze 1 $ \p -> pokeByteOff p 0 (0 :: Word8)
-i2osp m = B.allocAndFreeze sz (\p -> fillPtr p >> return ())
+i2osp 0 = B.allocAndFreeze 1  (\p -> Internal.i2osp 0 p 1 >> return ())
+i2osp m = B.allocAndFreeze sz (\p -> Internal.i2osp m p sz >> return ())
   where
-        !sz = lengthBytes m
-
-        fillPtr p = gmpExportInteger m p `onGmpUnsupported` export p (sz-1) m
-        export p ofs i
-            | ofs == 0  = pokeByteOff p ofs (fromIntegral i :: Word8)
-            | otherwise = do
-                let (i', b) = divMod256 i
-                pokeByteOff p ofs b
-                export p (ofs-1) i'
+        !sz = numBytes m
 
 -- | just like i2osp, but take an extra parameter for size.
 -- if the number is too big to fit in @len bytes, nothing is returned
 -- otherwise the number is padded with 0 to fit the @len required.
 i2ospOf :: B.ByteArray ba => Int -> Integer -> Maybe ba
-i2ospOf 0   _ = error "cannot create integer serialization in 0 bytes"
-i2ospOf len 0 = Just $ B.allocAndFreeze len $ \p -> memSet p 0 len
 i2ospOf len m
+    | len <= 0  = Nothing
+    | m < 0     = Nothing
     | sz > len  = Nothing
-    | otherwise = Just $ B.allocAndFreeze len $ \p -> memSet p 0 len >> fillPtr (p `plusPtr` (len - sz))
+    | otherwise = Just $ B.unsafeCreate len (\p -> Internal.i2ospOf m p len >> return ())
   where
-        !sz = lengthBytes m
-
-        fillPtr p = gmpExportInteger m p `onGmpUnsupported` export p (sz-1) m
-        export p ofs i
-            | ofs == 0  = pokeByteOff p ofs (fromIntegral i :: Word8)
-            | otherwise = do
-                let (i', b) = divMod256 i
-                pokeByteOff p ofs b
-                export p (ofs-1) i'
+        !sz = numBytes m
 
---
 -- | just like i2ospOf except that it doesn't expect a failure: i.e.
 -- an integer larger than the number of output bytes requested
 --
@@ -85,13 +51,3 @@
 -- the size (example the RSA modulo n).
 i2ospOf_ :: B.ByteArray ba => Int -> Integer -> ba
 i2ospOf_ len = maybe (error "i2ospOf_: integer is larger than expected") id . i2ospOf len
-
--- | returns the number of bytes to store an integer with i2osp
---
--- with integer-simple, this function is really slow.
-lengthBytes :: Integer -> Int
-lengthBytes n = gmpSizeInBytes n `onGmpUnsupported` nbBytes n
-  where
-    nbBytes !v
-        | v < 256   = 1
-        | otherwise = 1 + nbBytes (v `shiftR` 8)
diff --git a/Crypto/Number/Serialize/Internal.hs b/Crypto/Number/Serialize/Internal.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Number/Serialize/Internal.hs
@@ -0,0 +1,76 @@
+-- |
+-- Module      : Crypto.Number.Serialize.Internal
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+--
+-- fast serialization primitives for integer using raw pointers
+{-# LANGUAGE BangPatterns #-}
+module Crypto.Number.Serialize.Internal
+    ( i2osp
+    , i2ospOf
+    , os2ip
+    ) where
+
+import           Crypto.Number.Compat
+import           Crypto.Number.Basic
+import           Data.Bits
+import           Data.Memory.PtrMethods
+import           Data.Word (Word8)
+import           Foreign.Ptr
+import           Foreign.Storable
+
+-- | fill a pointer with the big endian binary representation of an integer
+--
+-- if the room available @ptrSz is less than the number of bytes needed,
+-- 0 is returned. Likewise if a parameter is invalid, 0 is returned.
+--
+-- returns the number of bytes written
+i2osp :: Integer -> Ptr Word8 -> Int -> IO Int
+i2osp m ptr ptrSz
+    | ptrSz <= 0 = return 0
+    | m < 0      = return 0
+    | m == 0     = pokeByteOff ptr 0 (0 :: Word8) >> return 1
+    | ptrSz < sz = return 0
+    | otherwise  = fillPtr ptr sz m >> return sz
+  where
+    !sz    = numBytes m
+
+-- | Similar to 'i2osp', except it will pad any remaining space with zero.
+i2ospOf :: Integer -> Ptr Word8 -> Int -> IO Int
+i2ospOf m ptr ptrSz
+    | ptrSz <= 0 = return 0
+    | m < 0      = return 0
+    | ptrSz < sz = return 0
+    | otherwise  = do
+        memSet ptr 0 ptrSz
+        fillPtr (ptr `plusPtr` padSz) sz m
+        return ptrSz
+  where
+    !sz    = numBytes m
+    !padSz = ptrSz - sz
+
+fillPtr :: Ptr Word8 -> Int -> Integer -> IO ()
+fillPtr p sz m = gmpExportInteger m p `onGmpUnsupported` export (sz-1) m
+  where
+    export ofs i
+        | ofs == 0  = pokeByteOff p ofs (fromIntegral i :: Word8)
+        | otherwise = do
+            let (i', b) = i `divMod` 256
+            pokeByteOff p ofs (fromIntegral b :: Word8)
+            export (ofs-1) i'
+
+-- | transform a big endian binary integer representation pointed by a pointer and a size
+-- into an integer
+os2ip :: Ptr Word8 -> Int -> IO Integer
+os2ip ptr ptrSz
+    | ptrSz <= 0 = return 0
+    | otherwise  = gmpImportInteger ptrSz ptr `onGmpUnsupported` loop 0 0 ptr
+  where
+    loop :: Integer -> Int -> Ptr Word8 -> IO Integer
+    loop !acc i p
+        | i == ptrSz = return acc
+        | otherwise  = do
+            w <- peekByteOff p i :: IO Word8
+            loop ((acc `shiftL` 8) .|. fromIntegral w) (i+1) p
diff --git a/Crypto/PubKey/ECC/P256.hs b/Crypto/PubKey/ECC/P256.hs
--- a/Crypto/PubKey/ECC/P256.hs
+++ b/Crypto/PubKey/ECC/P256.hs
@@ -11,8 +11,6 @@
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE EmptyDataDecls #-}
 {-# OPTIONS_GHC -fno-warn-unused-binds #-}
-{-# OPTIONS_GHC -fno-warn-unused-matches #-}
-{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 module Crypto.PubKey.ECC.P256
     ( Scalar
     , Point
@@ -22,39 +20,51 @@
     , pointsMulVarTime
     , pointIsValid
     , toPoint
+    , pointToIntegers
+    , pointFromIntegers
+    , pointToBinary
+    , pointFromBinary
     -- * scalar arithmetic
     , scalarZero
+    , scalarIsZero
     , scalarAdd
     , scalarSub
     , scalarInv
-    , scalarInvVarTime
     , scalarCmp
     , scalarFromBinary
     , scalarToBinary
+    , scalarFromInteger
+    , scalarToInteger
     ) where
 
 import           Data.Word
 import           Foreign.Ptr
 import           Foreign.C.Types
+import           Control.Monad
 
 import           Crypto.Internal.Compat
 import           Crypto.Internal.Imports
---import           Crypto.Internal.Memory
 import           Crypto.Internal.ByteArray
 import qualified Crypto.Internal.ByteArray as B
+import           Data.Memory.PtrMethods (memSet)
 import           Crypto.Error
+import           Crypto.Number.Serialize.Internal (os2ip, i2ospOf)
+import qualified Crypto.Number.Serialize as S (os2ip, i2ospOf)
 
 -- | A P256 scalar
-newtype Scalar = Scalar ScrubbedBytes
+newtype Scalar = Scalar Bytes
     deriving (Eq,ByteArrayAccess)
 
 -- | A P256 point
-data Point = Point !Bytes !Bytes
+newtype Point = Point Bytes
     deriving (Show,Eq)
 
 scalarSize :: Int
 scalarSize = 32
 
+pointSize :: Int
+pointSize = 64
+
 type P256Digit  = Word32
 
 data P256Scalar
@@ -73,8 +83,11 @@
 -- > scalar * G
 --
 toPoint :: Scalar -> Point
-toPoint s = withNewPoint $ \px py -> withScalar s $ \p ->
-    ccryptonite_p256_basepoint_mul p px py
+toPoint s
+    | scalarIsZero s = error "cannot create point from zero"
+    | otherwise      =
+        withNewPoint $ \px py -> withScalar s $ \p ->
+            ccryptonite_p256_basepoint_mul p px py
 
 -- | Add a point to another point
 pointAdd :: Point -> Point -> Point
@@ -83,14 +96,18 @@
         ccryptonite_p256e_point_add ax ay bx by dx dy
 
 -- | Multiply a point by a scalar
+--
+-- warning: variable time
 pointMul :: Scalar -> Point -> Point
 pointMul scalar p = withNewPoint $ \dx dy ->
-    withScalar scalar $ \n -> withPoint p $ \px py ->
-        ccryptonite_p256_point_mul n dx dy px py
+    withScalar scalar $ \n -> withPoint p $ \px py -> withScalarZero $ \nzero ->
+        ccryptonite_p256_points_mul_vartime nzero n px py dx dy
 
 -- | multiply the point @p with @n2 and add a lifted to curve value @n1
 --
 -- > n1 * G + n2 * p
+--
+-- warning: variable time
 pointsMulVarTime :: Scalar -> Scalar -> Point -> Point
 pointsMulVarTime n1 n2 p = withNewPoint $ \dx dy ->
     withScalar n1 $ \pn1 -> withScalar n2 $ \pn2 -> withPoint p $ \px py ->
@@ -102,6 +119,46 @@
     r <- ccryptonite_p256_is_valid_point px py
     return (r /= 0)
 
+pointToIntegers :: Point -> (Integer, Integer)
+pointToIntegers p = unsafeDoIO $ withPoint p $ \px py ->
+    allocTemp 32 (serialize (castPtr px) (castPtr py))
+  where
+    serialize px py temp = do
+        ccryptonite_p256_to_bin px temp
+        x <- os2ip temp scalarSize
+        ccryptonite_p256_to_bin py temp
+        y <- os2ip temp scalarSize
+        return (x,y)
+
+pointFromIntegers :: (Integer, Integer) -> Point
+pointFromIntegers (x,y) = withNewPoint $ \dx dy ->
+    allocTemp scalarSize (\temp -> fill temp (castPtr dx) x >> fill temp (castPtr dy) y)
+  where
+    -- put @n to @temp in big endian format, then from @temp to @dest in p256 scalar format
+    fill :: Ptr Word8 -> Ptr P256Scalar -> Integer -> IO ()
+    fill temp dest n = do
+        -- write the integer in big endian format to temp
+        memSet temp 0 scalarSize
+        e <- i2ospOf n temp scalarSize
+        if e == 0
+            then error "pointFromIntegers: filling failed"
+            else return ()
+        -- then fill dest with the P256 scalar from temp
+        ccryptonite_p256_from_bin temp dest
+
+pointToBinary :: ByteArray ba => Point -> ba
+pointToBinary p = B.unsafeCreate pointSize $ \dst -> withPoint p $ \px py -> do
+    ccryptonite_p256_to_bin (castPtr px) dst
+    ccryptonite_p256_to_bin (castPtr py) (dst `plusPtr` 32)
+
+pointFromBinary :: ByteArrayAccess ba => ba -> CryptoFailable Point
+pointFromBinary ba
+    | B.length ba /= pointSize = CryptoFailed $ CryptoError_PublicKeySizeInvalid
+    | otherwise                =
+        CryptoPassed $ withNewPoint $ \px py -> B.withByteArray ba $ \src -> do
+            ccryptonite_p256_from_bin src                        (castPtr px)
+            ccryptonite_p256_from_bin (src `plusPtr` scalarSize) (castPtr py)
+
 ------------------------------------------------------------------------
 -- Scalar methods
 ------------------------------------------------------------------------
@@ -110,14 +167,27 @@
 scalarZero :: Scalar
 scalarZero = withNewScalarFreeze $ \d -> ccryptonite_p256_init d
 
+scalarIsZero :: Scalar -> Bool
+scalarIsZero s = unsafeDoIO $ withScalar s $ \d -> do
+    result <- ccryptonite_p256_is_zero d
+    return $ result /= 0
+
+scalarNeedReducing :: Ptr P256Scalar -> IO Bool
+scalarNeedReducing d = do
+    c <- ccryptonite_p256_cmp d ccryptonite_SECP256r1_n
+    return (c >= 0)
+
 -- | Perform addition between two scalars
 --
 -- > a + b
 scalarAdd :: Scalar -> Scalar -> Scalar
 scalarAdd a b =
     withNewScalarFreeze $ \d -> withScalar a $ \pa -> withScalar b $ \pb -> do
-        void $ ccryptonite_p256_add pa pb d
-        ccryptonite_p256_mod ccryptonite_SECP256r1_n d d
+        carry <- ccryptonite_p256_add pa pb d
+        when (carry /= 0) $ void $ ccryptonite_p256_sub d ccryptonite_SECP256r1_n d
+        needReducing <- scalarNeedReducing d
+        when needReducing $ do
+            ccryptonite_p256_mod ccryptonite_SECP256r1_n d d
 
 -- | Perform subtraction between two scalars
 --
@@ -125,22 +195,20 @@
 scalarSub :: Scalar -> Scalar -> Scalar
 scalarSub a b =
     withNewScalarFreeze $ \d -> withScalar a $ \pa -> withScalar b $ \pb -> do
-        void $ ccryptonite_p256_sub pa pb d
-        ccryptonite_p256_mod ccryptonite_SECP256r1_n d d
+        borrow <- ccryptonite_p256_sub pa pb d
+        when (borrow /= 0) $ void $ ccryptonite_p256_add d ccryptonite_SECP256r1_n d
+        --needReducing <- scalarNeedReducing d
+        --when needReducing $ do
+        --    ccryptonite_p256_mod ccryptonite_SECP256r1_n d d
 
 -- | Give the inverse of the scalar
 --
 -- > 1 / a
+--
+-- warning: variable time
 scalarInv :: Scalar -> Scalar
 scalarInv a =
     withNewScalarFreeze $ \b -> withScalar a $ \pa ->
-        ccryptonite_p256_modinv ccryptonite_SECP256r1_n pa b
-
--- | similar to 'scalarInv' but instead of
--- trying to be constant time, do it as fast as possible
-scalarInvVarTime :: Scalar -> Scalar
-scalarInvVarTime a =
-    withNewScalarFreeze $ \b -> withScalar a $ \pa ->
         ccryptonite_p256_modinv_vartime ccryptonite_SECP256r1_n pa b
 
 -- | Compare 2 Scalar
@@ -157,32 +225,62 @@
     | otherwise                 =
         CryptoPassed $ withNewScalarFreeze $ \p -> B.withByteArray ba $ \b ->
             ccryptonite_p256_from_bin b p
+{-# NOINLINE scalarFromBinary #-}
 
 -- | convert a scalar to binary
 scalarToBinary :: ByteArray ba => Scalar -> ba
-scalarToBinary s = B.allocAndFreeze scalarSize $ \b -> withScalar s $ \p ->
+scalarToBinary s = B.unsafeCreate scalarSize $ \b -> withScalar s $ \p ->
     ccryptonite_p256_to_bin p b
+{-# NOINLINE scalarToBinary #-}
 
+scalarFromInteger :: Integer -> CryptoFailable Scalar
+scalarFromInteger i =
+    maybe (CryptoFailed CryptoError_SecretKeySizeInvalid) scalarFromBinary (S.i2ospOf 32 i :: Maybe Bytes)
+
+scalarToInteger :: Scalar -> Integer
+scalarToInteger s = S.os2ip (scalarToBinary s :: Bytes)
+
 ------------------------------------------------------------------------
 -- Memory Helpers
 ------------------------------------------------------------------------
 withNewPoint :: (Ptr P256X -> Ptr P256Y -> IO ()) -> Point
-withNewPoint f = unsafeDoIO $ do
-    (x,y) <- B.allocRet pointCoordSize $ \py -> B.alloc pointCoordSize $ \px -> f px py
-    return $! Point x y
-  where pointCoordSize = 32
+withNewPoint f = Point $ B.unsafeCreate pointSize $ \px -> f px (pxToPy px)
 {-# NOINLINE withNewPoint #-}
 
 withPoint :: Point -> (Ptr P256X -> Ptr P256Y -> IO a) -> IO a
-withPoint (Point x y) f = B.withByteArray x $ \px -> B.withByteArray y $ \py -> f px py
+withPoint (Point d) f = B.withByteArray d $ \px -> f px (pxToPy px)
 
+pxToPy :: Ptr P256X -> Ptr P256Y
+pxToPy px = castPtr (px `plusPtr` scalarSize)
+
 withNewScalarFreeze :: (Ptr P256Scalar -> IO ()) -> Scalar
 withNewScalarFreeze f = Scalar $ B.allocAndFreeze scalarSize f
 {-# NOINLINE withNewScalarFreeze #-}
 
+withTempScalar :: (Ptr P256Scalar -> IO a) -> IO a
+withTempScalar f = allocTempScrubbed scalarSize (f . castPtr)
+
 withScalar :: Scalar -> (Ptr P256Scalar -> IO a) -> IO a
 withScalar (Scalar d) f = B.withByteArray d f
 
+withScalarZero :: (Ptr P256Scalar -> IO a) -> IO a
+withScalarZero f =
+    withTempScalar $ \d -> do
+        ccryptonite_p256_init d
+        f d
+
+allocTemp :: Int -> (Ptr Word8 -> IO a) -> IO a
+allocTemp n f = ignoreSnd <$> B.allocRet n f
+  where
+    ignoreSnd :: (a, Bytes) -> a
+    ignoreSnd = fst
+
+allocTempScrubbed :: Int -> (Ptr Word8 -> IO a) -> IO a
+allocTempScrubbed n f = ignoreSnd <$> B.allocRet n f
+  where
+    ignoreSnd :: (a, ScrubbedBytes) -> a
+    ignoreSnd = fst
+
 ------------------------------------------------------------------------
 -- Foreign bindings
 ------------------------------------------------------------------------
@@ -195,10 +293,14 @@
 
 foreign import ccall "cryptonite_p256_init"
     ccryptonite_p256_init :: Ptr P256Scalar -> IO ()
+foreign import ccall "cryptonite_p256_is_zero"
+    ccryptonite_p256_is_zero :: Ptr P256Scalar -> IO CInt
 foreign import ccall "cryptonite_p256_clear"
     ccryptonite_p256_clear :: Ptr P256Scalar -> IO ()
 foreign import ccall "cryptonite_p256_add"
     ccryptonite_p256_add :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO CInt
+foreign import ccall "cryptonite_p256_add_d"
+    ccryptonite_p256_add_d :: Ptr P256Scalar -> P256Digit -> Ptr P256Scalar -> IO CInt
 foreign import ccall "cryptonite_p256_sub"
     ccryptonite_p256_sub :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO CInt
 foreign import ccall "cryptonite_p256_cmp"
@@ -207,8 +309,8 @@
     ccryptonite_p256_mod :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
 foreign import ccall "cryptonite_p256_modmul"
     ccryptonite_p256_modmul :: Ptr P256Scalar -> Ptr P256Scalar -> P256Digit -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
-foreign import ccall "cryptonite_p256_modinv"
-    ccryptonite_p256_modinv :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
+--foreign import ccall "cryptonite_p256_modinv"
+--    ccryptonite_p256_modinv :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
 foreign import ccall "cryptonite_p256_modinv_vartime"
     ccryptonite_p256_modinv_vartime :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
 foreign import ccall "cryptonite_p256_base_point_mul"
@@ -221,15 +323,13 @@
                                 -> Ptr P256X -> Ptr P256Y
                                 -> Ptr P256X -> Ptr P256Y
                                 -> IO ()
-foreign import ccall "cryptonite_p256_point_mul"
-    ccryptonite_p256_point_mul :: Ptr P256Scalar
-                               -> Ptr P256X -> Ptr P256Y
-                               -> Ptr P256X -> Ptr P256Y
-                               -> IO ()
+
+-- compute (out_x,out,y) = n1 * G + n2 * (in_x,in_y)
 foreign import ccall "cryptonite_p256_points_mul_vartime"
-    ccryptonite_p256_points_mul_vartime :: Ptr P256Scalar -> Ptr P256Scalar
-                                        -> Ptr P256X -> Ptr P256Y
-                                        -> Ptr P256X -> Ptr P256Y
+    ccryptonite_p256_points_mul_vartime :: Ptr P256Scalar -- n1
+                                        -> Ptr P256Scalar -- n2
+                                        -> Ptr P256X -> Ptr P256Y -- in_{x,y}
+                                        -> Ptr P256X -> Ptr P256Y -- out_{x,y}
                                         -> IO ()
 foreign import ccall "cryptonite_p256_is_valid_point"
     ccryptonite_p256_is_valid_point :: Ptr P256X -> Ptr P256Y -> IO CInt
diff --git a/Crypto/Random/Entropy/Windows.hs b/Crypto/Random/Entropy/Windows.hs
--- a/Crypto/Random/Entropy/Windows.hs
+++ b/Crypto/Random/Entropy/Windows.hs
@@ -15,7 +15,7 @@
     ) where
 
 import Data.Int (Int32)
-import Data.Word (Word32, Word8)
+import Data.Word
 import Foreign.C.String (CString, withCString)
 import Foreign.Ptr (Ptr, nullPtr)
 import Foreign.Marshal.Alloc (alloca)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -76,5 +76,4 @@
 TODO
 ----
 
-* finish google P256 binding
 * add support for XSalsa
diff --git a/cbits/cryptonite_sysrand.c b/cbits/cryptonite_sysrand.c
new file mode 100644
--- /dev/null
+++ b/cbits/cryptonite_sysrand.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 Vincent Hanquez <tab@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.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include "cryptonite_sha512.h"
+
+void cryptonite_sysrand_init(uint8_t *buf, uint32_t sz)
+{
+	struct timeval tv;
+	struct sha512_ctx ctx;
+	uint8_t out[64];
+	
+	gettimeofday(&tv, NULL);
+	cryptonite_sha512_init(&ctx);
+	cryptonite_sha512_update(&ctx, (uint8_t *) &tv, sizeof(tv));
+	cryptonite_sha512_finalize(&ctx, out);
+}
diff --git a/cbits/p256/p256.c b/cbits/p256/p256.c
--- a/cbits/p256/p256.c
+++ b/cbits/p256/p256.c
@@ -371,3 +371,18 @@
     p += 4;
   }
 }
+
+void cryptonite_p256_to_bin(const cryptonite_p256_int* src, uint8_t dst[P256_NBYTES])
+{
+	int i;
+	uint8_t* p = &dst[0];
+
+	for (i = P256_NDIGITS -1; i >= 0; --i) {
+		const cryptonite_p256_digit dig = P256_DIGIT(src, i);
+		p[0] = dig >> 24;
+		p[1] = dig >> 16;
+		p[2] = dig >> 8;
+		p[3] = dig;
+		p += 4;
+	}
+}
diff --git a/cryptonite.cabal b/cryptonite.cabal
--- a/cryptonite.cabal
+++ b/cryptonite.cabal
@@ -1,5 +1,5 @@
 Name:                cryptonite
-Version:             0.1
+Version:             0.2
 Synopsis:            Cryptography Primitives sink
 Description:
     A repository of cryptographic primitives.
@@ -86,6 +86,7 @@
                      Crypto.Number.ModArithmetic
                      Crypto.Number.Prime
                      Crypto.Number.Serialize
+                     Crypto.Number.Serialize.Internal
                      Crypto.KDF.PBKDF2
                      Crypto.KDF.Scrypt
                      Crypto.Hash
@@ -189,6 +190,7 @@
                    , cbits/cryptonite_tiger.c
                    , cbits/cryptonite_whirlpool.c
                    , cbits/cryptonite_scrypt.c
+                   , cbits/cryptonite_sysrand.c
   include-dirs:  cbits cbits/ed25519
 
   -- FIXME armel or mispel is also little endian.
@@ -254,6 +256,7 @@
                      KAT_PubKey.ECDSA
                      KAT_PubKey.OAEP
                      KAT_PubKey.PSS
+                     KAT_PubKey.P256
                      KAT_PubKey
                      KAT_RC4
                      KAT_Scrypt
diff --git a/tests/KAT_PubKey.hs b/tests/KAT_PubKey.hs
--- a/tests/KAT_PubKey.hs
+++ b/tests/KAT_PubKey.hs
@@ -17,6 +17,7 @@
 import KAT_PubKey.ECC
 import KAT_PubKey.ECDSA
 import Utils
+import qualified KAT_PubKey.P256 as P256
 
 data VectorMgf = VectorMgf { seed :: ByteString
                            , dbMask :: ByteString
@@ -39,6 +40,7 @@
     , dsaTests
     , eccTests
     , ecdsaTests
+    , P256.tests
     ]
 
 --newKats = [ eccKatTests ]
diff --git a/tests/KAT_PubKey/ECC.hs b/tests/KAT_PubKey/ECC.hs
--- a/tests/KAT_PubKey/ECC.hs
+++ b/tests/KAT_PubKey/ECC.hs
@@ -11,6 +11,43 @@
 
 import Imports
 
+instance Arbitrary ECC.Curve where
+    arbitrary = ECC.getCurveByName <$> elements
+        [ ECC.SEC_p112r1
+        , ECC.SEC_p112r2
+        , ECC.SEC_p128r1
+        , ECC.SEC_p128r2
+        , ECC.SEC_p160k1
+        , ECC.SEC_p160r1
+        , ECC.SEC_p160r2
+        , ECC.SEC_p192k1
+        , ECC.SEC_p192r1
+        , ECC.SEC_p224k1
+        , ECC.SEC_p224r1
+        , ECC.SEC_p256k1
+        , ECC.SEC_p256r1
+        , ECC.SEC_p384r1
+        , ECC.SEC_p521r1
+        , ECC.SEC_t113r1
+        , ECC.SEC_t113r2
+        , ECC.SEC_t131r1
+        , ECC.SEC_t131r2
+        , ECC.SEC_t163k1
+        , ECC.SEC_t163r1
+        , ECC.SEC_t163r2
+        , ECC.SEC_t193r1
+        , ECC.SEC_t193r2
+        , ECC.SEC_t233k1
+        , ECC.SEC_t233r1
+        , ECC.SEC_t239k1
+        , ECC.SEC_t283k1
+        , ECC.SEC_t283r1
+        , ECC.SEC_t409k1
+        , ECC.SEC_t409r1
+        , ECC.SEC_t571k1
+        , ECC.SEC_t571r1
+        ]
+
 data VectorPoint = VectorPoint
     { curve :: ECC.Curve
     , x     :: Integer
@@ -101,8 +138,18 @@
 
 doPointValidTest (i, vector) = testCase (show i) (valid vector @=? ECC.isPointValid (curve vector) (ECC.Point (x vector) (y vector)))
 
+
 eccTests = testGroup "ECC"
     [ testGroup "valid-point" $ map doPointValidTest (zip [katZero..] vectorsPoint)
+    , testGroup "property" $
+        [ testProperty "point-add" $ \curve (QAInteger r1) (QAInteger r2) ->
+            let curveN   = ECC.ecc_n . ECC.common_curve $ curve
+                curveGen = ECC.ecc_g . ECC.common_curve $ curve
+                p1       = ECC.pointMul curve r1 curveGen
+                p2       = ECC.pointMul curve r2 curveGen
+                pR       = ECC.pointMul curve ((r1 + r2) `mod` curveN) curveGen
+             in pR `propertyEq` ECC.pointAdd curve p1 p2
+        ]
     ]
 
 eccKatTests = do
diff --git a/tests/KAT_PubKey/P256.hs b/tests/KAT_PubKey/P256.hs
new file mode 100644
--- /dev/null
+++ b/tests/KAT_PubKey/P256.hs
@@ -0,0 +1,143 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module KAT_PubKey.P256 (tests) where
+
+import qualified Crypto.PubKey.ECC.Types as ECC
+import qualified Crypto.PubKey.ECC.Prim as ECC
+import qualified Crypto.PubKey.ECC.P256 as P256
+
+import           Data.ByteArray (Bytes)
+import           Crypto.Number.Serialize (i2ospOf, os2ip)
+import           Crypto.Number.ModArithmetic (inverseCoprimes)
+import           Crypto.Error
+
+import           Imports
+
+newtype P256Scalar = P256Scalar Integer
+    deriving (Show,Eq,Ord)
+
+instance Arbitrary P256Scalar where
+    arbitrary = P256Scalar . getQAInteger <$> arbitrary
+
+curve  = ECC.getCurveByName ECC.SEC_p256r1
+curveN = ECC.ecc_n . ECC.common_curve $ curve
+curveGen = ECC.ecc_g . ECC.common_curve $ curve
+
+pointP256ToECC :: P256.Point -> ECC.Point
+pointP256ToECC = uncurry ECC.Point . P256.pointToIntegers
+
+unP256Scalar :: P256Scalar -> P256.Scalar
+unP256Scalar (P256Scalar r') =
+    let r = if r' == 0 then 0x2901 else (r' `mod` curveN)
+        rBytes = i2ospScalar r
+     in case P256.scalarFromBinary rBytes of
+                    CryptoFailed err    -> error ("cannot convert scalar: " ++ show err)
+                    CryptoPassed scalar -> scalar
+  where
+    i2ospScalar :: Integer -> Bytes
+    i2ospScalar i =
+        case i2ospOf 32 i of
+            Nothing -> error "invalid size of P256 scalar"
+            Just b  -> b
+
+unP256 :: P256Scalar -> Integer
+unP256 (P256Scalar r') = if r' == 0 then 0x2901 else (r' `mod` curveN)
+
+p256ScalarToInteger :: P256.Scalar -> Integer
+p256ScalarToInteger s = os2ip (P256.scalarToBinary s :: Bytes)
+
+xS = 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9
+yS = 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256
+xT = 0x55a8b00f8da1d44e62f6b3b25316212e39540dc861c89575bb8cf92e35e0986b
+yT = 0x5421c3209c2d6c704835d82ac4c3dd90f61a8a52598b9e7ab656e9d8c8b24316
+xR = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e
+yR = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264
+
+tests = testGroup "P256"
+    [ testGroup "scalar"
+        [ testProperty "marshalling" $ \(QAInteger r') ->
+            let r = r' `mod` curveN
+                rBytes = i2ospScalar r
+             in case P256.scalarFromBinary rBytes of
+                    CryptoFailed err    -> error (show err)
+                    CryptoPassed scalar -> rBytes `propertyEq` P256.scalarToBinary scalar
+        , testProperty "add" $ \r1 r2 ->
+            let r = (unP256 r1 + unP256 r2) `mod` curveN
+                r' = P256.scalarAdd (unP256Scalar r1) (unP256Scalar r2)
+             in r `propertyEq` p256ScalarToInteger r'
+        , testProperty "add0" $ \r ->
+            let v = unP256 r
+                v' = P256.scalarAdd (unP256Scalar r) P256.scalarZero
+             in v `propertyEq` p256ScalarToInteger v'
+        , testProperty "add-n-1" $ \r ->
+            let nm1 = throwCryptoError $ P256.scalarFromInteger (curveN - 1)
+                v   = unP256 r
+                v'  = P256.scalarAdd (unP256Scalar r) nm1
+             in (((curveN - 1) + v) `mod` curveN) `propertyEq` p256ScalarToInteger v'
+        , testProperty "sub" $ \r1 r2 ->
+            let r = (unP256 r1 - unP256 r2) `mod` curveN
+                r' = P256.scalarSub (unP256Scalar r1) (unP256Scalar r2)
+                v = (unP256 r2 - unP256 r1) `mod` curveN
+                v' = P256.scalarSub (unP256Scalar r2) (unP256Scalar r1)
+             in propertyHold
+                    [ eqTest "r1-r2" r (p256ScalarToInteger r')
+                    , eqTest "r2-r1" v (p256ScalarToInteger v')
+                    ]
+        , testProperty "sub-n-1" $ \r ->
+            let nm1 = throwCryptoError $ P256.scalarFromInteger (curveN - 1)
+                v = unP256 r
+                v' = P256.scalarSub (unP256Scalar r) nm1
+             in ((v - (curveN - 1)) `mod` curveN) `propertyEq` p256ScalarToInteger v'
+        , testProperty "inv" $ \r' ->
+            let inv  = inverseCoprimes (unP256 r') curveN
+                inv' = P256.scalarInv (unP256Scalar r')
+             in if unP256 r' == 0 then True else inv `propertyEq` p256ScalarToInteger inv'
+        ]
+    , testGroup "point"
+        [ testProperty "marshalling" $ \rx ry ->
+            let p = P256.pointFromIntegers (unP256 rx, unP256 ry)
+                b = P256.pointToBinary p :: Bytes
+                p' = P256.pointFromBinary b
+             in propertyHold [ eqTest "point" (CryptoPassed p) p' ]
+        , testProperty "marshalling-integer" $ \rx ry ->
+            let p = P256.pointFromIntegers (unP256 rx, unP256 ry)
+                (x,y) = P256.pointToIntegers p
+             in propertyHold [ eqTest "x" (unP256 rx) x, eqTest "y" (unP256 ry) y ]
+        , testCase "valid-point-1" $ casePointIsValid (xS,yS)
+        , testCase "valid-point-2" $ casePointIsValid (xR,yR)
+        , testCase "valid-point-3" $ casePointIsValid (xT,yT)
+        , testCase "point-add-1" $
+            let s = P256.pointFromIntegers (xS, yS)
+                t = P256.pointFromIntegers (xT, yT)
+                r = P256.pointFromIntegers (xR, yR)
+             in r @=? P256.pointAdd s t
+        , testProperty "lift-to-curve" $ propertyLiftToCurve
+        , testProperty "point-add" $ propertyPointAdd
+        ]
+    ]
+  where
+    casePointIsValid pointTuple =
+        let s = P256.pointFromIntegers pointTuple in True @=? P256.pointIsValid s
+
+    propertyLiftToCurve r =
+        let p     = P256.toPoint (unP256Scalar r)
+            (x,y) = P256.pointToIntegers p
+            pEcc  = ECC.pointMul curve (unP256 r) curveGen
+         in pEcc `propertyEq` ECC.Point x y
+
+    propertyPointAdd r1 r2 =
+        let p1    = P256.toPoint (unP256Scalar r1)
+            p2    = P256.toPoint (unP256Scalar r2)
+            pe1   = ECC.pointMul curve (unP256 r1) curveGen
+            pe2   = ECC.pointMul curve (unP256 r2) curveGen
+            pR    = P256.toPoint (P256.scalarAdd (unP256Scalar r1) (unP256Scalar r2))
+            peR   = ECC.pointAdd curve pe1 pe2
+         in propertyHold [ eqTest "p256" pR (P256.pointAdd p1 p2)
+                         , eqTest "ecc" peR (pointP256ToECC pR)
+                         ]
+
+    i2ospScalar :: Integer -> Bytes
+    i2ospScalar i =
+        case i2ospOf 32 i of
+            Nothing -> error "invalid size of P256 scalar"
+            Just b  -> b
diff --git a/tests/Number.hs b/tests/Number.hs
--- a/tests/Number.hs
+++ b/tests/Number.hs
@@ -1,12 +1,24 @@
+{-# LANGUAGE OverloadedStrings #-}
 module Number (tests) where
 
 import Imports
 
+import Data.ByteArray (Bytes)
 import Crypto.Number.Basic
 import Crypto.Number.Generate
+import Crypto.Number.Serialize
 import Crypto.Number.Prime
 import Data.Bits
 
+serializationVectors :: [(Int, Integer, ByteString)]
+serializationVectors =
+    [ (128, 468189858948067662094510918729062682059955669513914188715630930503497261316361784677177564296207557978182700664806717692596876084916561811001371208806217360635705059859428069669992937334724312890015700331031248133952795914192719979937664050389500162437642525331653766885896869239678885404647468665996400635, "\x00\xaa\xae\x74\xc8\xec\x3c\x36\x06\x5e\x46\xca\x8e\x57\xab\x09\x87\xfd\xcd\x1f\xa4\xe7\xf9\xd2\x60\xd5\x4a\x1b\x74\xdc\xa8\x75\xd8\xdd\xff\x2b\x74\x28\x14\x59\x67\x6c\x82\xae\xa3\xa5\x1d\x3f\xb4\xb7\xfe\x5c\xd2\xf0\x7f\xd8\xd9\xa9\xb0\xce\x26\xc1\x26\x74\x96\xf5\xf6\x4c\x8f\x66\x7f\x5d\xf1\x68\x38\xd4\x03\x62\xe9\x30\xc8\xa1\xc1\x84\x97\x62\x20\xfd\xd7\x03\x35\xc1\x25\x45\x1b\x86\x81\x3d\xa4\x92\xc0\xd3\xdd\xfa\x86\x1d\xdf\x0a\xbb\xf4\xc0\x56\xf7\xa2\xb0\x3b\x52\xf7\xa5\x89\x4c\x69\x34\x91\x46\xd9\x57\xfb")
+    , (128, 40031303476923779996794876613623495515025748694978019540894726181695410095832601107261950025830235596060960914255795497479135806963313279476038687192202016132891881954743054164975707083302554941058329647014950354509055121290280892911153779672733723699997592027662953953692834215577119173225643193201177329, "\x00\x0e\x97\xf9\xd5\x79\xb9\x90\x7c\x85\x48\x49\x01\x19\x64\xfb\x76\x31\xcd\x51\xfb\x8a\x9d\x55\xe5\xd3\x7b\x87\x2d\xad\x63\x2d\x6b\x1c\x84\x3f\x65\x95\xb6\xf3\x1a\xa9\x43\x3f\x06\x46\x7b\xf8\xf3\x35\x45\x84\x11\x56\x91\x53\x43\xd7\xe1\x6d\x80\x64\x14\x45\x35\x4e\x93\x7d\x5e\x48\xec\xe0\x79\x7b\x44\x8e\xab\x0f\xc4\x5f\xc6\xa1\x71\xee\x37\xb1\x55\x51\x98\x44\x57\xe3\xc3\x56\x3a\x50\x27\xaf\xa5\x1d\x1a\x0a\x90\x19\x0d\x14\xed\x3d\x93\x40\x62\x76\xa3\xaa\x00\x23\x86\xca\x98\xb2\x6e\x02\x43\xa7\xbc\xb1\xb2\xf1")
+    , (128, 75152325976543603337003024341071663845101857195436434620947904288957274825323005869230041326941600298094896018190395352332646796347130114769768242670539699217743549573961461985255265474392937773768121046339453584830072421569334022498680626938734088755136253492360177084153487115846920446085149631919580041, "\x00\x1b\x65\xb1\x73\x74\xed\xd2\xcb\xb8\xf3\x6b\x3f\xc2\x05\xaa\x91\xab\x48\x5b\x03\x30\xae\x24\xa3\xec\x7a\x6a\xf0\x34\x73\x18\x04\xea\xe4\xd6\x19\x97\xc4\xc1\x13\x7d\x12\x0d\xd5\xcb\xbd\x18\x05\xc2\xce\x87\x66\x84\x12\xe8\x24\xa3\x31\x69\xfa\xf4\x2c\x21\x53\xa6\x04\x74\x78\xc4\x93\x0d\x38\x7f\x28\xfe\x80\x8e\xd2\x7b\x20\xc8\xf5\x1f\x0f\x73\x68\xb2\xe5\x08\xf1\x94\xa1\xe6\xcf\x3a\x2c\x12\x63\xda\x08\x3a\x78\x12\xb8\x11\x23\x3c\x38\x38\x10\x94\x2b\xac\x64\x5d\x67\x0c\xb6\x0d\xc3\x9a\x45\x39\x50\x8a\x63\x89")
+    , (128, 132094272981815297755209818914225029878347650582749561568514551350741192910991391836297682842650690115955454061006435646226436379226218676796260483719213285072886626400953065229934239690821114513313427305727000011361769875430428291375851099221794646192854831002408178061474948738788927399080262963320752452, "\x00\x30\x27\xe0\xbf\x46\xec\x77\x2d\xc6\x06\x77\xbc\x68\x87\x3c\x1b\x2e\xc7\xb7\x6c\x88\x25\xec\x8c\x95\xbf\x74\xe5\x37\x01\x25\x96\xe1\x70\x33\x5c\x7d\xab\x1f\xc2\x9c\xad\xf7\xca\x26\x85\x2d\xfc\x8f\xc7\xab\x49\x28\xa4\x47\xe6\xd5\x6e\xfa\x0a\xbb\x57\xe4\xa2\x51\xc7\xc6\x12\x0f\xa9\x98\x69\xb8\x05\x84\xc5\xe3\x28\x86\x0f\x54\x1d\xf9\x92\x42\x9f\xb1\x77\x2b\x58\x89\xe2\xfc\x22\xb0\x1e\x71\x78\xea\x39\xc1\x87\x4f\xd4\x83\x2c\x96\x1d\xea\xd5\xf9\xf9\xb9\x7b\x86\xfa\xf6\xad\x5b\xb1\x3c\xe7\x11\xd7\x96\x89\x44")
+    , (128, 577245873336454863811643140721674509319073059708446946821011267146688442860798353087462545395033001525475835015592425207995480357299993009193426638306801669333644226765032464458284920004140299209138389393494751627076239104390434285377314678827349631962212281858308570255468721491493027423799738158196939966, "\x00\xd2\x70\x41\xdb\x3d\xb5\xfe\x8c\xef\x79\xcf\x5b\x7b\x37\xb0\x05\xb8\x5a\x9b\x7d\x01\x28\xc7\xf5\x5a\x02\xba\xce\xbc\xf5\x8e\x91\x59\xd0\x42\x6f\x04\x82\x4b\x78\xb0\xdd\x91\x2e\x15\x9d\xea\x4f\x0c\x21\xc0\x67\x54\xa2\x39\xa8\xe1\x13\x8f\xa9\xff\x46\x2d\x11\x56\x04\xa0\xde\x64\xc8\x0f\xf4\x2c\xd2\x31\xdf\x2a\xfd\xac\xc7\x25\x58\xc8\xea\xfd\x47\x6e\xdd\x2a\x53\x02\x77\x49\xa7\x0d\x18\xfb\x05\x18\x4b\x28\xd3\xa2\x39\x8c\x83\x80\x90\xd1\xa8\x81\x56\x6f\xd1\x94\x9d\x65\x34\x95\x79\xc1\x27\xbc\x76\xc3\x5c\xbe")
+    ]
+
 tests = testGroup "number"
     [ testProperty "num-bits" $ \(Positive i) ->
         and [ (numBits (2^i-1) == i)
@@ -35,4 +47,11 @@
         -- to the next is quite high, as the number generated has two highest bit set.
         --
          in bits == numBits prime || (if baseBits < 64 then (bits + 1) == numBits prime else False)
-    ]
+    , testProperty "marshalling" $ \qaInt ->
+        getQAInteger qaInt == os2ip (i2osp (getQAInteger qaInt) :: Bytes)
+    , testGroup "marshalling-kat-to-bytearray" $ map toSerializationKat $ zip [katZero..] serializationVectors
+    , testGroup "marshalling-kat-to-integer" $ map toSerializationKatInteger $ zip [katZero..] serializationVectors
+    ] 
+  where
+    toSerializationKat (i, (sz, n, ba)) = testCase (show i) (ba @=? i2ospOf_ sz n)
+    toSerializationKatInteger (i, (_, n, ba)) = testCase (show i) (n @=? os2ip ba)
diff --git a/tests/Utils.hs b/tests/Utils.hs
--- a/tests/Utils.hs
+++ b/tests/Utils.hs
@@ -1,12 +1,17 @@
+{-# LANGUAGE ExistentialQuantification #-}
 module Utils where
 
+import Control.Applicative
 import Control.Monad (replicateM)
 import Data.Char
 import Data.Word
+import Data.List
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import Crypto.Random
+import Crypto.Number.Serialize (os2ip)
+import Prelude
 
 import Test.Tasty.QuickCheck
 
@@ -43,6 +48,23 @@
 instance Arbitrary Int0_2901 where
     arbitrary = Int0_2901 `fmap` choose (0,2901)
 
+-- | a integer wrapper with a better range property
+newtype QAInteger = QAInteger { getQAInteger :: Integer }
+    deriving (Show,Eq)
+
+instance Arbitrary QAInteger where
+    arbitrary = oneof
+        [ QAInteger . fromIntegral <$> (choose (0, 65536) :: Gen Int)  -- small integer
+        , larger <$> choose (0,4096) <*> choose (0, 65536) -- medium integer
+        , QAInteger . os2ip . B.pack <$> (choose (0,32) >>= \n -> replicateM n arbitrary) -- [ 0 .. 2^32 ] sized integer
+        ]
+      where
+        larger :: Int -> Int -> QAInteger
+        larger p b = QAInteger (fromIntegral p * somePrime + fromIntegral b)
+
+        somePrime :: Integer
+        somePrime = 18446744073709551557
+
 arbitraryBS :: Int -> Gen ByteString
 arbitraryBS n = B.pack `fmap` replicateM n arbitrary
 
@@ -84,7 +106,7 @@
         then
             let (b1, b2) = B.splitAt l b in
             b1 : splitB l b2
-        else    
+        else
             [ b ]
 
 assertBytesEq :: ByteString -> ByteString -> Bool
@@ -97,3 +119,26 @@
 
 propertyEq :: (Show a, Eq a) => a -> a -> Bool
 propertyEq = assertEq
+
+data PropertyTest =
+      forall a . (Show a, Eq a) => EqTest String a a
+
+type PropertyName = String
+
+eqTest :: (Show a, Eq a)
+       => PropertyName
+       -> a -- ^ expected value
+       -> a -- ^ got
+       -> PropertyTest
+eqTest name a b = EqTest name a b
+
+propertyHold :: [PropertyTest] -> Bool
+propertyHold l =
+    case foldl runProperty [] l of
+        []     -> True
+        failed -> error (intercalate "\n" failed)
+  where
+    runProperty acc (EqTest name a b)
+        | a == b    = acc
+        | otherwise =
+            (name ++ ": expected " ++ show a ++ " but got: " ++ show b) : acc
