Move pubkey recovery code to separate module
This commit is contained in:
		
							parent
							
								
									d49abbd5a0
								
							
						
					
					
						commit
						9f443be086
					
				| @ -8,12 +8,12 @@ compiler: | |||||||
|   - gcc |   - gcc | ||||||
| env: | env: | ||||||
|   global: |   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: |   matrix: | ||||||
|     - SCALAR=32bit |     - SCALAR=32bit    RECOVERY=yes | ||||||
|     - SCALAR=32bit    FIELD=32bit       ECDH=yes |     - SCALAR=32bit    FIELD=32bit       ECDH=yes | ||||||
|     - SCALAR=64bit |     - SCALAR=64bit | ||||||
|     - FIELD=64bit |     - FIELD=64bit     RECOVERY=yes | ||||||
|     - FIELD=64bit     ENDOMORPHISM=yes |     - FIELD=64bit     ENDOMORPHISM=yes | ||||||
|     - FIELD=64bit     ENDOMORPHISM=yes  ECDH=yes |     - FIELD=64bit     ENDOMORPHISM=yes  ECDH=yes | ||||||
|     - FIELD=64bit                       ASM=x86_64 |     - FIELD=64bit                       ASM=x86_64 | ||||||
| @ -21,7 +21,7 @@ env: | |||||||
|     - FIELD=32bit     SCHNORR=yes |     - FIELD=32bit     SCHNORR=yes | ||||||
|     - FIELD=32bit     ENDOMORPHISM=yes |     - FIELD=32bit     ENDOMORPHISM=yes | ||||||
|     - BIGNUM=no |     - BIGNUM=no | ||||||
|     - BIGNUM=no       ENDOMORPHISM=yes SCHNORR=yes |     - BIGNUM=no       ENDOMORPHISM=yes SCHNORR=yes  RECOVERY=yes | ||||||
|     - BIGNUM=no       STATICPRECOMPUTATION=no |     - BIGNUM=no       STATICPRECOMPUTATION=no | ||||||
|     - BUILD=distcheck |     - BUILD=distcheck | ||||||
|     - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC |     - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC | ||||||
|  | |||||||
| @ -51,13 +51,10 @@ libsecp256k1_la_LIBADD = $(SECP_LIBS) | |||||||
| 
 | 
 | ||||||
| noinst_PROGRAMS = | noinst_PROGRAMS = | ||||||
| if USE_BENCHMARK | 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_SOURCES = src/bench_verify.c | ||||||
| bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) | bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) | ||||||
| bench_verify_LDFLAGS = -static | 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_SOURCES = src/bench_sign.c | ||||||
| bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) | bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) | ||||||
| bench_sign_LDFLAGS = -static | bench_sign_LDFLAGS = -static | ||||||
| @ -106,3 +103,7 @@ endif | |||||||
| if ENABLE_MODULE_SCHNORR | if ENABLE_MODULE_SCHNORR | ||||||
| include src/modules/schnorr/Makefile.am.include | include src/modules/schnorr/Makefile.am.include | ||||||
| endif | endif | ||||||
|  | 
 | ||||||
|  | if ENABLE_MODULE_RECOVERY | ||||||
|  | include src/modules/recovery/Makefile.am.include | ||||||
|  | endif | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							| @ -114,6 +114,11 @@ AC_ARG_ENABLE(module_schnorr, | |||||||
|     [enable_module_schnorr=$enableval], |     [enable_module_schnorr=$enableval], | ||||||
|     [enable_module_schnorr=no]) |     [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], | AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], | ||||||
| [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) | [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) | ||||||
| 
 | 
 | ||||||
| @ -335,6 +340,10 @@ if test x"$enable_module_schnorr" = x"yes"; then | |||||||
|   AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) |   AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) | ||||||
| fi | 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_C_BIGENDIAN() | ||||||
| 
 | 
 | ||||||
| AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) | AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) | ||||||
| @ -345,6 +354,7 @@ AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) | |||||||
| AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) | AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) | ||||||
| 
 | 
 | ||||||
| AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) | 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_HEADERS([src/libsecp256k1-config.h]) | ||||||
| AC_CONFIG_FILES([Makefile libsecp256k1.pc]) | AC_CONFIG_FILES([Makefile libsecp256k1.pc]) | ||||||
| @ -357,6 +367,7 @@ AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) | |||||||
| AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"]) | AM_CONDITIONAL([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_ECDH], [test x"$enable_module_ecdh" = x"yes"]) | ||||||
| AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = 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 | dnl make sure nothing new is exported so that we don't break the cache | ||||||
| PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" | PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" | ||||||
|  | |||||||
| @ -56,24 +56,6 @@ typedef struct { | |||||||
|     unsigned char data[64]; |     unsigned char data[64]; | ||||||
| } secp256k1_ecdsa_signature_t; | } secp256k1_ecdsa_signature_t; | ||||||
| 
 | 
 | ||||||
| /** 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; |  | ||||||
| 
 |  | ||||||
| /** A pointer to a function to deterministically generate a nonce.
 | /** A pointer to a function to deterministically generate a nonce.
 | ||||||
|  * |  * | ||||||
|  * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. |  * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. | ||||||
| @ -270,33 +252,6 @@ int secp256k1_ecdsa_signature_parse_der( | |||||||
|     int inputlen |     int inputlen | ||||||
| ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); | ) 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) |  | ||||||
|  *  Out: sig:     a pointer to a signature object |  | ||||||
|  */ |  | ||||||
| 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 |  | ||||||
|  *  In:  sigin:  a pointer to a recoverable signature (cannot be NULL). |  | ||||||
|  *  Out: sig:    a pointer to a normal 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 DER format.
 | /** Serialize an ECDSA signature in DER format.
 | ||||||
|  * |  * | ||||||
|  *  Returns: 1 if enough space was available to serialize, 0 otherwise |  *  Returns: 1 if enough space was available to serialize, 0 otherwise | ||||||
| @ -315,21 +270,6 @@ int secp256k1_ecdsa_signature_serialize_der( | |||||||
|     const secp256k1_ecdsa_signature_t* sig |     const secp256k1_ecdsa_signature_t* sig | ||||||
| ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); | ) 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). |  | ||||||
|  */ |  | ||||||
| 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); |  | ||||||
| 
 |  | ||||||
| /** Verify an ECDSA signature.
 | /** Verify an ECDSA signature.
 | ||||||
|  * |  * | ||||||
|  *  Returns: 1: correct signature |  *  Returns: 1: correct signature | ||||||
| @ -366,8 +306,6 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; | |||||||
|  *           ndata:  pointer to arbitrary data used by the nonce generation function (can be NULL) |  *           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) |  *  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 |  * The sig always has an s value in the lower half of the range (From 0x1 | ||||||
|  * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, |  * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, | ||||||
|  * inclusive), unlike many other implementations. |  * inclusive), unlike many other implementations. | ||||||
| @ -404,42 +342,6 @@ int secp256k1_ecdsa_sign( | |||||||
|     const void *ndata |     const void *ndata | ||||||
| ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); | ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) 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. |  | ||||||
|  *  In:      ctx:    pointer to a context object, initialized for signing (cannot be NULL) |  | ||||||
|  *           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) |  | ||||||
|  */ |  | ||||||
| int secp256k1_ecdsa_sign_recoverable( |  | ||||||
|     const secp256k1_context_t* ctx, |  | ||||||
|     const unsigned char *msg32, |  | ||||||
|     secp256k1_ecdsa_recoverable_signature_t *sig, |  | ||||||
|     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_recoverable_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.
 | /** Verify an ECDSA secret key.
 | ||||||
|  * |  * | ||||||
|  *  Returns: 1: secret key is valid |  *  Returns: 1: secret key is valid | ||||||
|  | |||||||
							
								
								
									
										110
									
								
								include/secp256k1_recovery.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								include/secp256k1_recovery.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | |||||||
|  | #ifndef _SECP256K1_RECOVERY_ | ||||||
|  | # define _SECP256K1_RECOVERY_ | ||||||
|  | 
 | ||||||
|  | # include "secp256k1.h" | ||||||
|  | 
 | ||||||
|  | # ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | # endif | ||||||
|  | 
 | ||||||
|  | /** Opaque data structured that holds a parsed ECDSA signature,
 | ||||||
|  |  *  supporting pubkey recovery. | ||||||
|  |  * | ||||||
|  |  *  The exact representation of data inside is implementation defined and not | ||||||
|  |  *  guaranteed to be portable between different platforms or versions. It is | ||||||
|  |  *  however guaranteed to be 65 bytes in size, and can be safely copied/moved. | ||||||
|  |  *  If you need to convert to a format suitable for storage or transmission, use | ||||||
|  |  *  the secp256k1_ecdsa_signature_serialize_* and | ||||||
|  |  *  secp256k1_ecdsa_signature_serialize_* functions. | ||||||
|  |  * | ||||||
|  |  *  Furthermore, it is guaranteed to identical signatures (including their | ||||||
|  |  *  recoverability) will have identical representation, so they can be | ||||||
|  |  *  memcmp'ed. | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  |     unsigned char data[65]; | ||||||
|  | } secp256k1_ecdsa_recoverable_signature_t; | ||||||
|  | 
 | ||||||
|  | /** Parse a compact ECDSA signature (64 bytes + recovery id).
 | ||||||
|  |  * | ||||||
|  |  *  Returns: 1 when the signature could be parsed, 0 otherwise | ||||||
|  |  *  In:  ctx:     a secp256k1 context object | ||||||
|  |  *       input64: a pointer to a 64-byte compact signature | ||||||
|  |  *       recid:   the recovery id (0, 1, 2 or 3) | ||||||
|  |  *  Out: sig:     a pointer to a signature object | ||||||
|  |  */ | ||||||
|  | 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 | ||||||
|  |  *  In:  sigin:  a pointer to a recoverable signature (cannot be NULL). | ||||||
|  |  *  Out: sig:    a pointer to a normal 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 | ||||||
|  |  *  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). | ||||||
|  |  */ | ||||||
|  | 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. | ||||||
|  |  *  In:      ctx:    pointer to a context object, initialized for signing (cannot be NULL) | ||||||
|  |  *           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) | ||||||
|  |  */ | ||||||
|  | int secp256k1_ecdsa_sign_recoverable( | ||||||
|  |     const secp256k1_context_t* ctx, | ||||||
|  |     const unsigned char *msg32, | ||||||
|  |     secp256k1_ecdsa_recoverable_signature_t *sig, | ||||||
|  |     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_recoverable_signature_t *sig, | ||||||
|  |     secp256k1_pubkey_t *pubkey | ||||||
|  | ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); | ||||||
|  | 
 | ||||||
|  | # ifdef __cplusplus | ||||||
|  | } | ||||||
|  | # endif | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| @ -1,10 +1,11 @@ | |||||||
| /**********************************************************************
 | /**********************************************************************
 | ||||||
|  * Copyright (c) 2014 Pieter Wuille                                   * |  * Copyright (c) 2014-2015 Pieter Wuille                              * | ||||||
|  * Distributed under the MIT software license, see the accompanying   * |  * Distributed under the MIT software license, see the accompanying   * | ||||||
|  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
 |  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
 | ||||||
|  **********************************************************************/ |  **********************************************************************/ | ||||||
| 
 | 
 | ||||||
| #include "include/secp256k1.h" | #include "include/secp256k1.h" | ||||||
|  | #include "include/secp256k1_recovery.h" | ||||||
| #include "util.h" | #include "util.h" | ||||||
| #include "bench.h" | #include "bench.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								src/modules/recovery/Makefile.am.include
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/modules/recovery/Makefile.am.include
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | include_HEADERS += include/secp256k1_recovery.h | ||||||
|  | noinst_HEADERS += src/modules/recovery/main_impl.h | ||||||
|  | noinst_HEADERS += src/modules/recovery/tests_impl.h | ||||||
|  | if USE_BENCHMARK | ||||||
|  | noinst_PROGRAMS += bench_recover | ||||||
|  | bench_recover_SOURCES = src/bench_recover.c | ||||||
|  | bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) | ||||||
|  | bench_recover_LDFLAGS = -static | ||||||
|  | endif | ||||||
							
								
								
									
										156
									
								
								src/modules/recovery/main_impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								src/modules/recovery/main_impl.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | |||||||
|  | /**********************************************************************
 | ||||||
|  |  * Copyright (c) 2013-2015 Pieter Wuille                              * | ||||||
|  |  * Distributed under the MIT software license, see the accompanying   * | ||||||
|  |  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
 | ||||||
|  |  **********************************************************************/ | ||||||
|  | 
 | ||||||
|  | #ifndef _SECP256K1_MODULE_RECOVERY_MAIN_ | ||||||
|  | #define _SECP256K1_MODULE_RECOVERY_MAIN_ | ||||||
|  | 
 | ||||||
|  | #include "include/secp256k1_recovery.h" | ||||||
|  | 
 | ||||||
|  | static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context_t* ctx, secp256k1_scalar_t* r, secp256k1_scalar_t* s, int* recid, const secp256k1_ecdsa_recoverable_signature_t* sig) { | ||||||
|  |     (void)ctx; | ||||||
|  |     if (sizeof(secp256k1_scalar_t) == 32) { | ||||||
|  |         /* When the secp256k1_scalar_t type is exactly 32 byte, use its
 | ||||||
|  |          * representation inside secp256k1_ecdsa_signature_t, as conversion is very fast. | ||||||
|  |          * Note that secp256k1_ecdsa_signature_save must use the same representation. */ | ||||||
|  |         memcpy(r, &sig->data[0], 32); | ||||||
|  |         memcpy(s, &sig->data[32], 32); | ||||||
|  |     } else { | ||||||
|  |         secp256k1_scalar_set_b32(r, &sig->data[0], NULL); | ||||||
|  |         secp256k1_scalar_set_b32(s, &sig->data[32], NULL); | ||||||
|  |     } | ||||||
|  |     *recid = sig->data[64]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature_t* sig, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, int recid) { | ||||||
|  |     if (sizeof(secp256k1_scalar_t) == 32) { | ||||||
|  |         memcpy(&sig->data[0], r, 32); | ||||||
|  |         memcpy(&sig->data[32], s, 32); | ||||||
|  |     } else { | ||||||
|  |         secp256k1_scalar_get_b32(&sig->data[0], r); | ||||||
|  |         secp256k1_scalar_get_b32(&sig->data[32], s); | ||||||
|  |     } | ||||||
|  |     sig->data[64] = recid; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context_t* ctx, secp256k1_ecdsa_recoverable_signature_t* sig, const unsigned char *input64, int recid) { | ||||||
|  |     secp256k1_scalar_t r, s; | ||||||
|  |     int ret = 1; | ||||||
|  |     int overflow = 0; | ||||||
|  | 
 | ||||||
|  |     (void)ctx; | ||||||
|  |     ARG_CHECK(sig != NULL); | ||||||
|  |     ARG_CHECK(input64 != NULL); | ||||||
|  |     ARG_CHECK(recid >= 0 && recid <= 3); | ||||||
|  | 
 | ||||||
|  |     secp256k1_scalar_set_b32(&r, &input64[0], &overflow); | ||||||
|  |     ret &= !overflow; | ||||||
|  |     secp256k1_scalar_set_b32(&s, &input64[32], &overflow); | ||||||
|  |     ret &= !overflow; | ||||||
|  |     if (ret) { | ||||||
|  |         secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); | ||||||
|  |     } else { | ||||||
|  |         memset(sig, 0, sizeof(*sig)); | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context_t* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature_t* sig) { | ||||||
|  |     secp256k1_scalar_t r, s; | ||||||
|  | 
 | ||||||
|  |     (void)ctx; | ||||||
|  |     ARG_CHECK(output64 != NULL); | ||||||
|  |     ARG_CHECK(sig != NULL); | ||||||
|  | 
 | ||||||
|  |     secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); | ||||||
|  |     secp256k1_scalar_get_b32(&output64[0], &r); | ||||||
|  |     secp256k1_scalar_get_b32(&output64[32], &s); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const secp256k1_ecdsa_recoverable_signature_t* sigin) { | ||||||
|  |     secp256k1_scalar_t r, s; | ||||||
|  |     int recid; | ||||||
|  | 
 | ||||||
|  |     (void)ctx; | ||||||
|  |     ARG_CHECK(sig != NULL); | ||||||
|  |     ARG_CHECK(sigin != NULL); | ||||||
|  | 
 | ||||||
|  |     secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); | ||||||
|  |     secp256k1_ecdsa_signature_save(sig, &r, &s); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int secp256k1_ecdsa_sign_recoverable(const secp256k1_context_t* ctx, const unsigned char *msg32, secp256k1_ecdsa_recoverable_signature_t *signature, 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); | ||||||
|  |     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, msg32, seckey, NULL, count, noncedata); | ||||||
|  |             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, const unsigned char *msg32, const secp256k1_ecdsa_recoverable_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_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 | ||||||
							
								
								
									
										249
									
								
								src/modules/recovery/tests_impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								src/modules/recovery/tests_impl.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,249 @@ | |||||||
|  | /**********************************************************************
 | ||||||
|  |  * Copyright (c) 2013-2015 Pieter Wuille                              * | ||||||
|  |  * Distributed under the MIT software license, see the accompanying   * | ||||||
|  |  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
 | ||||||
|  |  **********************************************************************/ | ||||||
|  | 
 | ||||||
|  | #ifndef _SECP256K1_MODULE_RECOVERY_TESTS_ | ||||||
|  | #define _SECP256K1_MODULE_RECOVERY_TESTS_ | ||||||
|  | 
 | ||||||
|  | void test_ecdsa_recovery_end_to_end(void) { | ||||||
|  |     unsigned char extra[32] = {0x00}; | ||||||
|  |     unsigned char privkey[32]; | ||||||
|  |     unsigned char message[32]; | ||||||
|  |     secp256k1_ecdsa_signature_t signature[5]; | ||||||
|  |     secp256k1_ecdsa_recoverable_signature_t rsignature[5]; | ||||||
|  |     unsigned char sig[74]; | ||||||
|  |     secp256k1_pubkey_t pubkey; | ||||||
|  |     secp256k1_pubkey_t recpubkey; | ||||||
|  |     int recid = 0; | ||||||
|  | 
 | ||||||
|  |     /* Generate a random key and message. */ | ||||||
|  |     { | ||||||
|  |         secp256k1_scalar_t msg, key; | ||||||
|  |         random_scalar_order_test(&msg); | ||||||
|  |         random_scalar_order_test(&key); | ||||||
|  |         secp256k1_scalar_get_b32(privkey, &key); | ||||||
|  |         secp256k1_scalar_get_b32(message, &msg); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* Construct and verify corresponding public key. */ | ||||||
|  |     CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); | ||||||
|  |     CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); | ||||||
|  | 
 | ||||||
|  |     /* Serialize/parse compact and verify/recover. */ | ||||||
|  |     extra[0] = 0; | ||||||
|  |     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[0], privkey, NULL, NULL) == 1); | ||||||
|  |     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[4], privkey, NULL, NULL) == 1); | ||||||
|  |     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[1], privkey, NULL, extra) == 1); | ||||||
|  |     extra[31] = 1; | ||||||
|  |     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[2], privkey, NULL, extra) == 1); | ||||||
|  |     extra[31] = 0; | ||||||
|  |     extra[0] = 1; | ||||||
|  |     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[3], 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, message, &signature[4], &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, message, &signature[4], &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, message, &rsignature[4], &recpubkey) == 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, message, &signature[4], &pubkey) == 0); | ||||||
|  |     /* Recover again */ | ||||||
|  |     CHECK(secp256k1_ecdsa_recover(ctx, message, &rsignature[4], &recpubkey) == 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, msg32, &rsig, &pubkey)); | ||||||
|  |     CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); | ||||||
|  |     CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &pubkey)); | ||||||
|  |     CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); | ||||||
|  |     CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &rsig, &pubkey)); | ||||||
|  |     CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); | ||||||
|  |     CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); | ||||||
|  |         CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); | ||||||
|  |             CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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 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, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); | ||||||
|  |         CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); | ||||||
|  |         CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &pubkeyb) == 0); | ||||||
|  |         CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); | ||||||
|  |         CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &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 | ||||||
							
								
								
									
										148
									
								
								src/secp256k1.c
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								src/secp256k1.c
									
									
									
									
									
								
							| @ -155,32 +155,6 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context_t* ctx, unsigned char | |||||||
|             secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, compressed)); |             secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, compressed)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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) { | 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; |     (void)ctx; | ||||||
|     if (sizeof(secp256k1_scalar_t) == 32) { |     if (sizeof(secp256k1_scalar_t) == 32) { | ||||||
| @ -221,28 +195,6 @@ int secp256k1_ecdsa_signature_parse_der(const secp256k1_context_t* ctx, secp256k | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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_signature_serialize_der(const secp256k1_context_t* ctx, unsigned char *output, int *outputlen, const secp256k1_ecdsa_signature_t* sig) { | 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; |     secp256k1_scalar_t r, s; | ||||||
| 
 | 
 | ||||||
| @ -255,32 +207,6 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context_t* ctx, unsi | |||||||
|     return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); |     return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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_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 unsigned char *msg32, const secp256k1_ecdsa_signature_t *sig, const secp256k1_pubkey_t *pubkey) { | ||||||
|     secp256k1_ge_t q; |     secp256k1_ge_t q; | ||||||
|     secp256k1_scalar_t r, s; |     secp256k1_scalar_t r, s; | ||||||
| @ -377,76 +303,6 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms | |||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int secp256k1_ecdsa_sign_recoverable(const secp256k1_context_t* ctx, const unsigned char *msg32, secp256k1_ecdsa_recoverable_signature_t *signature, 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); |  | ||||||
|     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, msg32, seckey, NULL, count, noncedata); |  | ||||||
|             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, const unsigned char *msg32, const secp256k1_ecdsa_recoverable_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_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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { | int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { | ||||||
|     secp256k1_scalar_t sec; |     secp256k1_scalar_t sec; | ||||||
|     int ret; |     int ret; | ||||||
| @ -643,3 +499,7 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context_t* ctx, secp256k1_pubkey | |||||||
| #ifdef ENABLE_MODULE_SCHNORR | #ifdef ENABLE_MODULE_SCHNORR | ||||||
| # include "modules/schnorr/main_impl.h" | # include "modules/schnorr/main_impl.h" | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef ENABLE_MODULE_RECOVERY | ||||||
|  | # include "modules/recovery/main_impl.h" | ||||||
|  | #endif | ||||||
|  | |||||||
							
								
								
									
										242
									
								
								src/tests.c
									
									
									
									
									
								
							
							
						
						
									
										242
									
								
								src/tests.c
									
									
									
									
									
								
							| @ -1943,62 +1943,6 @@ void test_ecdsa_end_to_end(void) { | |||||||
|           secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 0); |           secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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, message, &rsignature[0], privkey, NULL, NULL) == 1); |  | ||||||
|     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[4], privkey, NULL, NULL) == 1); |  | ||||||
|     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[1], privkey, NULL, extra) == 1); |  | ||||||
|     extra[31] = 1; |  | ||||||
|     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[2], privkey, NULL, extra) == 1); |  | ||||||
|     extra[31] = 0; |  | ||||||
|     extra[0] = 1; |  | ||||||
|     CHECK(secp256k1_ecdsa_sign_recoverable(ctx, message, &rsignature[3], 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, message, &signature[4], &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, message, &signature[4], &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, message, &rsignature[4], &recpubkey) == 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, message, &signature[4], &pubkey) == 0); |  | ||||||
|     /* Recover again */ |  | ||||||
|     CHECK(secp256k1_ecdsa_recover(ctx, message, &rsignature[4], &recpubkey) == 0 || |  | ||||||
|           memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void test_random_pubkeys(void) { | void test_random_pubkeys(void) { | ||||||
|     secp256k1_ge_t elem; |     secp256k1_ge_t elem; | ||||||
|     secp256k1_ge_t elem2; |     secp256k1_ge_t elem2; | ||||||
| @ -2075,7 +2019,6 @@ void run_ecdsa_end_to_end(void) { | |||||||
|     int i; |     int i; | ||||||
|     for (i = 0; i < 64*count; i++) { |     for (i = 0; i < 64*count; i++) { | ||||||
|         test_ecdsa_end_to_end(); |         test_ecdsa_end_to_end(); | ||||||
|         test_ecdsa_recovery_end_to_end(); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -2215,184 +2158,8 @@ void test_ecdsa_edge_cases(void) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* 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, msg32, &rsig, &pubkey)); |  | ||||||
|     CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); |  | ||||||
|     CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &pubkey)); |  | ||||||
|     CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); |  | ||||||
|     CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &rsig, &pubkey)); |  | ||||||
|     CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); |  | ||||||
|     CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); |  | ||||||
|         CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); |  | ||||||
|             CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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 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, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); |  | ||||||
|         CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &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_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); |  | ||||||
|         CHECK(secp256k1_ecdsa_recover(ctx, msg32, &rsig, &pubkeyb) == 0); |  | ||||||
|         CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); |  | ||||||
|         CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void run_ecdsa_edge_cases(void) { | void run_ecdsa_edge_cases(void) { | ||||||
|     test_ecdsa_edge_cases(); |     test_ecdsa_edge_cases(); | ||||||
|     test_ecdsa_recovery_edge_cases(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef ENABLE_OPENSSL_TESTS | #ifdef ENABLE_OPENSSL_TESTS | ||||||
| @ -2457,6 +2224,10 @@ void run_ecdsa_openssl(void) { | |||||||
| # include "modules/schnorr/tests_impl.h" | # include "modules/schnorr/tests_impl.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef ENABLE_MODULE_RECOVERY | ||||||
|  | # include "modules/recovery/tests_impl.h" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||||
|     unsigned char seed16[16] = {0}; |     unsigned char seed16[16] = {0}; | ||||||
|     unsigned char run32[32] = {0}; |     unsigned char run32[32] = {0}; | ||||||
| @ -2565,6 +2336,11 @@ int main(int argc, char **argv) { | |||||||
|     run_schnorr_tests(); |     run_schnorr_tests(); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef ENABLE_MODULE_RECOVERY | ||||||
|  |     /* ECDSA pubkey recovery tests */ | ||||||
|  |     run_recovery_tests(); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     secp256k1_rand256(run32); |     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]); |     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]); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user