Merge pull request #295
authorPieter Wuille <pieter.wuille@gmail.com>
Sat, 19 Sep 2015 19:24:29 +0000 (21:24 +0200)
committerPieter Wuille <pieter.wuille@gmail.com>
Sat, 19 Sep 2015 19:24:31 +0000 (21:24 +0200)
c996d53 Print success (Pieter Wuille)

20 files changed:
.travis.yml
Makefile.am
build-aux/m4/bitcoin_secp.m4
configure.ac
include/secp256k1.h
include/secp256k1_ecdh.h
include/secp256k1_recovery.h [new file with mode: 0644]
include/secp256k1_schnorr.h
src/bench_recover.c
src/bench_schnorr_verify.c
src/bench_sign.c
src/bench_verify.c
src/field_5x52_impl.h
src/modules/recovery/Makefile.am.include [new file with mode: 0644]
src/modules/recovery/main_impl.h [new file with mode: 0644]
src/modules/recovery/tests_impl.h [new file with mode: 0644]
src/modules/schnorr/main_impl.h
src/modules/schnorr/tests_impl.h
src/secp256k1.c
src/tests.c

index 0e1c8f96c9ec602a37a0af32c55e341e3573540c..fba0892ddb7e205edf7ac4151ac637f76786e1b7 100644 (file)
@@ -8,12 +8,12 @@ compiler:
   - gcc
 env:
   global:
-    - FIELD=auto  BIGNUM=auto  SCALAR=auto  ENDOMORPHISM=no  STATICPRECOMPUTATION=yes  ASM=no  BUILD=check  EXTRAFLAGS=  HOST=  ECDH=no  schnorr=NO
+    - FIELD=auto  BIGNUM=auto  SCALAR=auto  ENDOMORPHISM=no  STATICPRECOMPUTATION=yes  ASM=no  BUILD=check  EXTRAFLAGS=  HOST=  ECDH=no  schnorr=NO  RECOVERY=NO
   matrix:
-    - SCALAR=32bit
+    - SCALAR=32bit    RECOVERY=yes
     - SCALAR=32bit    FIELD=32bit       ECDH=yes
     - SCALAR=64bit
-    - FIELD=64bit
+    - FIELD=64bit     RECOVERY=yes
     - FIELD=64bit     ENDOMORPHISM=yes
     - FIELD=64bit     ENDOMORPHISM=yes  ECDH=yes
     - FIELD=64bit                       ASM=x86_64
@@ -21,7 +21,7 @@ env:
     - FIELD=32bit     SCHNORR=yes
     - FIELD=32bit     ENDOMORPHISM=yes
     - BIGNUM=no
-    - BIGNUM=no       ENDOMORPHISM=yes SCHNORR=yes
+    - BIGNUM=no       ENDOMORPHISM=yes SCHNORR=yes  RECOVERY=yes
     - BIGNUM=no       STATICPRECOMPUTATION=no
     - BUILD=distcheck
     - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC
index 060a51af4b69045628315a318b0cfcf32495dd22..57524fab057671a6c66a2669eb0d03f1d46fe39e 100644 (file)
@@ -51,13 +51,10 @@ libsecp256k1_la_LIBADD = $(SECP_LIBS)
 
 noinst_PROGRAMS =
 if USE_BENCHMARK
-noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal
+noinst_PROGRAMS += bench_verify bench_sign bench_internal
 bench_verify_SOURCES = src/bench_verify.c
 bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
 bench_verify_LDFLAGS = -static
-bench_recover_SOURCES = src/bench_recover.c
-bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
-bench_recover_LDFLAGS = -static
 bench_sign_SOURCES = src/bench_sign.c
 bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
 bench_sign_LDFLAGS = -static
@@ -90,6 +87,7 @@ $(gen_context_BIN): $(gen_context_OBJECTS)
 
 $(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
 $(tests_OBJECTS): src/ecmult_static_context.h
+$(bench_internal_OBJECTS): src/ecmult_static_context.h
 
 src/ecmult_static_context.h: $(gen_context_BIN)
        ./$(gen_context_BIN)
@@ -106,3 +104,7 @@ endif
 if ENABLE_MODULE_SCHNORR
 include src/modules/schnorr/Makefile.am.include
 endif
+
+if ENABLE_MODULE_RECOVERY
+include src/modules/recovery/Makefile.am.include
+endif
index 4a398d6c93a58745e16959ba3b237a282fc4aa5b..d41bbb648708ba06cd0285d96b66ca532348e1e8 100644 (file)
@@ -16,8 +16,7 @@ AC_MSG_RESULT([$has_64bit_asm])
 
 dnl
 AC_DEFUN([SECP_OPENSSL_CHECK],[
-if test x"$use_pkgconfig" = x"yes"; then
-    : #NOP
+  has_libcrypto=no
   m4_ifdef([PKG_CHECK_MODULES],[
     PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no])
     if test x"$has_libcrypto" = x"yes"; then
@@ -27,11 +26,16 @@ if test x"$use_pkgconfig" = x"yes"; then
       LIBS="$TEMP_LIBS"
     fi
   ])
-else
-  AC_CHECK_HEADER(openssl/crypto.h,[AC_CHECK_LIB(crypto, main,[has_libcrypto=yes; CRYPTO_LIBS=-lcrypto; AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])]
-)])
-  LIBS=
-fi
+  if test x$has_libcrypto = xno; then
+    AC_CHECK_HEADER(openssl/crypto.h,[
+      AC_CHECK_LIB(crypto, main,[
+        has_libcrypto=yes
+        CRYPTO_LIBS=-lcrypto
+        AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])
+      ])
+    ])
+    LIBS=
+  fi
 if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
   AC_MSG_CHECKING(for EC functions in libcrypto)
   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
index 0dc83eea390265c9f655101486d018f5bc4a937f..3908e2f5c7fa277d436d16f81b30dd2150abd5b5 100644 (file)
@@ -30,15 +30,6 @@ if test x"$ac_cv_prog_cc_c89" = x"no"; then
   AC_MSG_ERROR([c89 compiler support required])
 fi
 
-case $host in
-  *mingw*)
-     use_pkgconfig=no
-     ;;
-   *)
-     use_pkgconfig=yes
-     ;;
-esac
-
 case $host_os in
   *darwin*)
      if  test x$cross_compiling != xyes; then
@@ -114,6 +105,11 @@ AC_ARG_ENABLE(module_schnorr,
     [enable_module_schnorr=$enableval],
     [enable_module_schnorr=no])
 
+AC_ARG_ENABLE(module_recovery,
+    AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
+    [enable_module_recovery=$enableval],
+    [enable_module_recovery=no])
+
 AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
 [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
 
@@ -335,6 +331,10 @@ if test x"$enable_module_schnorr" = x"yes"; then
   AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module])
 fi
 
+if test x"$enable_module_recovery" = x"yes"; then
+  AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
+fi
+
 AC_C_BIGENDIAN()
 
 AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
@@ -345,6 +345,7 @@ AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
 AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
 
 AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
+AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
 
 AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
 AC_CONFIG_FILES([Makefile libsecp256k1.pc])
@@ -357,6 +358,7 @@ AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
 AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"])
 AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
 AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
 
 dnl make sure nothing new is exported so that we don't break the cache
 PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
index 4fbd15f84fb4d02108f91743788e57b125736027..a287f89401442a6bae3136f76bdff43ec6d8d6a2 100644 (file)
@@ -5,6 +5,21 @@
 extern "C" {
 # endif
 
+/* These rules specify the order of arguments in API calls:
+ *
+ * 1. Context pointers go first, followed by output arguments, combined
+ *    output/input arguments, and finally input-only arguments.
+ * 2. Array lengths always immediately the follow the argument whose length
+ *    they describe, even if this violates rule 1.
+ * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
+ *    later go first. This means: signatures, public nonces, private nonces,
+ *    messages, public keys, secret keys, tweaks.
+ * 4. Arguments that are not data pointers go last, from more complex to less
+ *    complex: function pointers, algorithm names, messages, void pointers,
+ *    counts, flags, booleans.
+ * 5. Opaque data pointers follow the function pointer they are to be passed to.
+ */
+
 /** Opaque data structure that holds context information (precomputed tables etc.).
  *
  *  The purpose of context structures is to cache large precomputed data tables
@@ -40,36 +55,34 @@ typedef struct {
     unsigned char data[64];
 } secp256k1_pubkey_t;
 
-/** Opaque data structured that holds a parsed ECDSA signature, optionally
- *  supporting pubkey recovery.
+/** Opaque data structured that holds a parsed ECDSA signature.
  *
  *  The exact representation of data inside is implementation defined and not
  *  guaranteed to be portable between different platforms or versions. It is
- *  however guaranteed to be 65 bytes in size, and can be safely copied/moved.
+ *  however guaranteed to be 64 bytes in size, and can be safely copied/moved.
  *  If you need to convert to a format suitable for storage or transmission, use
  *  the secp256k1_ecdsa_signature_serialize_* and
  *  secp256k1_ecdsa_signature_serialize_* functions.
  *
- *  Furthermore, it is guaranteed to identical signatures (including their
- *  recoverability) will have identical representation, so they can be
- *  memcmp'ed.
+ *  Furthermore, it is guaranteed to identical signatures will have identical
+ *  representation, so they can be memcmp'ed.
  */
 typedef struct {
-    unsigned char data[65];
+    unsigned char data[64];
 } secp256k1_ecdsa_signature_t;
 
 /** A pointer to a function to deterministically generate a nonce.
  *
  * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
+ * Out:     nonce32:   pointer to a 32-byte array to be filled by the function.
  * In:      msg32:     the 32-byte message hash being verified (will not be NULL)
  *          key32:     pointer to a 32-byte secret key (will not be NULL)
  *          algo16:    pointer to a 16-byte array describing the signature
  *                     algorithm (will be NULL for ECDSA for compatibility).
+ *          data:      Arbitrary data pointer that is passed through.
  *          attempt:   how many iterations we have tried to find a nonce.
  *                     This will almost always be 0, but different attempt values
  *                     are required to result in a different nonce.
- *          data:      Arbitrary data pointer that is passed through.
- * Out:     nonce32:   pointer to a 32-byte array to be filled by the function.
  *
  * Except for test cases, this function should compute some cryptographic hash of
  * the message, the algorithm, the key and the attempt.
@@ -79,8 +92,8 @@ typedef int (*secp256k1_nonce_function_t)(
     const unsigned char *msg32,
     const unsigned char *key32,
     const unsigned char *algo16,
-    unsigned int attempt,
-    const void *data
+    const void *data,
+    unsigned int attempt
 );
 
 # if !defined(SECP256K1_GNUC_PREREQ)
@@ -134,7 +147,7 @@ secp256k1_context_t* secp256k1_context_create(
 /** Copies a secp256k1 context object.
  *
  *  Returns: a newly created context object.
- *  In:      ctx: an existing context to copy (cannot be NULL)
+ *  Args:    ctx: an existing context to copy (cannot be NULL)
  */
 secp256k1_context_t* secp256k1_context_clone(
     const secp256k1_context_t* ctx
@@ -143,7 +156,7 @@ secp256k1_context_t* secp256k1_context_clone(
 /** Destroy a secp256k1 context object.
  *
  *  The context pointer may not be used afterwards.
- *  In:     ctx: an existing context to destroy (cannot be NULL)
+ *  Args:   ctx: an existing context to destroy (cannot be NULL)
  */
 void secp256k1_context_destroy(
     secp256k1_context_t* ctx
@@ -163,10 +176,10 @@ void secp256k1_context_destroy(
  *  to cause a crash, though its return value and output arguments are
  *  undefined.
  *
- *  In:   ctx: an existing context object (cannot be NULL)
- *        fun: a pointer to a function to call when an illegal argument is
- *             passed to the API, taking a message and an opaque pointer
- *             (cannot be NULL).
+ *  Args: ctx:  an existing context object (cannot be NULL)
+ *  In:   fun:  a pointer to a function to call when an illegal argument is
+ *              passed to the API, taking a message and an opaque pointer
+ *              (cannot be NULL).
  *        data: the opaque pointer to pass to fun above.
  */
 void secp256k1_context_set_illegal_callback(
@@ -185,9 +198,9 @@ void secp256k1_context_set_illegal_callback(
  *  for that). After this callback returns, anything may happen, including
  *  crashing.
  *
- *  In:   ctx: an existing context object (cannot be NULL)
- *        fun: a pointer to a function to call when an interal error occurs,
- *             taking a message and an opaque pointer (cannot be NULL).
+ *  Args: ctx:  an existing context object (cannot be NULL)
+ *  In:   fun:  a pointer to a function to call when an interal error occurs,
+ *              taking a message and an opaque pointer (cannot be NULL).
  *        data: the opaque pointer to pass to fun above.
  */
 void secp256k1_context_set_error_callback(
@@ -200,11 +213,11 @@ void secp256k1_context_set_error_callback(
  *
  *  Returns: 1 if the public key was fully valid.
  *           0 if the public key could not be parsed or is invalid.
- *  In:  ctx:      a secp256k1 context object.
- *       input:    pointer to a serialized public key
- *       inputlen: length of the array pointed to by input
- *  Out: pubkey:   pointer to a pubkey object. If 1 is returned, it is set to a
- *                 parsed version of input. If not, its value is undefined.
+ *  Args: ctx:      a secp256k1 context object.
+ *  Out:  pubkey:   pointer to a pubkey object. If 1 is returned, it is set to a
+ *                  parsed version of input. If not, its value is undefined.
+ *  In:   input:    pointer to a serialized public key
+ *        inputlen: length of the array pointed to by input
  *
  *  This function supports parsing compressed (33 bytes, header byte 0x02 or
  *  0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header
@@ -220,14 +233,14 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
 /** Serialize a pubkey object into a serialized byte sequence.
  *
  *  Returns: 1 always.
- *  In:   ctx:        a secp256k1 context object.
- *        pubkey:     a pointer to a secp256k1_pubkey_t containing an initialized
- *                    public key.
- *        compressed: whether to serialize in compressed format.
+ *  Args: ctx:        a secp256k1 context object.
  *  Out:  output:     a pointer to a 65-byte (if compressed==0) or 33-byte (if
  *                    compressed==1) byte array to place the serialized key in.
  *        outputlen:  a pointer to an integer which will contain the serialized
  *                    size.
+ *  In:   pubkey:     a pointer to a secp256k1_pubkey_t containing an initialized
+ *                    public key.
+ *        compressed: whether to serialize in compressed format.
  */
 int secp256k1_ec_pubkey_serialize(
     const secp256k1_context_t* ctx,
@@ -240,14 +253,12 @@ int secp256k1_ec_pubkey_serialize(
 /** Parse a DER ECDSA signature.
  *
  *  Returns: 1 when the signature could be parsed, 0 otherwise.
- *  In:  ctx:      a secp256k1 context object
- *       input:    a pointer to the signature to be parsed
- *       inputlen: the length of the array pointed to be input
- *  Out: sig:      a pointer to a signature object
+ *  Args: ctx:      a secp256k1 context object
+ *  Out:  sig:      a pointer to a signature object
+ *  In:   input:    a pointer to the signature to be parsed
+ *        inputlen: the length of the array pointed to be input
  *
  *  Note that this function also supports some violations of DER and even BER.
- *
- *  The resulting signature object will not support pubkey recovery.
  */
 int secp256k1_ecdsa_signature_parse_der(
     const secp256k1_context_t* ctx,
@@ -256,34 +267,16 @@ int secp256k1_ecdsa_signature_parse_der(
     int inputlen
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
-/** Parse a compact ECDSA signature (64 bytes + recovery id).
- *
- *  Returns: 1 when the signature could be parsed, 0 otherwise
- *  In:  ctx:     a secp256k1 context object
- *       input64: a pointer to a 64-byte compact signature
- *       recid:   the recovery id (0, 1, 2 or 3, or -1 for unknown)
- *  Out: sig:     a pointer to a signature object
- *
- *  If recid is not -1, the resulting signature object will support pubkey
- *  recovery.
- */
-int secp256k1_ecdsa_signature_parse_compact(
-    const secp256k1_context_t* ctx,
-    secp256k1_ecdsa_signature_t* sig,
-    const unsigned char *input64,
-    int recid
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
 /** Serialize an ECDSA signature in DER format.
  *
  *  Returns: 1 if enough space was available to serialize, 0 otherwise
- *  In:     ctx:       a secp256k1 context object
- *          sig:       a pointer to an initialized signature object
+ *  Args:   ctx:       a secp256k1 context object
  *  Out:    output:    a pointer to an array to store the DER serialization
  *  In/Out: outputlen: a pointer to a length integer. Initially, this integer
  *                     should be set to the length of output. After the call
  *                     it will be set to the length of the serialization (even
  *                     if 0 was returned).
+ *  In:     sig:       a pointer to an initialized signature object
  */
 int secp256k1_ecdsa_signature_serialize_der(
     const secp256k1_context_t* ctx,
@@ -292,36 +285,19 @@ int secp256k1_ecdsa_signature_serialize_der(
     const secp256k1_ecdsa_signature_t* sig
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
 
-/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
- *
- *  Returns: 1
- *  In: ctx:       a secp256k1 context object
- *      sig:       a pointer to an initialized signature object (cannot be NULL)
- *  Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL)
- *       recid:    a pointer to an integer to hold the recovery id (can be NULL).
- *
- *  If recid is not NULL, the signature must support pubkey recovery.
- */
-int secp256k1_ecdsa_signature_serialize_compact(
-    const secp256k1_context_t* ctx,
-    unsigned char *output64,
-    int *recid,
-    const secp256k1_ecdsa_signature_t* sig
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
-
 /** Verify an ECDSA signature.
  *
  *  Returns: 1: correct signature
  *           0: incorrect or unparseable signature
- * In:       ctx:       a secp256k1 context object, initialized for verification.
+ *  Args:    ctx:       a secp256k1 context object, initialized for verification.
+ *  In:      sig:       the signature being verified (cannot be NULL)
  *           msg32:     the 32-byte message hash being verified (cannot be NULL)
- *           sig:       the signature being verified (cannot be NULL)
  *           pubkey:    pointer to an initialized public key to verify with (cannot be NULL)
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
     const secp256k1_context_t* ctx,
-    const unsigned char *msg32,
     const secp256k1_ecdsa_signature_t *sig,
+    const unsigned char *msg32,
     const secp256k1_pubkey_t *pubkey
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
 
@@ -338,14 +314,12 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
  *
  *  Returns: 1: signature created
  *           0: the nonce generation function failed, or the private key was invalid.
- *  In:      ctx:    pointer to a context object, initialized for signing (cannot be NULL)
- *           msg32:  the 32-byte message hash being signed (cannot be NULL)
+ *  Args:    ctx:    pointer to a context object, initialized for signing (cannot be NULL)
+ *  Out:     sig:    pointer to an array where the signature will be placed (cannot be NULL)
+ *  In:      msg32:  the 32-byte message hash being signed (cannot be NULL)
  *           seckey: pointer to a 32-byte secret key (cannot be NULL)
  *           noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
  *           ndata:  pointer to arbitrary data used by the nonce generation function (can be NULL)
- *  Out:     sig:    pointer to an array where the signature will be placed (cannot be NULL)
- *
- * The resulting signature will support pubkey recovery.
  *
  * The sig always has an s value in the lower half of the range (From 0x1
  * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
@@ -376,35 +350,19 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
  */
 int secp256k1_ecdsa_sign(
     const secp256k1_context_t* ctx,
-    const unsigned char *msg32,
     secp256k1_ecdsa_signature_t *sig,
+    const unsigned char *msg32,
     const unsigned char *seckey,
     secp256k1_nonce_function_t noncefp,
     const void *ndata
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
 
-/** Recover an ECDSA public key from a signature.
- *
- *  Returns: 1: public key successfully recovered (which guarantees a correct signature).
- *           0: otherwise.
- *  In:      ctx:        pointer to a context object, initialized for verification (cannot be NULL)
- *           msg32:      the 32-byte message hash assumed to be signed (cannot be NULL)
- *           sig:        pointer to initialized signature that supports pubkey recovery (cannot be NULL)
- *  Out:     pubkey:     pointer to the recoved public key (cannot be NULL)
- */
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
-    const secp256k1_context_t* ctx,
-    const unsigned char *msg32,
-    const secp256k1_ecdsa_signature_t *sig,
-    secp256k1_pubkey_t *pubkey
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-
 /** Verify an ECDSA secret key.
  *
  *  Returns: 1: secret key is valid
  *           0: secret key is invalid
- *  In:      ctx: pointer to a context object (cannot be NULL)
- *           seckey: pointer to a 32-byte secret key (cannot be NULL)
+ *  Args:    ctx: pointer to a context object (cannot be NULL)
+ *  In:      seckey: pointer to a 32-byte secret key (cannot be NULL)
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
     const secp256k1_context_t* ctx,
@@ -413,11 +371,11 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
 
 /** Compute the public key for a secret key.
  *
- *  In:     ctx:        pointer to a context object, initialized for signing (cannot be NULL)
- *          seckey:     pointer to a 32-byte private key (cannot be NULL)
- *  Out:    pubkey:     pointer to the created public key (cannot be NULL)
  *  Returns: 1: secret was valid, public key stores
  *           0: secret was invalid, try again
+ *  Args:   ctx:        pointer to a context object, initialized for signing (cannot be NULL)
+ *  Out:    pubkey:     pointer to the created public key (cannot be NULL)
+ *  In:     seckey:     pointer to a 32-byte private key (cannot be NULL)
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
     const secp256k1_context_t* ctx,
@@ -427,15 +385,15 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
 
 /** Export a private key in BER format.
  *
- *  In: ctx:         pointer to a context object, initialized for signing (cannot
- *                   be NULL)
- *      seckey:      pointer to a 32-byte secret key to export.
- *      compressed:  whether the key should be exported in compressed format.
- *  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.
  *  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.
+ *       compressed:  whether 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
@@ -446,19 +404,19 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export(
     const secp256k1_context_t* ctx,
-    const unsigned char *seckey,
     unsigned char *privkey,
     int *privkeylen,
+    const unsigned char *seckey,
     int compressed
 ) 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.
- * In:  ctx:        pointer to a context object (cannot be NULL).
- *      privkey:    pointer to a private key in DER format (cannot be NULL).
- *      privkeylen: length of the DER private key pointed to be privkey.
- * Out: seckey:     pointer to a 32-byte array for storing the private key.
- *                  (cannot be NULL).
+ * 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
@@ -474,13 +432,13 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Tweak a private key by adding tweak to it.
- * In:     ctx:    pointer to a context object (cannot be NULL).
- *         tweak:  pointer to a 32-byte tweak.
- * In/Out: seckey: pointer to a 32-byte private key.
  * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
  *          uniformly random 32-byte arrays, or if the resulting private key
  *          would be invalid (only when the tweak is the complement of the
  *          private key). 1 otherwise.
+ * Args:    ctx:    pointer to a context object (cannot be NULL).
+ * In/Out:  seckey: pointer to a 32-byte private key.
+ * In:      tweak:  pointer to a 32-byte tweak.
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
     const secp256k1_context_t* ctx,
@@ -489,14 +447,14 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Tweak a public key by adding tweak times the generator to it.
- * In:     ctx:    pointer to a context object initialized for validation
- *                 (cannot be NULL).
- *         tweak:  pointer to a 32-byte tweak.
- * In/Out: pubkey: pointer to a public key object.
  * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
  *          uniformly random 32-byte arrays, or if the resulting public key
  *          would be invalid (only when the tweak is the complement of the
  *          corresponding private key). 1 otherwise.
+ * Args:    ctx:    pointer to a context object initialized for validation
+ *                  (cannot be NULL).
+ * In/Out:  pubkey: pointer to a public key object.
+ * In:      tweak:  pointer to a 32-byte tweak.
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
     const secp256k1_context_t* ctx,
@@ -505,11 +463,11 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Tweak a private key by multiplying it by a tweak.
- * In:     ctx:    pointer to a context object (cannot be NULL).
- *         tweak:  pointer to a 32-byte tweak.
- * In/Out: seckey: pointer to a 32-byte private key.
  * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
  *          uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
+ * Args:   ctx:    pointer to a context object (cannot be NULL).
+ * In/Out: seckey: pointer to a 32-byte private key.
+ * In:     tweak:  pointer to a 32-byte tweak.
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
     const secp256k1_context_t* ctx,
@@ -518,12 +476,12 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Tweak a public key by multiplying it by a tweak value.
- * In:     ctx:    pointer to a context object initialized for validation
- *                 (cannot be NULL).
- *         tweak:  pointer to a 32-byte tweak.
- * In/Out: pubkey: pointer to a public key obkect.
  * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
  *          uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
+ * Args:    ctx:    pointer to a context object initialized for validation
+ *                 (cannot be NULL).
+ * In/Out:  pubkey: pointer to a public key obkect.
+ * In:      tweak:  pointer to a 32-byte tweak.
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
     const secp256k1_context_t* ctx,
@@ -534,8 +492,8 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
 /** Updates the context randomization.
  *  Returns: 1: randomization successfully updated
  *           0: error
- *  In:      ctx:       pointer to a context object (cannot be NULL)
- *           seed32:    pointer to a 32-byte random seed (NULL resets to initial state)
+ *  Args:    ctx:       pointer to a context object (cannot be NULL)
+ *  In:      seed32:    pointer to a 32-byte random seed (NULL resets to initial state)
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
     secp256k1_context_t* ctx,
@@ -545,20 +503,20 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
 /** Add a number of public keys together.
  *  Returns: 1: the sum of the public keys is valid.
  *           0: the sum of the public keys is not valid.
- *  In:     ctx:        pointer to a context object
- *          out:        pointer to pubkey for placing the resulting public key
+ *  Args:   ctx:        pointer to a context object
+ *  Out:    out:        pointer to pubkey for placing the resulting public key
  *                      (cannot be NULL)
+ *  In:     ins:        pointer to array of pointers to public keys (cannot be NULL)
  *          n:          the number of public keys to add together (must be at least 1)
- *          ins:        pointer to array of pointers to public keys (cannot be NULL)
  *  Use secp256k1_ec_pubkey_compress and secp256k1_ec_pubkey_decompress if the
  *  uncompressed format is needed.
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
     const secp256k1_context_t* ctx,
     secp256k1_pubkey_t *out,
-    int n,
-    const secp256k1_pubkey_t * const * ins
-) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
+    const secp256k1_pubkey_t * const * ins,
+    int n
+) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 # ifdef __cplusplus
 }
index 671c393faedded0cfa983e92f8ed8708a5a419d2..fa198e3c9a0264f26d262ec76d304cad9d6d16f9 100644 (file)
@@ -10,11 +10,11 @@ extern "C" {
 /** Compute an EC Diffie-Hellman secret in constant time
  *  Returns: 1: exponentiation was successful
  *           0: scalar was invalid (zero or overflow)
- *  In:      ctx:      pointer to a context object (cannot be NULL)
- *           point:    pointer to a public point
- *           scalar:   a 32-byte scalar with which to multiply the point
+ *  Args:    ctx:      pointer to a context object (cannot be NULL)
  *  Out:     result:   a 32-byte array which will be populated by an ECDH
  *                     secret computed from the point and scalar
+ *  In:      point:    pointer to a public point
+ *           scalar:   a 32-byte scalar with which to multiply the point
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
   const secp256k1_context_t* ctx,
diff --git a/include/secp256k1_recovery.h b/include/secp256k1_recovery.h
new file mode 100644 (file)
index 0000000..d0e6ec7
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef _SECP256K1_RECOVERY_
+# define _SECP256K1_RECOVERY_
+
+# include "secp256k1.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Opaque data structured that holds a parsed ECDSA signature,
+ *  supporting pubkey recovery.
+ *
+ *  The exact representation of data inside is implementation defined and not
+ *  guaranteed to be portable between different platforms or versions. It is
+ *  however guaranteed to be 65 bytes in size, and can be safely copied/moved.
+ *  If you need to convert to a format suitable for storage or transmission, use
+ *  the secp256k1_ecdsa_signature_serialize_* and
+ *  secp256k1_ecdsa_signature_serialize_* functions.
+ *
+ *  Furthermore, it is guaranteed to identical signatures (including their
+ *  recoverability) will have identical representation, so they can be
+ *  memcmp'ed.
+ */
+typedef struct {
+    unsigned char data[65];
+} secp256k1_ecdsa_recoverable_signature_t;
+
+/** Parse a compact ECDSA signature (64 bytes + recovery id).
+ *
+ *  Returns: 1 when the signature could be parsed, 0 otherwise
+ *  Args: ctx:     a secp256k1 context object
+ *  Out:  sig:     a pointer to a signature object
+ *  In:   input64: a pointer to a 64-byte compact signature
+ *        recid:   the recovery id (0, 1, 2 or 3)
+ */
+int secp256k1_ecdsa_recoverable_signature_parse_compact(
+    const secp256k1_context_t* ctx,
+    secp256k1_ecdsa_recoverable_signature_t* sig,
+    const unsigned char *input64,
+    int recid
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Convert a recoverable signature into a normal signature.
+ *
+ *  Returns: 1
+ *  Out: sig:    a pointer to a normal signature (cannot be NULL).
+ *  In:  sigin:  a pointer to a recoverable signature (cannot be NULL).
+ */
+int secp256k1_ecdsa_recoverable_signature_convert(
+    const secp256k1_context_t* ctx,
+    secp256k1_ecdsa_signature_t* sig,
+    const secp256k1_ecdsa_recoverable_signature_t* sigin
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
+ *
+ *  Returns: 1
+ *  Args: ctx:      a secp256k1 context object
+ *  Out:  output64: a pointer to a 64-byte array of the compact signature (cannot be NULL)
+ *        recid:    a pointer to an integer to hold the recovery id (can be NULL).
+ *  In:   sig:      a pointer to an initialized signature object (cannot be NULL)
+ */
+int secp256k1_ecdsa_recoverable_signature_serialize_compact(
+    const secp256k1_context_t* ctx,
+    unsigned char *output64,
+    int *recid,
+    const secp256k1_ecdsa_recoverable_signature_t* sig
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
+
+/** Create a recoverable ECDSA signature.
+ *
+ *  Returns: 1: signature created
+ *           0: the nonce generation function failed, or the private key was invalid.
+ *  Args:    ctx:    pointer to a context object, initialized for signing (cannot be NULL)
+ *  Out:     sig:    pointer to an array where the signature will be placed (cannot be NULL)
+ *  In:      msg32:  the 32-byte message hash being signed (cannot be NULL)
+ *           seckey: pointer to a 32-byte secret key (cannot be NULL)
+ *           noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
+ *           ndata:  pointer to arbitrary data used by the nonce generation function (can be NULL)
+ */
+int secp256k1_ecdsa_sign_recoverable(
+    const secp256k1_context_t* ctx,
+    secp256k1_ecdsa_recoverable_signature_t *sig,
+    const unsigned char *msg32,
+    const unsigned char *seckey,
+    secp256k1_nonce_function_t noncefp,
+    const void *ndata
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Recover an ECDSA public key from a signature.
+ *
+ *  Returns: 1: public key successfully recovered (which guarantees a correct signature).
+ *           0: otherwise.
+ *  Args:    ctx:        pointer to a context object, initialized for verification (cannot be NULL)
+ *  Out:     pubkey:     pointer to the recoved public key (cannot be NULL)
+ *  In:      sig:        pointer to initialized signature that supports pubkey recovery (cannot be NULL)
+ *           msg32:      the 32-byte message hash assumed to be signed (cannot be NULL)
+ */
+SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
+    const secp256k1_context_t* ctx,
+    secp256k1_pubkey_t *pubkey,
+    const secp256k1_ecdsa_recoverable_signature_t *sig,
+    const unsigned char *msg32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
index ff7b977f40c0e63cd5c8a8526fbd59f46e0d76ea..0880c771e87c3dcae6353c6a6269b93cee3c1d69 100644 (file)
@@ -13,21 +13,21 @@ extern "C" {
  *  Returns: 1: signature created
  *           0: the nonce generation function failed, or the private key was
  *              invalid.
- *  In:      ctx:    pointer to a context object, initialized for signing
+ *  Args:    ctx:    pointer to a context object, initialized for signing
  *                   (cannot be NULL)
- *           msg32:  the 32-byte message hash being signed (cannot be NULL)
+ *  Out:     sig64:  pointer to a 64-byte array where the signature will be
+ *                   placed (cannot be NULL)
+ *  In:      msg32:  the 32-byte message hash being signed (cannot be NULL)
  *           seckey: pointer to a 32-byte secret key (cannot be NULL)
  *           noncefp:pointer to a nonce generation function. If NULL,
  *                   secp256k1_nonce_function_default is used
  *           ndata:  pointer to arbitrary data used by the nonce generation
  *                   function (can be NULL)
- *  Out:     sig64:  pointer to a 64-byte array where the signature will be
- *                   placed (cannot be NULL)
  */
 int secp256k1_schnorr_sign(
   const secp256k1_context_t* ctx,
-  const unsigned char *msg32,
   unsigned char *sig64,
+  const unsigned char *msg32,
   const unsigned char *seckey,
   secp256k1_nonce_function_t noncefp,
   const void *ndata
@@ -36,15 +36,15 @@ int secp256k1_schnorr_sign(
 /** Verify a signature created by secp256k1_schnorr_sign.
  *  Returns: 1: correct signature
  *           0: incorrect signature
- *  In:      ctx:       a secp256k1 context object, initialized for verification.
+ *  Args:    ctx:       a secp256k1 context object, initialized for verification.
+ *  In:      sig64:     the 64-byte signature being verified (cannot be NULL)
  *           msg32:     the 32-byte message hash being verified (cannot be NULL)
- *           sig64:     the 64-byte signature being verified (cannot be NULL)
  *           pubkey:    the public key to verify with (cannot be NULL)
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
   const secp256k1_context_t* ctx,
-  const unsigned char *msg32,
   const unsigned char *sig64,
+  const unsigned char *msg32,
   const secp256k1_pubkey_t *pubkey
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
 
@@ -53,47 +53,47 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
  *  Returns: 1: public key successfully recovered (which guarantees a correct
  *           signature).
  *           0: otherwise.
- *  In:      ctx:        pointer to a context object, initialized for
+ *  Args:    ctx:        pointer to a context object, initialized for
  *                       verification (cannot be NULL)
- *           msg32:      the 32-byte message hash assumed to be signed (cannot
- *                       be NULL)
- *           sig64:      signature as 64 byte array (cannot be NULL)
  *  Out:     pubkey:     pointer to a pubkey to set to the recovered public key
  *                       (cannot be NULL).
+ *  In:      sig64:      signature as 64 byte array (cannot be NULL)
+ *           msg32:      the 32-byte message hash assumed to be signed (cannot
+ *                       be NULL)
  */
 int secp256k1_schnorr_recover(
   const secp256k1_context_t* ctx,
-  const unsigned char *msg32,
+  secp256k1_pubkey_t *pubkey,
   const unsigned char *sig64,
-  secp256k1_pubkey_t *pubkey
+  const unsigned char *msg32
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
 
 /** Generate a nonce pair deterministically for use with
  *  secp256k1_schnorr_partial_sign.
  *  Returns: 1: valid nonce pair was generated.
  *           0: otherwise (nonce generation function failed)
- *  In:      ctx:         pointer to a context object, initialized for signing
+ *  Args:    ctx:         pointer to a context object, initialized for signing
  *                        (cannot be NULL)
- *           msg32:       the 32-byte message hash assumed to be signed (cannot
+ *  Out:     pubnonce:    public side of the nonce (cannot be NULL)
+ *           privnonce32: private side of the nonce (32 byte) (cannot be NULL)
+ *  In:      msg32:       the 32-byte message hash assumed to be signed (cannot
  *                        be NULL)
  *           sec32:       the 32-byte private key (cannot be NULL)
  *           noncefp:     pointer to a nonce generation function. If NULL,
  *                        secp256k1_nonce_function_default is used
  *           noncedata:   pointer to arbitrary data used by the nonce generation
  *                        function (can be NULL)
- *  Out:     pubnonce:    public side of the nonce (cannot be NULL)
- *           privnonce32: private side of the nonce (32 byte) (cannot be NULL)
  *
  *  Do not use the output as a private/public key pair for signing/validation.
  */
 int secp256k1_schnorr_generate_nonce_pair(
   const secp256k1_context_t* ctx,
+  secp256k1_pubkey_t *pubnonce,
+  unsigned char *privnonce32,
   const unsigned char *msg32,
   const unsigned char *sec32,
   secp256k1_nonce_function_t noncefp,
-  const void* noncedata,
-  secp256k1_pubkey_t *pubnonce,
-  unsigned char *privnonce32
+  const void* noncedata
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
 
 /** Produce a partial Schnorr signature, which can be combined using
@@ -103,14 +103,14 @@ int secp256k1_schnorr_generate_nonce_pair(
  *           0: no valid signature exists with this combination of keys, nonces
  *              and message (chance around 1 in 2^128)
  *          -1: invalid private key, nonce, or public nonces.
- *  In:   ctx:             pointer to context object, initialized for signing (cannot
+ *  Args: ctx:             pointer to context object, initialized for signing (cannot
  *                         be NULL)
- *        msg32:           pointer to 32-byte message to sign
+ *  Out:  sig64:           pointer to 64-byte array to put partial signature in
+ *  In:   msg32:           pointer to 32-byte message to sign
  *        sec32:           pointer to 32-byte private key
- *        secnonce32:      pointer to 32-byte array containing our nonce
  *        pubnonce_others: pointer to pubkey containing the sum of the other's
  *                         nonces (see secp256k1_ec_pubkey_combine)
- *  Out:  sig64:           pointer to 64-byte array to put partial signature in
+ *        secnonce32:      pointer to 32-byte array containing our nonce
  *
  * The intended procedure for creating a multiparty signature is:
  * - Each signer S[i] with private key x[i] and public key Q[i] runs
@@ -140,11 +140,11 @@ int secp256k1_schnorr_generate_nonce_pair(
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
   const secp256k1_context_t* ctx,
-  const unsigned char *msg32,
   unsigned char *sig64,
+  const unsigned char *msg32,
   const unsigned char *sec32,
-  const unsigned char *secnonce32,
-  const secp256k1_pubkey_t *pubnonce_others
+  const secp256k1_pubkey_t *pubnonce_others,
+  const unsigned char *secnonce32
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
 
 /** Combine multiple Schnorr partial signatures.
@@ -152,19 +152,19 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
  *          0: the resulting signature is not valid (chance of 1 in 2^256)
  *         -1: some inputs were invalid, or the signatures were not created
  *             using the same set of nonces
- * In:     ctx:      pointer to a context object
- *         sig64:    pointer to a 64-byte array to place the combined signature
+ * Args:   ctx:      pointer to a context object
+ * Out:    sig64:    pointer to a 64-byte array to place the combined signature
  *                   (cannot be NULL)
- *         n:        the number of signatures to combine (at least 1)
- * Out:    sig64sin: pointer to an array of n pointers to 64-byte input
+ * In:     sig64sin: pointer to an array of n pointers to 64-byte input
  *                   signatures
+ *         n:        the number of signatures to combine (at least 1)
  */
 SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine(
   const secp256k1_context_t* ctx,
   unsigned char *sig64,
-  int n,
-  const unsigned char * const * sig64sin
-) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
+  const unsigned char * const * sig64sin,
+  int n
+) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 # ifdef __cplusplus
 }
index 1b198ec346b3d4f533f1ff30d09dcbc303f32022..3167ee74641540d48622dca6ba31e99712521fc7 100644 (file)
@@ -1,10 +1,11 @@
 /**********************************************************************
- * Copyright (c) 2014 Pieter Wuille                                   *
+ * Copyright (c) 2014-2015 Pieter Wuille                              *
  * Distributed under the MIT software license, see the accompanying   *
  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
  **********************************************************************/
 
 #include "include/secp256k1.h"
+#include "include/secp256k1_recovery.h"
 #include "util.h"
 #include "bench.h"
 
@@ -23,9 +24,9 @@ void bench_recover(void* arg) {
     for (i = 0; i < 20000; i++) {
         int j;
         int pubkeylen = 33;
-        secp256k1_ecdsa_signature_t sig;
-        CHECK(secp256k1_ecdsa_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));
-        CHECK(secp256k1_ecdsa_recover(data->ctx, data->msg, &sig, &pubkey));
+        secp256k1_ecdsa_recoverable_signature_t sig;
+        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));
+        CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg));
         CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, 1));
         for (j = 0; j < 32; j++) {
             data->sig[j + 32] = data->msg[j];    /* Move former message to S. */
index 274b6e02db7e752290eb3f7e8bcd0b38685b392b..192a383eeab5c64b66ee504289f1ed00e3e0f124 100644 (file)
@@ -34,7 +34,7 @@ static void benchmark_schnorr_init(void* arg) {
     for (k = 0; k < data->numsigs; k++) {
         secp256k1_pubkey_t pubkey;
         for (i = 0; i < 32; i++) data->sigs[k].key[i] = 33 + i + k;
-        secp256k1_schnorr_sign(data->ctx, data->msg, data->sigs[k].sig, data->sigs[k].key, NULL, NULL);
+        secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL);
         data->sigs[k].pubkeylen = 33;
         CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key));
         CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, 1));
@@ -49,7 +49,7 @@ static void benchmark_schnorr_verify(void* arg) {
         secp256k1_pubkey_t pubkey;
         data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
         CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen));
-        CHECK(secp256k1_schnorr_verify(data->ctx, data->msg, data->sigs[0].sig, &pubkey) == ((i & 0xFF) == 0));
+        CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0));
         data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
     }
 }
index e625da07a4ee6d57170ca703a0c609e4e13ede31..2f4107fc186d6634e6320b08d553d22fcd4c1164 100644 (file)
@@ -26,16 +26,16 @@ static void bench_sign(void* arg) {
     int i;
     bench_sign_t *data = (bench_sign_t*)arg;
 
-    unsigned char sig[64];
+    unsigned char sig[74];
     for (i = 0; i < 20000; i++) {
+        int siglen = 74;
         int j;
-        int recid = 0;
         secp256k1_ecdsa_signature_t signature;
-        CHECK(secp256k1_ecdsa_sign(data->ctx, data->msg, &signature, data->key, NULL, NULL));
-        CHECK(secp256k1_ecdsa_signature_serialize_compact(data->ctx, sig, &recid, &signature));
+        CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL));
+        CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature));
         for (j = 0; j < 32; j++) {
-            data->msg[j] = sig[j];             /* Move former R to message. */
-            data->key[j] = sig[j + 32];        /* Move former S to key.     */
+            data->msg[j] = sig[j];
+            data->key[j] = sig[j + 32];
         }
     }
 }
index b8c5bdf58f52af19fcfa58687c00c5ce56625509..f07cbb6197973686340afacf868444dda5dd33cd 100644 (file)
@@ -33,7 +33,7 @@ static void benchmark_verify(void* arg) {
         data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
         CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1);
         CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1);
-        CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, &sig, &pubkey) == (i == 0));
+        CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0));
         data->sig[data->siglen - 1] ^= (i & 0xFF);
         data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
         data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@@ -51,7 +51,7 @@ int main(void) {
     for (i = 0; i < 32; i++) data.msg[i] = 1 + i;
     for (i = 0; i < 32; i++) data.key[i] = 33 + i;
     data.siglen = 72;
-    CHECK(secp256k1_ecdsa_sign(data.ctx, data.msg, &sig, data.key, NULL, NULL));
+    CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL));
     CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig));
     CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
     CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, 1) == 1);
index 768e7c9a0af83f8927bde2143ede8861703a8336..9e109ba44b278f5ad5cbe943b348ef679195cbb5 100644 (file)
@@ -219,7 +219,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
 
     t4 &= 0x0FFFFFFFFFFFFULL;
 
-    t1 += (t0 >> 52); t0  = z0;
+    t1 += (t0 >> 52);
     t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;
     t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;
     t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;
diff --git a/src/modules/recovery/Makefile.am.include b/src/modules/recovery/Makefile.am.include
new file mode 100644 (file)
index 0000000..754469e
--- /dev/null
@@ -0,0 +1,9 @@
+include_HEADERS += include/secp256k1_recovery.h
+noinst_HEADERS += src/modules/recovery/main_impl.h
+noinst_HEADERS += src/modules/recovery/tests_impl.h
+if USE_BENCHMARK
+noinst_PROGRAMS += bench_recover
+bench_recover_SOURCES = src/bench_recover.c
+bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_recover_LDFLAGS = -static
+endif
diff --git a/src/modules/recovery/main_impl.h b/src/modules/recovery/main_impl.h
new file mode 100644 (file)
index 0000000..7f3d8a7
--- /dev/null
@@ -0,0 +1,156 @@
+/**********************************************************************
+ * Copyright (c) 2013-2015 Pieter Wuille                              *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_
+#define _SECP256K1_MODULE_RECOVERY_MAIN_
+
+#include "include/secp256k1_recovery.h"
+
+static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context_t* ctx, secp256k1_scalar_t* r, secp256k1_scalar_t* s, int* recid, const secp256k1_ecdsa_recoverable_signature_t* sig) {
+    (void)ctx;
+    if (sizeof(secp256k1_scalar_t) == 32) {
+        /* When the secp256k1_scalar_t type is exactly 32 byte, use its
+         * representation inside secp256k1_ecdsa_signature_t, as conversion is very fast.
+         * Note that secp256k1_ecdsa_signature_save must use the same representation. */
+        memcpy(r, &sig->data[0], 32);
+        memcpy(s, &sig->data[32], 32);
+    } else {
+        secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
+        secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
+    }
+    *recid = sig->data[64];
+}
+
+static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature_t* sig, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, int recid) {
+    if (sizeof(secp256k1_scalar_t) == 32) {
+        memcpy(&sig->data[0], r, 32);
+        memcpy(&sig->data[32], s, 32);
+    } else {
+        secp256k1_scalar_get_b32(&sig->data[0], r);
+        secp256k1_scalar_get_b32(&sig->data[32], s);
+    }
+    sig->data[64] = recid;
+}
+
+int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context_t* ctx, secp256k1_ecdsa_recoverable_signature_t* sig, const unsigned char *input64, int recid) {
+    secp256k1_scalar_t r, s;
+    int ret = 1;
+    int overflow = 0;
+
+    (void)ctx;
+    ARG_CHECK(sig != NULL);
+    ARG_CHECK(input64 != NULL);
+    ARG_CHECK(recid >= 0 && recid <= 3);
+
+    secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
+    ret &= !overflow;
+    secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
+    ret &= !overflow;
+    if (ret) {
+        secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid);
+    } else {
+        memset(sig, 0, sizeof(*sig));
+    }
+    return ret;
+}
+
+int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context_t* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature_t* sig) {
+    secp256k1_scalar_t r, s;
+
+    (void)ctx;
+    ARG_CHECK(output64 != NULL);
+    ARG_CHECK(sig != NULL);
+
+    secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig);
+    secp256k1_scalar_get_b32(&output64[0], &r);
+    secp256k1_scalar_get_b32(&output64[32], &s);
+    return 1;
+}
+
+int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const secp256k1_ecdsa_recoverable_signature_t* sigin) {
+    secp256k1_scalar_t r, s;
+    int recid;
+
+    (void)ctx;
+    ARG_CHECK(sig != NULL);
+    ARG_CHECK(sigin != NULL);
+
+    secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin);
+    secp256k1_ecdsa_signature_save(sig, &r, &s);
+    return 1;
+}
+
+int secp256k1_ecdsa_sign_recoverable(const secp256k1_context_t* ctx, secp256k1_ecdsa_recoverable_signature_t *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
+    secp256k1_scalar_t r, s;
+    secp256k1_scalar_t sec, non, msg;
+    int recid;
+    int ret = 0;
+    int overflow = 0;
+    unsigned int count = 0;
+    VERIFY_CHECK(ctx != NULL);
+    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+    ARG_CHECK(msg32 != NULL);
+    ARG_CHECK(signature != NULL);
+    ARG_CHECK(seckey != NULL);
+    if (noncefp == NULL) {
+        noncefp = secp256k1_nonce_function_default;
+    }
+
+    secp256k1_scalar_set_b32(&sec, seckey, &overflow);
+    /* Fail if the secret key is invalid. */
+    if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
+        secp256k1_scalar_set_b32(&msg, msg32, NULL);
+        while (1) {
+            unsigned char nonce32[32];
+            ret = noncefp(nonce32, seckey, msg32, NULL, noncedata, count);
+            if (!ret) {
+                break;
+            }
+            secp256k1_scalar_set_b32(&non, nonce32, &overflow);
+            memset(nonce32, 0, 32);
+            if (!secp256k1_scalar_is_zero(&non) && !overflow) {
+                if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
+                    break;
+                }
+            }
+            count++;
+        }
+        secp256k1_scalar_clear(&msg);
+        secp256k1_scalar_clear(&non);
+        secp256k1_scalar_clear(&sec);
+    }
+    if (ret) {
+        secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
+    } else {
+        memset(signature, 0, sizeof(*signature));
+    }
+    return ret;
+}
+
+int secp256k1_ecdsa_recover(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const secp256k1_ecdsa_recoverable_signature_t *signature, const unsigned char *msg32) {
+    secp256k1_ge_t q;
+    secp256k1_scalar_t r, s;
+    secp256k1_scalar_t m;
+    int recid;
+    VERIFY_CHECK(ctx != NULL);
+    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+    ARG_CHECK(msg32 != NULL);
+    ARG_CHECK(signature != NULL);
+    ARG_CHECK(pubkey != NULL);
+
+    secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
+    ARG_CHECK(recid >= 0 && recid < 4);
+    secp256k1_scalar_set_b32(&m, msg32, NULL);
+    if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
+        secp256k1_pubkey_save(pubkey, &q);
+        return 1;
+    } else {
+        memset(pubkey, 0, sizeof(*pubkey));
+        return 0;
+    }
+}
+
+#endif
diff --git a/src/modules/recovery/tests_impl.h b/src/modules/recovery/tests_impl.h
new file mode 100644 (file)
index 0000000..7a5b866
--- /dev/null
@@ -0,0 +1,249 @@
+/**********************************************************************
+ * Copyright (c) 2013-2015 Pieter Wuille                              *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
+#define _SECP256K1_MODULE_RECOVERY_TESTS_
+
+void test_ecdsa_recovery_end_to_end(void) {
+    unsigned char extra[32] = {0x00};
+    unsigned char privkey[32];
+    unsigned char message[32];
+    secp256k1_ecdsa_signature_t signature[5];
+    secp256k1_ecdsa_recoverable_signature_t rsignature[5];
+    unsigned char sig[74];
+    secp256k1_pubkey_t pubkey;
+    secp256k1_pubkey_t recpubkey;
+    int recid = 0;
+
+    /* Generate a random key and message. */
+    {
+        secp256k1_scalar_t msg, key;
+        random_scalar_order_test(&msg);
+        random_scalar_order_test(&key);
+        secp256k1_scalar_get_b32(privkey, &key);
+        secp256k1_scalar_get_b32(message, &msg);
+    }
+
+    /* Construct and verify corresponding public key. */
+    CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+
+    /* Serialize/parse compact and verify/recover. */
+    extra[0] = 0;
+    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1);
+    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1);
+    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1);
+    extra[31] = 1;
+    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1);
+    extra[31] = 0;
+    extra[0] = 1;
+    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
+    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
+    CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
+    memset(&rsignature[4], 0, sizeof(rsignature[4]));
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
+    CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
+    /* Parse compact (with recovery id) and recover. */
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
+    CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);
+    CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
+    /* Serialize/destroy/parse signature and verify again. */
+    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
+    sig[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
+    CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
+    /* Recover again */
+    CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||
+          memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
+}
+
+/* Tests several edge cases. */
+void test_ecdsa_recovery_edge_cases(void) {
+    const unsigned char msg32[32] = {
+        'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
+        'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
+        'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',
+        's', 's', 'a', 'g', 'e', '.', '.', '.'
+    };
+    const unsigned char sig64[64] = {
+        /* Generated by signing the above message with nonce 'This is the nonce we will use...'
+         * and secret key 0 (which is not valid), resulting in recid 0. */
+        0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
+        0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
+        0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
+        0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,
+        0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,
+        0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,
+        0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
+        0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
+    };
+    secp256k1_pubkey_t pubkey;
+    /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
+    const unsigned char sigb64[64] = {
+        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, 0x04,
+        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, 0x04,
+    };
+    secp256k1_pubkey_t pubkeyb;
+    secp256k1_ecdsa_recoverable_signature_t rsig;
+    secp256k1_ecdsa_signature_t sig;
+    int recid;
+
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0));
+    CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1));
+    CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2));
+    CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3));
+    CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+
+    for (recid = 0; recid < 4; recid++) {
+        int i;
+        int recid2;
+        /* (4,4) encoded in DER. */
+        unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
+        unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};
+        unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};
+        unsigned char sigbderalt1[39] = {
+            0x30, 0x25, 0x02, 0x20, 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, 0x04, 0x02, 0x01, 0x04,
+        };
+        unsigned char sigbderalt2[39] = {
+            0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 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, 0x04,
+        };
+        unsigned char sigbderalt3[40] = {
+            0x30, 0x26, 0x02, 0x21, 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, 0x00, 0x04, 0x02, 0x01, 0x04,
+        };
+        unsigned char sigbderalt4[40] = {
+            0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 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, 0x00, 0x04,
+        };
+        /* (order + r,4) encoded in DER. */
+        unsigned char sigbderlong[40] = {
+            0x30, 0x26, 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, 0x45, 0x02, 0x01, 0x04
+        };
+        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1);
+        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
+        for (recid2 = 0; recid2 < 4; recid2++) {
+            secp256k1_pubkey_t pubkey2b;
+            CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1);
+            CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1);
+            /* Verifying with (order + r,4) should always fail. */
+            CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 0);
+        }
+        /* DER parsing tests. */
+        /* Zero length r/s. */
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
+        /* Leading zeros. */
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
+        sigbderalt3[4] = 1;
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
+        sigbderalt4[7] = 1;
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
+        /* Damage signature. */
+        sigbder[7]++;
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+        sigbder[7]--;
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);
+        for(i = 0; i < 8; i++) {
+            int c;
+            unsigned char orig = sigbder[i];
+            /*Try every single-byte change.*/
+            for (c = 0; c < 256; c++) {
+                if (c == orig ) {
+                    continue;
+                }
+                sigbder[i] = c;
+                CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+            }
+            sigbder[i] = orig;
+        }
+    }
+
+    /* Test r/s equal to zero */
+    {
+        /* (1,1) encoded in DER. */
+        unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
+        unsigned char sigc64[64] = {
+            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,
+            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_pubkey_t pubkeyc;
+        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
+        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1);
+        sigcder[4] = 0;
+        sigc64[31] = 0;
+        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
+        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
+        sigcder[4] = 1;
+        sigcder[7] = 0;
+        sigc64[31] = 1;
+        sigc64[63] = 0;
+        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
+        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
+        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
+        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
+    }
+}
+
+void run_recovery_tests(void) {
+    int i;
+    for (i = 0; i < 64*count; i++) {
+        test_ecdsa_recovery_end_to_end();
+    }
+    test_ecdsa_recovery_edge_cases();
+}
+
+#endif
index f5250bffd0975a2521cc2cc47ed4d473aa2fb953..8548b26e470e6e6e754a1deeb13627692766ef82 100644 (file)
@@ -19,12 +19,12 @@ static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned
 
 static const unsigned char secp256k1_schnorr_algo16[16] = "Schnorr+SHA256  ";
 
-int secp256k1_schnorr_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
+int secp256k1_schnorr_sign(const secp256k1_context_t* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
     secp256k1_scalar_t sec, non;
     int ret = 0;
     int overflow = 0;
     unsigned int count = 0;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(sig64 != NULL);
@@ -36,7 +36,7 @@ int secp256k1_schnorr_sign(const secp256k1_context_t* ctx, const unsigned char *
     secp256k1_scalar_set_b32(&sec, seckey, NULL);
     while (1) {
         unsigned char nonce32[32];
-        ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, count, noncedata);
+        ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, noncedata, count);
         if (!ret) {
             break;
         }
@@ -57,9 +57,9 @@ int secp256k1_schnorr_sign(const secp256k1_context_t* ctx, const unsigned char *
     return ret;
 }
 
-int secp256k1_schnorr_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, const secp256k1_pubkey_t *pubkey) {
+int secp256k1_schnorr_verify(const secp256k1_context_t* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey_t *pubkey) {
     secp256k1_ge_t q;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(sig64 != NULL);
@@ -69,10 +69,10 @@ int secp256k1_schnorr_verify(const secp256k1_context_t* ctx, const unsigned char
     return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32);
 }
 
-int secp256k1_schnorr_recover(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, secp256k1_pubkey_t *pubkey) {
+int secp256k1_schnorr_recover(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *sig64, const unsigned char *msg32) {
     secp256k1_ge_t q;
 
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(sig64 != NULL);
@@ -87,14 +87,14 @@ int secp256k1_schnorr_recover(const secp256k1_context_t* ctx, const unsigned cha
     }
 }
 
-int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sec32, secp256k1_nonce_function_t noncefp, const void* noncedata, secp256k1_pubkey_t *pubnonce, unsigned char *privnonce32) {
+int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function_t noncefp, const void* noncedata) {
     int count = 0;
     int ret = 1;
     secp256k1_gej_t Qj;
     secp256k1_ge_t Q;
     secp256k1_scalar_t sec;
 
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(sec32 != NULL);
@@ -107,7 +107,7 @@ int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context_t* ctx, const
 
     do {
         int overflow;
-        ret = noncefp(privnonce32, msg32, sec32, secp256k1_schnorr_algo16, count++, noncedata);
+        ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, noncedata, count++);
         if (!ret) {
             break;
         }
@@ -129,11 +129,11 @@ int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context_t* ctx, const
     return ret;
 }
 
-int secp256k1_schnorr_partial_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *sec32, const unsigned char *secnonce32, const secp256k1_pubkey_t *pubnonce_others) {
+int secp256k1_schnorr_partial_sign(const secp256k1_context_t* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey_t *pubnonce_others, const unsigned char *secnonce32) {
     int overflow = 0;
     secp256k1_scalar_t sec, non;
     secp256k1_ge_t pubnon;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(sig64 != NULL);
@@ -153,7 +153,7 @@ int secp256k1_schnorr_partial_sign(const secp256k1_context_t* ctx, const unsigne
     return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32);
 }
 
-int secp256k1_schnorr_partial_combine(const secp256k1_context_t* ctx, unsigned char *sig64, int n, const unsigned char * const *sig64sin) {
+int secp256k1_schnorr_partial_combine(const secp256k1_context_t* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, int n) {
     ARG_CHECK(sig64 != NULL);
     ARG_CHECK(n >= 1);
     ARG_CHECK(sig64sin != NULL);
index 402eb63b25c5df0c03f062b24b44adf5fe8c9ee0..278cc5bd0937c5d56655af744f91686b43a44360 100644 (file)
@@ -26,14 +26,14 @@ void test_schnorr_end_to_end(void) {
     CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
 
     /* Schnorr sign. */
-    CHECK(secp256k1_schnorr_sign(ctx, message, schnorr_signature, privkey, NULL, NULL) == 1);
-    CHECK(secp256k1_schnorr_verify(ctx, message, schnorr_signature, &pubkey) == 1);
-    CHECK(secp256k1_schnorr_recover(ctx, message, schnorr_signature, &recpubkey) == 1);
+    CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1);
+    CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1);
+    CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1);
     CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
     /* Destroy signature and verify again. */
     schnorr_signature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
-    CHECK(secp256k1_schnorr_verify(ctx, message, schnorr_signature, &pubkey) == 0);
-    CHECK(secp256k1_schnorr_recover(ctx, message, schnorr_signature, &recpubkey) != 1 ||
+    CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0);
+    CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 ||
           memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
 }
 
@@ -103,7 +103,7 @@ void test_schnorr_threshold(void) {
             secp256k1_rand256_test(sec[i]);
         } while (!secp256k1_ec_seckey_verify(ctx, sec[i]));
         CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i]));
-        CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, msg, sec[i], NULL, NULL, &pubnonce[i], nonce[i]));
+        CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL));
         pubs[i] = &pub[i];
     }
     if (damage == 1) {
@@ -121,22 +121,22 @@ void test_schnorr_threshold(void) {
         for (j = i + 1; j < n; j++) {
             pubnonces[j - 1] = &pubnonce[j];
         }
-        CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, n - 1, pubnonces));
-        ret |= (secp256k1_schnorr_partial_sign(ctx, msg, sig[i], sec[i], nonce[i], &allpubnonce) != 1) * 1;
+        CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1));
+        ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1;
         sigs[i] = sig[i];
     }
     if (damage == 3) {
         sig[secp256k1_rand32() % n][secp256k1_rand32() % 64] ^= 1 + (secp256k1_rand32() % 255);
     }
-    ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, n, pubs) != 1) * 2;
+    ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2;
     if ((ret & 1) == 0) {
-        ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, n, sigs) != 1) * 4;
+        ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4;
     }
     if (damage == 4) {
         allsig[secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255);
     }
     if ((ret & 7) == 0) {
-        ret |= (secp256k1_schnorr_verify(ctx, msg, allsig, &allpub) != 1) * 8;
+        ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8;
     }
     CHECK((ret == 0) == (damage == 0));
 }
index 4699bff802c29deabdb494522565a06f735400bc..dbe97d05736f7a02584a6991cb106339c01ac185 100644 (file)
@@ -155,7 +155,7 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context_t* ctx, unsigned char
             secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, compressed));
 }
 
-static void secp256k1_ecdsa_signature_load(const secp256k1_context_t* ctx, secp256k1_scalar_t* r, secp256k1_scalar_t* s, int* recid, const secp256k1_ecdsa_signature_t* sig) {
+static void secp256k1_ecdsa_signature_load(const secp256k1_context_t* ctx, secp256k1_scalar_t* r, secp256k1_scalar_t* s, const secp256k1_ecdsa_signature_t* sig) {
     (void)ctx;
     if (sizeof(secp256k1_scalar_t) == 32) {
         /* When the secp256k1_scalar_t type is exactly 32 byte, use its
@@ -167,12 +167,9 @@ static void secp256k1_ecdsa_signature_load(const secp256k1_context_t* ctx, secp2
         secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
         secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
     }
-    if (recid) {
-        *recid = sig->data[64];
-    }
 }
 
-static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature_t* sig, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, int recid) {
+static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature_t* sig, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s) {
     if (sizeof(secp256k1_scalar_t) == 32) {
         memcpy(&sig->data[0], r, 32);
         memcpy(&sig->data[32], s, 32);
@@ -180,7 +177,6 @@ static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature_t* sig, con
         secp256k1_scalar_get_b32(&sig->data[0], r);
         secp256k1_scalar_get_b32(&sig->data[32], s);
     }
-    sig->data[64] = recid;
 }
 
 int secp256k1_ecdsa_signature_parse_der(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const unsigned char *input, int inputlen) {
@@ -191,7 +187,7 @@ int secp256k1_ecdsa_signature_parse_der(const secp256k1_context_t* ctx, secp256k
     ARG_CHECK(input != NULL);
 
     if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) {
-        secp256k1_ecdsa_signature_save(sig, &r, &s, -1);
+        secp256k1_ecdsa_signature_save(sig, &r, &s);
         return 1;
     } else {
         memset(sig, 0, sizeof(*sig));
@@ -199,28 +195,6 @@ int secp256k1_ecdsa_signature_parse_der(const secp256k1_context_t* ctx, secp256k
     }
 }
 
-int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const unsigned char *input64, int recid) {
-    secp256k1_scalar_t r, s;
-    int ret = 1;
-    int overflow = 0;
-
-    (void)ctx;
-    ARG_CHECK(sig != NULL);
-    ARG_CHECK(input64 != NULL);
-
-    secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
-    ret &= !overflow;
-    secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
-    ret &= !overflow;
-    ret &= (recid == -1 || (recid >= 0 && recid < 4));
-    if (ret) {
-        secp256k1_ecdsa_signature_save(sig, &r, &s, recid);
-    } else {
-        memset(sig, 0, sizeof(*sig));
-    }
-    return ret;
-}
-
 int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context_t* ctx, unsigned char *output, int *outputlen, const secp256k1_ecdsa_signature_t* sig) {
     secp256k1_scalar_t r, s;
 
@@ -229,45 +203,27 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context_t* ctx, unsi
     ARG_CHECK(outputlen != NULL);
     ARG_CHECK(sig != NULL);
 
-    secp256k1_ecdsa_signature_load(ctx, &r, &s, NULL, sig);
+    secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
     return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s);
 }
 
-int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context_t* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_signature_t* sig) {
-    secp256k1_scalar_t r, s;
-    int rec;
-
-    (void)ctx;
-    ARG_CHECK(output64 != NULL);
-    ARG_CHECK(sig != NULL);
-
-    secp256k1_ecdsa_signature_load(ctx, &r, &s, &rec, sig);
-    secp256k1_scalar_get_b32(&output64[0], &r);
-    secp256k1_scalar_get_b32(&output64[32], &s);
-    if (recid) {
-        ARG_CHECK(rec >= 0 && rec < 4);
-        *recid = rec;
-    }
-    return 1;
-}
-
-int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const secp256k1_ecdsa_signature_t *sig, const secp256k1_pubkey_t *pubkey) {
+int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const secp256k1_ecdsa_signature_t *sig, const unsigned char *msg32, const secp256k1_pubkey_t *pubkey) {
     secp256k1_ge_t q;
     secp256k1_scalar_t r, s;
     secp256k1_scalar_t m;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(sig != NULL);
     ARG_CHECK(pubkey != NULL);
 
     secp256k1_scalar_set_b32(&m, msg32, NULL);
-    secp256k1_ecdsa_signature_load(ctx, &r, &s, NULL, sig);
+    secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
     return (secp256k1_pubkey_load(ctx, &q, pubkey) &&
             secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m));
 }
 
-static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) {
+static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, const void *data, unsigned int counter) {
    unsigned char keydata[112];
    int keylen = 64;
    secp256k1_rfc6979_hmac_sha256_t rng;
@@ -301,14 +257,13 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
 const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
 const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979;
 
-int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, secp256k1_ecdsa_signature_t *signature, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
+int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
     secp256k1_scalar_t r, s;
     secp256k1_scalar_t sec, non, msg;
-    int recid;
     int ret = 0;
     int overflow = 0;
     unsigned int count = 0;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(signature != NULL);
@@ -323,14 +278,14 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms
         secp256k1_scalar_set_b32(&msg, msg32, NULL);
         while (1) {
             unsigned char nonce32[32];
-            ret = noncefp(nonce32, msg32, seckey, NULL, count, noncedata);
+            ret = noncefp(nonce32, msg32, seckey, NULL, noncedata, count);
             if (!ret) {
                 break;
             }
             secp256k1_scalar_set_b32(&non, nonce32, &overflow);
             memset(nonce32, 0, 32);
             if (!secp256k1_scalar_is_zero(&non) && !overflow) {
-                if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
+                if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {
                     break;
                 }
             }
@@ -341,41 +296,18 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms
         secp256k1_scalar_clear(&sec);
     }
     if (ret) {
-        secp256k1_ecdsa_signature_save(signature, &r, &s, recid);
+        secp256k1_ecdsa_signature_save(signature, &r, &s);
     } else {
         memset(signature, 0, sizeof(*signature));
     }
     return ret;
 }
 
-int secp256k1_ecdsa_recover(const secp256k1_context_t* ctx, const unsigned char *msg32, const secp256k1_ecdsa_signature_t *signature, secp256k1_pubkey_t *pubkey) {
-    secp256k1_ge_t q;
-    secp256k1_scalar_t r, s;
-    secp256k1_scalar_t m;
-    int recid;
-    ARG_CHECK(ctx != NULL);
-    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
-    ARG_CHECK(msg32 != NULL);
-    ARG_CHECK(signature != NULL);
-    ARG_CHECK(pubkey != NULL);
-
-    secp256k1_ecdsa_signature_load(ctx, &r, &s, &recid, signature);
-    ARG_CHECK(recid >= 0 && recid < 4);
-    secp256k1_scalar_set_b32(&m, msg32, NULL);
-    if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
-        secp256k1_pubkey_save(pubkey, &q);
-        return 1;
-    } else {
-        memset(pubkey, 0, sizeof(*pubkey));
-        return 0;
-    }
-}
-
 int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) {
     secp256k1_scalar_t sec;
     int ret;
     int overflow;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(seckey != NULL);
     (void)ctx;
 
@@ -391,7 +323,7 @@ int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, secp256k1_pubkey_
     secp256k1_scalar_t sec;
     int overflow;
     int ret = 0;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     ARG_CHECK(pubkey != NULL);
     ARG_CHECK(seckey != NULL);
@@ -413,7 +345,7 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char
     secp256k1_scalar_t sec;
     int ret = 0;
     int overflow = 0;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(seckey != NULL);
     ARG_CHECK(tweak != NULL);
     (void)ctx;
@@ -436,7 +368,7 @@ int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, secp256k1_pubk
     secp256k1_scalar_t term;
     int ret = 0;
     int overflow = 0;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
     ARG_CHECK(pubkey != NULL);
     ARG_CHECK(tweak != NULL);
@@ -459,7 +391,7 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char
     secp256k1_scalar_t sec;
     int ret = 0;
     int overflow = 0;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(seckey != NULL);
     ARG_CHECK(tweak != NULL);
     (void)ctx;
@@ -481,7 +413,7 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, secp256k1_pubk
     secp256k1_scalar_t factor;
     int ret = 0;
     int overflow = 0;
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
     ARG_CHECK(pubkey != NULL);
     ARG_CHECK(tweak != NULL);
@@ -499,13 +431,13 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, secp256k1_pubk
     return ret;
 }
 
-int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) {
+int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, unsigned char *privkey, int *privkeylen, const unsigned char *seckey, int compressed) {
     secp256k1_scalar_t key;
     int ret = 0;
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(seckey != NULL);
     ARG_CHECK(privkey != NULL);
     ARG_CHECK(privkeylen != NULL);
-    ARG_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
 
     secp256k1_scalar_set_b32(&key, seckey, NULL);
@@ -530,13 +462,13 @@ int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *s
 }
 
 int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) {
-    ARG_CHECK(ctx != NULL);
+    VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
     return 1;
 }
 
-int secp256k1_ec_pubkey_combine(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubnonce, int n, const secp256k1_pubkey_t * const *pubnonces) {
+int secp256k1_ec_pubkey_combine(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubnonce, const secp256k1_pubkey_t * const *pubnonces, int n) {
     int i;
     secp256k1_gej_t Qj;
     secp256k1_ge_t Q;
@@ -567,3 +499,7 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context_t* ctx, secp256k1_pubkey
 #ifdef ENABLE_MODULE_SCHNORR
 # include "modules/schnorr/main_impl.h"
 #endif
+
+#ifdef ENABLE_MODULE_RECOVERY
+# include "modules/recovery/main_impl.h"
+#endif
index d5a48d51c80b58d99dfafeb68bafd218eddec9d4..9adf53ca9108cb1d497961b468928a8935b18ae4 100644 (file)
@@ -1291,7 +1291,7 @@ void test_ec_combine(void) {
         secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum);
         secp256k1_ge_set_gej(&Q, &Qj);
         secp256k1_pubkey_save(&sd, &Q);
-        CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, i, d) == 1);
+        CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1);
         CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0);
     }
 }
@@ -1787,7 +1787,7 @@ void run_ecdsa_sign_verify(void) {
 }
 
 /** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */
-static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) {
+static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, const void *data, unsigned int counter) {
     (void)msg32;
     (void)key32;
     (void)algo16;
@@ -1795,15 +1795,15 @@ static int precomputed_nonce_function(unsigned char *nonce32, const unsigned cha
     return (counter == 0);
 }
 
-static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) {
+static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, const void *data, unsigned int counter) {
    /* Dummy nonce generator that has a fatal error on the first counter value. */
    if (counter == 0) {
        return 0;
    }
-   return nonce_function_rfc6979(nonce32, msg32, key32, algo16, counter - 1, data);
+   return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1);
 }
 
-static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) {
+static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, const void *data, unsigned int counter) {
    /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */
    if (counter < 3) {
        memset(nonce32, counter==0 ? 0 : 255, 32);
@@ -1830,7 +1830,7 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char
    if (counter > 5) {
        return 0;
    }
-   return nonce_function_rfc6979(nonce32, msg32, key32, algo16, counter - 5, data);
+   return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5);
 }
 
 int is_empty_signature(const secp256k1_ecdsa_signature_t *sig) {
@@ -1849,9 +1849,7 @@ void test_ecdsa_end_to_end(void) {
     unsigned char pubkeyc[65];
     int pubkeyclen = 65;
     secp256k1_pubkey_t pubkey;
-    secp256k1_pubkey_t recpubkey;
     unsigned char seckey[300];
-    int recid = 0;
     int seckeylen = 300;
 
     /* Generate a random key and message. */
@@ -1873,7 +1871,7 @@ void test_ecdsa_end_to_end(void) {
     CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
 
     /* Verify private key import and export. */
-    CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1);
+    CHECK(secp256k1_ec_privkey_export(ctx, seckey, &seckeylen, privkey, secp256k1_rand32() % 2) == 1);
     CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1);
     CHECK(memcmp(privkey, privkey2, 32) == 0);
 
@@ -1912,14 +1910,14 @@ void test_ecdsa_end_to_end(void) {
     }
 
     /* Sign. */
-    CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[0], privkey, NULL, NULL) == 1);
-    CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[4], privkey, NULL, NULL) == 1);
-    CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[1], privkey, NULL, extra) == 1);
+    CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
+    CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1);
+    CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1);
     extra[31] = 1;
-    CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[2], privkey, NULL, extra) == 1);
+    CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1);
     extra[31] = 0;
     extra[0] = 1;
-    CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[3], privkey, NULL, extra) == 1);
+    CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1);
     CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0);
     CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0);
     CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0);
@@ -1928,41 +1926,21 @@ void test_ecdsa_end_to_end(void) {
     CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0);
     CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0);
     /* Verify. */
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 1);
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[1], &pubkey) == 1);
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[2], &pubkey) == 1);
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[3], &pubkey) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1);
 
     /* Serialize/parse DER and verify again */
     CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
     memset(&signature[0], 0, sizeof(signature[0]));
     CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1);
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 1);
+    CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);
     /* Serialize/destroy/parse DER and verify again. */
     CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
     sig[secp256k1_rand32() % siglen] += 1 + (secp256k1_rand32() % 255);
     CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 ||
-          secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 0);
-
-    /* Serialize/parse compact (without recovery id) and verify again. */
-    CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, &recid, &signature[4]) == 1);
-    CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, NULL, &signature[4]) == 1);
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 1);
-    memset(&signature[4], 0, sizeof(signature[4]));
-    CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, -1) == 1);
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 1);
-    /* Parse compact (with recovery id) and recover. */
-    CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, recid) == 1);
-    CHECK(secp256k1_ecdsa_recover(ctx, message, &signature[4], &recpubkey) == 1);
-    CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
-    /* Serialize/destroy/parse signature and verify again. */
-    CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, &recid, &signature[4]) == 1);
-    sig[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
-    CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, recid) == 1);
-    CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 0);
-    /* Recover again */
-    CHECK(secp256k1_ecdsa_recover(ctx, message, &signature[4], &recpubkey) == 0 ||
-          memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
+          secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0);
 }
 
 void test_random_pubkeys(void) {
@@ -2046,142 +2024,8 @@ void run_ecdsa_end_to_end(void) {
 
 /* Tests several edge cases. */
 void test_ecdsa_edge_cases(void) {
-    const unsigned char msg32[32] = {
-        'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
-        'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
-        'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',
-        's', 's', 'a', 'g', 'e', '.', '.', '.'
-    };
-    const unsigned char sig64[64] = {
-        /* Generated by signing the above message with nonce 'This is the nonce we will use...'
-         * and secret key 0 (which is not valid), resulting in recid 0. */
-        0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
-        0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
-        0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
-        0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,
-        0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,
-        0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,
-        0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
-        0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
-    };
-    secp256k1_pubkey_t pubkey;
     int t;
-    /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
-    const unsigned char sigb64[64] = {
-        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, 0x04,
-        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, 0x04,
-    };
-    secp256k1_pubkey_t pubkeyb;
     secp256k1_ecdsa_signature_t sig;
-    int recid;
-
-    CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 0));
-    CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
-    CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 1));
-    CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
-    CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 2));
-    CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
-    CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 3));
-    CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
-
-    for (recid = 0; recid < 4; recid++) {
-        int i;
-        int recid2;
-        /* (4,4) encoded in DER. */
-        unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
-        unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};
-        unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};
-        unsigned char sigbderalt1[39] = {
-            0x30, 0x25, 0x02, 0x20, 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, 0x04, 0x02, 0x01, 0x04,
-        };
-        unsigned char sigbderalt2[39] = {
-            0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 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, 0x04,
-        };
-        unsigned char sigbderalt3[40] = {
-            0x30, 0x26, 0x02, 0x21, 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, 0x00, 0x04, 0x02, 0x01, 0x04,
-        };
-        unsigned char sigbderalt4[40] = {
-            0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 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, 0x00, 0x04,
-        };
-        /* (order + r,4) encoded in DER. */
-        unsigned char sigbderlong[40] = {
-            0x30, 0x26, 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, 0x45, 0x02, 0x01, 0x04
-        };
-        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigb64, recid) == 1);
-        CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 1);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
-        for (recid2 = 0; recid2 < 4; recid2++) {
-            secp256k1_pubkey_t pubkey2b;
-            CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigb64, recid2) == 1);
-            CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey2b) == 1);
-            /* Verifying with (order + r,4) should always fail. */
-            CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 0);
-        }
-        /* DER parsing tests. */
-        /* Zero length r/s. */
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
-        /* Leading zeros. */
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
-        sigbderalt3[4] = 1;
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
-        sigbderalt4[7] = 1;
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
-        /* Damage signature. */
-        sigbder[7]++;
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 0);
-        sigbder[7]--;
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);
-        for(i = 0; i < 8; i++) {
-            int c;
-            unsigned char orig = sigbder[i];
-            /*Try every single-byte change.*/
-            for (c = 0; c < 256; c++) {
-                if (c == orig ) {
-                    continue;
-                }
-                sigbder[i] = c;
-                CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 0);
-            }
-            sigbder[i] = orig;
-        }
-    }
 
     /* Test the case where ECDSA recomputes a point that is infinity. */
     {
@@ -2199,41 +2043,6 @@ void test_ecdsa_edge_cases(void) {
         CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
     }
 
-    /* Test r/s equal to zero */
-    {
-        /* (1,1) encoded in DER. */
-        unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
-        unsigned char sigc64[64] = {
-            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,
-            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_pubkey_t pubkeyc;
-        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1);
-        CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyc) == 1);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 1);
-        sigcder[4] = 0;
-        sigc64[31] = 0;
-        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1);
-        CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 0);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0);
-        sigcder[4] = 1;
-        sigcder[7] = 0;
-        sigc64[31] = 1;
-        sigc64[63] = 0;
-        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1);
-        CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 0);
-        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
-        CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0);
-    }
-
     /*Signature where s would be zero.*/
     {
         unsigned char signature[72];
@@ -2262,11 +2071,11 @@ void test_ecdsa_edge_cases(void) {
             0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,
             0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
         };
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 0);
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 0);
+        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, msg, &sig, key, precomputed_nonce_function, nonce) == 1);
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 1);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1);
         siglen = 72;
         CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);
         siglen = 10;
@@ -2287,33 +2096,33 @@ void test_ecdsa_edge_cases(void) {
         msg[31] = 1;
         /* High key results in signature failure. */
         memset(key, 0xFF, 32);
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);
         CHECK(is_empty_signature(&sig));
         /* Zero key results in signature failure. */
         memset(key, 0, 32);
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);
         CHECK(is_empty_signature(&sig));
         /* Nonce function failure results in signature failure. */
         key[31] = 1;
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_fail, extra) == 0);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0);
         CHECK(is_empty_signature(&sig));
         /* The retry loop successfully makes its way to the first good value. */
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_retry, extra) == 1);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1);
         CHECK(!is_empty_signature(&sig));
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, nonce_function_rfc6979, extra) == 1);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1);
         CHECK(!is_empty_signature(&sig2));
         CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
         /* The default nonce function is determinstic. */
-        CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
+        CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
         CHECK(!is_empty_signature(&sig2));
         CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
         /* The default nonce function changes output with different messages. */
         for(i = 0; i < 256; i++) {
             int j;
             msg[0] = i;
-            CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
+            CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
             CHECK(!is_empty_signature(&sig2));
-            secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, NULL, &sig2);
+            secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
             for (j = 0; j < i; j++) {
                 CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
             }
@@ -2324,9 +2133,9 @@ void test_ecdsa_edge_cases(void) {
         for(i = 256; i < 512; i++) {
             int j;
             key[0] = i - 256;
-            CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
+            CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
             CHECK(!is_empty_signature(&sig2));
-            secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, NULL, &sig2);
+            secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
             for (j = 0; j < i; j++) {
                 CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
             }
@@ -2344,8 +2153,8 @@ void test_ecdsa_edge_cases(void) {
             0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
         };
         int outlen = 300;
-        CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0));
-        CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1));
+        CHECK(!secp256k1_ec_privkey_export(ctx, privkey, &outlen, seckey, 0));
+        CHECK(!secp256k1_ec_privkey_export(ctx, privkey, &outlen, seckey, 1));
     }
 }
 
@@ -2415,6 +2224,10 @@ void run_ecdsa_openssl(void) {
 # include "modules/schnorr/tests_impl.h"
 #endif
 
+#ifdef ENABLE_MODULE_RECOVERY
+# include "modules/recovery/tests_impl.h"
+#endif
+
 int main(int argc, char **argv) {
     unsigned char seed16[16] = {0};
     unsigned char run32[32] = {0};
@@ -2523,6 +2336,11 @@ int main(int argc, char **argv) {
     run_schnorr_tests();
 #endif
 
+#ifdef ENABLE_MODULE_RECOVERY
+    /* ECDSA pubkey recovery tests */
+    run_recovery_tests();
+#endif
+
     secp256k1_rand256(run32);
     printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]);
 
This page took 0.111717 seconds and 4 git commands to generate.