Skip to content

Commit 8e48aa6

Browse files
committed
Add secp256k1_ec_pubkey_negate and secp256k1_ec_privkey_negate
1 parent c5b32e1 commit 8e48aa6

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

include/secp256k1.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,28 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
491491
const unsigned char *seckey
492492
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
493493

494+
/** Negates a private key in place.
495+
*
496+
* Returns: 1 always
497+
* Args: ctx: pointer to a context object
498+
* In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
499+
*/
500+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
501+
const secp256k1_context* ctx,
502+
unsigned char *seckey
503+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
504+
505+
/** Negates a public key in place.
506+
*
507+
* Returns: 1 always
508+
* Args: ctx: pointer to a context object
509+
* In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
510+
*/
511+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
512+
const secp256k1_context* ctx,
513+
secp256k1_pubkey *pubkey
514+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
515+
494516
/** Tweak a private key by adding tweak to it.
495517
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
496518
* uniformly random 32-byte arrays, or if the resulting private key

src/secp256k1.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,33 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
424424
return ret;
425425
}
426426

427+
int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
428+
secp256k1_scalar sec;
429+
VERIFY_CHECK(ctx != NULL);
430+
ARG_CHECK(seckey != NULL);
431+
432+
secp256k1_scalar_set_b32(&sec, seckey, NULL);
433+
secp256k1_scalar_negate(&sec, &sec);
434+
secp256k1_scalar_get_b32(seckey, &sec);
435+
436+
return 1;
437+
}
438+
439+
int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {
440+
int ret = 0;
441+
secp256k1_ge p;
442+
VERIFY_CHECK(ctx != NULL);
443+
ARG_CHECK(pubkey != NULL);
444+
445+
ret = secp256k1_pubkey_load(ctx, &p, pubkey);
446+
memset(pubkey, 0, sizeof(*pubkey));
447+
if (ret) {
448+
secp256k1_ge_neg(&p, &p);
449+
secp256k1_pubkey_save(pubkey, &p);
450+
}
451+
return ret;
452+
}
453+
427454
int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
428455
secp256k1_scalar term;
429456
secp256k1_scalar sec;

src/tests.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <stdio.h>
1212
#include <stdlib.h>
13+
#include <string.h>
1314

1415
#include <time.h>
1516

@@ -135,6 +136,7 @@ void random_scalar_order(secp256k1_scalar *num) {
135136

136137
void run_context_tests(void) {
137138
secp256k1_pubkey pubkey;
139+
secp256k1_pubkey zero_pubkey;
138140
secp256k1_ecdsa_signature sig;
139141
unsigned char ctmp[32];
140142
int32_t ecount;
@@ -149,6 +151,8 @@ void run_context_tests(void) {
149151
secp256k1_scalar msg, key, nonce;
150152
secp256k1_scalar sigr, sigs;
151153

154+
memset(&zero_pubkey, 0, sizeof(zero_pubkey));
155+
152156
ecount = 0;
153157
ecount2 = 10;
154158
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
@@ -201,12 +205,20 @@ void run_context_tests(void) {
201205
CHECK(ecount == 2);
202206
CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0);
203207
CHECK(ecount2 == 13);
204-
CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
208+
CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1);
205209
CHECK(ecount == 2);
206-
CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
210+
CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1);
211+
CHECK(ecount == 2);
212+
CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0);
213+
CHECK(ecount2 == 14);
214+
CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0);
215+
CHECK(ecount == 3);
216+
CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
207217
CHECK(ecount == 3);
218+
CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
219+
CHECK(ecount == 4);
208220
CHECK(secp256k1_context_randomize(sign, NULL) == 1);
209-
CHECK(ecount2 == 13);
221+
CHECK(ecount2 == 14);
210222
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
211223
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
212224

@@ -3436,6 +3448,7 @@ void test_ecdsa_end_to_end(void) {
34363448
unsigned char pubkeyc[65];
34373449
size_t pubkeyclen = 65;
34383450
secp256k1_pubkey pubkey;
3451+
secp256k1_pubkey pubkey_tmp;
34393452
unsigned char seckey[300];
34403453
size_t seckeylen = 300;
34413454

@@ -3457,6 +3470,13 @@ void test_ecdsa_end_to_end(void) {
34573470
memset(&pubkey, 0, sizeof(pubkey));
34583471
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
34593472

3473+
/* Verify negation changes the key and changes it back */
3474+
memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey));
3475+
CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
3476+
CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0);
3477+
CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
3478+
CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0);
3479+
34603480
/* Verify private key import and export. */
34613481
CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
34623482
CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);

0 commit comments

Comments
 (0)