Skip to content

Commit

Permalink
Merge PR bitcoin#994 (bitcoin-core/secp256k1) and PR bitcoin#23480(bi…
Browse files Browse the repository at this point in the history
…tcoin/bitcoin)
  • Loading branch information
w0xlt committed Oct 5, 2022
1 parent 5d76ac1 commit 6f70adb
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 19 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2020,7 +2020,7 @@ LIBS_TEMP="$LIBS"
unset LIBS
LIBS="$LIBS_TEMP"

ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig"
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig --enable-module-ecdh"
AC_CONFIG_SUBDIRS([src/secp256k1])

AC_OUTPUT
Expand Down
30 changes: 30 additions & 0 deletions src/secp256k1/include/secp256k1_ecdh.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ typedef int (*secp256k1_ecdh_hash_function)(
* Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;

/** An implementation of SHA256 hash function that applies to the x-only part of a public key.
* Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_xonly_sha256;

/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
* Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
Expand Down Expand Up @@ -56,6 +60,32 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
void *data
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

#include "secp256k1_extrakeys.h"

/** Compute an EC Diffie-Hellman secret in constant time (xonly version)
* (Only present if extrakeys is enabled).
*
* Returns: 1: exponentiation was successful
* 0: scalar was invalid (zero or overflow) or hashfp returned 0
* Args: ctx: pointer to a context object.
* Out: output: pointer to an array to be filled by hashfp.
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an initialized public key.
* seckey: a 32-byte scalar with which to multiply the point.
* hashfp: pointer to a hash function. If NULL,
* secp256k1_ecdh_hash_function_xonly_sha256 is used
* (in which case, 32 bytes will be written to output).
* data: arbitrary data pointer that is passed through to hashfp
* (can be NULL for secp256k1_ecdh_hash_function_xonly_sha256).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh_xonly(
const secp256k1_context* ctx,
unsigned char *output,
const secp256k1_xonly_pubkey *pubkey,
const unsigned char *scalar,
secp256k1_ecdh_hash_function hashfp,
void *data
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

#ifdef __cplusplus
}
#endif
Expand Down
78 changes: 60 additions & 18 deletions src/secp256k1/src/modules/ecdh/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,41 +23,43 @@ static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char
return 1;
}

static int ecdh_hash_function_xonly_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
secp256k1_sha256 sha;
(void)data;
(void)y32;

secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, x32, 32);
secp256k1_sha256_finalize(&sha, output);

return 1;
}

const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_xonly_sha256 = ecdh_hash_function_xonly_sha256;
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;

int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
static int ecdh_core(unsigned char *output, secp256k1_ge *pt, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
int ret = 0;
int overflow = 0;
secp256k1_gej res;
secp256k1_ge pt;
secp256k1_scalar s;
unsigned char x[32];
unsigned char y[32];

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);

if (hashfp == NULL) {
hashfp = secp256k1_ecdh_hash_function_default;
}

secp256k1_pubkey_load(ctx, &pt, point);
secp256k1_scalar_set_b32(&s, scalar, &overflow);

overflow |= secp256k1_scalar_is_zero(&s);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);

secp256k1_ecmult_const(&res, &pt, &s, 256);
secp256k1_ge_set_gej(&pt, &res);
secp256k1_ecmult_const(&res, pt, &s, 256);
secp256k1_ge_set_gej(pt, &res);

/* Compute a hash of the point */
secp256k1_fe_normalize(&pt.x);
secp256k1_fe_normalize(&pt.y);
secp256k1_fe_get_b32(x, &pt.x);
secp256k1_fe_get_b32(y, &pt.y);
secp256k1_fe_normalize(&pt->x);
secp256k1_fe_normalize(&pt->y);
secp256k1_fe_get_b32(x, &pt->x);
secp256k1_fe_get_b32(y, &pt->y);

ret = hashfp(output, x, y, data);

Expand All @@ -68,4 +70,44 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
return !!ret & !overflow;
}

int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
secp256k1_ge pt;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);

if (hashfp == NULL) {
hashfp = secp256k1_ecdh_hash_function_default;
}

secp256k1_pubkey_load(ctx, &pt, point);
return ecdh_core(output, &pt, scalar, hashfp, data);
}

#ifdef ENABLE_MODULE_EXTRAKEYS
#include "../../../include/secp256k1_extrakeys.h"

int secp256k1_ecdh_xonly(const secp256k1_context* ctx, unsigned char *output, const secp256k1_xonly_pubkey *pubkey, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
secp256k1_ge pt;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(pubkey != NULL);
ARG_CHECK(scalar != NULL);

if (hashfp == NULL) {
hashfp = secp256k1_ecdh_hash_function_xonly_sha256;
}

/* FIXME: this is secp256k1_xonly_pubkey_load(), but that's buried inside
* extrakeys/main_impl.h. */
if (!secp256k1_pubkey_load(ctx, &pt, (const secp256k1_pubkey *) pubkey)) {
return 0;
}
return ecdh_core(output, &pt, scalar, hashfp, data);
}
#endif /* ENABLE_MODULE_EXTRAKEYS */

#endif /* SECP256K1_MODULE_ECDH_MAIN_H */
30 changes: 30 additions & 0 deletions src/secp256k1/src/modules/extrakeys/tests_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -579,13 +579,43 @@ void test_keypair_add(void) {
secp256k1_context_destroy(verify);
}

void test_xonly_ecdh(void) {
#ifdef ENABLE_MODULE_ECDH
unsigned char sk1[32], sk2[32];
secp256k1_keypair keypair1, keypair2;
secp256k1_xonly_pubkey xpubkey1, xpubkey2;
secp256k1_pubkey pubkey1;
unsigned char output1[32], output2[32], output3[32];

/* Create random points */
secp256k1_testrand256(sk1);
secp256k1_testrand256(sk2);
CHECK(secp256k1_keypair_create(ctx, &keypair1, sk1) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair2, sk2) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xpubkey1, NULL, &keypair1) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xpubkey2, NULL, &keypair2) == 1);

/* They should get the same shared secret. */
CHECK(secp256k1_ecdh_xonly(ctx, output1, &xpubkey1, sk2, NULL, NULL) == 1);
CHECK(secp256k1_ecdh_xonly(ctx, output2, &xpubkey2, sk1, NULL, NULL) == 1);
CHECK(memcmp(output1, output2, sizeof(output1)) == 0);

/* We can also do ECDH via normal compressed pubkey functions, if we
* use the same hashfn */
CHECK(secp256k1_keypair_pub(ctx, &pubkey1, &keypair1) == 1);
CHECK(secp256k1_ecdh(ctx, output3, &pubkey1, sk2, secp256k1_ecdh_hash_function_xonly_sha256, NULL) == 1);
CHECK(memcmp(output1, output3, sizeof(output1)) == 0);
#endif /* ENABLE_MODULE_ECDH */
}

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();
test_xonly_pubkey_comparison();
test_xonly_ecdh();

/* keypair tests */
test_keypair();
Expand Down

0 comments on commit 6f70adb

Please sign in to comment.