extrakeys: Add keypair_xonly_tweak_add
This commit is contained in:
		
							parent
							
								
									58254463f9
								
							
						
					
					
						commit
						6fcb5b845d
					
				| @ -202,6 +202,33 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( | |||||||
|     const secp256k1_keypair *keypair |     const secp256k1_keypair *keypair | ||||||
| ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); | ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); | ||||||
| 
 | 
 | ||||||
|  | /** Tweak a keypair by adding tweak32 to the secret key and updating the public
 | ||||||
|  |  *  key accordingly. | ||||||
|  |  * | ||||||
|  |  *  Calling this function and then secp256k1_keypair_pub results in the same | ||||||
|  |  *  public key as calling secp256k1_keypair_xonly_pub and then | ||||||
|  |  *  secp256k1_xonly_pubkey_tweak_add. | ||||||
|  |  * | ||||||
|  |  *  Returns: 0 if the arguments are invalid or the resulting keypair would be | ||||||
|  |  *           invalid (only when the tweak is the negation of the keypair's | ||||||
|  |  *           secret key). 1 otherwise. | ||||||
|  |  * | ||||||
|  |  *  Args:       ctx: pointer to a context object initialized for verification | ||||||
|  |  *                   (cannot be NULL) | ||||||
|  |  *  In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to | ||||||
|  |  *                   an invalid value if this function returns 0 (cannot be | ||||||
|  |  *                   NULL). | ||||||
|  |  *  In:     tweak32: pointer to a 32-byte tweak. If the tweak is invalid according | ||||||
|  |  *                   to secp256k1_ec_seckey_verify, this function returns 0. For | ||||||
|  |  *                   uniformly random 32-byte arrays the chance of being invalid | ||||||
|  |  *                   is negligible (around 1 in 2^128) (cannot be NULL). | ||||||
|  |  */ | ||||||
|  | SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add( | ||||||
|  |     const secp256k1_context* ctx, | ||||||
|  |     secp256k1_keypair *keypair, | ||||||
|  |     const unsigned char *tweak32 | ||||||
|  | ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -214,4 +214,35 @@ int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pu | |||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) { | ||||||
|  |     secp256k1_ge pk; | ||||||
|  |     secp256k1_scalar sk; | ||||||
|  |     int y_parity; | ||||||
|  |     int ret; | ||||||
|  | 
 | ||||||
|  |     VERIFY_CHECK(ctx != NULL); | ||||||
|  |     ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); | ||||||
|  |     ARG_CHECK(keypair != NULL); | ||||||
|  |     ARG_CHECK(tweak32 != NULL); | ||||||
|  | 
 | ||||||
|  |     ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair); | ||||||
|  |     memset(keypair, 0, sizeof(*keypair)); | ||||||
|  | 
 | ||||||
|  |     y_parity = secp256k1_extrakeys_ge_even_y(&pk); | ||||||
|  |     if (y_parity == 1) { | ||||||
|  |         secp256k1_scalar_negate(&sk, &sk); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32); | ||||||
|  |     ret &= secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32); | ||||||
|  | 
 | ||||||
|  |     secp256k1_declassify(ctx, &ret, sizeof(ret)); | ||||||
|  |     if (ret) { | ||||||
|  |         secp256k1_keypair_save(keypair, &sk, &pk); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     secp256k1_scalar_clear(&sk); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -401,6 +401,114 @@ void test_keypair(void) { | |||||||
|     secp256k1_context_destroy(verify); |     secp256k1_context_destroy(verify); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void test_keypair_add(void) { | ||||||
|  |     unsigned char sk[32]; | ||||||
|  |     secp256k1_keypair keypair; | ||||||
|  |     unsigned char overflows[32]; | ||||||
|  |     unsigned char zeros96[96] = { 0 }; | ||||||
|  |     unsigned char tweak[32]; | ||||||
|  |     int i; | ||||||
|  |     int ecount = 0; | ||||||
|  |     secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); | ||||||
|  |     secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); | ||||||
|  |     secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); | ||||||
|  | 
 | ||||||
|  |     CHECK(sizeof(zeros96) == sizeof(keypair)); | ||||||
|  |     secp256k1_rand256(sk); | ||||||
|  |     secp256k1_rand256(tweak); | ||||||
|  |     memset(overflows, 0xFF, 32); | ||||||
|  |     CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); | ||||||
|  | 
 | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 0); | ||||||
|  |     CHECK(ecount == 1); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 0); | ||||||
|  |     CHECK(ecount == 2); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0); | ||||||
|  |     CHECK(ecount == 3); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0); | ||||||
|  |     CHECK(ecount == 4); | ||||||
|  |     /* This does not set the keypair to zeroes */ | ||||||
|  |     CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) != 0); | ||||||
|  | 
 | ||||||
|  |     /* Invalid tweak zeroes the keypair */ | ||||||
|  |     CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0); | ||||||
|  |     CHECK(memcmp(&keypair, zeros96, sizeof(keypair))  == 0); | ||||||
|  | 
 | ||||||
|  |     /* A zero tweak is fine */ | ||||||
|  |     CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1); | ||||||
|  | 
 | ||||||
|  |     /* Fails if the resulting keypair was (sk=0, pk=infinity) */ | ||||||
|  |     for (i = 0; i < count; i++) { | ||||||
|  |         secp256k1_scalar scalar_tweak; | ||||||
|  |         secp256k1_keypair keypair_tmp; | ||||||
|  |         secp256k1_rand256(sk); | ||||||
|  |         CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); | ||||||
|  |         memcpy(&keypair_tmp, &keypair, sizeof(keypair)); | ||||||
|  |         /* Because sk may be negated before adding, we need to try with tweak =
 | ||||||
|  |          * sk as well as tweak = -sk. */ | ||||||
|  |         secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); | ||||||
|  |         secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); | ||||||
|  |         secp256k1_scalar_get_b32(tweak, &scalar_tweak); | ||||||
|  |         CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0) | ||||||
|  |               || (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0)); | ||||||
|  |         CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0 | ||||||
|  |               || memcmp(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* Invalid keypair with a valid tweak */ | ||||||
|  |     memset(&keypair, 0, sizeof(keypair)); | ||||||
|  |     secp256k1_rand256(tweak); | ||||||
|  |     ecount = 0; | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); | ||||||
|  |     CHECK(ecount == 1); | ||||||
|  |     CHECK(memcmp(&keypair, zeros96, sizeof(keypair))  == 0); | ||||||
|  |     /* Only seckey part of keypair invalid */ | ||||||
|  |     CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); | ||||||
|  |     memset(&keypair, 0, 32); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); | ||||||
|  |     CHECK(ecount == 2); | ||||||
|  |     /* Only pubkey part of keypair invalid */ | ||||||
|  |     CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); | ||||||
|  |     memset(&keypair.data[32], 0, 64); | ||||||
|  |     CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); | ||||||
|  |     CHECK(ecount == 3); | ||||||
|  | 
 | ||||||
|  |     /* Check that the keypair_tweak_add implementation is correct */ | ||||||
|  |     CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); | ||||||
|  |     for (i = 0; i < count; i++) { | ||||||
|  |         secp256k1_xonly_pubkey internal_pk; | ||||||
|  |         secp256k1_xonly_pubkey output_pk; | ||||||
|  |         secp256k1_pubkey output_pk_xy; | ||||||
|  |         secp256k1_pubkey output_pk_expected; | ||||||
|  |         unsigned char pk32[32]; | ||||||
|  |         int pk_parity; | ||||||
|  | 
 | ||||||
|  |         secp256k1_rand256(tweak); | ||||||
|  |         CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1); | ||||||
|  |         CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); | ||||||
|  |         CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1); | ||||||
|  | 
 | ||||||
|  |         /* Check that it passes xonly_pubkey_tweak_add_check */ | ||||||
|  |         CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1); | ||||||
|  |         CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1); | ||||||
|  | 
 | ||||||
|  |         /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ | ||||||
|  |         CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1); | ||||||
|  |         CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1); | ||||||
|  |         CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); | ||||||
|  | 
 | ||||||
|  |         /* Check that the secret key in the keypair is tweaked correctly */ | ||||||
|  |         CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1); | ||||||
|  |         CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); | ||||||
|  |     } | ||||||
|  |     secp256k1_context_destroy(none); | ||||||
|  |     secp256k1_context_destroy(sign); | ||||||
|  |     secp256k1_context_destroy(verify); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void run_extrakeys_tests(void) { | void run_extrakeys_tests(void) { | ||||||
|     /* xonly key test cases */ |     /* xonly key test cases */ | ||||||
|     test_xonly_pubkey(); |     test_xonly_pubkey(); | ||||||
| @ -410,6 +518,7 @@ void run_extrakeys_tests(void) { | |||||||
| 
 | 
 | ||||||
|     /* keypair tests */ |     /* keypair tests */ | ||||||
|     test_keypair(); |     test_keypair(); | ||||||
|  |     test_keypair_add(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -57,7 +57,9 @@ int main(void) { | |||||||
|         msg[i] = i + 1; |         msg[i] = i + 1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_DECLASSIFY); |     ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | ||||||
|  |                                    | SECP256K1_CONTEXT_VERIFY | ||||||
|  |                                    | SECP256K1_CONTEXT_DECLASSIFY); | ||||||
| 
 | 
 | ||||||
|     /* Test keygen. */ |     /* Test keygen. */ | ||||||
|     VALGRIND_MAKE_MEM_UNDEFINED(key, 32); |     VALGRIND_MAKE_MEM_UNDEFINED(key, 32); | ||||||
| @ -122,11 +124,18 @@ int main(void) { | |||||||
|     VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); |     VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); | ||||||
|     CHECK(ret); |     CHECK(ret); | ||||||
| 
 | 
 | ||||||
|  |     /* Test keypair_create and keypair_xonly_tweak_add. */ | ||||||
| #if ENABLE_MODULE_EXTRAKEYS | #if ENABLE_MODULE_EXTRAKEYS | ||||||
|     VALGRIND_MAKE_MEM_UNDEFINED(key, 32); |     VALGRIND_MAKE_MEM_UNDEFINED(key, 32); | ||||||
|     ret = secp256k1_keypair_create(ctx, &keypair, key); |     ret = secp256k1_keypair_create(ctx, &keypair, key); | ||||||
|     VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); |     VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); | ||||||
|     CHECK(ret == 1); |     CHECK(ret == 1); | ||||||
|  | 
 | ||||||
|  |     /* The tweak is not treated as a secret in keypair_tweak_add */ | ||||||
|  |     VALGRIND_MAKE_MEM_DEFINED(msg, 32); | ||||||
|  |     ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg); | ||||||
|  |     VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); | ||||||
|  |     CHECK(ret == 1); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     secp256k1_context_destroy(ctx); |     secp256k1_context_destroy(ctx); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user