diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h index 0c5dff2c9..6fc7b290f 100644 --- a/src/secp256k1/include/secp256k1_extrakeys.h +++ b/src/secp256k1/include/secp256k1_extrakeys.h @@ -1,236 +1,249 @@ #ifndef SECP256K1_EXTRAKEYS_H #define SECP256K1_EXTRAKEYS_H #include "secp256k1.h" #ifdef __cplusplus extern "C" { #endif /** Opaque data structure that holds a parsed and valid "x-only" public key. * An x-only pubkey encodes a point whose Y coordinate is even. It is * serialized using only its X coordinate (32 bytes). See BIP-340 for more * information about x-only pubkeys. * * 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 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage, transmission, or * comparison, use secp256k1_xonly_pubkey_serialize and * secp256k1_xonly_pubkey_parse. */ typedef struct { unsigned char data[64]; } secp256k1_xonly_pubkey; /** Opaque data structure that holds a keypair consisting of a secret and a * public key. * * 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 96 bytes in size, and can be safely copied/moved. */ typedef struct { unsigned char data[96]; } secp256k1_keypair; /** Parse a 32-byte sequence into a xonly_pubkey object. * * Returns: 1 if the public key was fully valid. * 0 if the public key could not be parsed or is invalid. * * Args: ctx: a secp256k1 context object (cannot be NULL). * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a * parsed version of input. If not, it's set to an invalid value. * (cannot be NULL). * In: input32: pointer to a serialized xonly_pubkey (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse( const secp256k1_context* ctx, secp256k1_xonly_pubkey* pubkey, const unsigned char *input32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Serialize an xonly_pubkey object into a 32-byte sequence. * * Returns: 1 always. * * Args: ctx: a secp256k1 context object (cannot be NULL). * Out: output32: a pointer to a 32-byte array to place the serialized key in * (cannot be NULL). * In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an * initialized public key (cannot be NULL). */ SECP256K1_API int secp256k1_xonly_pubkey_serialize( const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey* pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey. * * Returns: 1 if the public key was successfully converted * 0 otherwise * * Args: ctx: pointer to a context object (cannot be NULL) * Out: xonly_pubkey: pointer to an x-only public key object for placing the * converted public key (cannot be NULL) * pk_parity: pointer to an integer that will be set to 1 if the point * encoded by xonly_pubkey is the negation of the pubkey and * set to 0 otherwise. (can be NULL) * In: pubkey: pointer to a public key that is converted (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); /** Tweak an x-only public key by adding the generator multiplied with tweak32 * to it. * * Note that the resulting point can not in general be represented by an x-only * pubkey because it may have an odd Y coordinate. Instead, the output_pubkey * is a normal secp256k1_pubkey. * * Returns: 0 if the arguments are invalid or the resulting public key would be * invalid (only when the tweak is the negation of the corresponding * secret key). 1 otherwise. * * Args: ctx: pointer to a context object initialized for verification * (cannot be NULL) * Out: output_pubkey: pointer to a public key to store the result. Will be set * to an invalid value if this function returns 0 (cannot * be NULL) * In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to. * (cannot be NULL). * 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_xonly_pubkey_tweak_add( const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Checks that a tweaked pubkey is the result of calling * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32. * * The tweaked pubkey is represented by its 32-byte x-only serialization and * its pk_parity, which can both be obtained by converting the result of * tweak_add to a secp256k1_xonly_pubkey. * * Note that this alone does _not_ verify that the tweaked pubkey is a * commitment. If the tweak is not chosen in a specific way, the tweaked pubkey * can easily be the result of a different internal_pubkey and tweak. * * Returns: 0 if the arguments are invalid or the tweaked pubkey is not the * result of tweaking the internal_pubkey with tweak32. 1 otherwise. * Args: ctx: pointer to a context object initialized for verification * (cannot be NULL) * In: tweaked_pubkey32: pointer to a serialized xonly_pubkey (cannot be NULL) * tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization * is passed in as tweaked_pubkey32). This must match the * pk_parity value that is returned when calling * secp256k1_xonly_pubkey with the tweaked pubkey, or * this function will fail. * internal_pubkey: pointer to an x-only public key object to apply the * tweak to (cannot be NULL) * tweak32: pointer to a 32-byte tweak (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check( const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); /** Compute the keypair for a secret key. * * Returns: 1: secret was valid, keypair is ready to use * 0: secret was invalid, try again with a different secret * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) * Out: keypair: pointer to the created keypair (cannot be NULL) * In: seckey: pointer to a 32-byte secret key (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create( const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Get the secret key from a keypair. + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: seckey: pointer to a 32-byte buffer for the secret key (cannot be NULL) + * In: keypair: pointer to a keypair (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( + const secp256k1_context* ctx, + unsigned char *seckey, + const secp256k1_keypair *keypair +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + /** Get the public key from a keypair. * * Returns: 0 if the arguments are invalid. 1 otherwise. * Args: ctx: pointer to a context object (cannot be NULL) * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to * the keypair public key. If not, it's set to an invalid value. * (cannot be NULL) * In: keypair: pointer to a keypair (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Get the x-only public key from a keypair. * * This is the same as calling secp256k1_keypair_pub and then * secp256k1_xonly_pubkey_from_pubkey. * * Returns: 0 if the arguments are invalid. 1 otherwise. * Args: ctx: pointer to a context object (cannot be NULL) * Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set * to the keypair public key after converting it to an * xonly_pubkey. If not, it's set to an invalid value (cannot be * NULL). * pk_parity: pointer to an integer that will be set to the pk_parity * argument of secp256k1_xonly_pubkey_from_pubkey (can be NULL). * In: keypair: pointer to a keypair (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, 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 #endif /* SECP256K1_EXTRAKEYS_H */ diff --git a/src/secp256k1/src/modules/extrakeys/main_impl.h b/src/secp256k1/src/modules/extrakeys/main_impl.h index e8beaa3f1..81be7e7d5 100644 --- a/src/secp256k1/src/modules/extrakeys/main_impl.h +++ b/src/secp256k1/src/modules/extrakeys/main_impl.h @@ -1,251 +1,261 @@ /*********************************************************************** * Copyright (c) 2020 Jonas Nick * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ #ifndef _SECP256K1_MODULE_EXTRAKEYS_MAIN_ #define _SECP256K1_MODULE_EXTRAKEYS_MAIN_ #include "include/secp256k1.h" #include "include/secp256k1_extrakeys.h" static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) { return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey); } static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) { secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge); } int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) { secp256k1_ge pk; secp256k1_fe x; VERIFY_CHECK(ctx != NULL); ARG_CHECK(pubkey != NULL); memset(pubkey, 0, sizeof(*pubkey)); ARG_CHECK(input32 != NULL); if (!secp256k1_fe_set_b32(&x, input32)) { return 0; } if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) { return 0; } if (!secp256k1_ge_is_in_correct_subgroup(&pk)) { return 0; } secp256k1_xonly_pubkey_save(pubkey, &pk); return 1; } int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) { secp256k1_ge pk; VERIFY_CHECK(ctx != NULL); ARG_CHECK(output32 != NULL); memset(output32, 0, 32); ARG_CHECK(pubkey != NULL); if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) { return 0; } secp256k1_fe_get_b32(output32, &pk.x); return 1; } /** Keeps a group element as is if it has an even Y and otherwise negates it. * y_parity is set to 0 in the former case and to 1 in the latter case. * Requires that the coordinates of r are normalized. */ static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) { int y_parity = 0; VERIFY_CHECK(!secp256k1_ge_is_infinity(r)); if (secp256k1_fe_is_odd(&r->y)) { secp256k1_fe_negate(&r->y, &r->y, 1); y_parity = 1; } return y_parity; } int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) { secp256k1_ge pk; int tmp; VERIFY_CHECK(ctx != NULL); ARG_CHECK(xonly_pubkey != NULL); ARG_CHECK(pubkey != NULL); if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { return 0; } tmp = secp256k1_extrakeys_ge_even_y(&pk); if (pk_parity != NULL) { *pk_parity = tmp; } secp256k1_xonly_pubkey_save(xonly_pubkey, &pk); return 1; } int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { secp256k1_ge pk; VERIFY_CHECK(ctx != NULL); ARG_CHECK(output_pubkey != NULL); memset(output_pubkey, 0, sizeof(*output_pubkey)); ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(internal_pubkey != NULL); ARG_CHECK(tweak32 != NULL); if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) || !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) { return 0; } secp256k1_pubkey_save(output_pubkey, &pk); return 1; } int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { secp256k1_ge pk; unsigned char pk_expected32[32]; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(internal_pubkey != NULL); ARG_CHECK(tweaked_pubkey32 != NULL); ARG_CHECK(tweak32 != NULL); if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) || !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) { return 0; } secp256k1_fe_normalize_var(&pk.x); secp256k1_fe_normalize_var(&pk.y); secp256k1_fe_get_b32(pk_expected32, &pk.x); return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0 && secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity; } static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) { secp256k1_scalar_get_b32(&keypair->data[0], sk); secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk); } static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) { int ret; ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]); /* We can declassify ret here because sk is only zero if a keypair function * failed (which zeroes the keypair) and its return value is ignored. */ secp256k1_declassify(ctx, &ret, sizeof(ret)); ARG_CHECK(ret); return ret; } /* Load a keypair into pk and sk (if non-NULL). This function declassifies pk * and ARG_CHECKs that the keypair is not invalid. It always initializes sk and * pk with dummy values. */ static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) { int ret; const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32]; /* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's * invalid. */ secp256k1_declassify(ctx, pubkey, sizeof(*pubkey)); ret = secp256k1_pubkey_load(ctx, pk, pubkey); if (sk != NULL) { ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair); } if (!ret) { *pk = secp256k1_ge_const_g; if (sk != NULL) { *sk = secp256k1_scalar_one; } } return ret; } int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) { secp256k1_scalar sk; secp256k1_ge pk; int ret = 0; VERIFY_CHECK(ctx != NULL); ARG_CHECK(keypair != NULL); memset(keypair, 0, sizeof(*keypair)); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(seckey32 != NULL); ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32); secp256k1_keypair_save(keypair, &sk, &pk); secp256k1_memczero(keypair, sizeof(*keypair), !ret); secp256k1_scalar_clear(&sk); return ret; } +int secp256k1_keypair_sec(const secp256k1_context* ctx, unsigned char *seckey, const secp256k1_keypair *keypair) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + memset(seckey, 0, 32); + ARG_CHECK(keypair != NULL); + + memcpy(seckey, &keypair->data[0], 32); + return 1; +} + int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) { VERIFY_CHECK(ctx != NULL); ARG_CHECK(pubkey != NULL); memset(pubkey, 0, sizeof(*pubkey)); ARG_CHECK(keypair != NULL); memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey)); return 1; } int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) { secp256k1_ge pk; int tmp; VERIFY_CHECK(ctx != NULL); ARG_CHECK(pubkey != NULL); memset(pubkey, 0, sizeof(*pubkey)); ARG_CHECK(keypair != NULL); if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) { return 0; } tmp = secp256k1_extrakeys_ge_even_y(&pk); if (pk_parity != NULL) { *pk_parity = tmp; } secp256k1_xonly_pubkey_save(pubkey, &pk); 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 diff --git a/src/secp256k1/src/modules/extrakeys/tests_impl.h b/src/secp256k1/src/modules/extrakeys/tests_impl.h index 5b15968d8..880543195 100644 --- a/src/secp256k1/src/modules/extrakeys/tests_impl.h +++ b/src/secp256k1/src/modules/extrakeys/tests_impl.h @@ -1,524 +1,549 @@ /*********************************************************************** * Copyright (c) 2020 Jonas Nick * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ #ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_ #define _SECP256K1_MODULE_EXTRAKEYS_TESTS_ #include "secp256k1_extrakeys.h" static secp256k1_context* api_test_context(int flags, int *ecount) { secp256k1_context *ctx0 = secp256k1_context_create(flags); secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount); secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount); return ctx0; } void test_xonly_pubkey(void) { secp256k1_pubkey pk; secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; secp256k1_ge pk1; secp256k1_ge pk2; secp256k1_fe y; unsigned char sk[32]; unsigned char xy_sk[32]; unsigned char buf32[32]; unsigned char ones32[32]; unsigned char zeros64[64] = { 0 }; int pk_parity; int i; int ecount; 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); secp256k1_testrand256(sk); memset(ones32, 0xFF, 32); secp256k1_testrand256(xy_sk); CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); /* Test xonly_pubkey_from_pubkey */ ecount = 0; CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0); CHECK(ecount == 2); memset(&pk, 0, sizeof(pk)); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0); CHECK(ecount == 3); /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ memset(sk, 0, sizeof(sk)); sk[0] = 1; CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); CHECK(pk_parity == 0); /* Choose a secret key such that pubkey and xonly_pubkey are each others * negation. */ sk[0] = 2; CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); CHECK(pk_parity == 1); secp256k1_pubkey_load(ctx, &pk1, &pk); secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk); CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1); secp256k1_fe_negate(&y, &pk2.y, 1); CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ ecount = 0; CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0); CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); CHECK(ecount == 2); { /* A pubkey filled with 0s will fail to serialize due to pubkey_load * special casing. */ secp256k1_xonly_pubkey pk_tmp; memset(&pk_tmp, 0, sizeof(pk_tmp)); CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0); } /* pubkey_load called illegal callback */ CHECK(ecount == 3); CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1); ecount = 0; CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0); CHECK(ecount == 2); /* Serialization and parse roundtrip */ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1); CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); /* Test parsing invalid field elements */ memset(&xonly_pk, 1, sizeof(xonly_pk)); /* Overflowing field element */ CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); memset(&xonly_pk, 1, sizeof(xonly_pk)); /* There's no point with x-coordinate 0 on secp256k1 */ CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); /* If a random 32-byte string can not be parsed with ec_pubkey_parse * (because interpreted as X coordinate it does not correspond to a point on * the curve) then xonly_pubkey_parse should fail as well. */ for (i = 0; i < count; i++) { unsigned char rand33[33]; secp256k1_testrand256(&rand33[1]); rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) { memset(&xonly_pk, 1, sizeof(xonly_pk)); CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); } else { CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1); } } CHECK(ecount == 2); secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(verify); } void test_xonly_pubkey_tweak(void) { unsigned char zeros64[64] = { 0 }; unsigned char overflows[32]; unsigned char sk[32]; secp256k1_pubkey internal_pk; secp256k1_xonly_pubkey internal_xonly_pk; secp256k1_pubkey output_pk; int pk_parity; unsigned char tweak[32]; int i; int ecount; 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); memset(overflows, 0xff, sizeof(overflows)); secp256k1_testrand256(tweak); secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); ecount = 0; CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 2); CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 3); CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0); CHECK(ecount == 4); /* NULL internal_xonly_pk zeroes the output_pk */ CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0); CHECK(ecount == 5); /* NULL tweak zeroes the output_pk */ CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); /* Invalid tweak zeroes the output_pk */ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); /* A zero tweak is fine */ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1); /* Fails if the resulting key was infinity */ for (i = 0; i < count; i++) { secp256k1_scalar scalar_tweak; /* 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_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0) || (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0)); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); } /* Invalid pk with a valid tweak */ memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); secp256k1_testrand256(tweak); ecount = 0; CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(verify); } void test_xonly_pubkey_tweak_check(void) { unsigned char zeros64[64] = { 0 }; unsigned char overflows[32]; unsigned char sk[32]; secp256k1_pubkey internal_pk; secp256k1_xonly_pubkey internal_xonly_pk; secp256k1_pubkey output_pk; secp256k1_xonly_pubkey output_xonly_pk; unsigned char output_pk32[32]; unsigned char buf32[32]; int pk_parity; unsigned char tweak[32]; int ecount; 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); memset(overflows, 0xff, sizeof(overflows)); secp256k1_testrand256(tweak); secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); ecount = 0; CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 2); CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 3); /* invalid pk_parity value */ CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 3); CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0); CHECK(ecount == 4); CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0); CHECK(ecount == 5); memset(tweak, 1, sizeof(tweak)); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1); /* Wrong pk_parity */ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0); /* Wrong public key */ CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); /* Overflowing tweak not allowed */ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(ecount == 5); secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(verify); } /* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 * additional pubkeys by calling tweak_add. Then verifies every tweak starting * from the last pubkey. */ #define N_PUBKEYS 32 void test_xonly_pubkey_tweak_recursive(void) { unsigned char sk[32]; secp256k1_pubkey pk[N_PUBKEYS]; unsigned char pk_serialized[32]; unsigned char tweak[N_PUBKEYS - 1][32]; int i; secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1); /* Add tweaks */ for (i = 0; i < N_PUBKEYS - 1; i++) { secp256k1_xonly_pubkey xonly_pk; memset(tweak[i], i + 1, sizeof(tweak[i])); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1); } /* Verify tweaks */ for (i = N_PUBKEYS - 1; i > 0; i--) { secp256k1_xonly_pubkey xonly_pk; int pk_parity; CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1); } } #undef N_PUBKEYS void test_keypair(void) { unsigned char sk[32]; + unsigned char sk_tmp[32]; unsigned char zeros96[96] = { 0 }; unsigned char overflows[32]; secp256k1_keypair keypair; secp256k1_pubkey pk, pk_tmp; secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; int pk_parity, pk_parity_tmp; int ecount; 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)); memset(overflows, 0xFF, sizeof(overflows)); /* Test keypair_create */ ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(none, &keypair, sk) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 1); CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 2); CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0); CHECK(ecount == 3); CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 4); /* Invalid secret key */ CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); /* Test keypair_pub */ ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1); CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0); CHECK(ecount == 1); CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0); CHECK(ecount == 2); CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); /* Using an invalid keypair is fine for keypair_pub */ memset(&keypair, 0, sizeof(keypair)); CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1); CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); /* keypair holds the same pubkey as pubkey_create */ CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1); CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); /** Test keypair_xonly_pub **/ ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0); CHECK(ecount == 1); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0); CHECK(ecount == 2); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); /* Using an invalid keypair will set the xonly_pk to 0 (first reset * xonly_pk). */ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); memset(&keypair, 0, sizeof(keypair)); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); CHECK(ecount == 3); /** keypair holds the same xonly pubkey as pubkey_create **/ CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); CHECK(pk_parity == pk_parity_tmp); + /* Test keypair_seckey */ + ecount = 0; + secp256k1_testrand256(sk); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); + CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1); + CHECK(secp256k1_keypair_sec(none, NULL, &keypair) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_keypair_sec(none, sk_tmp, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); + + /* keypair returns the same seckey it got */ + CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); + CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); + + + /* Using an invalid keypair is fine for keypair_seckey */ + memset(&keypair, 0, sizeof(keypair)); + CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); + secp256k1_context_destroy(none); secp256k1_context_destroy(sign); 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_testrand256(sk); secp256k1_testrand256(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(secp256k1_memcmp_var(&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(secp256k1_memcmp_var(&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_testrand256(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(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 || secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); } /* Invalid keypair with a valid tweak */ memset(&keypair, 0, sizeof(keypair)); secp256k1_testrand256(tweak); ecount = 0; CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); CHECK(ecount == 1); CHECK(secp256k1_memcmp_var(&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]; + unsigned char sk32[32]; int pk_parity; secp256k1_testrand256(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(secp256k1_memcmp_var(&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(secp256k1_keypair_sec(none, sk32, &keypair) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, sk32) == 1); CHECK(secp256k1_memcmp_var(&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(); test_xonly_pubkey_tweak(); test_xonly_pubkey_tweak_check(); test_xonly_pubkey_tweak_recursive(); /* keypair tests */ test_keypair(); test_keypair_add(); } #endif diff --git a/src/secp256k1/src/valgrind_ctime_test.c b/src/secp256k1/src/valgrind_ctime_test.c index 73c8435f6..f894ab0e5 100644 --- a/src/secp256k1/src/valgrind_ctime_test.c +++ b/src/secp256k1/src/valgrind_ctime_test.c @@ -1,170 +1,176 @@ /*********************************************************************** * Copyright (c) 2020 Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ #include #include "include/secp256k1.h" #include "assumptions.h" #include "util.h" #ifdef ENABLE_MODULE_ECDH # include "include/secp256k1_ecdh.h" #endif #ifdef ENABLE_MODULE_RECOVERY # include "include/secp256k1_recovery.h" #endif #ifdef ENABLE_MODULE_SCHNORR # include "include/secp256k1_schnorr.h" #endif #ifdef ENABLE_MODULE_EXTRAKEYS # include "include/secp256k1_extrakeys.h" #endif #ifdef ENABLE_MODULE_SCHNORRSIG #include "include/secp256k1_schnorrsig.h" #endif int main(void) { secp256k1_context* ctx; secp256k1_ecdsa_signature signature; secp256k1_pubkey pubkey; size_t siglen = 74; size_t outputlen = 33; int i; int ret; unsigned char msg[32]; unsigned char key[32]; unsigned char sig[74]; unsigned char spubkey[33]; #ifdef ENABLE_MODULE_RECOVERY secp256k1_ecdsa_recoverable_signature recoverable_signature; int recid; #endif #ifdef ENABLE_MODULE_EXTRAKEYS secp256k1_keypair keypair; #endif if (!RUNNING_ON_VALGRIND) { fprintf(stderr, "This test can only usefully be run inside valgrind.\n"); fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n"); exit(1); } /** In theory, testing with a single secret input should be sufficient: * If control flow depended on secrets the tool would generate an error. */ for (i = 0; i < 32; i++) { key[i] = i + 65; } for (i = 0; i < 32; i++) { msg[i] = i + 1; } ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_DECLASSIFY); /* Test keygen. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key); VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(secp256k1_pubkey)); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); /* Test signing. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(secp256k1_ecdsa_signature)); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); #ifdef ENABLE_MODULE_ECDH /* Test ECDH. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); #endif #ifdef ENABLE_MODULE_RECOVERY /* Test signing a recoverable signature. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); VALGRIND_MAKE_MEM_DEFINED(&recoverable_signature, sizeof(recoverable_signature)); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); CHECK(recid >= 0 && recid <= 3); #endif #if ENABLE_MODULE_SCHNORR /* Test schnorr signing. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_schnorr_sign(ctx, sig, msg, key, NULL, NULL); VALGRIND_MAKE_MEM_DEFINED(&sig, sizeof(64)); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret); #endif VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ec_seckey_verify(ctx, key); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ec_seckey_negate(ctx, key); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); VALGRIND_MAKE_MEM_UNDEFINED(key, 32); VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); VALGRIND_MAKE_MEM_UNDEFINED(key, 32); VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); /* Test context randomisation. Do this last because it leaves the context tainted. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_context_randomize(ctx, key); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret); /* Test keypair_create and keypair_xonly_tweak_add. */ #ifdef 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); + + VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + VALGRIND_MAKE_MEM_UNDEFINED(&keypair, sizeof(keypair)); + ret = secp256k1_keypair_sec(ctx, key, &keypair); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); #endif #ifdef ENABLE_MODULE_SCHNORRSIG VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_keypair_create(ctx, &keypair, key); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); #endif secp256k1_context_destroy(ctx); return 0; }