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
 | 
			
		||||
) 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
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -214,4 +214,35 @@ int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pu
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
@ -401,6 +401,114 @@ void test_keypair(void) {
 | 
			
		||||
    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) {
 | 
			
		||||
    /* xonly key test cases */
 | 
			
		||||
    test_xonly_pubkey();
 | 
			
		||||
@ -410,6 +518,7 @@ void run_extrakeys_tests(void) {
 | 
			
		||||
 | 
			
		||||
    /* keypair tests */
 | 
			
		||||
    test_keypair();
 | 
			
		||||
    test_keypair_add();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,9 @@ int main(void) {
 | 
			
		||||
        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. */
 | 
			
		||||
    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
 | 
			
		||||
@ -122,11 +124,18 @@ int main(void) {
 | 
			
		||||
    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
 | 
			
		||||
    CHECK(ret);
 | 
			
		||||
 | 
			
		||||
    /* Test keypair_create and keypair_xonly_tweak_add. */
 | 
			
		||||
#if ENABLE_MODULE_EXTRAKEYS
 | 
			
		||||
    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
 | 
			
		||||
    ret = secp256k1_keypair_create(ctx, &keypair, key);
 | 
			
		||||
    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    secp256k1_context_destroy(ctx);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user