Skip to content

Commit b66e0d1

Browse files
committed
Add x-only ECDH functionality to ecdh module
1 parent ee7aaf2 commit b66e0d1

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

include/secp256k1_ecdh.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ typedef int (*secp256k1_ecdh_hash_function)(
2525
void *data
2626
);
2727

28+
/** A pointer to a function that hashes an X coordinate to obtain an ECDH secret
29+
*
30+
* Returns: 1 if the point was successfully hashed.
31+
* 0 will cause secp256k1_ecdh_xonly to fail and return 0.
32+
* Other return values are not allowed, and the behaviour of
33+
* secp256k1_ecdh_xonly is undefined for other return values.
34+
* Out: output: pointer to an array to be filled by the function
35+
* In: x32: pointer to a 32-byte x coordinate
36+
* data: arbitrary data pointer that is passed through
37+
*/
38+
typedef int (*secp256k1_ecdh_xonly_hash_function)(
39+
unsigned char *output,
40+
const unsigned char *x32,
41+
void *data
42+
);
43+
2844
/** An implementation of SHA256 hash function that applies to compressed public key.
2945
* Populates the output parameter with 32 bytes. */
3046
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
@@ -33,6 +49,10 @@ SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sh
3349
* Populates the output parameter with 32 bytes. */
3450
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
3551

52+
/** An implementation of SHA256 hash function that applies to the X coordinate.
53+
* Populates the output parameter with 32 bytes. */
54+
SECP256K1_API const secp256k1_ecdh_xonly_hash_function secp256k1_ecdh_xonly_hash_function_sha256;
55+
3656
/** Compute an EC Diffie-Hellman secret in constant time
3757
*
3858
* Returns: 1: exponentiation was successful
@@ -56,6 +76,33 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
5676
void *data
5777
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
5878

79+
/** Compute an EC X-only Diffie-Hellman secret in constant time
80+
*
81+
* Returns: 1: exponentiation was successful
82+
* 0: scalar was invalid (zero or overflow), input is not a valid X coordinate, or hashfp
83+
* returned 0.
84+
* Args: ctx: pointer to a context object.
85+
* Out: output: pointer to an array to be filled by hashfp.
86+
* In: xpubkey: a pointer to the 32-byte serialization of an x-only public key (see the
87+
* extrakeys module for details).
88+
* seckey: a 32-byte scalar with which to multiply the point.
89+
* hashfp: pointer to a hash function. If NULL,
90+
* secp256k1_ecdh_xonly+hash_function_sha256 is used
91+
* (in which case, 32 bytes will be written to output).
92+
* data: arbitrary data pointer that is passed through to hashfp
93+
* (can be NULL for secp256k1_ecdh_xonly_hash_function_sha256).
94+
*
95+
* The function is constant time in seckey. It is not constant time in xpubkey, hashfp, or the output.
96+
*/
97+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh_xonly(
98+
const secp256k1_context* ctx,
99+
unsigned char *output,
100+
const unsigned char *xpubkey,
101+
const unsigned char *seckey,
102+
secp256k1_ecdh_xonly_hash_function hashfp,
103+
void *data
104+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
105+
59106
#ifdef __cplusplus
60107
}
61108
#endif

src/modules/ecdh/main_impl.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,20 @@ static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char
2323
return 1;
2424
}
2525

26+
static int ecdh_xonly_hash_function_sha256(unsigned char *output, const unsigned char *x32, void *data) {
27+
secp256k1_sha256 sha;
28+
(void)data;
29+
30+
secp256k1_sha256_initialize(&sha);
31+
secp256k1_sha256_write(&sha, x32, 32);
32+
secp256k1_sha256_finalize(&sha, output);
33+
34+
return 1;
35+
}
36+
2637
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
2738
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
39+
const secp256k1_ecdh_xonly_hash_function secp256k1_ecdh_xonly_hash_function_sha256 = ecdh_xonly_hash_function_sha256;
2840

2941
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) {
3042
int ret = 0;
@@ -68,4 +80,49 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
6880
return !!ret & !overflow;
6981
}
7082

83+
int secp256k1_ecdh_xonly(const secp256k1_context* ctx, unsigned char *output, const unsigned char* xpubkey, const unsigned char *scalar, secp256k1_ecdh_xonly_hash_function hashfp, void *data) {
84+
int ret;
85+
int overflow;
86+
secp256k1_fe x;
87+
unsigned char x32[32];
88+
secp256k1_scalar s;
89+
90+
VERIFY_CHECK(ctx != NULL);
91+
ARG_CHECK(output != NULL);
92+
ARG_CHECK(xpubkey != NULL);
93+
ARG_CHECK(scalar != NULL);
94+
95+
if (hashfp == NULL) {
96+
hashfp = secp256k1_ecdh_xonly_hash_function_sha256;
97+
}
98+
99+
if (!secp256k1_fe_set_b32_limit(&x, xpubkey)) {
100+
/* X-only public key overflow, bail out early (we don't need to be constant time in pubkey). */
101+
memset(output, 0, 32);
102+
return 0;
103+
}
104+
105+
secp256k1_scalar_set_b32(&s, scalar, &overflow);
106+
107+
overflow |= secp256k1_scalar_is_zero(&s);
108+
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
109+
110+
if (!secp256k1_ecmult_const_xonly(&x, &x, NULL, &s, 0)) {
111+
/* Input is not a valid X coordinate, bail out early. */
112+
memset(output, 0, 32);
113+
return 0;
114+
}
115+
116+
/* Compute a hash of the point */
117+
secp256k1_fe_normalize(&x);
118+
secp256k1_fe_get_b32(x32, &x);
119+
120+
ret = hashfp(output, x32, data);
121+
122+
memset(x32, 0, 32);
123+
secp256k1_scalar_clear(&s);
124+
125+
return !!ret & !overflow;
126+
}
127+
71128
#endif /* SECP256K1_MODULE_ECDH_MAIN_H */

0 commit comments

Comments
 (0)