- 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
- 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
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
$(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)
if ENABLE_MODULE_SCHNORR
include src/modules/schnorr/Makefile.am.include
endif
+
+if ENABLE_MODULE_RECOVERY
+include src/modules/recovery/Makefile.am.include
+endif
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
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([[
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
[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])
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])
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])
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"
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
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.
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)
/** 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
/** 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
* 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(
* 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(
*
* 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
/** 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,
/** 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,
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,
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);
*
* 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,
*/
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,
/** 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,
/** 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
*/
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
) 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,
) 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,
) 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,
) 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,
/** 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,
/** 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
}
/** 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,
--- /dev/null
+#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
* 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
/** 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);
* 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
* 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
*/
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.
* 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
}
/**********************************************************************
- * 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"
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. */
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));
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);
}
}
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];
}
}
}
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);
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);
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;
--- /dev/null
+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
--- /dev/null
+/**********************************************************************
+ * 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
--- /dev/null
+/**********************************************************************
+ * 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
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);
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;
}
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);
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);
}
}
-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);
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;
}
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);
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);
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);
}
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) {
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));
}
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
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);
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) {
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));
}
}
-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;
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;
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);
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;
}
}
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;
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);
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;
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);
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;
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);
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);
}
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;
#ifdef ENABLE_MODULE_SCHNORR
# include "modules/schnorr/main_impl.h"
#endif
+
+#ifdef ENABLE_MODULE_RECOVERY
+# include "modules/recovery/main_impl.h"
+#endif
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);
}
}
}
/** 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;
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);
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) {
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. */
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);
}
/* 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);
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) {
/* 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. */
{
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];
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;
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]));
}
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]));
}
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));
}
}
# 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};
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]);