Skip to content

Commit 5894e1f

Browse files
committed
Return 0 if the given seckey is invalid in privkey_negate, privkey_tweak_add and privkey_tweak_mul
1 parent 8f814cd commit 5894e1f

File tree

4 files changed

+77
-20
lines changed

4 files changed

+77
-20
lines changed

include/secp256k1.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -579,9 +579,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
579579

580580
/** Negates a private key in place.
581581
*
582-
* Returns: 1 always
582+
* Returns: 0 if the given private key is invalid according to
583+
* secp256k1_ec_seckey_verify. 1 otherwise
583584
* Args: ctx: pointer to a context object
584-
* In/Out: seckey: pointer to the 32-byte private key to be negated (cannot be NULL)
585+
* In/Out: seckey: pointer to the 32-byte private key to be negated. The private
586+
* key should be valid according to secp256k1_ec_seckey_verify
587+
* (cannot be NULL)
585588
*/
586589
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
587590
const secp256k1_context* ctx,
@@ -601,9 +604,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
601604

602605
/** Tweak a private key by adding tweak to it.
603606
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
604-
* uniformly random 32-byte arrays, or if the resulting private key
605-
* would be invalid (only when the tweak is the complement of the
606-
* private key). 1 otherwise.
607+
* uniformly random 32-byte arrays, or if the given private key is
608+
* invalid according to secp256k1_ec_seckey_verify, or if the resulting
609+
* private key would be invalid (only when the tweak is the complement
610+
* of the private key). 1 otherwise.
607611
* Args: ctx: pointer to a context object (cannot be NULL).
608612
* In/Out: seckey: pointer to a 32-byte private key.
609613
* In: tweak: pointer to a 32-byte tweak.
@@ -616,9 +620,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
616620

617621
/** Tweak a public key by adding tweak times the generator to it.
618622
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
619-
* uniformly random 32-byte arrays, or if the resulting public key
620-
* would be invalid (only when the tweak is the complement of the
621-
* corresponding private key). 1 otherwise.
623+
* uniformly random 32-byte arrays, or if the given private key is
624+
* invalid according to secp256k1_ec_seckey_verify, or if the resulting
625+
* public key would be invalid (only when the tweak is the complement
626+
* of the corresponding private key). 1 otherwise.
622627
* Args: ctx: pointer to a context object initialized for validation
623628
* (cannot be NULL).
624629
* In/Out: pubkey: pointer to a public key object.

src/eckey_impl.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,7 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
5454

5555
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
5656
secp256k1_scalar_add(key, key, tweak);
57-
if (secp256k1_scalar_is_zero(key)) {
58-
return 0;
59-
}
60-
return 1;
57+
return !secp256k1_scalar_is_zero(key);
6158
}
6259

6360
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {

src/secp256k1.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -556,15 +556,17 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
556556

557557
int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
558558
secp256k1_scalar sec;
559+
int ret = 0;
559560
VERIFY_CHECK(ctx != NULL);
560561
ARG_CHECK(seckey != NULL);
561562

562-
secp256k1_scalar_set_b32(&sec, seckey, NULL);
563+
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
564+
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
563565
secp256k1_scalar_negate(&sec, &sec);
564566
secp256k1_scalar_get_b32(seckey, &sec);
565567

566568
secp256k1_scalar_clear(&sec);
567-
return 1;
569+
return ret;
568570
}
569571

570572
int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {
@@ -592,9 +594,9 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
592594
ARG_CHECK(tweak != NULL);
593595

594596
secp256k1_scalar_set_b32(&term, tweak, &overflow);
595-
secp256k1_scalar_set_b32(&sec, seckey, NULL);
597+
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
596598

597-
ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(&sec, &term);
599+
ret &= (!overflow) & secp256k1_eckey_privkey_tweak_add(&sec, &term);
598600
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
599601
secp256k1_scalar_get_b32(seckey, &sec);
600602

@@ -637,8 +639,8 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *
637639
ARG_CHECK(tweak != NULL);
638640

639641
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
640-
secp256k1_scalar_set_b32(&sec, seckey, NULL);
641-
ret = (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
642+
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
643+
ret &= (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
642644
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
643645
secp256k1_scalar_get_b32(seckey, &sec);
644646

src/tests.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4000,7 +4000,20 @@ void run_eckey_edge_case_test(void) {
40004000
CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0);
40014001
CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
40024002
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
4003-
/* Overflowing key tweak zeroizes. */
4003+
/* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
4004+
seckey, the seckey is zeroized. */
4005+
memcpy(ctmp, orderc, 32);
4006+
memset(ctmp2, 0, 32);
4007+
ctmp2[31] = 0x01;
4008+
CHECK(secp256k1_ec_seckey_verify(ctx, ctmp2) == 1);
4009+
CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
4010+
CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 0);
4011+
CHECK(memcmp(zeros, ctmp, 32) == 0);
4012+
memcpy(ctmp, orderc, 32);
4013+
CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0);
4014+
CHECK(memcmp(zeros, ctmp, 32) == 0);
4015+
/* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
4016+
tweak, the seckey is zeroized. */
40044017
memcpy(ctmp, orderc, 32);
40054018
ctmp[31] = 0x40;
40064019
CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0);
@@ -4011,13 +4024,20 @@ void run_eckey_edge_case_test(void) {
40114024
CHECK(memcmp(zeros, ctmp, 32) == 0);
40124025
memcpy(ctmp, orderc, 32);
40134026
ctmp[31] = 0x40;
4027+
/* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing
4028+
tweak, the pubkey is zeroized. */
40144029
CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0);
40154030
CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
40164031
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
40174032
CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0);
40184033
CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
40194034
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
4020-
/* Private key tweaks results in a key of zero. */
4035+
/* If the resulting key in secp256k1_ec_seckey_tweak_add and
4036+
* secp256k1_ec_pubkey_tweak_add is 0 the functions fail and in the latter
4037+
* case the pubkey is zeroized. */
4038+
memcpy(ctmp, orderc, 32);
4039+
ctmp[31] = 0x40;
4040+
memset(ctmp2, 0, 32);
40214041
ctmp2[31] = 1;
40224042
CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0);
40234043
CHECK(memcmp(zeros, ctmp2, 32) == 0);
@@ -4157,6 +4177,36 @@ void run_eckey_edge_case_test(void) {
41574177
secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
41584178
}
41594179

4180+
void run_eckey_negate_test(void) {
4181+
unsigned char seckey[32];
4182+
unsigned char seckey_tmp[32];
4183+
4184+
random_scalar_order_b32(seckey);
4185+
memcpy(seckey_tmp, seckey, 32);
4186+
4187+
/* Verify negation changes the key and changes it back */
4188+
CHECK(secp256k1_ec_privkey_negate(ctx, seckey) == 1);
4189+
CHECK(memcmp(seckey, seckey_tmp, 32) != 0);
4190+
CHECK(secp256k1_ec_privkey_negate(ctx, seckey) == 1);
4191+
CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
4192+
4193+
/* Negating all 0s fails */
4194+
memset(seckey, 0, 32);
4195+
memset(seckey_tmp, 0, 32);
4196+
CHECK(secp256k1_ec_privkey_negate(ctx, seckey) == 0);
4197+
/* Check that seckey is not modified */
4198+
CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
4199+
4200+
/* Negating an overflowing seckey fails and the seckey is zeroed. In this
4201+
* test, the seckey has 16 random bytes to ensure that ec_privkey_negate
4202+
* doesn't just set seckey to a constant value in case of failure. */
4203+
random_scalar_order_b32(seckey);
4204+
memset(seckey, 0xFF, 16);
4205+
memset(seckey_tmp, 0, 32);
4206+
CHECK(secp256k1_ec_privkey_negate(ctx, seckey) == 0);
4207+
CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
4208+
}
4209+
41604210
void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
41614211
secp256k1_scalar nonce;
41624212
do {
@@ -5347,6 +5397,9 @@ int main(int argc, char **argv) {
53475397
/* EC key edge cases */
53485398
run_eckey_edge_case_test();
53495399

5400+
/* EC key arithmetic test */
5401+
run_eckey_negate_test();
5402+
53505403
#ifdef ENABLE_MODULE_ECDH
53515404
/* ecdh tests */
53525405
run_ecdh_tests();

0 commit comments

Comments
 (0)