ecdsa-s2c: add actual sign-to-contract functionality

Co-authored-by: Marko Bencun <mbencun+pgp@gmail.com>
Co-authored-by: Jonas Nick <jonasd.nick@gmail.com>
This commit is contained in:
Andrew Poelstra 2020-12-05 23:34:14 +00:00
parent 8e46cac5b3
commit 290dee566e
5 changed files with 376 additions and 4 deletions

View File

@ -51,6 +51,43 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_seria
const secp256k1_ecdsa_s2c_opening* opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ecdsa_sign, but s2c_data32 is committed to inside the nonce
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* s2c_opening: if non-NULL, pointer to an secp256k1_ecdsa_s2c_opening structure to populate
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* s2c_data32: pointer to a 32-byte data to commit to in the nonce (cannot be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_s2c_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
secp256k1_ecdsa_s2c_opening* s2c_opening,
const unsigned char* msg32,
const unsigned char* seckey,
const unsigned char* s2c_data32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
/** Verify a sign-to-contract commitment.
*
* Returns: 1: the signature contains a commitment to data32 (though it does
* not necessarily need to be a valid siganture!)
* 0: incorrect opening
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig: the signature containing the sign-to-contract commitment (cannot be NULL)
* data32: the 32-byte data that was committed to (cannot be NULL)
* opening: pointer to the opening created during signing (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_verify_commit(
const secp256k1_context* ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *data32,
const secp256k1_ecdsa_s2c_opening *opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
}
#endif

View File

@ -10,6 +10,14 @@
#include "include/secp256k1.h"
#include "include/secp256k1_ecdsa_s2c.h"
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge) {
secp256k1_pubkey_save((secp256k1_pubkey*) opening, ge);
}
static int secp256k1_ecdsa_s2c_opening_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_ecdsa_s2c_opening* opening) {
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey*) opening);
}
int secp256k1_ecdsa_s2c_opening_parse(const secp256k1_context* ctx, secp256k1_ecdsa_s2c_opening* opening, const unsigned char* input33) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(opening != NULL);
@ -25,4 +33,108 @@ int secp256k1_ecdsa_s2c_opening_serialize(const secp256k1_context* ctx, unsigned
return secp256k1_ec_pubkey_serialize(ctx, output33, &out_len, (const secp256k1_pubkey*) opening, SECP256K1_EC_COMPRESSED);
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("s2c/ecdsa/point")||SHA256("s2c/ecdsa/point"). */
static void secp256k1_s2c_ecdsa_point_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0xa9b21c7bul;
sha->s[1] = 0x358c3e3eul;
sha->s[2] = 0x0b6863d1ul;
sha->s[3] = 0xc62b2035ul;
sha->s[4] = 0xb44b40ceul;
sha->s[5] = 0x254a8912ul;
sha->s[6] = 0x0f85d0d4ul;
sha->s[7] = 0x8a5bf91cul;
sha->bytes = 64;
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("s2c/ecdsa/data")||SHA256("s2c/ecdsa/data"). */
static void secp256k1_s2c_ecdsa_data_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0xfeefd675ul;
sha->s[1] = 0x73166c99ul;
sha->s[2] = 0xe2309cb8ul;
sha->s[3] = 0x6d458113ul;
sha->s[4] = 0x01d3a512ul;
sha->s[5] = 0x00e18112ul;
sha->s[6] = 0x37ee0874ul;
sha->s[7] = 0x421fc55ful;
sha->bytes = 64;
}
int secp256k1_ecdsa_s2c_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature* signature, secp256k1_ecdsa_s2c_opening* s2c_opening, const unsigned char
*msg32, const unsigned char *seckey, const unsigned char* s2c_data32) {
secp256k1_scalar r, s;
int ret;
unsigned char ndata[32];
secp256k1_sha256 s2c_sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(s2c_data32 != NULL);
/* Provide `s2c_data32` to the nonce function as additional data to
* derive the nonce. It is first hashed because it should be possible
* to derive nonces even if only a SHA256 commitment to the data is
* known. This is important in the ECDSA anti-klepto protocol. */
secp256k1_s2c_ecdsa_data_sha256_tagged(&s2c_sha);
secp256k1_sha256_write(&s2c_sha, s2c_data32, 32);
secp256k1_sha256_finalize(&s2c_sha, ndata);
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, &s2c_sha, s2c_opening, s2c_data32, msg32, seckey, NULL, ndata);
secp256k1_scalar_cmov(&r, &secp256k1_scalar_zero, !ret);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_zero, !ret);
secp256k1_ecdsa_signature_save(signature, &r, &s);
return ret;
}
int secp256k1_ecdsa_s2c_verify_commit(const secp256k1_context* ctx, const secp256k1_ecdsa_signature* sig, const unsigned char* data32, const secp256k1_ecdsa_s2c_opening* opening) {
secp256k1_ge commitment_ge;
secp256k1_ge original_pubnonce_ge;
unsigned char x_bytes[32];
secp256k1_scalar sigr, sigs, x_scalar;
secp256k1_sha256 s2c_sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(sig != NULL);
ARG_CHECK(data32 != NULL);
ARG_CHECK(opening != NULL);
if (!secp256k1_ecdsa_s2c_opening_load(ctx, &original_pubnonce_ge, opening)) {
return 0;
}
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
if (!secp256k1_ec_commit(&ctx->ecmult_ctx, &commitment_ge, &original_pubnonce_ge, &s2c_sha, data32, 32)) {
return 0;
}
/* Check that sig_r == commitment_x (mod n)
* sig_r is the x coordinate of R represented by a scalar.
* commitment_x is the x coordinate of the commitment (field element).
*
* Note that we are only checking the x-coordinate -- this is because the y-coordinate
* is not part of the ECDSA signature (and therefore not part of the commitment!)
*/
secp256k1_ecdsa_signature_load(ctx, &sigr, &sigs, sig);
secp256k1_fe_normalize(&commitment_ge.x);
secp256k1_fe_get_b32(x_bytes, &commitment_ge.x);
/* Do not check overflow; overflowing a scalar does not affect whether
* or not the R value is a cryptographic commitment, only whether it
* is a valid R value for an ECDSA signature. If users care about that
* they should use `ecdsa_verify` or `anti_klepto_host_verify`. In other
* words, this check would be (at best) unnecessary, and (at worst)
* insufficient. */
secp256k1_scalar_set_b32(&x_scalar, x_bytes, NULL);
return secp256k1_scalar_eq(&sigr, &x_scalar);
}
#endif /* SECP256K1_ECDSA_S2C_MAIN_H */

View File

@ -9,6 +9,27 @@
#include "include/secp256k1_ecdsa_s2c.h"
static void test_ecdsa_s2c_tagged_hash(void) {
unsigned char tag_data[14] = "s2c/ecdsa/data";
unsigned char tag_point[15] = "s2c/ecdsa/point";
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
unsigned char output[32];
unsigned char output_optimized[32];
secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data));
secp256k1_s2c_ecdsa_data_sha256_tagged(&sha_optimized);
secp256k1_sha256_finalize(&sha, output);
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
secp256k1_sha256_initialize_tagged(&sha, tag_point, sizeof(tag_point));
secp256k1_s2c_ecdsa_point_sha256_tagged(&sha_optimized);
secp256k1_sha256_finalize(&sha, output);
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
}
void run_s2c_opening_test(void) {
int i = 0;
unsigned char output[33];
@ -62,15 +83,176 @@ void run_s2c_opening_test(void) {
secp256k1_testrand256(&input[1]);
/* Set pubkey oddness tag to first bit of input[1] */
input[0] = (input[1] & 1) + 2;
i++;
}
secp256k1_context_destroy(none);
}
static void test_ecdsa_s2c_api(void) {
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_ecdsa_s2c_opening s2c_opening;
secp256k1_ecdsa_signature sig;
const unsigned char msg[32] = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm";
const unsigned char sec[32] = "ssssssssssssssssssssssssssssssss";
const unsigned char s2c_data[32] = "dddddddddddddddddddddddddddddddd";
secp256k1_pubkey pk;
int32_t ecount;
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sec));
ecount = 0;
CHECK(secp256k1_ecdsa_s2c_sign(both, NULL, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, NULL, msg, sec, s2c_data) == 1);
CHECK(ecount == 1); /* NULL opening is not an API error */
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, NULL, sec, s2c_data) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, NULL, s2c_data) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, sec, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_s2c_sign(none, &sig, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_sign(vrfy, &sig, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_s2c_sign(sign, &sig, &s2c_opening, msg, sec, s2c_data) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pk) == 1);
ecount = 0;
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, NULL, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, &sig, NULL, &s2c_opening) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, &sig, s2c_data, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_verify_commit(none, &sig, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_s2c_verify_commit(sign, &sig, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, sec, &s2c_opening) == 0);
CHECK(ecount == 5); /* wrong data is not an API error */
/* Signing with NULL s2c_opening gives the same result */
CHECK(secp256k1_ecdsa_s2c_sign(sign, &sig, NULL, msg, sec, s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1);
secp256k1_context_destroy(both);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(none);
}
/* When using sign-to-contract commitments, the nonce function is fixed, so we can use fixtures to test. */
typedef struct {
unsigned char s2c_data[32];
unsigned char expected_s2c_opening[33];
} ecdsa_s2c_test;
static ecdsa_s2c_test ecdsa_s2c_tests[] = {
{
"\x1b\xf6\xfb\x42\xf4\x1e\xb8\x76\xc4\xd7\xaa\x0d\x67\x24\x2b\x00\xba\xab\x99\xdc\x20\x84\x49\x3e\x4e\x63\x27\x7f\xa1\xf7\x7f\x22",
"\x03\xf0\x30\xde\xf3\x18\x8c\x0f\x56\xfc\xea\x87\x43\x5b\x30\x76\x43\xf4\x5d\xaf\xe2\x2c\xbc\x82\xfd\x56\x03\x4f\xae\x97\x41\x7d\x3a",
},
{
"\x35\x19\x9a\x8f\xbf\x84\xad\x6e\xf6\x9a\x18\x4c\x1b\x19\x28\x5b\xef\xbe\x06\xe6\x0b\x62\x64\xe6\xd3\x73\x89\x3f\x68\x55\xe2\x4a",
"\x03\x90\x17\x17\xce\x7c\x74\x84\xa2\xce\x1b\x7d\xc7\x40\x3b\x14\xe0\x35\x49\x71\x39\x3e\xc0\x92\xa7\xf3\xe0\xc8\xe4\xe2\xd2\x63\x9d",
},
};
static void test_ecdsa_s2c_fixed_vectors(void) {
const unsigned char privkey[32] = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
};
const unsigned char message[32] = {
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
};
size_t i;
for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) {
secp256k1_ecdsa_s2c_opening s2c_opening;
unsigned char opening_ser[33];
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
secp256k1_ecdsa_signature signature;
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, test->s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(ctx, opening_ser, &s2c_opening) == 1);
CHECK(memcmp(test->expected_s2c_opening, opening_ser, sizeof(opening_ser)) == 0);
}
}
static void test_ecdsa_s2c_sign_verify(void) {
unsigned char privkey[32];
secp256k1_pubkey pubkey;
unsigned char message[32];
unsigned char noncedata[32];
unsigned char s2c_data[32];
unsigned char s2c_data2[32];
secp256k1_ecdsa_signature signature;
secp256k1_ecdsa_s2c_opening s2c_opening;
/* Generate a random key, message, noncedata and s2c_data. */
{
secp256k1_scalar key;
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(privkey, &key);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
secp256k1_testrand256_test(message);
secp256k1_testrand256_test(noncedata);
secp256k1_testrand256_test(s2c_data);
secp256k1_testrand256_test(s2c_data2);
}
{ /* invalid privkeys */
unsigned char zero_privkey[32] = {0};
unsigned char overflow_privkey[32] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, NULL, message, zero_privkey, s2c_data) == 0);
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, NULL, message, overflow_privkey, s2c_data) == 0);
}
/* Check that the sign-to-contract signature is valid, with s2c_data. Also check the commitment. */
{
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, message, &pubkey) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 1);
}
/* Check that an invalid commitment does not verify */
{
unsigned char sigbytes[64];
size_t i;
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, message, &pubkey) == 1);
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sigbytes, &signature) == 1);
for(i = 0; i < 32; i++) {
/* change one byte */
sigbytes[i] = (((int)sigbytes[i]) + 1) % 256;
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 0);
/* revert */
sigbytes[i] = (((int)sigbytes[i]) + 255) % 256;
}
}
}
static void run_ecdsa_s2c_tests(void) {
run_s2c_opening_test();
test_ecdsa_s2c_tagged_hash();
test_ecdsa_s2c_api();
test_ecdsa_s2c_fixed_vectors();
test_ecdsa_s2c_sign_verify();
}
#endif /* SECP256K1_MODULE_ECDSA_S2C_TESTS_H */

View File

@ -129,7 +129,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msg32, seckey, noncefp, noncedata);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, NULL, NULL, NULL, msg32, seckey, noncefp, noncedata);
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
return ret;
}

View File

@ -37,6 +37,18 @@
# include "modules/rangeproof/rangeproof.h"
#endif
#ifdef ENABLE_MODULE_ECDSA_S2C
# include "include/secp256k1_ecdsa_s2c.h"
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge);
#else
typedef void secp256k1_ecdsa_s2c_opening;
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge) {
(void) opening;
(void) ge;
VERIFY_CHECK(0);
}
#endif
#define ARG_CHECK(cond) do { \
if (EXPECT(!(cond), 0)) { \
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
@ -488,7 +500,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, secp256k1_sha256* s2c_sha, secp256k1_ecdsa_s2c_opening *s2c_opening, const unsigned char* s2c_data32, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
secp256k1_scalar sec, non, msg;
int ret = 0;
int is_sec_valid;
@ -503,6 +515,11 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_default;
}
/* sign-to-contract commitments only work with the default nonce function,
* because we need to ensure that s2c_data is actually hashed into the nonce and
* not just ignored. Otherwise an attacker can exfiltrate the secret key by
* signing the same message thrice with different commitments. */
VERIFY_CHECK(s2c_data32 == NULL || noncefp == secp256k1_nonce_function_default);
/* Fail if the secret key is invalid. */
is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey);
@ -518,6 +535,30 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
/* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */
secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid));
if (is_nonce_valid) {
if (s2c_data32 != NULL) {
secp256k1_gej nonce_pj;
secp256k1_ge nonce_p;
/* Compute original nonce commitment/pubkey */
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_pj, &non);
secp256k1_ge_set_gej(&nonce_p, &nonce_pj);
if (s2c_opening != NULL) {
secp256k1_ecdsa_s2c_opening_save(s2c_opening, &nonce_p);
}
/* Because the nonce is valid, the nonce point isn't the point
* at infinity and we can declassify that information to be able to
* serialize the point. */
secp256k1_declassify(ctx, &nonce_p.infinity, sizeof(nonce_p.infinity));
/* Tweak nonce with s2c commitment. */
ret = secp256k1_ec_commit_seckey(&non, &nonce_p, s2c_sha, s2c_data32, 32);
secp256k1_declassify(ctx, &ret, sizeof(ret)); /* may be secret that the tweak falied, but happens with negligible probability */
if (!ret) {
break;
}
}
ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid);
/* The final signature is no longer a secret, nor is the fact that we were successful or not. */
secp256k1_declassify(ctx, &ret, sizeof(ret));
@ -553,7 +594,7 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, msg32, seckey, noncefp, noncedata);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, NULL, NULL, NULL, msg32, seckey, noncefp, noncedata);
secp256k1_ecdsa_signature_save(signature, &r, &s);
return ret;
}