Skip to content

Commit 49a9bd8

Browse files
elichaiFabcien
authored andcommitted
[SECP256K1] Extract the secret key from a keypair
Summary: ``` With schnorrsig if you need to tweak the secret key (for BIP32) you must use the keypair API to get compatible secret/public keys which you do by calling secp256k1_keypair_xonly_tweak_add(), but after that there's no currently a way to extract the secret key back for storage. so I added a secp256k1_keypair_seckey function to extract the key ``` Backport of [[bitcoin-core/secp256k1#845 | secp256k1#845]] Test Plan: ninja check-secp256k1 Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D9381
1 parent 151dc0f commit 49a9bd8

File tree

4 files changed

+55
-1
lines changed

4 files changed

+55
-1
lines changed

include/secp256k1_extrakeys.h

+13
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
165165
const unsigned char *seckey
166166
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
167167

168+
/** Get the secret key from a keypair.
169+
*
170+
* Returns: 0 if the arguments are invalid. 1 otherwise.
171+
* Args: ctx: pointer to a context object (cannot be NULL)
172+
* Out: seckey: pointer to a 32-byte buffer for the secret key (cannot be NULL)
173+
* In: keypair: pointer to a keypair (cannot be NULL)
174+
*/
175+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
176+
const secp256k1_context* ctx,
177+
unsigned char *seckey,
178+
const secp256k1_keypair *keypair
179+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
180+
168181
/** Get the public key from a keypair.
169182
*
170183
* Returns: 0 if the arguments are invalid. 1 otherwise.

src/modules/extrakeys/main_impl.h

+10
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,16 @@ int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *ke
186186
return ret;
187187
}
188188

189+
int secp256k1_keypair_sec(const secp256k1_context* ctx, unsigned char *seckey, const secp256k1_keypair *keypair) {
190+
VERIFY_CHECK(ctx != NULL);
191+
ARG_CHECK(seckey != NULL);
192+
memset(seckey, 0, 32);
193+
ARG_CHECK(keypair != NULL);
194+
195+
memcpy(seckey, &keypair->data[0], 32);
196+
return 1;
197+
}
198+
189199
int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) {
190200
VERIFY_CHECK(ctx != NULL);
191201
ARG_CHECK(pubkey != NULL);

src/modules/extrakeys/tests_impl.h

+26-1
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ void test_xonly_pubkey_tweak_recursive(void) {
311311

312312
void test_keypair(void) {
313313
unsigned char sk[32];
314+
unsigned char sk_tmp[32];
314315
unsigned char zeros96[96] = { 0 };
315316
unsigned char overflows[32];
316317
secp256k1_keypair keypair;
@@ -396,6 +397,28 @@ void test_keypair(void) {
396397
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
397398
CHECK(pk_parity == pk_parity_tmp);
398399

400+
/* Test keypair_seckey */
401+
ecount = 0;
402+
secp256k1_testrand256(sk);
403+
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
404+
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
405+
CHECK(secp256k1_keypair_sec(none, NULL, &keypair) == 0);
406+
CHECK(ecount == 1);
407+
CHECK(secp256k1_keypair_sec(none, sk_tmp, NULL) == 0);
408+
CHECK(ecount == 2);
409+
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
410+
411+
/* keypair returns the same seckey it got */
412+
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
413+
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
414+
CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0);
415+
416+
417+
/* Using an invalid keypair is fine for keypair_seckey */
418+
memset(&keypair, 0, sizeof(keypair));
419+
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
420+
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
421+
399422
secp256k1_context_destroy(none);
400423
secp256k1_context_destroy(sign);
401424
secp256k1_context_destroy(verify);
@@ -484,6 +507,7 @@ void test_keypair_add(void) {
484507
secp256k1_pubkey output_pk_xy;
485508
secp256k1_pubkey output_pk_expected;
486509
unsigned char pk32[32];
510+
unsigned char sk32[32];
487511
int pk_parity;
488512

489513
secp256k1_testrand256(tweak);
@@ -501,7 +525,8 @@ void test_keypair_add(void) {
501525
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
502526

503527
/* Check that the secret key in the keypair is tweaked correctly */
504-
CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1);
528+
CHECK(secp256k1_keypair_sec(none, sk32, &keypair) == 1);
529+
CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, sk32) == 1);
505530
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
506531
}
507532
secp256k1_context_destroy(none);

src/valgrind_ctime_test.c

+6
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ int main(void) {
153153
ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg);
154154
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
155155
CHECK(ret == 1);
156+
157+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
158+
VALGRIND_MAKE_MEM_UNDEFINED(&keypair, sizeof(keypair));
159+
ret = secp256k1_keypair_sec(ctx, key, &keypair);
160+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
161+
CHECK(ret == 1);
156162
#endif
157163

158164
#ifdef ENABLE_MODULE_SCHNORRSIG

0 commit comments

Comments
 (0)