Move pubkey recovery code to separate module
This commit is contained in:
		
							parent
							
								
									d49abbd5a0
								
							
						
					
					
						commit
						9f443be086
					
				| @ -8,12 +8,12 @@ compiler: | ||||
|   - gcc | ||||
| env: | ||||
|   global: | ||||
|     - FIELD=auto  BIGNUM=auto  SCALAR=auto  ENDOMORPHISM=no  STATICPRECOMPUTATION=yes  ASM=no  BUILD=check  EXTRAFLAGS=  HOST=  ECDH=no  schnorr=NO | ||||
|     - FIELD=auto  BIGNUM=auto  SCALAR=auto  ENDOMORPHISM=no  STATICPRECOMPUTATION=yes  ASM=no  BUILD=check  EXTRAFLAGS=  HOST=  ECDH=no  schnorr=NO  RECOVERY=NO | ||||
|   matrix: | ||||
|     - SCALAR=32bit | ||||
|     - SCALAR=32bit    RECOVERY=yes | ||||
|     - SCALAR=32bit    FIELD=32bit       ECDH=yes | ||||
|     - SCALAR=64bit | ||||
|     - FIELD=64bit | ||||
|     - FIELD=64bit     RECOVERY=yes | ||||
|     - FIELD=64bit     ENDOMORPHISM=yes | ||||
|     - FIELD=64bit     ENDOMORPHISM=yes  ECDH=yes | ||||
|     - FIELD=64bit                       ASM=x86_64 | ||||
| @ -21,7 +21,7 @@ env: | ||||
|     - FIELD=32bit     SCHNORR=yes | ||||
|     - FIELD=32bit     ENDOMORPHISM=yes | ||||
|     - BIGNUM=no | ||||
|     - BIGNUM=no       ENDOMORPHISM=yes SCHNORR=yes | ||||
|     - BIGNUM=no       ENDOMORPHISM=yes SCHNORR=yes  RECOVERY=yes | ||||
|     - BIGNUM=no       STATICPRECOMPUTATION=no | ||||
|     - BUILD=distcheck | ||||
|     - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC | ||||
|  | ||||
| @ -51,13 +51,10 @@ libsecp256k1_la_LIBADD = $(SECP_LIBS) | ||||
| 
 | ||||
| noinst_PROGRAMS = | ||||
| if USE_BENCHMARK | ||||
| noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal | ||||
| noinst_PROGRAMS += bench_verify bench_sign bench_internal | ||||
| bench_verify_SOURCES = src/bench_verify.c | ||||
| bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) | ||||
| bench_verify_LDFLAGS = -static | ||||
| bench_recover_SOURCES = src/bench_recover.c | ||||
| bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) | ||||
| bench_recover_LDFLAGS = -static | ||||
| bench_sign_SOURCES = src/bench_sign.c | ||||
| bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) | ||||
| bench_sign_LDFLAGS = -static | ||||
| @ -106,3 +103,7 @@ endif | ||||
| if ENABLE_MODULE_SCHNORR | ||||
| include src/modules/schnorr/Makefile.am.include | ||||
| endif | ||||
| 
 | ||||
| if ENABLE_MODULE_RECOVERY | ||||
| include src/modules/recovery/Makefile.am.include | ||||
| endif | ||||
|  | ||||
							
								
								
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							| @ -114,6 +114,11 @@ AC_ARG_ENABLE(module_schnorr, | ||||
|     [enable_module_schnorr=$enableval], | ||||
|     [enable_module_schnorr=no]) | ||||
| 
 | ||||
| AC_ARG_ENABLE(module_recovery, | ||||
|     AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), | ||||
|     [enable_module_recovery=$enableval], | ||||
|     [enable_module_recovery=no]) | ||||
| 
 | ||||
| AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], | ||||
| [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) | ||||
| 
 | ||||
| @ -335,6 +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]) | ||||
| fi | ||||
| 
 | ||||
| if test x"$enable_module_recovery" = x"yes"; then | ||||
|   AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) | ||||
| fi | ||||
| 
 | ||||
| AC_C_BIGENDIAN() | ||||
| 
 | ||||
| AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) | ||||
| @ -345,6 +354,7 @@ AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) | ||||
| AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) | ||||
| 
 | ||||
| AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) | ||||
| AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) | ||||
| 
 | ||||
| AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) | ||||
| AC_CONFIG_FILES([Makefile libsecp256k1.pc]) | ||||
| @ -357,6 +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([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" | ||||
|  | ||||
| @ -56,24 +56,6 @@ typedef struct { | ||||
|     unsigned char data[64]; | ||||
| } 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.
 | ||||
|  * | ||||
|  * 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 | ||||
| ) 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.
 | ||||
|  * | ||||
|  *  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 | ||||
| ) 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.
 | ||||
|  * | ||||
|  *  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) | ||||
|  *  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, | ||||
|  * inclusive), unlike many other implementations. | ||||
| @ -404,42 +342,6 @@ int secp256k1_ecdsa_sign( | ||||
|     const void *ndata | ||||
| ) 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.
 | ||||
|  * | ||||
|  *  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   * | ||||
|  * 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" | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										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)); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     (void)ctx; | ||||
|     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) { | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     secp256k1_ge_t q; | ||||
|     secp256k1_scalar_t r, s; | ||||
| @ -377,76 +303,6 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms | ||||
|     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) { | ||||
|     secp256k1_scalar_t sec; | ||||
|     int ret; | ||||
| @ -643,3 +499,7 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context_t* ctx, secp256k1_pubkey | ||||
| #ifdef ENABLE_MODULE_SCHNORR | ||||
| # include "modules/schnorr/main_impl.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_MODULE_RECOVERY | ||||
| # include "modules/recovery/main_impl.h" | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     secp256k1_ge_t elem; | ||||
|     secp256k1_ge_t elem2; | ||||
| @ -2075,7 +2019,6 @@ void run_ecdsa_end_to_end(void) { | ||||
|     int i; | ||||
|     for (i = 0; i < 64*count; i++) { | ||||
|         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) { | ||||
|     test_ecdsa_edge_cases(); | ||||
|     test_ecdsa_recovery_edge_cases(); | ||||
| } | ||||
| 
 | ||||
| #ifdef ENABLE_OPENSSL_TESTS | ||||
| @ -2457,6 +2224,10 @@ void run_ecdsa_openssl(void) { | ||||
| # include "modules/schnorr/tests_impl.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_MODULE_RECOVERY | ||||
| # include "modules/recovery/tests_impl.h" | ||||
| #endif | ||||
| 
 | ||||
| int main(int argc, char **argv) { | ||||
|     unsigned char seed16[16] = {0}; | ||||
|     unsigned char run32[32] = {0}; | ||||
| @ -2565,6 +2336,11 @@ int main(int argc, char **argv) { | ||||
|     run_schnorr_tests(); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_MODULE_RECOVERY | ||||
|     /* ECDSA pubkey recovery tests */ | ||||
|     run_recovery_tests(); | ||||
| #endif | ||||
| 
 | ||||
|     secp256k1_rand256(run32); | ||||
|     printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user