diff --git a/Makefile.am b/Makefile.am
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,6 +41,7 @@
 noinst_HEADERS += src/field_impl.h
 noinst_HEADERS += src/bench.h
 noinst_HEADERS += contrib/lax_der_parsing.h
+noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libsecp256k1.pc
diff --git a/haskell/src/Crypto/Secp256k1.hs b/haskell/src/Crypto/Secp256k1.hs
--- a/haskell/src/Crypto/Secp256k1.hs
+++ b/haskell/src/Crypto/Secp256k1.hs
@@ -2,14 +2,12 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-|
 Module      : Crypto.Secp256k1
-Description : ECDSA on curve secp256k1
-License     : PublicDomain
-Maintainer  : root@haskoin.com
+License     : MIT
+Maintainer  : Jean-Pierre Rupp <root@haskoin.com>
 Stability   : experimental
 Portability : POSIX
 
-This module exposes crytpographic functions from Bitcoin’s secp256k1 library.
-Depends on <https://github.com/bitcoin/secp256k1 secp256k1>.
+Crytpographic functions from Bitcoin’s secp256k1 library.
 -}
 module Crypto.Secp256k1
     ( -- * Messages
@@ -22,9 +20,6 @@
     , secKey
     , getSecKey
     , derivePubKey
-    -- ** BER
-    , importSecKey
-    , exportSecKey
 
     -- * Public Keys
     , PubKey
@@ -69,19 +64,10 @@
 import           Test.QuickCheck
 import           Text.Read
 
--- | Internal public key data type.
 newtype PubKey = PubKey (ForeignPtr PubKey64)
-
--- | Internal message data type.
 newtype Msg = Msg (ForeignPtr Msg32)
-
--- | Internal signature data type.
 newtype Sig = Sig (ForeignPtr Sig64)
-
--- | Internal secret key data type.
 newtype SecKey = SecKey (ForeignPtr SecKey32)
-
--- | Internal tweak data type for addition and multiplication.
 newtype Tweak = Tweak (ForeignPtr Tweak32)
 
 decodeHex :: ConvertibleStrings a ByteString => a -> Maybe ByteString
@@ -168,7 +154,7 @@
 instance Eq Tweak where
     ft1 == ft2 = getTweak ft1 == getTweak ft2
 
--- | Create internal message data from 32-byte 'ByteString'.
+-- | Import 32-byte 'ByteString' as 'Msg'.
 msg :: ByteString -> Maybe Msg
 msg bs
     | BS.length bs == 32 = unsafePerformIO $ do
@@ -177,7 +163,7 @@
         return $ Just $ Msg fp
     | otherwise = Nothing
 
--- | Create internal secret key data from 32-byte 'ByteString'.
+-- | Import 32-byte 'ByteString' as 'SecKey'.
 secKey :: ByteString -> Maybe SecKey
 secKey bs
     | BS.length bs == 32 = unsafePerformIO $ do
@@ -191,8 +177,8 @@
     | otherwise = Nothing
 
 -- | Convert signature to a normalized lower-S form. Boolean value 'True'
--- indicates that the signature was normalized, 'False' indicates that it was
--- already normal.
+-- indicates that the signature changed, 'False' indicates that it was already
+-- normal.
 normalizeSig :: Sig -> (Sig, Bool)
 normalizeSig (Sig fg) = unsafePerformIO $ do
     fg' <- mallocForeignPtr
@@ -200,7 +186,7 @@
         ecdsaSignatureNormalize ctx pg' pg
     return (Sig fg', isSuccess ret)
 
--- | Create internal tweak data from 32-byte 'ByteString'.
+-- | 32-Byte 'ByteString' as 'Tweak'.
 tweak :: ByteString -> Maybe Tweak
 tweak bs
     | BS.length bs == 32 = unsafePerformIO $ do
@@ -213,7 +199,7 @@
 getSecKey :: SecKey -> ByteString
 getSecKey (SecKey fk) = getSecKey32 $ unsafePerformIO $ withForeignPtr fk peek
 
--- | Get 64-byte internal public key representation.
+-- Get 64-byte public key.
 getPubKey :: PubKey -> ByteString
 getPubKey (PubKey fp) = getPubKey64 $ unsafePerformIO $ withForeignPtr fp peek
 
@@ -225,14 +211,14 @@
 getTweak :: Tweak -> ByteString
 getTweak (Tweak ft) = getTweak32 $ unsafePerformIO $ withForeignPtr ft peek
 
--- | Read DER-encoded public key.
+-- | Import DER-encoded public key.
 importPubKey :: ByteString -> Maybe PubKey
 importPubKey bs = unsafePerformIO $ useByteString bs $ \(b, l) -> do
     fp <- mallocForeignPtr
     ret <- withForeignPtr fp $ \p -> ecPubKeyParse ctx p b l
     if isSuccess ret then return $ Just $ PubKey fp else return Nothing
 
--- | Encode public key as DER.  First argument 'True' for compressed output.
+-- | Encode public key as DER. First argument 'True' for compressed output.
 exportPubKey :: Bool -> PubKey -> ByteString
 exportPubKey compress (PubKey pub) = unsafePerformIO $
     withForeignPtr pub $ \p -> alloca $ \l -> allocaBytes z $ \o -> do
@@ -245,7 +231,6 @@
     c = if compress then compressed else uncompressed
     z = if compress then 33 else 65
 
--- | Get compact signature.
 exportCompactSig :: Sig -> CompactSig
 exportCompactSig (Sig fg) = unsafePerformIO $
     withForeignPtr fg $ \pg -> alloca $ \pc -> do
@@ -253,7 +238,6 @@
         unless (isSuccess ret) $ error "Could not obtain compact signature"
         peek pc
 
--- | Read compact signature.
 importCompactSig :: CompactSig -> Maybe Sig
 importCompactSig c = unsafePerformIO $ alloca $ \pc -> do
     poke pc c
@@ -261,7 +245,7 @@
     ret <- withForeignPtr fg $ \pg -> ecdsaSignatureParseCompact ctx pg pc
     if isSuccess ret then return $ Just $ Sig fg else return Nothing
 
--- | Read DER-encoded signature.
+-- | Import DER-encoded signature.
 importSig :: ByteString -> Maybe Sig
 importSig bs = unsafePerformIO $
     useByteString bs $ \(b, l) -> do
@@ -277,7 +261,7 @@
         ret <- withForeignPtr fg $ \g -> laxDerParse ctx g b l
         if isSuccess ret then return $ Just $ Sig fg else return Nothing
 
--- | Encode signature as DER.
+-- | Encode signature as strict DER.
 exportSig :: Sig -> ByteString
 exportSig (Sig fg) = unsafePerformIO $
     withForeignPtr fg $ \g -> alloca $ \l -> allocaBytes 72 $ \o -> do
@@ -293,7 +277,6 @@
     withForeignPtr fp $ \p -> withForeignPtr fg $ \g ->
         withForeignPtr fm $ \m -> isSuccess <$> ecdsaVerify ctx g m p
 
--- | Sign message using secret key.
 signMsg :: SecKey -> Msg -> Sig
 signMsg (SecKey fk) (Msg fm) = unsafePerformIO $
     withForeignPtr fk $ \k -> withForeignPtr fm $ \m -> do
@@ -302,7 +285,6 @@
         unless (isSuccess ret) $ error "could not sign message"
         return $ Sig fg
 
--- | Obtain public key from secret key.
 derivePubKey :: SecKey -> PubKey
 derivePubKey (SecKey fk) = unsafePerformIO $ withForeignPtr fk $ \k -> do
     fp <- mallocForeignPtr
@@ -310,27 +292,7 @@
     unless (isSuccess ret) $ error "could not compute public key"
     return $ PubKey fp
 
--- | Read BER-encoded secret key.
-importSecKey :: ByteString -> Maybe SecKey
-importSecKey bs = unsafePerformIO $
-    useByteString bs $ \(b, l) -> do
-        fk <- mallocForeignPtr
-        ret <- withForeignPtr fk $ \k -> ecSecKeyImport ctx k b l
-        if isSuccess ret then return $ Just $ SecKey fk else return Nothing
-
--- | Encode secret key as BER.  First argument 'True' for compressed output.
-exportSecKey :: Bool -> SecKey -> ByteString
-exportSecKey compress (SecKey fk) = unsafePerformIO $
-    withForeignPtr fk $ \k -> alloca $ \l -> allocaBytes 279 $ \o -> do
-        poke l 279
-        ret <- ecSecKeyExport ctx o l k c
-        unless (isSuccess ret) $ error "could not export secret key"
-        n <- peek l
-        packByteString (o, n)
-  where
-    c = if compress then compressed else uncompressed
-
--- | Add tweak to secret key using ECDSA addition.
+-- | Add tweak to secret key.
 tweakAddSecKey :: SecKey -> Tweak -> Maybe SecKey
 tweakAddSecKey (SecKey fk) (Tweak ft) = unsafePerformIO $
     withForeignPtr fk $ \k -> withForeignPtr ft $ \t -> do
@@ -341,7 +303,7 @@
             ecSecKeyTweakAdd ctx k' t
         if isSuccess ret then return $ Just $ SecKey fk' else return Nothing
 
--- | Multiply secret key by tweak using ECDSA multiplication.
+-- | Multiply secret key by tweak.
 tweakMulSecKey :: SecKey -> Tweak -> Maybe SecKey
 tweakMulSecKey (SecKey fk) (Tweak ft) = unsafePerformIO $
     withForeignPtr fk $ \k -> withForeignPtr ft $ \t -> do
@@ -352,8 +314,7 @@
             ecSecKeyTweakMul ctx k' t
         if isSuccess ret then return $ Just $ SecKey fk' else return Nothing
 
--- | Perform ECDSA addition between the public key point and the point obtained
--- by multiplying the tweak scalar by the curve generator.
+-- | Add tweak to public key. Tweak is multiplied first by G to obtain a point.
 tweakAddPubKey :: PubKey -> Tweak -> Maybe PubKey
 tweakAddPubKey (PubKey fp) (Tweak ft) = unsafePerformIO $
     withForeignPtr fp $ \p -> withForeignPtr ft $ \t -> do
@@ -364,8 +325,8 @@
             ecPubKeyTweakAdd ctx p' t
         if isSuccess ret then return $ Just $ PubKey fp' else return Nothing
 
--- | Perform ECDSA multiplication between the public key point and the point
--- obtained by multiplying the tweak scalar by the curve generator.
+-- | Multiply public key by tweak. Tweak is multiplied first by G to obtain a
+-- point.
 tweakMulPubKey :: PubKey -> Tweak -> Maybe PubKey
 tweakMulPubKey (PubKey fp) (Tweak ft) = unsafePerformIO $
     withForeignPtr fp $ \p -> withForeignPtr ft $ \t -> do
@@ -376,7 +337,7 @@
             ecPubKeyTweakMul ctx p' t
         if isSuccess ret then return $ Just $ PubKey fp' else return Nothing
 
--- | Add multiple public keys together using ECDSA addition.
+-- | Add multiple public keys together.
 combinePubKeys :: [PubKey] -> Maybe PubKey
 combinePubKeys pubs = unsafePerformIO $ pointers [] pubs $ \ps ->
     allocaArray (length ps) $ \a -> do
diff --git a/haskell/src/Crypto/Secp256k1/Internal.hs b/haskell/src/Crypto/Secp256k1/Internal.hs
--- a/haskell/src/Crypto/Secp256k1/Internal.hs
+++ b/haskell/src/Crypto/Secp256k1/Internal.hs
@@ -1,25 +1,23 @@
 {-|
 Module      : Crypto.Secp256k1.Internal
-Description : secp256k1 C bindings
-License     : PublicDomain
-Maintainer  : root@haskoin.com
+License     : MIT
+Maintainer  : Jean-Pierre Rupp <root@haskoin.com>
 Stability   : experimental
 Portability : POSIX
 
-The API in this module may change at any time.  This is an internal module
-only exposed for hacking and experimentation.
+The API for this module may change at any time. This is an internal module only
+exposed for hacking and experimentation.
 -}
 module Crypto.Secp256k1.Internal where
 
 import           Control.Monad
-import           Data.Binary            (Binary, get, put)
-import           Data.Binary.Get        (runGet)
-import           Data.Binary.Put        (runPut)
-import           Data.ByteString        (ByteString, packCStringLen)
-import           Data.ByteString.Lazy   (fromStrict, toStrict)
-import           Data.ByteString.Unsafe (unsafePackCStringLen,
-                                         unsafeUseAsCStringLen)
-import           Data.LargeWord         (LargeKey (LargeKey), Word256)
+import           Data.Binary          (Binary, get, put)
+import           Data.Binary.Get      (runGet)
+import           Data.Binary.Put      (runPut)
+import           Data.ByteString      (ByteString, packCStringLen,
+                                       useAsCStringLen)
+import           Data.ByteString.Lazy (fromStrict, toStrict)
+import           Data.LargeWord       (LargeKey (LargeKey), Word256)
 import           Foreign
 import           Foreign.C
 import           System.Entropy
@@ -78,23 +76,23 @@
     -> Ret
 
 verify :: CtxFlags
-verify = CtxFlags 1
+verify = CtxFlags 0x0101
 
 sign :: CtxFlags
-sign = CtxFlags 2
+sign = CtxFlags 0x0201
 
 signVerify :: CtxFlags
-signVerify = CtxFlags 3
+signVerify = CtxFlags 0x0301
 
 compressed :: SerFlags
-compressed = SerFlags 1
+compressed = SerFlags 0x0102
 
 uncompressed :: SerFlags
-uncompressed = SerFlags 0
+uncompressed = SerFlags 0x0002
 
 useByteString :: ByteString -> ((Ptr CUChar, CSize) -> IO a) -> IO a
 useByteString bs f =
-    unsafeUseAsCStringLen bs $ \(b, l) -> f (castPtr b, fromIntegral l)
+    useAsCStringLen bs $ \(b, l) -> f (castPtr b, fromIntegral l)
 
 packByteString :: (Ptr CUChar, CSize) -> IO ByteString
 packByteString (b, l) = packCStringLen (castPtr b, fromIntegral l)
@@ -116,7 +114,7 @@
 instance Storable CompactSig where
     sizeOf _ = 64
     alignment _ = 1
-    peek p = (runGet get . fromStrict) <$> unsafePackCStringLen (castPtr p, 64)
+    peek p = (runGet get . fromStrict) <$> packCStringLen (castPtr p, 64)
     poke p cs = useByteString bs $ \(b, _) -> copyArray (castPtr p) b 64 where
         bs = toStrict $ runPut $ put cs
 
@@ -319,25 +317,6 @@
     :: Ptr Ctx
     -> Ptr PubKey64
     -> Ptr SecKey32
-    -> IO Ret
-
-foreign import ccall
-    "secp256k1.h secp256k1_ec_privkey_export"
-    ecSecKeyExport
-    :: Ptr Ctx
-    -> Ptr CUChar -- ^ array to store BER-encoded key (allocate 279 bytes)
-    -> Ptr CSize -- ^ size of previous array, will be updated
-    -> Ptr SecKey32
-    -> SerFlags
-    -> IO Ret
-
-foreign import ccall
-    "secp256k1.h secp256k1_ec_privkey_import"
-    ecSecKeyImport
-    :: Ptr Ctx
-    -> Ptr SecKey32
-    -> Ptr CUChar -- ^ BER-encoded private key
-    -> CSize
     -> IO Ret
 
 foreign import ccall
diff --git a/haskell/test/Crypto/Secp256k1/Internal/Tests.hs b/haskell/test/Crypto/Secp256k1/Internal/Tests.hs
--- a/haskell/test/Crypto/Secp256k1/Internal/Tests.hs
+++ b/haskell/test/Crypto/Secp256k1/Internal/Tests.hs
@@ -39,8 +39,6 @@
     , testGroup "Secret keys"
         [ testCase "Verify secret key"        ecSecKeyVerifyTest
         , testCase "Create public key"        ecPubkeyCreateTest
-        , testCase "Serialize BER secret key" ecSecKeyExportTest
-        , testCase "Import BER secret key"    ecSecKeyImportTest
         , testCase "Tweak add secret key"     ecSecKeyTweakAddTest
         , testCase "Tweak mult. secret key"   ecSecKeyTweakMulTest
         ]
@@ -300,40 +298,6 @@
     pub = fst $ B16.decode
         "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\
         \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
-
-ecSecKeyExportTest :: Assertion
-ecSecKeyExportTest = do
-    ret <- liftIO $ alloca $ \k ->
-        allocaBytes 279 $ \o -> alloca $ \ol -> do
-            poke ol 279
-            poke k key
-            x <- signCtx
-            ecSecKeyExport x o ol k uncompressed
-    assertBool "successful secret key BER serialization" $ isSuccess ret
-  where
-    key = SecKey32 $ fst $ B16.decode
-        "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
-
-ecSecKeyImportTest :: Assertion
-ecSecKeyImportTest = do
-    (ret, dec) <- liftIO $ do
-        x <- signCtx
-        ber <- allocaBytes 279 $ \o -> alloca $ \ol -> alloca $ \k -> do
-            poke ol 279
-            poke k key
-            rets <- ecSecKeyExport x o ol k uncompressed
-            unless (isSuccess rets) $ error "failed to serialize key"
-            len <- fromIntegral <$> peek ol
-            packCStringLen (castPtr o, len)
-        useAsCStringLen ber $ \(b, bl) -> alloca $ \k -> do
-            ret <- ecSecKeyImport x k (castPtr b) (fromIntegral bl)
-            dec <- peek k
-            return (ret, dec)
-    assertBool "successful secret key BER deserialization" $ isSuccess ret
-    assertEqual "keys match" key dec
-  where
-    key = SecKey32 $ fst $ B16.decode
-        "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
 
 ecSecKeyTweakAddTest :: Assertion
 ecSecKeyTweakAddTest = do
diff --git a/haskell/test/Crypto/Secp256k1/Tests.hs b/haskell/test/Crypto/Secp256k1/Tests.hs
--- a/haskell/test/Crypto/Secp256k1/Tests.hs
+++ b/haskell/test/Crypto/Secp256k1/Tests.hs
@@ -1,10 +1,8 @@
 module Crypto.Secp256k1.Tests (tests) where
 
 import           Crypto.Secp256k1
-import qualified Data.Binary                          as Bin
 import qualified Data.ByteString.Base16               as B16
 import qualified Data.ByteString.Char8                as B8
-import qualified Data.ByteString.Lazy                 as BL
 import           Data.Maybe                           (fromJust)
 import           Data.String                          (fromString)
 import           Data.String.Conversions              (cs)
@@ -123,9 +121,9 @@
   where
     fg = signMsg fk fm
 
-serializeSecKeyTest :: (SecKey, Bool) -> Bool
-serializeSecKeyTest (fk, b) =
-    case importSecKey $ exportSecKey b fk of
+serializeSecKeyTest :: SecKey -> Bool
+serializeSecKeyTest fk =
+    case secKey $ getSecKey fk of
         Just fk' -> fk == fk'
         Nothing -> False
 
diff --git a/include/secp256k1.h b/include/secp256k1.h
--- a/include/secp256k1.h
+++ b/include/secp256k1.h
@@ -147,12 +147,23 @@
 #  define SECP256K1_ARG_NONNULL(_x)
 # endif
 
+/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
+#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
+#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
+#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
+/** The higher bits contain the actual data. Do not use directly. */
+#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
+#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
+#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
+
 /** Flags to pass to secp256k1_context_create. */
-# define SECP256K1_CONTEXT_VERIFY (1 << 0)
-# define SECP256K1_CONTEXT_SIGN   (1 << 1)
+#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
+#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
+#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
 
 /** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */
-# define SECP256K1_EC_COMPRESSED  (1 << 0)
+#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
+#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
 
 /** Create a secp256k1 context object.
  *
@@ -261,7 +272,7 @@
  *  In:   pubkey:     a pointer to a secp256k1_pubkey containing an initialized
  *                    public key.
  *        flags:      SECP256K1_EC_COMPRESSED if serialization should be in
- *                    compressed format.
+ *                    compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
  */
 SECP256K1_API int secp256k1_ec_pubkey_serialize(
     const secp256k1_context* ctx,
@@ -476,55 +487,6 @@
     const secp256k1_context* ctx,
     secp256k1_pubkey *pubkey,
     const unsigned char *seckey
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
-/** Export a private key in BER format.
- *
- *  Returns: 1 if the private key was valid.
- *  Args: ctx:        pointer to a context object, initialized for signing (cannot
- *                    be NULL)
- *  Out: privkey:     pointer to an array for storing the private key in BER.
- *                    Should have space for 279 bytes, and cannot be NULL.
- *       privkeylen:  Pointer to an int where the length of the private key in
- *                    privkey will be stored.
- *  In:  seckey:      pointer to a 32-byte secret key to export.
- *       flags:       SECP256K1_EC_COMPRESSED if the key should be exported in
- *                    compressed format.
- *
- *  This function is purely meant for compatibility with applications that
- *  require BER encoded keys. When working with secp256k1-specific code, the
- *  simple 32-byte private keys are sufficient.
- *
- *  Note that this function does not guarantee correct DER output. It is
- *  guaranteed to be parsable by secp256k1_ec_privkey_import.
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export(
-    const secp256k1_context* ctx,
-    unsigned char *privkey,
-    size_t *privkeylen,
-    const unsigned char *seckey,
-    unsigned int flags
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-
-/** Import a private key in DER format.
- * Returns: 1 if a private key was extracted.
- * Args: ctx:        pointer to a context object (cannot be NULL).
- * Out:  seckey:     pointer to a 32-byte array for storing the private key.
- *                   (cannot be NULL).
- * In:   privkey:    pointer to a private key in DER format (cannot be NULL).
- *       privkeylen: length of the DER private key pointed to be privkey.
- *
- * This function will accept more than just strict DER, and even allow some BER
- * violations. The public key stored inside the DER-encoded private key is not
- * verified for correctness, nor are the curve parameters. Use this function
- * only if you know in advance it is supposed to contain a secp256k1 private
- * key.
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import(
-    const secp256k1_context* ctx,
-    unsigned char *seckey,
-    const unsigned char *privkey,
-    size_t privkeylen
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Tweak a private key by adding tweak to it.
diff --git a/secp256k1.cabal b/secp256k1.cabal
--- a/secp256k1.cabal
+++ b/secp256k1.cabal
@@ -1,12 +1,12 @@
 name:                secp256k1
-version:             0.4.0
+version:             0.4.1
 synopsis:            secp256k1 bindings for Haskell
 description:         Please see README.md
 homepage:            http://github.com/haskoin/secp256k1#readme
 license:             MIT
 license-file:        COPYING
 author:              Pieter Wuille
-maintainer:          root@haskoin.com
+maintainer:          Jean-Pierre Rupp <root@haskoin.com>
 copyright:           (c) 2013 Pieter Wuille
 category:            Crypto
 build-type:          Custom
diff --git a/src/ecdsa.h b/src/ecdsa.h
--- a/src/ecdsa.h
+++ b/src/ecdsa.h
@@ -17,6 +17,5 @@
 static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s);
 static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
 static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
-static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid);
 
 #endif
diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h
--- a/src/ecdsa_impl.h
+++ b/src/ecdsa_impl.h
@@ -238,11 +238,11 @@
      *  secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
      */
     if (secp256k1_gej_eq_x_var(&xr, &pr)) {
-        /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */
+        /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */
         return 1;
     }
     if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
-        /* xr + p >= n, so we can skip testing the second case. */
+        /* xr + n >= p, so we can skip testing the second case. */
         return 0;
     }
     secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);
@@ -253,39 +253,6 @@
     return 0;
 }
 
-static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) {
-    unsigned char brx[32];
-    secp256k1_fe fx;
-    secp256k1_ge x;
-    secp256k1_gej xj;
-    secp256k1_scalar rn, u1, u2;
-    secp256k1_gej qj;
-
-    if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
-        return 0;
-    }
-
-    secp256k1_scalar_get_b32(brx, sigr);
-    VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */
-    if (recid & 2) {
-        if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
-            return 0;
-        }
-        secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
-    }
-    if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
-        return 0;
-    }
-    secp256k1_gej_set_ge(&xj, &x);
-    secp256k1_scalar_inverse_var(&rn, sigr);
-    secp256k1_scalar_mul(&u1, &rn, message);
-    secp256k1_scalar_negate(&u1, &u1);
-    secp256k1_scalar_mul(&u2, &rn, sigs);
-    secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
-    secp256k1_ge_set_gej_var(pubkey, &qj);
-    return !secp256k1_gej_is_infinity(&qj);
-}
-
 static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {
     unsigned char b[32];
     secp256k1_gej rp;
@@ -301,6 +268,7 @@
     secp256k1_scalar_set_b32(sigr, b, &overflow);
     if (secp256k1_scalar_is_zero(sigr)) {
         /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */
+        /* This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. */
         secp256k1_gej_clear(&rp);
         secp256k1_ge_clear(&r);
         return 0;
diff --git a/src/eckey.h b/src/eckey.h
--- a/src/eckey.h
+++ b/src/eckey.h
@@ -15,10 +15,7 @@
 #include "ecmult_gen.h"
 
 static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);
-static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, unsigned int flags);
-
-static int secp256k1_eckey_privkey_parse(secp256k1_scalar *key, const unsigned char *privkey, size_t privkeylen);
-static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context *ctx, unsigned char *privkey, size_t *privkeylen, const secp256k1_scalar *key, unsigned int flags);
+static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed);
 
 static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);
 static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
diff --git a/src/eckey_impl.h b/src/eckey_impl.h
--- a/src/eckey_impl.h
+++ b/src/eckey_impl.h
@@ -33,123 +33,20 @@
     }
 }
 
-static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, unsigned int flags) {
+static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {
     if (secp256k1_ge_is_infinity(elem)) {
         return 0;
     }
     secp256k1_fe_normalize_var(&elem->x);
     secp256k1_fe_normalize_var(&elem->y);
     secp256k1_fe_get_b32(&pub[1], &elem->x);
-    if (flags & SECP256K1_EC_COMPRESSED) {
+    if (compressed) {
         *size = 33;
         pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
     } else {
         *size = 65;
         pub[0] = 0x04;
         secp256k1_fe_get_b32(&pub[33], &elem->y);
-    }
-    return 1;
-}
-
-static int secp256k1_eckey_privkey_parse(secp256k1_scalar *key, const unsigned char *privkey, size_t privkeylen) {
-    unsigned char c[32] = {0};
-    const unsigned char *end = privkey + privkeylen;
-    int lenb = 0;
-    int len = 0;
-    int overflow = 0;
-    /* sequence header */
-    if (end < privkey+1 || *privkey != 0x30) {
-        return 0;
-    }
-    privkey++;
-    /* sequence length constructor */
-    if (end < privkey+1 || !(*privkey & 0x80)) {
-        return 0;
-    }
-    lenb = *privkey & ~0x80; privkey++;
-    if (lenb < 1 || lenb > 2) {
-        return 0;
-    }
-    if (end < privkey+lenb) {
-        return 0;
-    }
-    /* sequence length */
-    len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
-    privkey += lenb;
-    if (end < privkey+len) {
-        return 0;
-    }
-    /* sequence element 0: version number (=1) */
-    if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
-        return 0;
-    }
-    privkey += 3;
-    /* sequence element 1: octet string, up to 32 bytes */
-    if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
-        return 0;
-    }
-    memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]);
-    secp256k1_scalar_set_b32(key, c, &overflow);
-    memset(c, 0, 32);
-    return !overflow;
-}
-
-static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context *ctx, unsigned char *privkey, size_t *privkeylen, const secp256k1_scalar *key, unsigned int flags) {
-    secp256k1_gej rp;
-    secp256k1_ge r;
-    size_t pubkeylen = 0;
-    secp256k1_ecmult_gen(ctx, &rp, key);
-    secp256k1_ge_set_gej(&r, &rp);
-    if (flags & SECP256K1_EC_COMPRESSED) {
-        static const unsigned char begin[] = {
-            0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
-        };
-        static const unsigned char middle[] = {
-            0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
-            0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-            0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
-            0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
-            0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
-            0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-            0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
-            0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
-        };
-        unsigned char *ptr = privkey;
-        memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
-        secp256k1_scalar_get_b32(ptr, key); ptr += 32;
-        memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
-        if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) {
-            return 0;
-        }
-        ptr += pubkeylen;
-        *privkeylen = ptr - privkey;
-    } else {
-        static const unsigned char begin[] = {
-            0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
-        };
-        static const unsigned char middle[] = {
-            0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
-            0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-            0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
-            0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
-            0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
-            0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
-            0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
-            0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-            0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
-            0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
-        };
-        unsigned char *ptr = privkey;
-        memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
-        secp256k1_scalar_get_b32(ptr, key); ptr += 32;
-        memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
-        if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) {
-            return 0;
-        }
-        ptr += pubkeylen;
-        *privkeylen = ptr - privkey;
     }
     return 1;
 }
diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h
--- a/src/ecmult_gen_impl.h
+++ b/src/ecmult_gen_impl.h
@@ -40,8 +40,13 @@
         static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
         secp256k1_fe nums_x;
         secp256k1_ge nums_ge;
-        VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
-        VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0));
+        int r;
+        r = secp256k1_fe_set_b32(&nums_x, nums_b32);
+        (void)r;
+        VERIFY_CHECK(r);
+        r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
+        (void)r;
+        VERIFY_CHECK(r);
         secp256k1_gej_set_ge(&nums_gej, &nums_ge);
         /* Add G to make the bits in x uniformly distributed. */
         secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL);
@@ -182,7 +187,7 @@
         secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
         retry = !secp256k1_fe_set_b32(&s, nonce32);
         retry |= secp256k1_fe_is_zero(&s);
-    } while (retry);
+    } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
     /* Randomize the projection to defend against multiplier sidechannels. */
     secp256k1_gej_rescale(&ctx->initial, &s);
     secp256k1_fe_clear(&s);
@@ -191,7 +196,7 @@
         secp256k1_scalar_set_b32(&b, nonce32, &retry);
         /* A blinding value of 0 works, but would undermine the projection hardening. */
         retry |= secp256k1_scalar_is_zero(&b);
-    } while (retry);
+    } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
     secp256k1_rfc6979_hmac_sha256_finalize(&rng);
     memset(nonce32, 0, 32);
     secp256k1_ecmult_gen(ctx, &gb, &b);
diff --git a/src/field_impl.h b/src/field_impl.h
--- a/src/field_impl.h
+++ b/src/field_impl.h
@@ -224,6 +224,7 @@
         0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
     };
     unsigned char b[32];
+    int res;
     secp256k1_fe c = *a;
     secp256k1_fe_normalize_var(&c);
     secp256k1_fe_get_b32(b, &c);
@@ -231,7 +232,9 @@
     secp256k1_num_set_bin(&m, prime, 32);
     secp256k1_num_mod_inverse(&n, &n, &m);
     secp256k1_num_get_bin(b, 32, &n);
-    VERIFY_CHECK(secp256k1_fe_set_b32(r, b));
+    res = secp256k1_fe_set_b32(r, b);
+    (void)res;
+    VERIFY_CHECK(res);
     /* Verify the result is the (unique) valid inverse using non-GMP code. */
     secp256k1_fe_mul(&c, &c, r);
     secp256k1_fe_add(&c, &negone);
diff --git a/src/modules/recovery/main_impl.h b/src/modules/recovery/main_impl.h
--- a/src/modules/recovery/main_impl.h
+++ b/src/modules/recovery/main_impl.h
@@ -84,6 +84,42 @@
     return 1;
 }
 
+static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) {
+    unsigned char brx[32];
+    secp256k1_fe fx;
+    secp256k1_ge x;
+    secp256k1_gej xj;
+    secp256k1_scalar rn, u1, u2;
+    secp256k1_gej qj;
+    int r;
+
+    if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
+        return 0;
+    }
+
+    secp256k1_scalar_get_b32(brx, sigr);
+    r = secp256k1_fe_set_b32(&fx, brx);
+    (void)r;
+    VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
+    if (recid & 2) {
+        if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
+            return 0;
+        }
+        secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
+    }
+    if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
+        return 0;
+    }
+    secp256k1_gej_set_ge(&xj, &x);
+    secp256k1_scalar_inverse_var(&rn, sigr);
+    secp256k1_scalar_mul(&u1, &rn, message);
+    secp256k1_scalar_negate(&u1, &u1);
+    secp256k1_scalar_mul(&u2, &rn, sigs);
+    secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
+    secp256k1_ge_set_gej_var(pubkey, &qj);
+    return !secp256k1_gej_is_infinity(&qj);
+}
+
 int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
     secp256k1_scalar r, s;
     secp256k1_scalar sec, non, msg;
diff --git a/src/num_gmp_impl.h b/src/num_gmp_impl.h
--- a/src/num_gmp_impl.h
+++ b/src/num_gmp_impl.h
@@ -70,6 +70,7 @@
 
 static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
     mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
+    (void)c;
     VERIFY_CHECK(c == 0);
     r->limbs = a->limbs;
     while (r->limbs > 1 && r->data[r->limbs-1]==0) {
@@ -125,6 +126,7 @@
     }
     sn = NUM_LIMBS+1;
     gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
+    (void)gn;
     VERIFY_CHECK(gn == 1);
     VERIFY_CHECK(g[0] == 1);
     r->neg = a->neg ^ m->neg;
diff --git a/src/secp256k1.c b/src/secp256k1.c
--- a/src/secp256k1.c
+++ b/src/secp256k1.c
@@ -62,13 +62,20 @@
     ret->illegal_callback = default_illegal_callback;
     ret->error_callback = default_error_callback;
 
+    if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
+            secp256k1_callback_call(&ret->illegal_callback,
+                                    "Invalid flags");
+            free(ret);
+            return NULL;
+    }
+
     secp256k1_ecmult_context_init(&ret->ecmult_ctx);
     secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
 
-    if (flags & SECP256K1_CONTEXT_SIGN) {
+    if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
         secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback);
     }
-    if (flags & SECP256K1_CONTEXT_VERIFY) {
+    if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
         secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback);
     }
 
@@ -166,8 +173,9 @@
     ARG_CHECK(output != NULL);
     ARG_CHECK(outputlen != NULL);
     ARG_CHECK(pubkey != NULL);
+    ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION);
     return (secp256k1_pubkey_load(ctx, &Q, pubkey) &&
-            secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, flags));
+            secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, flags & SECP256K1_FLAGS_BIT_COMPRESSION));
 }
 
 static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) {
@@ -300,8 +308,10 @@
    /* We feed a byte array to the PRNG as input, consisting of:
     * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
     * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
-    * - optionally 16 extra bytes with the algorithm name (the extra data bytes
-    *   are set to zeroes when not present, while the algorithm name is).
+    * - optionally 16 extra bytes with the algorithm name.
+    * Because the arguments have distinct fixed lengths it is not possible for
+    *  different argument mixtures to emulate each other and result in the same
+    *  nonces.
     */
    memcpy(keydata, key32, 32);
    memcpy(keydata + 32, msg32, 32);
@@ -310,9 +320,8 @@
        keylen = 96;
    }
    if (algo16 != NULL) {
-       memset(keydata + keylen, 0, 96 - keylen);
-       memcpy(keydata + 96, algo16, 16);
-       keylen = 112;
+       memcpy(keydata + keylen, algo16, 16);
+       keylen += 16;
    }
    secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen);
    memset(keydata, 0, sizeof(keydata));
@@ -399,13 +408,13 @@
 
     secp256k1_scalar_set_b32(&sec, seckey, &overflow);
     ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec));
-    secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
-    secp256k1_ge_set_gej(&p, &pj);
-    secp256k1_pubkey_save(pubkey, &p);
-    secp256k1_scalar_clear(&sec);
-    if (!ret) {
-        memset(pubkey, 0, sizeof(*pubkey));
+    memset(pubkey, 0, sizeof(*pubkey));
+    if (ret) {
+        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
+        secp256k1_ge_set_gej(&p, &pj);
+        secp256k1_pubkey_save(pubkey, &p);
     }
+    secp256k1_scalar_clear(&sec);
     return ret;
 }
 
@@ -423,6 +432,7 @@
     secp256k1_scalar_set_b32(&sec, seckey, NULL);
 
     ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term);
+    memset(seckey, 0, 32);
     if (ret) {
         secp256k1_scalar_get_b32(seckey, &sec);
     }
@@ -443,12 +453,13 @@
     ARG_CHECK(tweak != NULL);
 
     secp256k1_scalar_set_b32(&term, tweak, &overflow);
-    if (!overflow && secp256k1_pubkey_load(ctx, &p, pubkey)) {
-        ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term);
-        if (ret) {
+    ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
+    memset(pubkey, 0, sizeof(*pubkey));
+    if (ret) {
+        if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) {
             secp256k1_pubkey_save(pubkey, &p);
         } else {
-            memset(pubkey, 0, sizeof(*pubkey));
+            ret = 0;
         }
     }
 
@@ -468,6 +479,7 @@
     secp256k1_scalar_set_b32(&factor, tweak, &overflow);
     secp256k1_scalar_set_b32(&sec, seckey, NULL);
     ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
+    memset(seckey, 0, 32);
     if (ret) {
         secp256k1_scalar_get_b32(seckey, &sec);
     }
@@ -488,45 +500,16 @@
     ARG_CHECK(tweak != NULL);
 
     secp256k1_scalar_set_b32(&factor, tweak, &overflow);
-    if (!overflow && secp256k1_pubkey_load(ctx, &p, pubkey)) {
-        ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor);
-        if (ret) {
+    ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
+    memset(pubkey, 0, sizeof(*pubkey));
+    if (ret) {
+        if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) {
             secp256k1_pubkey_save(pubkey, &p);
         } else {
-            memset(pubkey, 0, sizeof(*pubkey));
+            ret = 0;
         }
     }
 
-    return ret;
-}
-
-int secp256k1_ec_privkey_export(const secp256k1_context* ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *seckey, unsigned int flags) {
-    secp256k1_scalar key;
-    int ret = 0;
-    VERIFY_CHECK(ctx != NULL);
-    ARG_CHECK(seckey != NULL);
-    ARG_CHECK(privkey != NULL);
-    ARG_CHECK(privkeylen != NULL);
-    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
-
-    secp256k1_scalar_set_b32(&key, seckey, NULL);
-    ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, flags);
-    secp256k1_scalar_clear(&key);
-    return ret;
-}
-
-int secp256k1_ec_privkey_import(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *privkey, size_t privkeylen) {
-    secp256k1_scalar key;
-    int ret = 0;
-    ARG_CHECK(seckey != NULL);
-    ARG_CHECK(privkey != NULL);
-    (void)ctx;
-
-    ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen);
-    if (ret) {
-        secp256k1_scalar_get_b32(seckey, &key);
-    }
-    secp256k1_scalar_clear(&key);
     return ret;
 }
 
diff --git a/src/tests.c b/src/tests.c
--- a/src/tests.c
+++ b/src/tests.c
@@ -25,6 +25,7 @@
 #endif
 
 #include "contrib/lax_der_parsing.h"
+#include "contrib/lax_der_privatekey_parsing.h"
 
 #if !defined(VG_CHECK)
 # if defined(VALGRIND)
@@ -40,6 +41,22 @@
 static int count = 64;
 static secp256k1_context *ctx = NULL;
 
+static void counting_illegal_callback_fn(const char* str, void* data) {
+    /* Dummy callback function that just counts. */
+    int32_t *p;
+    (void)str;
+    p = data;
+    (*p)++;
+}
+
+static void uncounting_illegal_callback_fn(const char* str, void* data) {
+    /* Dummy callback function that just counts (backwards). */
+    int32_t *p;
+    (void)str;
+    p = data;
+    (*p)--;
+}
+
 void random_field_element_test(secp256k1_fe *fe) {
     do {
         unsigned char b32[32];
@@ -117,7 +134,12 @@
 }
 
 void run_context_tests(void) {
-    secp256k1_context *none = secp256k1_context_create(0);
+    secp256k1_pubkey pubkey;
+    secp256k1_ecdsa_signature sig;
+    unsigned char ctmp[32];
+    int32_t ecount;
+    int32_t ecount2;
+    secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
     secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
     secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
@@ -127,6 +149,13 @@
     secp256k1_scalar msg, key, nonce;
     secp256k1_scalar sigr, sigs;
 
+    ecount = 0;
+    ecount2 = 10;
+    secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2);
+    secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL);
+    CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
+
     /*** clone and destroy all of them to make sure cloning was complete ***/
     {
         secp256k1_context *ctx_tmp;
@@ -137,12 +166,54 @@
         ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp);
     }
 
+    /* Verify that the error callback makes it across the clone. */
+    CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
+    /* And that it resets back to default. */
+    secp256k1_context_set_error_callback(sign, NULL, NULL);
+    CHECK(vrfy->error_callback.fn == sign->error_callback.fn);
+
     /*** attempt to use them ***/
     random_scalar_order_test(&msg);
     random_scalar_order_test(&key);
     secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key);
     secp256k1_ge_set_gej(&pub, &pubj);
 
+    /* Verify context-type checking illegal-argument errors. */
+    memset(ctmp, 1, 32);
+    CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0);
+    CHECK(ecount == 1);
+    VG_UNDEF(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1);
+    VG_CHECK(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0);
+    CHECK(ecount == 2);
+    VG_UNDEF(&sig, sizeof(sig));
+    CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1);
+    VG_CHECK(&sig, sizeof(sig));
+    CHECK(ecount2 == 10);
+    CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0);
+    CHECK(ecount2 == 11);
+    CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0);
+    CHECK(ecount2 == 12);
+    CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0);
+    CHECK(ecount2 == 13);
+    CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
+    CHECK(ecount == 3);
+    CHECK(secp256k1_context_randomize(sign, NULL) == 1);
+    CHECK(ecount2 == 13);
+    secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
+    secp256k1_context_set_illegal_callback(sign, NULL, NULL);
+
+    /* This shouldn't leak memory, due to already-set tests. */
+    secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL);
+    secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL);
+
     /* obtain a working nonce */
     do {
         random_scalar_order_test(&nonce);
@@ -1724,6 +1795,11 @@
         test_constant_wnaf_negate(&n);
         test_constant_wnaf(&n, 4 + (i % 10));
     }
+    secp256k1_scalar_set_int(&n, 0);
+    CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1);
+    CHECK(secp256k1_scalar_is_zero(&n));
+    CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1);
+    CHECK(secp256k1_scalar_is_zero(&n));
 }
 
 void test_ecmult_constants(void) {
@@ -1836,22 +1912,6 @@
 }
 #endif
 
-static void counting_illegal_callback_fn(const char* str, void* data) {
-    /* Dummy callback function that just counts. */
-    int32_t *p;
-    (void)str;
-    p = data;
-    (*p)++;
-}
-
-static void uncounting_illegal_callback_fn(const char* str, void* data) {
-    /* Dummy callback function that just counts (backwards). */
-    int32_t *p;
-    (void)str;
-    p = data;
-    (*p)--;
-}
-
 void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) {
     unsigned char pubkeyc[65];
     secp256k1_pubkey pubkey;
@@ -1904,7 +1964,7 @@
                     VG_CHECK(&pubkey, sizeof(pubkey));
                     outl = 65;
                     VG_UNDEF(pubkeyo, 65);
-                    CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, 0) == 1);
+                    CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
                     VG_CHECK(pubkeyo, outl);
                     CHECK(outl == 65);
                     CHECK(pubkeyo[0] == 4);
@@ -2228,6 +2288,175 @@
     }
 }
 
+void run_eckey_edge_case_test(void) {
+    const unsigned char orderc[32] = {
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+        0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
+        0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
+    };
+    const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00};
+    unsigned char ctmp[32];
+    unsigned char ctmp2[32];
+    secp256k1_pubkey pubkey;
+    secp256k1_pubkey pubkey2;
+    int32_t ecount;
+    /* Group order is too large, reject. */
+    CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0);
+    VG_UNDEF(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0);
+    VG_CHECK(&pubkey, sizeof(pubkey));
+    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+    /* Maximum value is too large, reject. */
+    memset(ctmp, 255, 32);
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+    memset(&pubkey, 1, sizeof(pubkey));
+    VG_UNDEF(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
+    VG_CHECK(&pubkey, sizeof(pubkey));
+    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+    /* Zero is too small, reject. */
+    memset(ctmp, 0, 32);
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+    memset(&pubkey, 1, sizeof(pubkey));
+    VG_UNDEF(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
+    VG_CHECK(&pubkey, sizeof(pubkey));
+    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+    /* One must be accepted. */
+    ctmp[31] = 0x01;
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+    memset(&pubkey, 0, sizeof(pubkey));
+    VG_UNDEF(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);
+    VG_CHECK(&pubkey, sizeof(pubkey));
+    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+    /* Group order + 1 is too large, reject. */
+    memcpy(ctmp, orderc, 32);
+    ctmp[31] = 0x42;
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+    memset(&pubkey, 1, sizeof(pubkey));
+    VG_UNDEF(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
+    VG_CHECK(&pubkey, sizeof(pubkey));
+    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+    /* -1 must be accepted. */
+    ctmp[31] = 0x40;
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+    memset(&pubkey, 0, sizeof(pubkey));
+    VG_UNDEF(&pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);
+    VG_CHECK(&pubkey, sizeof(pubkey));
+    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+    /* Tweak of zero leaves the value changed. */
+    memset(ctmp2, 0, 32);
+    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1);
+    CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40);
+    memcpy(&pubkey2, &pubkey, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+    CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
+    /* Multiply tweak of zero zeroizes the output. */
+    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0);
+    CHECK(memcmp(zeros, ctmp, 32) == 0);
+    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0);
+    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+    memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+    /* Overflowing key tweak zeroizes. */
+    memcpy(ctmp, orderc, 32);
+    ctmp[31] = 0x40;
+    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0);
+    CHECK(memcmp(zeros, ctmp, 32) == 0);
+    memcpy(ctmp, orderc, 32);
+    ctmp[31] = 0x40;
+    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0);
+    CHECK(memcmp(zeros, ctmp, 32) == 0);
+    memcpy(ctmp, orderc, 32);
+    ctmp[31] = 0x40;
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0);
+    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+    memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0);
+    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+    memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+    /* Private key tweaks results in a key of zero. */
+    ctmp2[31] = 1;
+    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0);
+    CHECK(memcmp(zeros, ctmp2, 32) == 0);
+    ctmp2[31] = 1;
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
+    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+    memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+    /* Tweak computation wraps and results in a key of 1. */
+    ctmp2[31] = 2;
+    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1);
+    CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1);
+    ctmp2[31] = 2;
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+    ctmp2[31] = 1;
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1);
+    CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
+    /* Tweak mul * 2 = 1+1. */
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+    ctmp2[31] = 2;
+    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1);
+    CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
+    /* Test argument errors. */
+    ecount = 0;
+    secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+    CHECK(ecount == 0);
+    /* Zeroize pubkey on parse error. */
+    memset(&pubkey, 0, 32);
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
+    CHECK(ecount == 1);
+    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+    memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+    memset(&pubkey2, 0, 32);
+    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0);
+    CHECK(ecount == 2);
+    CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0);
+    /* Plain argument errors. */
+    ecount = 0;
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+    CHECK(ecount == 0);
+    CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0);
+    CHECK(ecount == 1);
+    ecount = 0;
+    memset(ctmp2, 0, 32);
+    ctmp2[31] = 4;
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0);
+    CHECK(ecount == 2);
+    ecount = 0;
+    memset(ctmp2, 0, 32);
+    ctmp2[31] = 4;
+    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0);
+    CHECK(ecount == 2);
+    ecount = 0;
+    memset(ctmp2, 0, 32);
+    CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0);
+    CHECK(ecount == 2);
+    ecount = 0;
+    memset(ctmp2, 0, 32);
+    ctmp2[31] = 1;
+    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0);
+    CHECK(ecount == 2);
+    ecount = 0;
+    CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0);
+    CHECK(ecount == 1);
+    memset(&pubkey, 1, sizeof(pubkey));
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0);
+    CHECK(ecount == 2);
+    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+    secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+}
+
 void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
     secp256k1_scalar nonce;
     do {
@@ -2346,13 +2575,13 @@
     CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
 
     /* Verify exporting and importing public key. */
-    CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1)) == 1);
+    CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED));
     memset(&pubkey, 0, sizeof(pubkey));
     CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
 
     /* Verify private key import and export. */
-    CHECK(secp256k1_ec_privkey_export(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1) ? SECP256K1_EC_COMPRESSED : 0);
-    CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1);
+    CHECK(secp256k1_ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
+    CHECK(secp256k1_ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
     CHECK(memcmp(privkey, privkey2, 32) == 0);
 
     /* Optionally tweak the keys using addition. */
@@ -2469,7 +2698,7 @@
         size_t size = len;
         firstb = in[0];
         /* If the pubkey can be parsed, it should round-trip... */
-        CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, (len == 33) ? SECP256K1_EC_COMPRESSED : 0));
+        CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33));
         CHECK(size == len);
         CHECK(memcmp(&in[1], &out[1], len-1) == 0);
         /* ... except for the type of hybrid inputs. */
@@ -2838,7 +3067,6 @@
     }
 }
 
-
 /* Tests several edge cases. */
 void test_ecdsa_edge_cases(void) {
     int t;
@@ -2860,11 +3088,159 @@
         CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
     }
 
-    /*Signature where s would be zero.*/
+    /* Verify signature with r of zero fails. */
     {
-        unsigned char signature[72];
+        const unsigned char pubkey_mods_zero[33] = {
+            0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0,
+            0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41,
+            0x41
+        };
+        secp256k1_ge key;
+        secp256k1_scalar msg;
+        secp256k1_scalar sr, ss;
+        secp256k1_scalar_set_int(&ss, 1);
+        secp256k1_scalar_set_int(&msg, 0);
+        secp256k1_scalar_set_int(&sr, 0);
+        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33));
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+    }
+
+    /* Verify signature with s of zero fails. */
+    {
+        const unsigned char pubkey[33] = {
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x01
+        };
+        secp256k1_ge key;
+        secp256k1_scalar msg;
+        secp256k1_scalar sr, ss;
+        secp256k1_scalar_set_int(&ss, 0);
+        secp256k1_scalar_set_int(&msg, 0);
+        secp256k1_scalar_set_int(&sr, 1);
+        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+    }
+
+    /* Verify signature with message 0 passes. */
+    {
+        const unsigned char pubkey[33] = {
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x02
+        };
+        const unsigned char pubkey2[33] = {
+            0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0,
+            0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41,
+            0x43
+        };
+        secp256k1_ge key;
+        secp256k1_ge key2;
+        secp256k1_scalar msg;
+        secp256k1_scalar sr, ss;
+        secp256k1_scalar_set_int(&ss, 2);
+        secp256k1_scalar_set_int(&msg, 0);
+        secp256k1_scalar_set_int(&sr, 2);
+        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+        CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33));
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+        secp256k1_scalar_negate(&ss, &ss);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+        secp256k1_scalar_set_int(&ss, 1);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0);
+    }
+
+    /* Verify signature with message 1 passes. */
+    {
+        const unsigned char pubkey[33] = {
+            0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22,
+            0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05,
+            0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c,
+            0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76,
+            0x25
+        };
+        const unsigned char pubkey2[33] = {
+            0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40,
+            0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae,
+            0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f,
+            0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10,
+            0x62
+        };
+        const unsigned char csr[32] = {
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,
+            0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb
+        };
+        secp256k1_ge key;
+        secp256k1_ge key2;
+        secp256k1_scalar msg;
+        secp256k1_scalar sr, ss;
+        secp256k1_scalar_set_int(&ss, 1);
+        secp256k1_scalar_set_int(&msg, 1);
+        secp256k1_scalar_set_b32(&sr, csr, NULL);
+        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+        CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33));
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+        secp256k1_scalar_negate(&ss, &ss);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+        secp256k1_scalar_set_int(&ss, 2);
+        secp256k1_scalar_inverse_var(&ss, &ss);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0);
+    }
+
+    /* Verify signature with message -1 passes. */
+    {
+        const unsigned char pubkey[33] = {
+            0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0,
+            0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52,
+            0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27,
+            0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20,
+            0xf1
+        };
+        const unsigned char csr[32] = {
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,
+            0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee
+        };
+        secp256k1_ge key;
+        secp256k1_scalar msg;
+        secp256k1_scalar sr, ss;
+        secp256k1_scalar_set_int(&ss, 1);
+        secp256k1_scalar_set_int(&msg, 1);
+        secp256k1_scalar_negate(&msg, &msg);
+        secp256k1_scalar_set_b32(&sr, csr, NULL);
+        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+        secp256k1_scalar_negate(&ss, &ss);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+        secp256k1_scalar_set_int(&ss, 3);
+        secp256k1_scalar_inverse_var(&ss, &ss);
+        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+    }
+
+    /* Signature where s would be zero. */
+    {
+        secp256k1_pubkey pubkey;
         size_t siglen;
-        const unsigned char nonce[32] = {
+        int32_t ecount;
+        unsigned char signature[72];
+        static const unsigned char nonce[32] = {
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -2888,15 +3264,40 @@
             0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,
             0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
         };
+        ecount = 0;
+        secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
         CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0);
         CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0);
         msg[31] = 0xaa;
         CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1);
+        CHECK(ecount == 0);
+        CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0);
+        CHECK(ecount == 1);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0);
+        CHECK(ecount == 2);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0);
+        CHECK(ecount == 3);
         CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1);
+        CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0);
+        CHECK(ecount == 4);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0);
+        CHECK(ecount == 5);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0);
+        CHECK(ecount == 6);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1);
         siglen = 72;
+        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0);
+        CHECK(ecount == 7);
+        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0);
+        CHECK(ecount == 8);
+        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0);
+        CHECK(ecount == 9);
         CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);
         siglen = 10;
         CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0);
+        CHECK(ecount == 9);
+        secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
     }
 
     /* Nonce function corner cases. */
@@ -2960,6 +3361,34 @@
         key[0] = 0;
     }
 
+    {
+        /* Check that optional nonce arguments do not have equivilent effect. */
+        const unsigned char zeros[32] = {0};
+        unsigned char nonce[32];
+        unsigned char nonce2[32];
+        unsigned char nonce3[32];
+        unsigned char nonce4[32];
+        VG_UNDEF(nonce,32);
+        VG_UNDEF(nonce2,32);
+        VG_UNDEF(nonce3,32);
+        VG_UNDEF(nonce4,32);
+        CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1);
+        VG_CHECK(nonce,32);
+        CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1);
+        VG_CHECK(nonce2,32);
+        CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1);
+        VG_CHECK(nonce3,32);
+        CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1);
+        VG_CHECK(nonce4,32);
+        CHECK(memcmp(nonce, nonce2, 32) != 0);
+        CHECK(memcmp(nonce, nonce3, 32) != 0);
+        CHECK(memcmp(nonce, nonce4, 32) != 0);
+        CHECK(memcmp(nonce2, nonce3, 32) != 0);
+        CHECK(memcmp(nonce2, nonce4, 32) != 0);
+        CHECK(memcmp(nonce3, nonce4, 32) != 0);
+    }
+
+
     /* Privkey export where pubkey is the point at infinity. */
     {
         unsigned char privkey[300];
@@ -2970,9 +3399,9 @@
             0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
         };
         size_t outlen = 300;
-        CHECK(!secp256k1_ec_privkey_export(ctx, privkey, &outlen, seckey, 0));
+        CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0));
         outlen = 300;
-        CHECK(!secp256k1_ec_privkey_export(ctx, privkey, &outlen, seckey, SECP256K1_EC_COMPRESSED));
+        CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1));
     }
 }
 
@@ -2987,7 +3416,7 @@
     const unsigned char* pbegin = privkey;
     int compr = secp256k1_rand_bits(1);
     EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
-    CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr ? SECP256K1_EC_COMPRESSED : 0));
+    CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr));
     CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
     CHECK(EC_KEY_check_key(ec_key));
     return ec_key;
@@ -3137,8 +3566,11 @@
     run_endomorphism_tests();
 #endif
 
-    /* EC point parser test*/
+    /* EC point parser test */
     run_ec_pubkey_parse_test();
+
+    /* EC key edge cases */
+    run_eckey_edge_case_test();
 
 #ifdef ENABLE_MODULE_ECDH
     /* ecdh tests */
