secp256k1 0.4.0 → 0.4.1
raw patch · 17 files changed
+612/−425 lines, 17 files
Files
- Makefile.am +1/−0
- haskell/src/Crypto/Secp256k1.hs +19/−58
- haskell/src/Crypto/Secp256k1/Internal.hs +18/−39
- haskell/test/Crypto/Secp256k1/Internal/Tests.hs +0/−36
- haskell/test/Crypto/Secp256k1/Tests.hs +3/−5
- include/secp256k1.h +15/−53
- secp256k1.cabal +2/−2
- src/ecdsa.h +0/−1
- src/ecdsa_impl.h +3/−35
- src/eckey.h +1/−4
- src/eckey_impl.h +2/−105
- src/ecmult_gen_impl.h +9/−4
- src/field_impl.h +4/−1
- src/modules/recovery/main_impl.h +36/−0
- src/num_gmp_impl.h +2/−0
- src/secp256k1.c +35/−52
- src/tests.c +462/−30
Makefile.am view
@@ -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
haskell/src/Crypto/Secp256k1.hs view
@@ -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
haskell/src/Crypto/Secp256k1/Internal.hs view
@@ -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
haskell/test/Crypto/Secp256k1/Internal/Tests.hs view
@@ -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
haskell/test/Crypto/Secp256k1/Tests.hs view
@@ -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
include/secp256k1.h view
@@ -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.
secp256k1.cabal view
@@ -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
src/ecdsa.h view
@@ -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
src/ecdsa_impl.h view
@@ -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;
src/eckey.h view
@@ -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);
src/eckey_impl.h view
@@ -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; }
src/ecmult_gen_impl.h view
@@ -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);
src/field_impl.h view
@@ -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);
src/modules/recovery/main_impl.h view
@@ -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;
src/num_gmp_impl.h view
@@ -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;
src/secp256k1.c view
@@ -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; }
src/tests.c view
@@ -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 */