Skip to content

Commit f39f99b

Browse files
Merge bitcoin#701: Make ec_ arithmetic more consistent and add documentation
7e3952a Clarify documentation of tweak functions. (Jonas Nick) 89853a0 Make tweak function documentation more consistent. (Jonas Nick) 41fc785 Make ec_privkey functions aliases for ec_seckey_negate, ec_seckey_tweak_add and ec_seckey_mul (Jonas Nick) 22911ee Rename private key to secret key in public API (with the exception of function names) (Jonas Nick) 5a73f14 Mention that value is unspecified for In/Out parameters if the function returns 0 (Jonas Nick) f03df0e Define valid ECDSA keys in the documentation of seckey_verify (Jonas Nick) 5894e1f Return 0 if the given seckey is invalid in privkey_negate, privkey_tweak_add and privkey_tweak_mul (Jonas Nick) 8f814cd Add test for boundary conditions of scalar_set_b32 with respect to overflows (Jonas Nick) 3fec982 Use scalar_set_b32_seckey in ecdsa_sign, pubkey_create and seckey_verify (Jonas Nick) 9ab2cbe Add scalar_set_b32_seckey which does the same as scalar_set_b32 and also returns whether it's a valid secret key (Jonas Nick) Pull request description: Fixes bitcoin#671. Supersedes bitcoin#668. This PR unifies handling of invalid secret keys by introducing a new function `scalar_set_b32_secret` which returns false if the b32 overflows or is 0. By using this in `privkey_{negate, tweak_add, tweak_mul}` these function will now return 0 if the secret key is invalid which matches the behavior of `ecdsa_sign` and `pubkey_create`. Instead of deciding whether to zeroize the secret key on failure, I only added documentation for now that the value is undefined on failure. ACKs for top commit: real-or-random: ACK 7e3952a I read the diff carefully and tested the changes apoelstra: ACK 7e3952a Tree-SHA512: 8e9a66799cd3b6ec1c3acb731d6778035417e3dca9300d840e2437346ff0ac94f0c9be4de20aa2fac9bb4ae2f8a36d4e6a34795a640b9cfbfee8311decb102f0
2 parents 39198a0 + 7e3952a commit f39f99b

File tree

9 files changed

+290
-92
lines changed

9 files changed

+290
-92
lines changed

include/secp256k1.h

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extern "C" {
1414
* 2. Array lengths always immediately the follow the argument whose length
1515
* they describe, even if this violates rule 1.
1616
* 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
17-
* later go first. This means: signatures, public nonces, private nonces,
17+
* later go first. This means: signatures, public nonces, secret nonces,
1818
* messages, public keys, secret keys, tweaks.
1919
* 4. Arguments that are not data pointers go last, from more complex to less
2020
* complex: function pointers, algorithm names, messages, void pointers,
@@ -531,7 +531,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
531531
/** Create an ECDSA signature.
532532
*
533533
* Returns: 1: signature created
534-
* 0: the nonce generation function failed, or the private key was invalid.
534+
* 0: the nonce generation function failed, or the secret key was invalid.
535535
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
536536
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
537537
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
@@ -552,6 +552,11 @@ SECP256K1_API int secp256k1_ecdsa_sign(
552552
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
553553

554554
/** Verify an ECDSA secret key.
555+
*
556+
* A secret key is valid if it is not 0 and less than the secp256k1 curve order
557+
* when interpreted as an integer (most significant byte first). The
558+
* probability of choosing a 32-byte string uniformly at random which is an
559+
* invalid secret key is negligible.
555560
*
556561
* Returns: 1: secret key is valid
557562
* 0: secret key is invalid
@@ -569,20 +574,32 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
569574
* 0: secret was invalid, try again
570575
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
571576
* Out: pubkey: pointer to the created public key (cannot be NULL)
572-
* In: seckey: pointer to a 32-byte private key (cannot be NULL)
577+
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
573578
*/
574579
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
575580
const secp256k1_context* ctx,
576581
secp256k1_pubkey *pubkey,
577582
const unsigned char *seckey
578583
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
579584

580-
/** Negates a private key in place.
585+
/** Negates a secret key in place.
581586
*
582-
* Returns: 1 always
583-
* Args: ctx: pointer to a context object
584-
* In/Out: seckey: pointer to the 32-byte private key to be negated (cannot be NULL)
587+
* Returns: 0 if the given secret key is invalid according to
588+
* secp256k1_ec_seckey_verify. 1 otherwise
589+
* Args: ctx: pointer to a context object
590+
* In/Out: seckey: pointer to the 32-byte secret key to be negated. If the
591+
* secret key is invalid according to
592+
* secp256k1_ec_seckey_verify, this function returns 0 and
593+
* seckey will be set to some unspecified value. (cannot be
594+
* NULL)
585595
*/
596+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
597+
const secp256k1_context* ctx,
598+
unsigned char *seckey
599+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
600+
601+
/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in
602+
* future versions. */
586603
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
587604
const secp256k1_context* ctx,
588605
unsigned char *seckey
@@ -599,57 +616,93 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
599616
secp256k1_pubkey *pubkey
600617
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
601618

602-
/** Tweak a private key by adding tweak to it.
603-
* 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-
* Args: ctx: pointer to a context object (cannot be NULL).
608-
* In/Out: seckey: pointer to a 32-byte private key.
609-
* In: tweak: pointer to a 32-byte tweak.
610-
*/
619+
/** Tweak a secret key by adding tweak to it.
620+
*
621+
* Returns: 0 if the arguments are invalid or the resulting secret key would be
622+
* invalid (only when the tweak is the negation of the secret key). 1
623+
* otherwise.
624+
* Args: ctx: pointer to a context object (cannot be NULL).
625+
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
626+
* invalid according to secp256k1_ec_seckey_verify, this
627+
* function returns 0. seckey will be set to some unspecified
628+
* value if this function returns 0. (cannot be NULL)
629+
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
630+
* secp256k1_ec_seckey_verify, this function returns 0. For
631+
* uniformly random 32-byte arrays the chance of being invalid
632+
* is negligible (around 1 in 2^128) (cannot be NULL).
633+
*/
634+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
635+
const secp256k1_context* ctx,
636+
unsigned char *seckey,
637+
const unsigned char *tweak
638+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
639+
640+
/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
641+
* future versions. */
611642
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
612643
const secp256k1_context* ctx,
613644
unsigned char *seckey,
614645
const unsigned char *tweak
615646
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
616647

617648
/** Tweak a public key by adding tweak times the generator to it.
618-
* 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.
622-
* Args: ctx: pointer to a context object initialized for validation
649+
*
650+
* Returns: 0 if the arguments are invalid or the resulting public key would be
651+
* invalid (only when the tweak is the negation of the corresponding
652+
* secret key). 1 otherwise.
653+
* Args: ctx: pointer to a context object initialized for validation
623654
* (cannot be NULL).
624-
* In/Out: pubkey: pointer to a public key object.
625-
* In: tweak: pointer to a 32-byte tweak.
655+
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
656+
* invalid value if this function returns 0 (cannot be NULL).
657+
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
658+
* secp256k1_ec_seckey_verify, this function returns 0. For
659+
* uniformly random 32-byte arrays the chance of being invalid
660+
* is negligible (around 1 in 2^128) (cannot be NULL).
626661
*/
627662
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
628663
const secp256k1_context* ctx,
629664
secp256k1_pubkey *pubkey,
630665
const unsigned char *tweak
631666
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
632667

633-
/** Tweak a private key by multiplying it by a tweak.
634-
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
635-
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
636-
* Args: ctx: pointer to a context object (cannot be NULL).
637-
* In/Out: seckey: pointer to a 32-byte private key.
638-
* In: tweak: pointer to a 32-byte tweak.
668+
/** Tweak a secret key by multiplying it by a tweak.
669+
*
670+
* Returns: 0 if the arguments are invalid. 1 otherwise.
671+
* Args: ctx: pointer to a context object (cannot be NULL).
672+
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
673+
* invalid according to secp256k1_ec_seckey_verify, this
674+
* function returns 0. seckey will be set to some unspecified
675+
* value if this function returns 0. (cannot be NULL)
676+
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
677+
* secp256k1_ec_seckey_verify, this function returns 0. For
678+
* uniformly random 32-byte arrays the chance of being invalid
679+
* is negligible (around 1 in 2^128) (cannot be NULL).
639680
*/
681+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
682+
const secp256k1_context* ctx,
683+
unsigned char *seckey,
684+
const unsigned char *tweak
685+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
686+
687+
/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
688+
* future versions. */
640689
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
641690
const secp256k1_context* ctx,
642691
unsigned char *seckey,
643692
const unsigned char *tweak
644693
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
645694

646695
/** Tweak a public key by multiplying it by a tweak value.
647-
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
648-
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
649-
* Args: ctx: pointer to a context object initialized for validation
650-
* (cannot be NULL).
651-
* In/Out: pubkey: pointer to a public key object.
652-
* In: tweak: pointer to a 32-byte tweak.
696+
*
697+
* Returns: 0 if the arguments are invalid. 1 otherwise.
698+
* Args: ctx: pointer to a context object initialized for validation
699+
* (cannot be NULL).
700+
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
701+
* invalid value if this function returns 0 (cannot be NULL).
702+
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
703+
* secp256k1_ec_seckey_verify, this function returns 0. For
704+
* uniformly random 32-byte arrays the chance of being invalid
705+
* is negligible (around 1 in 2^128) (cannot be NULL).
653706
*/
654707
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
655708
const secp256k1_context* ctx,
@@ -688,6 +741,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
688741
) SECP256K1_ARG_NONNULL(1);
689742

690743
/** Add a number of public keys together.
744+
*
691745
* Returns: 1: the sum of the public keys is valid.
692746
* 0: the sum of the public keys is not valid.
693747
* Args: ctx: pointer to a context object

include/secp256k1_ecdh.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_func
4141
* Out: output: pointer to an array to be filled by hashfp
4242
* In: pubkey: a pointer to a secp256k1_pubkey containing an
4343
* initialized public key
44-
* privkey: a 32-byte scalar with which to multiply the point
44+
* seckey: a 32-byte scalar with which to multiply the point
4545
* hashfp: pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used
4646
* (in which case, 32 bytes will be written to output)
4747
* data: arbitrary data pointer that is passed through to hashfp
@@ -50,7 +50,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
5050
const secp256k1_context* ctx,
5151
unsigned char *output,
5252
const secp256k1_pubkey *pubkey,
53-
const unsigned char *privkey,
53+
const unsigned char *seckey,
5454
secp256k1_ecdh_hash_function hashfp,
5555
void *data
5656
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

include/secp256k1_recovery.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
7070
/** Create a recoverable ECDSA signature.
7171
*
7272
* Returns: 1: signature created
73-
* 0: the nonce generation function failed, or the private key was invalid.
73+
* 0: the nonce generation function failed, or the secret key was invalid.
7474
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
7575
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
7676
* In: msg32: the 32-byte message hash being signed (cannot be NULL)

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/scalar.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, uns
3939
*/
4040
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow);
4141

42+
/** Set a scalar from a big endian byte array and returns 1 if it is a valid
43+
* seckey and 0 otherwise. */
44+
static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin);
45+
4246
/** Set a scalar to an unsigned integer. */
4347
static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v);
4448

src/scalar_impl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
5555
}
5656
#endif
5757

58+
static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) {
59+
int overflow;
60+
secp256k1_scalar_set_b32(r, bin, &overflow);
61+
return (!overflow) & (!secp256k1_scalar_is_zero(r));
62+
}
63+
5864
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
5965
#if defined(EXHAUSTIVE_TEST_ORDER)
6066
int i;

0 commit comments

Comments
 (0)