extrakeys: Add keypair struct with create, pub and pub_xonly
This commit is contained in:
parent
f0010349b8
commit
58254463f9
|
@ -23,6 +23,17 @@ typedef struct {
|
||||||
unsigned char data[64];
|
unsigned char data[64];
|
||||||
} secp256k1_xonly_pubkey;
|
} 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.
|
/** Parse a 32-byte sequence into a xonly_pubkey object.
|
||||||
*
|
*
|
||||||
* Returns: 1 if the public key was fully valid.
|
* Returns: 1 if the public key was fully valid.
|
||||||
|
@ -140,6 +151,57 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
|
||||||
const unsigned char *tweak32
|
const unsigned char *tweak32
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
) 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 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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -125,4 +125,93 @@ int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const u
|
||||||
&& secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
|
&& 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);
|
||||||
|
memczero(keypair, sizeof(*keypair), !ret);
|
||||||
|
|
||||||
|
secp256k1_scalar_clear(&sk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -309,12 +309,107 @@ void test_xonly_pubkey_tweak_recursive(void) {
|
||||||
}
|
}
|
||||||
#undef N_PUBKEYS
|
#undef N_PUBKEYS
|
||||||
|
|
||||||
|
void test_keypair(void) {
|
||||||
|
unsigned char sk[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_rand256(sk);
|
||||||
|
CHECK(secp256k1_keypair_create(none, &keypair, sk) == 0);
|
||||||
|
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||||
|
CHECK(ecount == 1);
|
||||||
|
CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 0);
|
||||||
|
CHECK(memcmp(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(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||||
|
CHECK(ecount == 4);
|
||||||
|
|
||||||
|
/* Invalid secret key */
|
||||||
|
CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0);
|
||||||
|
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||||
|
CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0);
|
||||||
|
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||||
|
|
||||||
|
/* Test keypair_pub */
|
||||||
|
ecount = 0;
|
||||||
|
secp256k1_rand256(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(memcmp(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(memcmp(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(memcmp(&pk, &pk_tmp, sizeof(pk)) == 0);
|
||||||
|
|
||||||
|
/** Test keypair_xonly_pub **/
|
||||||
|
ecount = 0;
|
||||||
|
secp256k1_rand256(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(memcmp(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(memcmp(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(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
|
||||||
|
CHECK(pk_parity == pk_parity_tmp);
|
||||||
|
|
||||||
|
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();
|
||||||
test_xonly_pubkey_tweak();
|
test_xonly_pubkey_tweak();
|
||||||
test_xonly_pubkey_tweak_check();
|
test_xonly_pubkey_tweak_check();
|
||||||
test_xonly_pubkey_tweak_recursive();
|
test_xonly_pubkey_tweak_recursive();
|
||||||
|
|
||||||
|
/* keypair tests */
|
||||||
|
test_keypair();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
# include "include/secp256k1_recovery.h"
|
# include "include/secp256k1_recovery.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_MODULE_EXTRAKEYS
|
||||||
|
# include "include/secp256k1_extrakeys.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
secp256k1_context* ctx;
|
secp256k1_context* ctx;
|
||||||
secp256k1_ecdsa_signature signature;
|
secp256k1_ecdsa_signature signature;
|
||||||
|
@ -33,6 +37,9 @@ int main(void) {
|
||||||
secp256k1_ecdsa_recoverable_signature recoverable_signature;
|
secp256k1_ecdsa_recoverable_signature recoverable_signature;
|
||||||
int recid;
|
int recid;
|
||||||
#endif
|
#endif
|
||||||
|
#if ENABLE_MODULE_EXTRAKEYS
|
||||||
|
secp256k1_keypair keypair;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!RUNNING_ON_VALGRIND) {
|
if (!RUNNING_ON_VALGRIND) {
|
||||||
fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
|
fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
|
||||||
|
@ -115,6 +122,13 @@ int main(void) {
|
||||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||||
CHECK(ret);
|
CHECK(ret);
|
||||||
|
|
||||||
|
#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);
|
||||||
|
#endif
|
||||||
|
|
||||||
secp256k1_context_destroy(ctx);
|
secp256k1_context_destroy(ctx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue