crypto/secp256k1: update to github.com/bitcoin-core/secp256k1 @ 9d560f9 (#3544)
- Use defined constants instead of hard-coding their integer value. - Allocate secp256k1 structs on the C stack instead of converting []byte - Remove dead code
This commit is contained in:
@@ -4,6 +4,5 @@ noinst_HEADERS += src/modules/ecdh/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_ecdh
|
||||
bench_ecdh_SOURCES = src/bench_ecdh.c
|
||||
bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_ecdh_LDFLAGS = -static
|
||||
bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
||||
|
@@ -16,10 +16,10 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
|
||||
secp256k1_gej res;
|
||||
secp256k1_ge pt;
|
||||
secp256k1_scalar s;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(result != NULL);
|
||||
ARG_CHECK(point != NULL);
|
||||
ARG_CHECK(scalar != NULL);
|
||||
(void)ctx;
|
||||
|
||||
secp256k1_pubkey_load(ctx, &pt, point);
|
||||
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
||||
|
@@ -7,6 +7,35 @@
|
||||
#ifndef _SECP256K1_MODULE_ECDH_TESTS_
|
||||
#define _SECP256K1_MODULE_ECDH_TESTS_
|
||||
|
||||
void test_ecdh_api(void) {
|
||||
/* Setup context that just counts errors */
|
||||
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_pubkey point;
|
||||
unsigned char res[32];
|
||||
unsigned char s_one[32] = { 0 };
|
||||
int32_t ecount = 0;
|
||||
s_one[31] = 1;
|
||||
|
||||
secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
|
||||
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
|
||||
|
||||
/* Check all NULLs are detected */
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Cleanup */
|
||||
secp256k1_context_destroy(tctx);
|
||||
}
|
||||
|
||||
void test_ecdh_generator_basepoint(void) {
|
||||
unsigned char s_one[32] = { 0 };
|
||||
secp256k1_pubkey point[2];
|
||||
@@ -68,6 +97,7 @@ void test_bad_scalar(void) {
|
||||
}
|
||||
|
||||
void run_ecdh_tests(void) {
|
||||
test_ecdh_api();
|
||||
test_ecdh_generator_basepoint();
|
||||
test_bad_scalar();
|
||||
}
|
||||
|
@@ -4,6 +4,5 @@ noinst_HEADERS += src/modules/recovery/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_recover
|
||||
bench_recover_SOURCES = src/bench_recover.c
|
||||
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_recover_LDFLAGS = -static
|
||||
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
||||
|
45
crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h
Normal file → Executable file
45
crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h
Normal file → Executable file
@@ -63,6 +63,7 @@ int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_cont
|
||||
(void)ctx;
|
||||
ARG_CHECK(output64 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(recid != NULL);
|
||||
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig);
|
||||
secp256k1_scalar_get_b32(&output64[0], &r);
|
||||
@@ -83,6 +84,42 @@ int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) {
|
||||
unsigned char brx[32];
|
||||
secp256k1_fe fx;
|
||||
secp256k1_ge x;
|
||||
secp256k1_gej xj;
|
||||
secp256k1_scalar rn, u1, u2;
|
||||
secp256k1_gej qj;
|
||||
int r;
|
||||
|
||||
if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_get_b32(brx, sigr);
|
||||
r = secp256k1_fe_set_b32(&fx, brx);
|
||||
(void)r;
|
||||
VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
|
||||
if (recid & 2) {
|
||||
if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&xj, &x);
|
||||
secp256k1_scalar_inverse_var(&rn, sigr);
|
||||
secp256k1_scalar_mul(&u1, &rn, message);
|
||||
secp256k1_scalar_negate(&u1, &u1);
|
||||
secp256k1_scalar_mul(&u2, &rn, sigs);
|
||||
secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
|
||||
secp256k1_ge_set_gej_var(pubkey, &qj);
|
||||
return !secp256k1_gej_is_infinity(&qj);
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
secp256k1_scalar r, s;
|
||||
secp256k1_scalar sec, non, msg;
|
||||
@@ -101,16 +138,15 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
|
||||
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
|
||||
/* Fail if the secret key is invalid. */
|
||||
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
|
||||
unsigned char nonce32[32];
|
||||
unsigned int count = 0;
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
while (1) {
|
||||
unsigned char nonce32[32];
|
||||
ret = noncefp(nonce32, seckey, msg32, NULL, (void*)noncedata, count);
|
||||
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||
memset(nonce32, 0, 32);
|
||||
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
||||
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
|
||||
break;
|
||||
@@ -118,6 +154,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
|
||||
}
|
||||
count++;
|
||||
}
|
||||
memset(nonce32, 0, 32);
|
||||
secp256k1_scalar_clear(&msg);
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
@@ -142,7 +179,7 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
|
||||
ARG_CHECK(recid >= 0 && recid < 4);
|
||||
VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */
|
||||
secp256k1_scalar_set_b32(&m, msg32, NULL);
|
||||
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
|
||||
secp256k1_pubkey_save(pubkey, &q);
|
||||
|
@@ -7,6 +7,146 @@
|
||||
#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
|
||||
#define _SECP256K1_MODULE_RECOVERY_TESTS_
|
||||
|
||||
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
||||
(void) msg32;
|
||||
(void) key32;
|
||||
(void) algo16;
|
||||
(void) data;
|
||||
|
||||
/* On the first run, return 0 to force a second run */
|
||||
if (counter == 0) {
|
||||
memset(nonce32, 0, 32);
|
||||
return 1;
|
||||
}
|
||||
/* On the second run, return an overflow to force a third run */
|
||||
if (counter == 1) {
|
||||
memset(nonce32, 0xff, 32);
|
||||
return 1;
|
||||
}
|
||||
/* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
|
||||
memset(nonce32, 1, 32);
|
||||
return secp256k1_rand_bits(1);
|
||||
}
|
||||
|
||||
void test_ecdsa_recovery_api(void) {
|
||||
/* Setup contexts that just count errors */
|
||||
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_pubkey pubkey;
|
||||
secp256k1_pubkey recpubkey;
|
||||
secp256k1_ecdsa_signature normal_sig;
|
||||
secp256k1_ecdsa_recoverable_signature recsig;
|
||||
unsigned char privkey[32] = { 1 };
|
||||
unsigned char message[32] = { 2 };
|
||||
int32_t ecount = 0;
|
||||
int recid = 0;
|
||||
unsigned char sig[74];
|
||||
unsigned char zero_privkey[32] = { 0 };
|
||||
unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &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);
|
||||
|
||||
/* Construct and verify corresponding public key. */
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
|
||||
|
||||
/* Check bad contexts and NULLs for signing */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
|
||||
secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
|
||||
CHECK(ecount == 5);
|
||||
/* These will all fail, but not in ARG_CHECK way */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
|
||||
/* This one will succeed. */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
/* Check signing with a goofy nonce function */
|
||||
|
||||
/* Check bad contexts and NULLs for recovery */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
/* Check NULLs for conversion */
|
||||
CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
|
||||
|
||||
/* Check NULLs for de/serialization */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
|
||||
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
|
||||
CHECK(ecount == 7);
|
||||
/* overflow in signature will fail but not affect ecount */
|
||||
memcpy(sig, over_privkey, 32);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
/* cleanup */
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
secp256k1_context_destroy(both);
|
||||
}
|
||||
|
||||
void test_ecdsa_recovery_end_to_end(void) {
|
||||
unsigned char extra[32] = {0x00};
|
||||
unsigned char privkey[32];
|
||||
@@ -34,6 +174,7 @@ void test_ecdsa_recovery_end_to_end(void) {
|
||||
/* Serialize/parse compact and verify/recover. */
|
||||
extra[0] = 0;
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1);
|
||||
extra[31] = 1;
|
||||
@@ -43,6 +184,7 @@ void test_ecdsa_recovery_end_to_end(void) {
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
|
||||
CHECK(memcmp(&signature[4], &signature[0], 64) == 0);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
|
||||
memset(&rsignature[4], 0, sizeof(rsignature[4]));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
|
||||
@@ -54,7 +196,7 @@ void test_ecdsa_recovery_end_to_end(void) {
|
||||
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
|
||||
/* Serialize/destroy/parse signature and verify again. */
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
|
||||
sig[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
|
||||
sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
|
||||
@@ -161,25 +303,24 @@ void test_ecdsa_recovery_edge_cases(void) {
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1);
|
||||
/* Verifying with (order + r,4) should always fail. */
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
|
||||
}
|
||||
/* DER parsing tests. */
|
||||
/* Zero length r/s. */
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
|
||||
/* Leading zeros. */
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
|
||||
sigbderalt3[4] = 1;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
|
||||
sigbderalt4[7] = 1;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
|
||||
sigbderalt3[4] = 1;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
|
||||
sigbderalt4[7] = 1;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
|
||||
/* Damage signature. */
|
||||
sigbder[7]++;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
|
||||
@@ -240,6 +381,9 @@ void test_ecdsa_recovery_edge_cases(void) {
|
||||
|
||||
void run_recovery_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
test_ecdsa_recovery_api();
|
||||
}
|
||||
for (i = 0; i < 64*count; i++) {
|
||||
test_ecdsa_recovery_end_to_end();
|
||||
}
|
||||
|
@@ -1,11 +0,0 @@
|
||||
include_HEADERS += include/secp256k1_schnorr.h
|
||||
noinst_HEADERS += src/modules/schnorr/main_impl.h
|
||||
noinst_HEADERS += src/modules/schnorr/schnorr.h
|
||||
noinst_HEADERS += src/modules/schnorr/schnorr_impl.h
|
||||
noinst_HEADERS += src/modules/schnorr/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_schnorr_verify
|
||||
bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
|
||||
bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_schnorr_verify_LDFLAGS = -static
|
||||
endif
|
@@ -1,164 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORR_MAIN
|
||||
#define SECP256K1_MODULE_SCHNORR_MAIN
|
||||
|
||||
#include "include/secp256k1_schnorr.h"
|
||||
#include "modules/schnorr/schnorr_impl.h"
|
||||
|
||||
static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
|
||||
secp256k1_sha256_t sha;
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, r32, 32);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, h32);
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 ";
|
||||
|
||||
int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
secp256k1_scalar sec, non;
|
||||
int ret = 0;
|
||||
int overflow = 0;
|
||||
unsigned int count = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_default;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
||||
while (1) {
|
||||
unsigned char nonce32[32];
|
||||
ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||
memset(nonce32, 0, 32);
|
||||
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
||||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
if (!ret) {
|
||||
memset(sig64, 0, 64);
|
||||
}
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
|
||||
secp256k1_ge q;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
secp256k1_pubkey_load(ctx, &q, pubkey);
|
||||
return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32);
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) {
|
||||
secp256k1_ge q;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) {
|
||||
secp256k1_pubkey_save(pubkey, &q);
|
||||
return 1;
|
||||
} else {
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
int count = 0;
|
||||
int ret = 1;
|
||||
secp256k1_gej Qj;
|
||||
secp256k1_ge Q;
|
||||
secp256k1_scalar sec;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sec32 != NULL);
|
||||
ARG_CHECK(pubnonce != NULL);
|
||||
ARG_CHECK(privnonce32 != NULL);
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_default;
|
||||
}
|
||||
|
||||
do {
|
||||
int overflow;
|
||||
ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&sec, privnonce32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&sec)) {
|
||||
continue;
|
||||
}
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec);
|
||||
secp256k1_ge_set_gej(&Q, &Qj);
|
||||
|
||||
secp256k1_pubkey_save(pubnonce, &Q);
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
secp256k1_scalar_clear(&sec);
|
||||
if (!ret) {
|
||||
memset(pubnonce, 0, sizeof(*pubnonce));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar sec, non;
|
||||
secp256k1_ge pubnon;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(sec32 != NULL);
|
||||
ARG_CHECK(secnonce32 != NULL);
|
||||
ARG_CHECK(pubnonce_others != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&sec, sec32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&sec)) {
|
||||
return -1;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, secnonce32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&non)) {
|
||||
return -1;
|
||||
}
|
||||
secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others);
|
||||
return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32);
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, int n) {
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(n >= 1);
|
||||
ARG_CHECK(sig64sin != NULL);
|
||||
return secp256k1_schnorr_sig_combine(sig64, n, sig64sin);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,20 +0,0 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_SCHNORR_H_
|
||||
#define _SECP256K1_MODULE_SCHNORR_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32);
|
||||
|
||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
||||
static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
||||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, int n, const unsigned char * const *sig64ins);
|
||||
|
||||
#endif
|
@@ -1,207 +0,0 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_SCHNORR_IMPL_H_
|
||||
#define _SECP256K1_SCHNORR_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "schnorr.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
/**
|
||||
* Custom Schnorr-based signature scheme. They support multiparty signing, public key
|
||||
* recovery and batch validation.
|
||||
*
|
||||
* Rationale for verifying R's y coordinate:
|
||||
* In order to support batch validation and public key recovery, the full R point must
|
||||
* be known to verifiers, rather than just its x coordinate. In order to not risk
|
||||
* being more strict in batch validation than normal validation, validators must be
|
||||
* required to reject signatures with incorrect y coordinate. This is only possible
|
||||
* by including a (relatively slow) field inverse, or a field square root. However,
|
||||
* batch validation offers potentially much higher benefits than this cost.
|
||||
*
|
||||
* Rationale for having an implicit y coordinate oddness:
|
||||
* If we commit to having the full R point known to verifiers, there are two mechanism.
|
||||
* Either include its oddness in the signature, or give it an implicit fixed value.
|
||||
* As the R y coordinate can be flipped by a simple negation of the nonce, we choose the
|
||||
* latter, as it comes with nearly zero impact on signing or validation performance, and
|
||||
* saves a byte in the signature.
|
||||
*
|
||||
* Signing:
|
||||
* Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0)
|
||||
*
|
||||
* Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce).
|
||||
* Compute 32-byte r, the serialization of R's x coordinate.
|
||||
* Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order.
|
||||
* Compute scalar s = k - h * x.
|
||||
* The signature is (r, s).
|
||||
*
|
||||
*
|
||||
* Verification:
|
||||
* Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s)
|
||||
*
|
||||
* Signature is invalid if s >= order.
|
||||
* Signature is invalid if r >= p.
|
||||
* Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order.
|
||||
* Option 1 (faster for single verification):
|
||||
* Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd.
|
||||
* Signature is valid if the serialization of R's x coordinate equals r.
|
||||
* Option 2 (allows batch validation and pubkey recovery):
|
||||
* Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve.
|
||||
* Signature is valid if R + h * Q + s * G == 0.
|
||||
*/
|
||||
|
||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
||||
secp256k1_gej Rj;
|
||||
secp256k1_ge Ra;
|
||||
unsigned char h32[32];
|
||||
secp256k1_scalar h, s;
|
||||
int overflow;
|
||||
secp256k1_scalar n;
|
||||
|
||||
if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) {
|
||||
return 0;
|
||||
}
|
||||
n = *nonce;
|
||||
|
||||
secp256k1_ecmult_gen(ctx, &Rj, &n);
|
||||
if (pubnonce != NULL) {
|
||||
secp256k1_gej_add_ge(&Rj, &Rj, pubnonce);
|
||||
}
|
||||
secp256k1_ge_set_gej(&Ra, &Rj);
|
||||
secp256k1_fe_normalize(&Ra.y);
|
||||
if (secp256k1_fe_is_odd(&Ra.y)) {
|
||||
/* R's y coordinate is odd, which is not allowed (see rationale above).
|
||||
Force it to be even by negating the nonce. Note that this even works
|
||||
for multiparty signing, as the R point is known to all participants,
|
||||
which can all decide to flip the sign in unison, resulting in the
|
||||
overall R point to be negated too. */
|
||||
secp256k1_scalar_negate(&n, &n);
|
||||
}
|
||||
secp256k1_fe_normalize(&Ra.x);
|
||||
secp256k1_fe_get_b32(sig64, &Ra.x);
|
||||
hash(h32, sig64, msg32);
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&h, h32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
||||
secp256k1_scalar_clear(&n);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_mul(&s, &h, key);
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
secp256k1_scalar_add(&s, &s, &n);
|
||||
secp256k1_scalar_clear(&n);
|
||||
secp256k1_scalar_get_b32(sig64 + 32, &s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
||||
secp256k1_gej Qj, Rj;
|
||||
secp256k1_ge Ra;
|
||||
secp256k1_fe Rx;
|
||||
secp256k1_scalar h, s;
|
||||
unsigned char hh[32];
|
||||
int overflow;
|
||||
|
||||
if (secp256k1_ge_is_infinity(pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
hash(hh, sig64, msg32);
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&h, hh, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
||||
return 0;
|
||||
}
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_fe_set_b32(&Rx, sig64)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&Qj, pubkey);
|
||||
secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s);
|
||||
if (secp256k1_gej_is_infinity(&Rj)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej_var(&Ra, &Rj);
|
||||
secp256k1_fe_normalize_var(&Ra.y);
|
||||
if (secp256k1_fe_is_odd(&Ra.y)) {
|
||||
return 0;
|
||||
}
|
||||
return secp256k1_fe_equal_var(&Rx, &Ra.x);
|
||||
}
|
||||
|
||||
static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
||||
secp256k1_gej Qj, Rj;
|
||||
secp256k1_ge Ra;
|
||||
secp256k1_fe Rx;
|
||||
secp256k1_scalar h, s;
|
||||
unsigned char hh[32];
|
||||
int overflow;
|
||||
|
||||
hash(hh, sig64, msg32);
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&h, hh, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
||||
return 0;
|
||||
}
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_fe_set_b32(&Rx, sig64)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&Rj, &Ra);
|
||||
secp256k1_scalar_inverse_var(&h, &h);
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
secp256k1_scalar_mul(&s, &s, &h);
|
||||
secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s);
|
||||
if (secp256k1_gej_is_infinity(&Qj)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(pubkey, &Qj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, int n, const unsigned char * const *sig64ins) {
|
||||
secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar si;
|
||||
int overflow;
|
||||
secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow);
|
||||
if (overflow) {
|
||||
return -1;
|
||||
}
|
||||
if (i) {
|
||||
if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_add(&s, &s, &si);
|
||||
}
|
||||
if (secp256k1_scalar_is_zero(&s)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(sig64, sig64ins[0], 32);
|
||||
secp256k1_scalar_get_b32(sig64 + 32, &s);
|
||||
secp256k1_scalar_clear(&s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,175 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORR_TESTS
|
||||
#define SECP256K1_MODULE_SCHNORR_TESTS
|
||||
|
||||
#include "include/secp256k1_schnorr.h"
|
||||
|
||||
void test_schnorr_end_to_end(void) {
|
||||
unsigned char privkey[32];
|
||||
unsigned char message[32];
|
||||
unsigned char schnorr_signature[64];
|
||||
secp256k1_pubkey pubkey, recpubkey;
|
||||
|
||||
/* Generate a random key and message. */
|
||||
{
|
||||
secp256k1_scalar key;
|
||||
random_scalar_order_test(&key);
|
||||
secp256k1_scalar_get_b32(privkey, &key);
|
||||
secp256k1_rand256_test(message);
|
||||
}
|
||||
|
||||
/* Construct and verify corresponding public key. */
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
|
||||
|
||||
/* Schnorr sign. */
|
||||
CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1);
|
||||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1);
|
||||
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
|
||||
/* Destroy signature and verify again. */
|
||||
schnorr_signature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
|
||||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0);
|
||||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 ||
|
||||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
|
||||
}
|
||||
|
||||
/** Horribly broken hash function. Do not use for anything but tests. */
|
||||
void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
|
||||
int i;
|
||||
for (i = 0; i < 32; i++) {
|
||||
h32[i] = r32[i] ^ msg32[i];
|
||||
}
|
||||
}
|
||||
|
||||
void test_schnorr_sign_verify(void) {
|
||||
unsigned char msg32[32];
|
||||
unsigned char sig64[3][64];
|
||||
secp256k1_gej pubkeyj[3];
|
||||
secp256k1_ge pubkey[3];
|
||||
secp256k1_scalar nonce[3], key[3];
|
||||
int i = 0;
|
||||
int k;
|
||||
|
||||
secp256k1_rand256_test(msg32);
|
||||
|
||||
for (k = 0; k < 3; k++) {
|
||||
random_scalar_order_test(&key[k]);
|
||||
|
||||
do {
|
||||
random_scalar_order_test(&nonce[k]);
|
||||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) {
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]);
|
||||
secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]);
|
||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32));
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
int pos = secp256k1_rand32() % 64;
|
||||
int mod = 1 + (secp256k1_rand32() % 255);
|
||||
sig64[k][pos] ^= mod;
|
||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0);
|
||||
sig64[k][pos] ^= mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_schnorr_threshold(void) {
|
||||
unsigned char msg[32];
|
||||
unsigned char sec[5][32];
|
||||
secp256k1_pubkey pub[5];
|
||||
unsigned char nonce[5][32];
|
||||
secp256k1_pubkey pubnonce[5];
|
||||
unsigned char sig[5][64];
|
||||
const unsigned char* sigs[5];
|
||||
unsigned char allsig[64];
|
||||
const secp256k1_pubkey* pubs[5];
|
||||
secp256k1_pubkey allpub;
|
||||
int n, i;
|
||||
int damage;
|
||||
int ret = 0;
|
||||
|
||||
damage = (secp256k1_rand32() % 2) ? (1 + (secp256k1_rand32() % 4)) : 0;
|
||||
secp256k1_rand256_test(msg);
|
||||
n = 2 + (secp256k1_rand32() % 4);
|
||||
for (i = 0; i < n; i++) {
|
||||
do {
|
||||
secp256k1_rand256_test(sec[i]);
|
||||
} while (!secp256k1_ec_seckey_verify(ctx, sec[i]));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i]));
|
||||
CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL));
|
||||
pubs[i] = &pub[i];
|
||||
}
|
||||
if (damage == 1) {
|
||||
nonce[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255);
|
||||
} else if (damage == 2) {
|
||||
sec[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_pubkey allpubnonce;
|
||||
const secp256k1_pubkey *pubnonces[4];
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
pubnonces[j] = &pubnonce[j];
|
||||
}
|
||||
for (j = i + 1; j < n; j++) {
|
||||
pubnonces[j - 1] = &pubnonce[j];
|
||||
}
|
||||
CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1));
|
||||
ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1;
|
||||
sigs[i] = sig[i];
|
||||
}
|
||||
if (damage == 3) {
|
||||
sig[secp256k1_rand32() % n][secp256k1_rand32() % 64] ^= 1 + (secp256k1_rand32() % 255);
|
||||
}
|
||||
ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2;
|
||||
if ((ret & 1) == 0) {
|
||||
ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4;
|
||||
}
|
||||
if (damage == 4) {
|
||||
allsig[secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255);
|
||||
}
|
||||
if ((ret & 7) == 0) {
|
||||
ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8;
|
||||
}
|
||||
CHECK((ret == 0) == (damage == 0));
|
||||
}
|
||||
|
||||
void test_schnorr_recovery(void) {
|
||||
unsigned char msg32[32];
|
||||
unsigned char sig64[64];
|
||||
secp256k1_ge Q;
|
||||
|
||||
secp256k1_rand256_test(msg32);
|
||||
secp256k1_rand256_test(sig64);
|
||||
secp256k1_rand256_test(sig64 + 32);
|
||||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) {
|
||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
void run_schnorr_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 32*count; i++) {
|
||||
test_schnorr_end_to_end();
|
||||
}
|
||||
for (i = 0; i < 32 * count; i++) {
|
||||
test_schnorr_sign_verify();
|
||||
}
|
||||
for (i = 0; i < 16 * count; i++) {
|
||||
test_schnorr_recovery();
|
||||
}
|
||||
for (i = 0; i < 10 * count; i++) {
|
||||
test_schnorr_threshold();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user