From 8fcee9ab053a59d1c4573ad033994769fe6dda55 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 3 Apr 2018 22:06:07 +0000 Subject: [PATCH 01/25] add chacha20 function --- src/scalar.h | 3 ++ src/scalar_4x64_impl.h | 93 ++++++++++++++++++++++++++++++++++ src/scalar_8x32_impl.h | 100 +++++++++++++++++++++++++++++++++++++ src/scalar_low_impl.h | 5 ++ src/tests.c | 110 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 311 insertions(+) diff --git a/src/scalar.h b/src/scalar.h index 59304cb66e..640693a5e3 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -103,4 +103,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); +/** Generate two scalars from a 32-byte seed and an integer using the chacha20 stream cipher */ +static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx); + #endif /* SECP256K1_SCALAR_H */ diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index d378335d99..1000d9a962 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -7,6 +7,9 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include "scalar.h" +#include + /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) #define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) @@ -946,4 +949,94 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); } +#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) +#define QUARTERROUND(a,b,c,d) \ + a += b; d = ROTL32(d ^ a, 16); \ + c += d; b = ROTL32(b ^ c, 12); \ + a += b; d = ROTL32(d ^ a, 8); \ + c += d; b = ROTL32(b ^ c, 7); + +#ifdef WORDS_BIGENDIAN +#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define BE32(p) (p) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define LE32(p) (p) +#endif + +static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx) { + size_t n; + size_t over_count = 0; + uint32_t seed32[8]; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int over1, over2; + + memcpy((void *) seed32, (const void *) seed, 32); + do { + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + x4 = LE32(seed32[0]); + x5 = LE32(seed32[1]); + x6 = LE32(seed32[2]); + x7 = LE32(seed32[3]); + x8 = LE32(seed32[4]); + x9 = LE32(seed32[5]); + x10 = LE32(seed32[6]); + x11 = LE32(seed32[7]); + x12 = idx; + x13 = idx >> 32; + x14 = 0; + x15 = over_count; + + n = 10; + while (n--) { + QUARTERROUND(x0, x4, x8,x12) + QUARTERROUND(x1, x5, x9,x13) + QUARTERROUND(x2, x6,x10,x14) + QUARTERROUND(x3, x7,x11,x15) + QUARTERROUND(x0, x5,x10,x15) + QUARTERROUND(x1, x6,x11,x12) + QUARTERROUND(x2, x7, x8,x13) + QUARTERROUND(x3, x4, x9,x14) + } + + x0 += 0x61707865; + x1 += 0x3320646e; + x2 += 0x79622d32; + x3 += 0x6b206574; + x4 += LE32(seed32[0]); + x5 += LE32(seed32[1]); + x6 += LE32(seed32[2]); + x7 += LE32(seed32[3]); + x8 += LE32(seed32[4]); + x9 += LE32(seed32[5]); + x10 += LE32(seed32[6]); + x11 += LE32(seed32[7]); + x12 += idx; + x13 += idx >> 32; + x14 += 0; + x15 += over_count; + + r1->d[3] = LE32((uint64_t) x0) << 32 | LE32(x1); + r1->d[2] = LE32((uint64_t) x2) << 32 | LE32(x3); + r1->d[1] = LE32((uint64_t) x4) << 32 | LE32(x5); + r1->d[0] = LE32((uint64_t) x6) << 32 | LE32(x7); + r2->d[3] = LE32((uint64_t) x8) << 32 | LE32(x9); + r2->d[2] = LE32((uint64_t) x10) << 32 | LE32(x11); + r2->d[1] = LE32((uint64_t) x12) << 32 | LE32(x13); + r2->d[0] = LE32((uint64_t) x14) << 32 | LE32(x15); + + over1 = secp256k1_scalar_check_overflow(r1); + over2 = secp256k1_scalar_check_overflow(r2); + over_count++; + } while (over1 | over2); +} + +#undef ROTL32 +#undef QUARTERROUND +#undef BE32 +#undef LE32 + #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index 4f9ed61fea..f99c741e40 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include + /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) #define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) @@ -718,4 +720,102 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); } +#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) +#define QUARTERROUND(a,b,c,d) \ + a += b; d = ROTL32(d ^ a, 16); \ + c += d; b = ROTL32(b ^ c, 12); \ + a += b; d = ROTL32(d ^ a, 8); \ + c += d; b = ROTL32(b ^ c, 7); + +#ifdef WORDS_BIGENDIAN +#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define BE32(p) (p) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define LE32(p) (p) +#endif + +static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx) { + size_t n; + size_t over_count = 0; + uint32_t seed32[8]; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int over1, over2; + + memcpy((void *) seed32, (const void *) seed, 32); + do { + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + x4 = LE32(seed32[0]); + x5 = LE32(seed32[1]); + x6 = LE32(seed32[2]); + x7 = LE32(seed32[3]); + x8 = LE32(seed32[4]); + x9 = LE32(seed32[5]); + x10 = LE32(seed32[6]); + x11 = LE32(seed32[7]); + x12 = idx; + x13 = idx >> 32; + x14 = 0; + x15 = over_count; + + n = 10; + while (n--) { + QUARTERROUND(x0, x4, x8,x12) + QUARTERROUND(x1, x5, x9,x13) + QUARTERROUND(x2, x6,x10,x14) + QUARTERROUND(x3, x7,x11,x15) + QUARTERROUND(x0, x5,x10,x15) + QUARTERROUND(x1, x6,x11,x12) + QUARTERROUND(x2, x7, x8,x13) + QUARTERROUND(x3, x4, x9,x14) + } + + x0 += 0x61707865; + x1 += 0x3320646e; + x2 += 0x79622d32; + x3 += 0x6b206574; + x4 += LE32(seed32[0]); + x5 += LE32(seed32[1]); + x6 += LE32(seed32[2]); + x7 += LE32(seed32[3]); + x8 += LE32(seed32[4]); + x9 += LE32(seed32[5]); + x10 += LE32(seed32[6]); + x11 += LE32(seed32[7]); + x12 += idx; + x13 += idx >> 32; + x14 += 0; + x15 += over_count; + + r1->d[7] = LE32(x0); + r1->d[6] = LE32(x1); + r1->d[5] = LE32(x2); + r1->d[4] = LE32(x3); + r1->d[3] = LE32(x4); + r1->d[2] = LE32(x5); + r1->d[1] = LE32(x6); + r1->d[0] = LE32(x7); + r2->d[7] = LE32(x8); + r2->d[6] = LE32(x9); + r2->d[5] = LE32(x10); + r2->d[4] = LE32(x11); + r2->d[3] = LE32(x12); + r2->d[2] = LE32(x13); + r2->d[1] = LE32(x14); + r2->d[0] = LE32(x15); + + over1 = secp256k1_scalar_check_overflow(r1); + over2 = secp256k1_scalar_check_overflow(r2); + over_count++; + } while (over1 | over2); +} + +#undef ROTL32 +#undef QUARTERROUND +#undef BE32 +#undef LE32 + #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index c80e70c5a2..88e52d8031 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -111,4 +111,9 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const return *a == *b; } +SECP256K1_INLINE static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t n) { + *r1 = (seed[0] + n) % EXHAUSTIVE_TEST_ORDER; + *r2 = (seed[1] + n) % EXHAUSTIVE_TEST_ORDER; +} + #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/tests.c b/src/tests.c index d408a5c30a..1322fd5dc4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1077,12 +1077,122 @@ void scalar_test(void) { } +void scalar_chacha_tests(void) { + /* Test vectors 1 to 4 from https://tools.ietf.org/html/rfc8439#appendix-A + * Note that scalar_set_b32 and scalar_get_b32 represent integers + * underlying the scalar in big-endian format. */ + unsigned char expected1[64] = { + 0xad, 0xe0, 0xb8, 0x76, 0x90, 0x3d, 0xf1, 0xa0, + 0xe5, 0x6a, 0x5d, 0x40, 0x28, 0xbd, 0x86, 0x53, + 0xb8, 0x19, 0xd2, 0xbd, 0x1a, 0xed, 0x8d, 0xa0, + 0xcc, 0xef, 0x36, 0xa8, 0xc7, 0x0d, 0x77, 0x8b, + 0x7c, 0x59, 0x41, 0xda, 0x8d, 0x48, 0x57, 0x51, + 0x3f, 0xe0, 0x24, 0x77, 0x37, 0x4a, 0xd8, 0xb8, + 0xf4, 0xb8, 0x43, 0x6a, 0x1c, 0xa1, 0x18, 0x15, + 0x69, 0xb6, 0x87, 0xc3, 0x86, 0x65, 0xee, 0xb2 + }; + unsigned char expected2[64] = { + 0xbe, 0xe7, 0x07, 0x9f, 0x7a, 0x38, 0x51, 0x55, + 0x7c, 0x97, 0xba, 0x98, 0x0d, 0x08, 0x2d, 0x73, + 0xa0, 0x29, 0x0f, 0xcb, 0x69, 0x65, 0xe3, 0x48, + 0x3e, 0x53, 0xc6, 0x12, 0xed, 0x7a, 0xee, 0x32, + 0x76, 0x21, 0xb7, 0x29, 0x43, 0x4e, 0xe6, 0x9c, + 0xb0, 0x33, 0x71, 0xd5, 0xd5, 0x39, 0xd8, 0x74, + 0x28, 0x1f, 0xed, 0x31, 0x45, 0xfb, 0x0a, 0x51, + 0x1f, 0x0a, 0xe1, 0xac, 0x6f, 0x4d, 0x79, 0x4b + }; + unsigned char seed3[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + unsigned char expected3[64] = { + 0x24, 0x52, 0xeb, 0x3a, 0x92, 0x49, 0xf8, 0xec, + 0x8d, 0x82, 0x9d, 0x9b, 0xdd, 0xd4, 0xce, 0xb1, + 0xe8, 0x25, 0x20, 0x83, 0x60, 0x81, 0x8b, 0x01, + 0xf3, 0x84, 0x22, 0xb8, 0x5a, 0xaa, 0x49, 0xc9, + 0xbb, 0x00, 0xca, 0x8e, 0xda, 0x3b, 0xa7, 0xb4, + 0xc4, 0xb5, 0x92, 0xd1, 0xfd, 0xf2, 0x73, 0x2f, + 0x44, 0x36, 0x27, 0x4e, 0x25, 0x61, 0xb3, 0xc8, + 0xeb, 0xdd, 0x4a, 0xa6, 0xa0, 0x13, 0x6c, 0x00 + }; + unsigned char seed4[32] = { + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned char expected4[64] = { + 0xfb, 0x4d, 0xd5, 0x72, 0x4b, 0xc4, 0x2e, 0xf1, + 0xdf, 0x92, 0x26, 0x36, 0x32, 0x7f, 0x13, 0x94, + 0xa7, 0x8d, 0xea, 0x8f, 0x5e, 0x26, 0x90, 0x39, + 0xa1, 0xbe, 0xbb, 0xc1, 0xca, 0xf0, 0x9a, 0xae, + 0xa2, 0x5a, 0xb2, 0x13, 0x48, 0xa6, 0xb4, 0x6c, + 0x1b, 0x9d, 0x9b, 0xcb, 0x09, 0x2c, 0x5b, 0xe6, + 0x54, 0x6c, 0xa6, 0x24, 0x1b, 0xec, 0x45, 0xd5, + 0x87, 0xf4, 0x74, 0x73, 0x96, 0xf0, 0x99, 0x2e + }; + unsigned char seed5[32] = { + 0x32, 0x56, 0x56, 0xf4, 0x29, 0x02, 0xc2, 0xf8, + 0xa3, 0x4b, 0x96, 0xf5, 0xa7, 0xf7, 0xe3, 0x6c, + 0x92, 0xad, 0xa5, 0x18, 0x1c, 0xe3, 0x41, 0xae, + 0xc3, 0xf3, 0x18, 0xd0, 0xfa, 0x5b, 0x72, 0x53 + }; + unsigned char expected5[64] = { + 0xe7, 0x56, 0xd3, 0x28, 0xe9, 0xc6, 0x19, 0x5c, + 0x6f, 0x17, 0x8e, 0x21, 0x8c, 0x1e, 0x72, 0x11, + 0xe7, 0xbd, 0x17, 0x0d, 0xac, 0x14, 0xad, 0xe9, + 0x3d, 0x9f, 0xb6, 0x92, 0xd6, 0x09, 0x20, 0xfb, + 0x43, 0x8e, 0x3b, 0x6d, 0xe3, 0x33, 0xdc, 0xc7, + 0x6c, 0x07, 0x6f, 0xbb, 0x1f, 0xb4, 0xc8, 0xb5, + 0xe3, 0x6c, 0xe5, 0x12, 0xd9, 0xd7, 0x64, 0x0c, + 0xf5, 0xa7, 0x0d, 0xab, 0x79, 0x03, 0xf1, 0x81 + }; + + secp256k1_scalar exp_r1, exp_r2; + secp256k1_scalar r1, r2; + unsigned char seed0[32] = { 0 }; + + secp256k1_scalar_chacha20(&r1, &r2, seed0, 0); + secp256k1_scalar_set_b32(&exp_r1, &expected1[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected1[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed0, 1); + secp256k1_scalar_set_b32(&exp_r1, &expected2[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected2[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed3, 1); + secp256k1_scalar_set_b32(&exp_r1, &expected3[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected3[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed4, 2); + secp256k1_scalar_set_b32(&exp_r1, &expected4[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected4[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed5, 0x6ff8602a7a78e2f2ULL); + secp256k1_scalar_set_b32(&exp_r1, &expected5[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected5[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); +} + void run_scalar_tests(void) { int i; for (i = 0; i < 128 * count; i++) { scalar_test(); } + scalar_chacha_tests(); + { /* (-1)+1 should be zero. */ secp256k1_scalar s, o; From 6bd94240b7c3b0fa79e4b7ffc41c2aadc7ccf058 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 9 May 2018 15:37:35 +0000 Subject: [PATCH 02/25] Add schnorrsig module which implements BIP-schnorr [0] compatible signing, verification and batch verification. [0] https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki --- .gitignore | 2 +- .travis.yml | 12 +- Makefile.am | 4 + configure.ac | 15 + include/secp256k1.h | 6 + include/secp256k1_schnorrsig.h | 126 ++++ src/bench_schnorrsig.c | 128 ++++ src/modules/schnorrsig/Makefile.am.include | 8 + src/modules/schnorrsig/main_impl.h | 332 ++++++++++ src/modules/schnorrsig/tests_impl.h | 721 +++++++++++++++++++++ src/scalar_4x64_impl.h | 19 +- src/scalar_8x32_impl.h | 35 +- src/secp256k1.c | 28 + src/tests.c | 9 + 14 files changed, 1408 insertions(+), 37 deletions(-) create mode 100644 include/secp256k1_schnorrsig.h create mode 100644 src/bench_schnorrsig.c create mode 100644 src/modules/schnorrsig/Makefile.am.include create mode 100644 src/modules/schnorrsig/main_impl.h create mode 100644 src/modules/schnorrsig/tests_impl.h diff --git a/.gitignore b/.gitignore index 55d325aeef..905be98730 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ bench_inv bench_ecdh bench_ecmult +bench_schnorrsig bench_sign bench_verify -bench_schnorr_verify bench_recover bench_internal tests diff --git a/.travis.yml b/.travis.yml index e11c5ced23..e6678b1b77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,20 +11,20 @@ cache: - src/java/guava/ env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no JNI=no SCHNORRSIG=no - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar matrix: - SCALAR=32bit RECOVERY=yes - - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - SCALAR=64bit - - FIELD=64bit RECOVERY=yes + - FIELD=64bit RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - FIELD=64bit ENDOMORPHISM=yes - - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC @@ -67,4 +67,4 @@ before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD diff --git a/Makefile.am b/Makefile.am index f420944e8f..87076d1345 100644 --- a/Makefile.am +++ b/Makefile.am @@ -178,6 +178,10 @@ if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include endif +if ENABLE_MODULE_SCHNORRSIG +include src/modules/schnorrsig/Makefile.am.include +endif + if ENABLE_MODULE_RECOVERY include src/modules/recovery/Makefile.am.include endif diff --git a/configure.ac b/configure.ac index 2a8db0a51c..1048a83852 100644 --- a/configure.ac +++ b/configure.ac @@ -129,6 +129,11 @@ AC_ARG_ENABLE(module_ecdh, [enable_module_ecdh=$enableval], [enable_module_ecdh=no]) +AC_ARG_ENABLE(module_schnorrsig, + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]), + [enable_module_schnorrsig=$enableval], + [enable_module_schnorrsig=no]) + AC_ARG_ENABLE(module_recovery, AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [enable_module_recovery=$enableval], @@ -512,6 +517,10 @@ if test x"$enable_module_ecdh" = x"yes"; then AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) fi +if test x"$enable_module_schnorrsig" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module]) +fi + if test x"$enable_module_recovery" = x"yes"; then AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) fi @@ -531,11 +540,15 @@ if test x"$enable_experimental" = x"yes"; then AC_MSG_NOTICE([WARNING: experimental build]) AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) + AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig]) AC_MSG_NOTICE([******]) else if test x"$enable_module_ecdh" = x"yes"; then AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) fi + if test x"$enable_module_schnorrsig" = x"yes"; then + AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.]) + fi if test x"$set_asm" = x"arm"; then AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) fi @@ -554,6 +567,7 @@ AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) AM_CONDITIONAL([USE_JNI], [test x"$use_jni" = x"yes"]) AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) @@ -576,6 +590,7 @@ echo " with benchmarks = $use_benchmark" echo " with coverage = $enable_coverage" echo " module ecdh = $enable_module_ecdh" echo " module recovery = $enable_module_recovery" +echo " module schnorrsig = $enable_module_schnorrsig" echo echo " asm = $set_asm" echo " bignum = $set_bignum" diff --git a/include/secp256k1.h b/include/secp256k1.h index fc27626dd8..10eaff1594 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -523,6 +523,12 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize( */ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; +/** An implementation of the nonce generation function as defined in BIP-schnorr. + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * extra entropy. + */ +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr; + /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h new file mode 100644 index 0000000000..77a9f0bc95 --- /dev/null +++ b/include/secp256k1_schnorrsig.h @@ -0,0 +1,126 @@ +#ifndef SECP256K1_SCHNORRSIG_H +#define SECP256K1_SCHNORRSIG_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This module implements a variant of Schnorr signatures compliant with + * BIP-schnorr + * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki). + */ + +/** Opaque data structure that holds a parsed Schnorr signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the `secp256k1_schnorrsig_serialize` and + * `secp256k1_schnorrsig_parse` functions. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_schnorrsig; + +/** Serialize a Schnorr signature. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: out64: pointer to a 64-byte array to store the serialized signature + * In: sig: pointer to the signature + * + * See secp256k1_schnorrsig_parse for details about the encoding. + */ +SECP256K1_API int secp256k1_schnorrsig_serialize( + const secp256k1_context* ctx, + unsigned char *out64, + const secp256k1_schnorrsig* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a Schnorr signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: pointer to a signature object + * In: in64: pointer to the 64-byte signature to be parsed + * + * The signature is serialized in the form R||s, where R is a 32-byte public + * key (x-coordinate only; the y-coordinate is considered to be the unique + * y-coordinate satisfying the curve equation that is a quadratic residue) + * and s is a 32-byte big-endian scalar. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_schnorrsig_parse( + const secp256k1_context* ctx, + secp256k1_schnorrsig* sig, + const unsigned char *in64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Create a Schnorr signature. + * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to the returned signature (cannot be NULL) + * In: msg32: the 32-byte message being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bipschnorr is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_schnorrsig_sign( + const secp256k1_context* ctx, + secp256k1_schnorrsig *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verify a Schnorr signature. + * + * Returns: 1: correct signature + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) + * msg32: the 32-byte message being verified (cannot be NULL) + * pubkey: pointer to a public key to verify with (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( + const secp256k1_context* ctx, + const secp256k1_schnorrsig *sig, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verifies a set of Schnorr signatures. + * + * Returns 1 if all succeeded, 0 otherwise. In particular, returns 1 if n_sigs is 0. + * + * Args: ctx: a secp256k1 context object, initialized for verification. + * scratch: scratch space used for the multiexponentiation + * In: sig: array of signatures, or NULL if there are no signatures + * msg32: array of messages, or NULL if there are no signatures + * pk: array of public keys, or NULL if there are no signatures + * n_sigs: number of signatures in above arrays. Must be smaller than + * 2^31 and smaller than half the maximum size_t value. Must be 0 + * if above arrays are NULL. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch( + const secp256k1_context* ctx, + secp256k1_scratch_space *scratch, + const secp256k1_schnorrsig *const *sig, + const unsigned char *const *msg32, + const secp256k1_pubkey *const *pk, + size_t n_sigs +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_SCHNORRSIG_H */ diff --git a/src/bench_schnorrsig.c b/src/bench_schnorrsig.c new file mode 100644 index 0000000000..b68adf5312 --- /dev/null +++ b/src/bench_schnorrsig.c @@ -0,0 +1,128 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorrsig.h" +#include "util.h" +#include "bench.h" + +#define MAX_SIGS (32768) + +typedef struct { + secp256k1_context *ctx; + secp256k1_scratch_space *scratch; + size_t n; + const unsigned char **pk; + const secp256k1_schnorrsig **sigs; + const unsigned char **msgs; +} bench_schnorrsig_data; + +void bench_schnorrsig_sign(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i; + unsigned char sk[32] = "benchmarkexample secrettemplate"; + unsigned char msg[32] = "benchmarkexamplemessagetemplate"; + secp256k1_schnorrsig sig; + + for (i = 0; i < 1000; i++) { + msg[0] = i; + msg[1] = i >> 8; + sk[0] = i; + sk[1] = i >> 8; + CHECK(secp256k1_schnorrsig_sign(data->ctx, &sig, msg, sk, NULL, NULL)); + } +} + +void bench_schnorrsig_verify(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i; + + for (i = 0; i < 1000; i++) { + secp256k1_pubkey pk; + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pk, data->pk[i], 33) == 1); + CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk)); + } +} + +void bench_schnorrsig_verify_n(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i, j; + const secp256k1_pubkey **pk = (const secp256k1_pubkey **)malloc(data->n * sizeof(*pk)); + + CHECK(pk != NULL); + for (j = 0; j < MAX_SIGS/data->n; j++) { + for (i = 0; i < data->n; i++) { + secp256k1_pubkey *pk_nonconst = (secp256k1_pubkey *)malloc(sizeof(*pk_nonconst)); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, pk_nonconst, data->pk[i], 33) == 1); + pk[i] = pk_nonconst; + } + CHECK(secp256k1_schnorrsig_verify_batch(data->ctx, data->scratch, data->sigs, data->msgs, pk, data->n)); + for (i = 0; i < data->n; i++) { + free((void *)pk[i]); + } + } + free(pk); +} + +int main(void) { + size_t i; + bench_schnorrsig_data data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); + data.scratch = secp256k1_scratch_space_create(data.ctx, 1024 * 1024 * 1024); + data.pk = (const unsigned char **)malloc(MAX_SIGS * sizeof(unsigned char *)); + data.msgs = (const unsigned char **)malloc(MAX_SIGS * sizeof(unsigned char *)); + data.sigs = (const secp256k1_schnorrsig **)malloc(MAX_SIGS * sizeof(secp256k1_schnorrsig *)); + + for (i = 0; i < MAX_SIGS; i++) { + unsigned char sk[32]; + unsigned char *msg = (unsigned char *)malloc(32); + secp256k1_schnorrsig *sig = (secp256k1_schnorrsig *)malloc(sizeof(*sig)); + unsigned char *pk_char = (unsigned char *)malloc(33); + secp256k1_pubkey pk; + size_t pk_len = 33; + msg[0] = sk[0] = i; + msg[1] = sk[1] = i >> 8; + msg[2] = sk[2] = i >> 16; + msg[3] = sk[3] = i >> 24; + memset(&msg[4], 'm', 28); + memset(&sk[4], 's', 28); + + data.pk[i] = pk_char; + data.msgs[i] = msg; + data.sigs[i] = sig; + + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pk, sk)); + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, pk_char, &pk_len, &pk, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, sk, NULL, NULL)); + } + + run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, 1000); + run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, 1000); + for (i = 1; i <= MAX_SIGS; i *= 2) { + char name[64]; + sprintf(name, "schnorrsig_batch_verify_%d", (int) i); + + data.n = i; + run_benchmark(name, bench_schnorrsig_verify_n, NULL, NULL, (void *) &data, 3, MAX_SIGS); + } + + for (i = 0; i < MAX_SIGS; i++) { + free((void *)data.pk[i]); + free((void *)data.msgs[i]); + free((void *)data.sigs[i]); + } + free(data.pk); + free(data.msgs); + free(data.sigs); + + secp256k1_scratch_space_destroy(data.ctx, data.scratch); + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/modules/schnorrsig/Makefile.am.include b/src/modules/schnorrsig/Makefile.am.include new file mode 100644 index 0000000000..a82bafe43f --- /dev/null +++ b/src/modules/schnorrsig/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_schnorrsig.h +noinst_HEADERS += src/modules/schnorrsig/main_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_schnorrsig +bench_schnorrsig_SOURCES = src/bench_schnorrsig.c +bench_schnorrsig_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h new file mode 100644 index 0000000000..739e98b0c3 --- /dev/null +++ b/src/modules/schnorrsig/main_impl.h @@ -0,0 +1,332 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_ +#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_ + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorrsig.h" +#include "hash.h" + +int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig) { + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out64 != NULL); + ARG_CHECK(sig != NULL); + memcpy(out64, sig->data, 64); + return 1; +} + +int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64) { + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in64 != NULL); + memcpy(sig->data, in64, 64); + return 1; +} + +int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) { + secp256k1_scalar x; + secp256k1_scalar e; + secp256k1_scalar k; + secp256k1_gej pkj; + secp256k1_gej rj; + secp256k1_ge pk; + secp256k1_ge r; + secp256k1_sha256 sha; + int overflow; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(seckey != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_bipschnorr; + } + secp256k1_scalar_set_b32(&x, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (overflow || secp256k1_scalar_is_zero(&x)) { + memset(sig, 0, sizeof(*sig)); + return 0; + } + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x); + secp256k1_ge_set_gej(&pk, &pkj); + + if (!noncefp(buf, msg32, seckey, NULL, (void*)ndata, 0)) { + return 0; + } + secp256k1_scalar_set_b32(&k, buf, NULL); + if (secp256k1_scalar_is_zero(&k)) { + return 0; + } + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); + secp256k1_ge_set_gej(&r, &rj); + + if (!secp256k1_fe_is_quad_var(&r.y)) { + secp256k1_scalar_negate(&k, &k); + } + secp256k1_fe_normalize(&r.x); + secp256k1_fe_get_b32(&sig->data[0], &r.x); + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &sig->data[0], 32); + secp256k1_eckey_pubkey_serialize(&pk, buf, &buflen, 1); + secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, buf); + + secp256k1_scalar_set_b32(&e, buf, NULL); + secp256k1_scalar_mul(&e, &e, &x); + secp256k1_scalar_add(&e, &e, &k); + + secp256k1_scalar_get_b32(&sig->data[32], &e); + secp256k1_scalar_clear(&k); + secp256k1_scalar_clear(&x); + + return 1; +} + +/* Helper function for verification and batch verification. + * Computes R = sG - eP. */ +static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp256k1_gej *rj, const secp256k1_scalar *s, const secp256k1_scalar *e, const secp256k1_pubkey *pk) { + secp256k1_scalar nege; + secp256k1_ge pkp; + secp256k1_gej pkj; + + secp256k1_scalar_negate(&nege, e); + + if (!secp256k1_pubkey_load(ctx, &pkp, pk)) { + return 0; + } + secp256k1_gej_set_ge(&pkj, &pkp); + + /* rj = s*G + (-e)*pkj */ + secp256k1_ecmult(&ctx->ecmult_ctx, rj, &pkj, &nege, s); + return 1; +} + +int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk) { + secp256k1_scalar s; + secp256k1_scalar e; + secp256k1_gej rj; + secp256k1_fe rx; + secp256k1_sha256 sha; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(pk != NULL); + + if (!secp256k1_fe_set_b32(&rx, &sig->data[0])) { + return 0; + } + + secp256k1_scalar_set_b32(&s, &sig->data[32], &overflow); + if (overflow) { + return 0; + } + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &sig->data[0], 32); + secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED); + secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, buf); + secp256k1_scalar_set_b32(&e, buf, NULL); + + if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pk) + || !secp256k1_gej_has_quad_y_var(&rj) /* fails if rj is infinity */ + || !secp256k1_gej_eq_x_var(&rx, &rj)) { + return 0; + } + + return 1; +} + +/* Data that is used by the batch verification ecmult callback */ +typedef struct { + const secp256k1_context *ctx; + /* Seed for the random number generator */ + unsigned char chacha_seed[32]; + /* Caches randomizers generated by the PRNG which returns two randomizers per call. Caching + * avoids having to call the PRNG twice as often. The very first randomizer will be set to 1 and + * the PRNG is called at every odd indexed schnorrsig to fill the cache. */ + secp256k1_scalar randomizer_cache[2]; + /* Signature, message, public key tuples to verify */ + const secp256k1_schnorrsig *const *sig; + const unsigned char *const *msg32; + const secp256k1_pubkey *const *pk; + size_t n_sigs; +} secp256k1_schnorrsig_verify_ecmult_context; + +/* Callback function which is called by ecmult_multi in order to convert the ecmult_context + * consisting of signature, message and public key tuples into scalars and points. */ +static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { + secp256k1_schnorrsig_verify_ecmult_context *ecmult_context = (secp256k1_schnorrsig_verify_ecmult_context *) data; + + if (idx % 4 == 2) { + /* Every idx corresponds to a (scalar,point)-tuple. So this callback is called with 4 + * consecutive tuples before we need to call the RNG for new randomizers: + * (-randomizer_cache[0], R1) + * (-randomizer_cache[0]*e1, P1) + * (-randomizer_cache[1], R2) + * (-randomizer_cache[1]*e2, P2) */ + secp256k1_scalar_chacha20(&ecmult_context->randomizer_cache[0], &ecmult_context->randomizer_cache[1], ecmult_context->chacha_seed, idx / 4); + } + + /* R */ + if (idx % 2 == 0) { + secp256k1_fe rx; + *sc = ecmult_context->randomizer_cache[(idx / 2) % 2]; + if (!secp256k1_fe_set_b32(&rx, &ecmult_context->sig[idx / 2]->data[0])) { + return 0; + } + if (!secp256k1_ge_set_xquad(pt, &rx)) { + return 0; + } + /* eP */ + } else { + unsigned char buf[33]; + size_t buflen = sizeof(buf); + secp256k1_sha256 sha; + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32); + secp256k1_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED); + secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_sha256_write(&sha, ecmult_context->msg32[idx / 2], 32); + secp256k1_sha256_finalize(&sha, buf); + + secp256k1_scalar_set_b32(sc, buf, NULL); + secp256k1_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]); + + if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, ecmult_context->pk[idx / 2])) { + return 0; + } + } + return 1; +} + +/** Helper function for batch verification. Hashes signature verification data into the + * randomization seed and initializes ecmult_context. + * + * Returns 1 if the randomizer was successfully initialized. + * + * Args: ctx: a secp256k1 context object + * Out: ecmult_context: context for batch_ecmult_callback + * In/Out sha: an initialized sha256 object which hashes the schnorrsig input in order to get a + * seed for the randomizer PRNG + * In: sig: array of signatures, or NULL if there are no signatures + * msg32: array of messages, or NULL if there are no signatures + * pk: array of public keys, or NULL if there are no signatures + * n_sigs: number of signatures in above arrays (must be 0 if they are NULL) + */ +static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { + size_t i; + + if (n_sigs > 0) { + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(pk != NULL); + } + + for (i = 0; i < n_sigs; i++) { + unsigned char buf[33]; + size_t buflen = sizeof(buf); + secp256k1_sha256_write(sha, sig[i]->data, 64); + secp256k1_sha256_write(sha, msg32[i], 32); + secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED); + secp256k1_sha256_write(sha, buf, buflen); + } + ecmult_context->ctx = ctx; + ecmult_context->sig = sig; + ecmult_context->msg32 = msg32; + ecmult_context->pk = pk; + ecmult_context->n_sigs = n_sigs; + + return 1; +} + +/** Helper function for batch verification. Sums the s part of all signatures multiplied by their + * randomizer. + * + * Returns 1 if s is successfully summed. + * + * In/Out: s: the s part of the input sigs is added to this s argument + * In: chacha_seed: PRNG seed for computing randomizers + * sig: array of signatures, or NULL if there are no signatures + * n_sigs: number of signatures in above array (must be 0 if they are NULL) + */ +static int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned char *chacha_seed, const secp256k1_schnorrsig *const *sig, size_t n_sigs) { + secp256k1_scalar randomizer_cache[2]; + size_t i; + + secp256k1_scalar_set_int(&randomizer_cache[0], 1); + for (i = 0; i < n_sigs; i++) { + int overflow; + secp256k1_scalar term; + if (i % 2 == 1) { + secp256k1_scalar_chacha20(&randomizer_cache[0], &randomizer_cache[1], chacha_seed, i / 2); + } + + secp256k1_scalar_set_b32(&term, &sig[i]->data[32], &overflow); + if (overflow) { + return 0; + } + secp256k1_scalar_mul(&term, &term, &randomizer_cache[i % 2]); + secp256k1_scalar_add(s, s, &term); + } + return 1; +} + +/* schnorrsig batch verification. + * Seeds a random number generator with the inputs and derives a random number ai for every + * signature i. Fails if y-coordinate of any R is not a quadratic residue or if + * 0 != -(s1 + a2*s2 + ... + au*su)G + R1 + a2*R2 + ... + au*Ru + e1*P1 + (a2*e2)P2 + ... + (au*eu)Pu. */ +int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_scratch *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { + secp256k1_schnorrsig_verify_ecmult_context ecmult_context; + secp256k1_sha256 sha; + secp256k1_scalar s; + secp256k1_gej rj; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(scratch != NULL); + /* Check that n_sigs is less than half of the maximum size_t value. This is necessary because + * the number of points given to ecmult_multi is 2*n_sigs. */ + ARG_CHECK(n_sigs <= SIZE_MAX / 2); + /* Check that n_sigs is less than 2^31 to ensure the same behavior of this function on 32-bit + * and 64-bit platforms. */ + ARG_CHECK(n_sigs < ((uint32_t)1 << 31)); + + secp256k1_sha256_initialize(&sha); + if (!secp256k1_schnorrsig_verify_batch_init_randomizer(ctx, &ecmult_context, &sha, sig, msg32, pk, n_sigs)) { + return 0; + } + secp256k1_sha256_finalize(&sha, ecmult_context.chacha_seed); + secp256k1_scalar_set_int(&ecmult_context.randomizer_cache[0], 1); + + secp256k1_scalar_clear(&s); + if (!secp256k1_schnorrsig_verify_batch_sum_s(&s, ecmult_context.chacha_seed, sig, n_sigs)) { + return 0; + } + secp256k1_scalar_negate(&s, &s); + + return secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs) + && secp256k1_gej_is_infinity(&rj); +} + +#endif diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h new file mode 100644 index 0000000000..2de43af1e3 --- /dev/null +++ b/src/modules/schnorrsig/tests_impl.h @@ -0,0 +1,721 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_ +#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_ + +#include "secp256k1_schnorrsig.h" + +void test_schnorrsig_serialize(void) { + secp256k1_schnorrsig sig; + unsigned char in[64]; + unsigned char out[64]; + + memset(in, 0x12, 64); + CHECK(secp256k1_schnorrsig_parse(ctx, &sig, in)); + CHECK(secp256k1_schnorrsig_serialize(ctx, out, &sig)); + CHECK(memcmp(in, out, 64) == 0); +} + +void test_schnorrsig_api(secp256k1_scratch_space *scratch) { + unsigned char sk1[32]; + unsigned char sk2[32]; + unsigned char sk3[32]; + unsigned char msg[32]; + unsigned char sig64[64]; + secp256k1_pubkey pk[3]; + secp256k1_schnorrsig sig; + const secp256k1_schnorrsig *sigptr = &sig; + const unsigned char *msgptr = msg; + const secp256k1_pubkey *pkptr = &pk[0]; + + /** setup **/ + 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); + int ecount; + + 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); + + secp256k1_rand256(sk1); + secp256k1_rand256(sk2); + secp256k1_rand256(sk3); + secp256k1_rand256(msg); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk1) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk[2], sk3) == 1); + + /** main test body **/ + ecount = 0; + CHECK(secp256k1_schnorrsig_sign(none, &sig, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_sign(vrfy, &sig, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_sign(sign, &sig, msg, sk1, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_sign(sign, &sig, NULL, sk1, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_schnorrsig_sign(sign, &sig, msg, NULL, NULL, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_schnorrsig_serialize(none, sig64, &sig) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_schnorrsig_serialize(none, NULL, &sig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_serialize(none, sig64, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_parse(none, &sig, sig64) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_parse(none, NULL, sig64) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_parse(none, &sig, NULL) == 0); + CHECK(ecount == 4); + + ecount = 0; + CHECK(secp256k1_schnorrsig_verify(none, &sig, msg, &pk[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_verify(sign, &sig, msg, &pk[0]) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, &pk[0]) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, NULL, &pk[0]) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_schnorrsig_verify_batch(none, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_verify_batch(sign, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, NULL, NULL, 0) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, NULL, &pkptr, 1) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, NULL, 1) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (size_t)1 << (sizeof(size_t)*8-1)) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (uint32_t)1 << 31) == 0); + CHECK(ecount == 7); + + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + +/* Helper function for schnorrsig_bip_vectors + * Signs the message and checks that it's the same as expected_sig. */ +void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *msg, const unsigned char *expected_sig) { + secp256k1_schnorrsig sig; + unsigned char serialized_sig[64]; + secp256k1_pubkey pk; + + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL)); + CHECK(secp256k1_schnorrsig_serialize(ctx, serialized_sig, &sig)); + CHECK(memcmp(serialized_sig, expected_sig, 64) == 0); + + CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &pk)); +} + +/* Helper function for schnorrsig_bip_vectors + * Checks that both verify and verify_batch return the same value as expected. */ +void test_schnorrsig_bip_vectors_check_verify(secp256k1_scratch_space *scratch, const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig_serialized, int expected) { + const unsigned char *msg_arr[1]; + const secp256k1_schnorrsig *sig_arr[1]; + const secp256k1_pubkey *pk_arr[1]; + secp256k1_pubkey pk; + secp256k1_schnorrsig sig; + + CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_schnorrsig_parse(ctx, &sig, sig_serialized)); + + sig_arr[0] = &sig; + msg_arr[0] = msg32; + pk_arr[0] = &pk; + + CHECK(expected == secp256k1_schnorrsig_verify(ctx, &sig, msg32, &pk)); + CHECK(expected == secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); +} + +/* Test vectors according to BIP-schnorr + * (https://github.com/sipa/bips/blob/7f6a73e53c8bbcf2d008ea0546f76433e22094a8/bip-schnorr/test-vectors.csv). + */ +void test_schnorrsig_bip_vectors(secp256k1_scratch_space *scratch) { + { + /* Test vector 1 */ + const unsigned char sk1[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + const unsigned char pk1[33] = { + 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, + 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, + 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98 + }; + const unsigned char msg1[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig1[64] = { + 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, + 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, + 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, + 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, + 0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3, + 0x4D, 0xFF, 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84, + 0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1, + 0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05 + }; + test_schnorrsig_bip_vectors_check_signing(sk1, pk1, msg1, sig1); + test_schnorrsig_bip_vectors_check_verify(scratch, pk1, msg1, sig1, 1); + } + { + /* Test vector 2 */ + const unsigned char sk2[32] = { + 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, + 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, + 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, + 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF + }; + const unsigned char pk2[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg2[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig2[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_signing(sk2, pk2, msg2, sig2); + test_schnorrsig_bip_vectors_check_verify(scratch, pk2, msg2, sig2, 1); + } + { + /* Test vector 3 */ + const unsigned char sk3[32] = { + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC7 + }; + const unsigned char pk3[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg3[32] = { + 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig3[64] = { + 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, + 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, + 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, + 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, + 0x00, 0x88, 0x03, 0x71, 0xD0, 0x17, 0x66, 0x93, + 0x5B, 0x92, 0xD2, 0xAB, 0x4C, 0xD5, 0xC8, 0xA2, + 0xA5, 0x83, 0x7E, 0xC5, 0x7F, 0xED, 0x76, 0x60, + 0x77, 0x3A, 0x05, 0xF0, 0xDE, 0x14, 0x23, 0x80 + }; + test_schnorrsig_bip_vectors_check_signing(sk3, pk3, msg3, sig3); + test_schnorrsig_bip_vectors_check_verify(scratch, pk3, msg3, sig3, 1); + } + { + /* Test vector 4 */ + const unsigned char pk4[33] = { + 0x03, 0xDE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, + 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, + 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, + 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, + 0x34 + }; + const unsigned char msg4[32] = { + 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, + 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, + 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, + 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 + }; + const unsigned char sig4[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, + 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, + 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, + 0x02, 0xA8, 0xDC, 0x32, 0xE6, 0x4E, 0x86, 0xA3, + 0x33, 0xF2, 0x0E, 0xF5, 0x6E, 0xAC, 0x9B, 0xA3, + 0x0B, 0x72, 0x46, 0xD6, 0xD2, 0x5E, 0x22, 0xAD, + 0xB8, 0xC6, 0xBE, 0x1A, 0xEB, 0x08, 0xD4, 0x9D + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk4, msg4, sig4, 1); + } + { + /* Test vector 5 */ + const unsigned char pk5[33] = { + 0x03, 0x1B, 0x84, 0xC5, 0x56, 0x7B, 0x12, 0x64, + 0x40, 0x99, 0x5D, 0x3E, 0xD5, 0xAA, 0xBA, 0x05, + 0x65, 0xD7, 0x1E, 0x18, 0x34, 0x60, 0x48, 0x19, + 0xFF, 0x9C, 0x17, 0xF5, 0xE9, 0xD5, 0xDD, 0x07, + 0x8F + }; + const unsigned char msg5[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig5[64] = { + 0x52, 0x81, 0x85, 0x79, 0xAC, 0xA5, 0x97, 0x67, + 0xE3, 0x29, 0x1D, 0x91, 0xB7, 0x6B, 0x63, 0x7B, + 0xEF, 0x06, 0x20, 0x83, 0x28, 0x49, 0x92, 0xF2, + 0xD9, 0x5F, 0x56, 0x4C, 0xA6, 0xCB, 0x4E, 0x35, + 0x30, 0xB1, 0xDA, 0x84, 0x9C, 0x8E, 0x83, 0x04, + 0xAD, 0xC0, 0xCF, 0xE8, 0x70, 0x66, 0x03, 0x34, + 0xB3, 0xCF, 0xC1, 0x8E, 0x82, 0x5E, 0xF1, 0xDB, + 0x34, 0xCF, 0xAE, 0x3D, 0xFC, 0x5D, 0x81, 0x87 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk5, msg5, sig5, 1); + } + { + /* Test vector 6 */ + const unsigned char pk6[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg6[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 + }; + const unsigned char sig6[64] = { + 0x57, 0x0D, 0xD4, 0xCA, 0x83, 0xD4, 0xE6, 0x31, + 0x7B, 0x8E, 0xE6, 0xBA, 0xE8, 0x34, 0x67, 0xA1, + 0xBF, 0x41, 0x9D, 0x07, 0x67, 0x12, 0x2D, 0xE4, + 0x09, 0x39, 0x44, 0x14, 0xB0, 0x50, 0x80, 0xDC, + 0xE9, 0xEE, 0x5F, 0x23, 0x7C, 0xBD, 0x10, 0x8E, + 0xAB, 0xAE, 0x1E, 0x37, 0x75, 0x9A, 0xE4, 0x7F, + 0x8E, 0x42, 0x03, 0xDA, 0x35, 0x32, 0xEB, 0x28, + 0xDB, 0x86, 0x0F, 0x33, 0xD6, 0x2D, 0x49, 0xBD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk6, msg6, sig6, 1); + } + { + /* Test vector 7 */ + const unsigned char pk7[33] = { + 0x03, 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, + 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, + 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, + 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, + 0x34 + }; + secp256k1_pubkey pk7_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_ec_pubkey_parse(ctx, &pk7_parsed, pk7, 33)); + } + { + /* Test vector 8 */ + const unsigned char pk8[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg8[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig8[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A, + 0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46, + 0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14, + 0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk8, msg8, sig8, 0); + } + { + /* Test vector 9 */ + const unsigned char pk9[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg9[32] = { + 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig9[64] = { + 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, + 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, + 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, + 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, + 0xD0, 0x92, 0xF9, 0xD8, 0x60, 0xF1, 0x77, 0x6A, + 0x1F, 0x74, 0x12, 0xAD, 0x8A, 0x1E, 0xB5, 0x0D, + 0xAC, 0xCC, 0x22, 0x2B, 0xC8, 0xC0, 0xE2, 0x6B, + 0x20, 0x56, 0xDF, 0x2F, 0x27, 0x3E, 0xFD, 0xEC + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk9, msg9, sig9, 0); + } + { + /* Test vector 10 */ + const unsigned char pk10[33] = { + 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, + 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, + 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98 + }; + const unsigned char msg10[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig10[64] = { + 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, + 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, + 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, + 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, + 0x8F, 0xCE, 0x56, 0x77, 0xCE, 0x7A, 0x62, 0x3C, + 0xB2, 0x00, 0x11, 0x22, 0x57, 0x97, 0xCE, 0x7A, + 0x8D, 0xE1, 0xDC, 0x6C, 0xCD, 0x4F, 0x75, 0x4A, + 0x47, 0xDA, 0x6C, 0x60, 0x0E, 0x59, 0x54, 0x3C + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk10, msg10, sig10, 0); + } + { + /* Test vector 11 */ + const unsigned char pk11[33] = { + 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg11[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig11[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk11, msg11, sig11, 0); + } + { + /* Test vector 12 */ + const unsigned char pk12[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg12[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig12[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9E, 0x9D, 0x01, 0xAF, 0x98, 0x8B, 0x5C, 0xED, + 0xCE, 0x47, 0x22, 0x1B, 0xFA, 0x9B, 0x22, 0x27, + 0x21, 0xF3, 0xFA, 0x40, 0x89, 0x15, 0x44, 0x4A, + 0x4B, 0x48, 0x90, 0x21, 0xDB, 0x55, 0x77, 0x5F + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk12, msg12, sig12, 0); + } + { + /* Test vector 13 */ + const unsigned char pk13[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg13[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig13[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xD3, 0x7D, 0xDF, 0x02, 0x54, 0x35, 0x18, 0x36, + 0xD8, 0x4B, 0x1B, 0xD6, 0xA7, 0x95, 0xFD, 0x5D, + 0x52, 0x30, 0x48, 0xF2, 0x98, 0xC4, 0x21, 0x4D, + 0x18, 0x7F, 0xE4, 0x89, 0x29, 0x47, 0xF7, 0x28 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk13, msg13, sig13, 0); + } + { + /* Test vector 14 */ + const unsigned char pk14[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg14[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x14, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig14[64] = { + 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk14, msg14, sig14, 0); + } + { + /* Test vector 15 */ + const unsigned char pk15[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg15[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig15[64] = { + 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, 0xFC, 0x2F, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk15, msg15, sig15, 0); + } + { + /* Test vector 16 */ + const unsigned char pk16[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg16[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig16[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk16, msg16, sig16, 0); + } +} + +/* Nonce function that returns constant 0 */ +static int nonce_function_failing(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; + (void) counter; + (void) nonce32; + return 0; +} + +/* Nonce function that sets nonce to 0 */ +static int nonce_function_0(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; + (void) counter; + + memset(nonce32, 0, 32); + return 1; +} + +void test_schnorrsig_sign(void) { + unsigned char sk[32]; + const unsigned char msg[32] = "this is a msg for a schnorrsig.."; + secp256k1_schnorrsig sig; + + memset(sk, 23, sizeof(sk)); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL) == 1); + + /* Overflowing secret key */ + memset(sk, 0xFF, sizeof(sk)); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL) == 0); + memset(sk, 23, sizeof(sk)); + + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, nonce_function_failing, NULL) == 0); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, nonce_function_0, NULL) == 0); +} + +#define N_SIGS 200 +/* Creates N_SIGS valid signatures and verifies them with verify and verify_batch. Then flips some + * bits and checks that verification now fails. */ +void test_schnorrsig_sign_verify(secp256k1_scratch_space *scratch) { + const unsigned char sk[32] = "shhhhhhhh! this key is a secret."; + unsigned char msg[N_SIGS][32]; + secp256k1_schnorrsig sig[N_SIGS]; + size_t i; + const secp256k1_schnorrsig *sig_arr[N_SIGS]; + const unsigned char *msg_arr[N_SIGS]; + const secp256k1_pubkey *pk_arr[N_SIGS]; + secp256k1_pubkey pk; + + CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk)); + + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, NULL, NULL, NULL, 0)); + + for (i = 0; i < N_SIGS; i++) { + secp256k1_rand256(msg[i]); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig[i], msg[i], sk, NULL, NULL)); + CHECK(secp256k1_schnorrsig_verify(ctx, &sig[i], msg[i], &pk)); + sig_arr[i] = &sig[i]; + msg_arr[i] = msg[i]; + pk_arr[i] = &pk; + } + + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 2)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, N_SIGS)); + + { + /* Flip a few bits in the signature and in the message and check that + * verify and verify_batch fail */ + size_t sig_idx = secp256k1_rand_int(4); + size_t byte_idx = secp256k1_rand_int(32); + unsigned char xorbyte = secp256k1_rand_int(254)+1; + sig[sig_idx].data[byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + sig[sig_idx].data[byte_idx] ^= xorbyte; + + byte_idx = secp256k1_rand_int(32); + sig[sig_idx].data[32+byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + sig[sig_idx].data[32+byte_idx] ^= xorbyte; + + byte_idx = secp256k1_rand_int(32); + msg[sig_idx][byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + msg[sig_idx][byte_idx] ^= xorbyte; + + /* Check that above bitflips have been reversed correctly */ + CHECK(secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + } +} +#undef N_SIGS + +void run_schnorrsig_tests(void) { + secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024); + + test_schnorrsig_serialize(); + test_schnorrsig_api(scratch); + test_schnorrsig_bip_vectors(scratch); + test_schnorrsig_sign(); + test_schnorrsig_sign_verify(scratch); + + secp256k1_scratch_space_destroy(ctx, scratch); +} + +#endif diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 1000d9a962..268cc68d60 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -958,9 +958,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, #ifdef WORDS_BIGENDIAN #define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) -#define BE32(p) (p) #else -#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) #define LE32(p) (p) #endif @@ -1019,14 +1017,14 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2 x14 += 0; x15 += over_count; - r1->d[3] = LE32((uint64_t) x0) << 32 | LE32(x1); - r1->d[2] = LE32((uint64_t) x2) << 32 | LE32(x3); - r1->d[1] = LE32((uint64_t) x4) << 32 | LE32(x5); - r1->d[0] = LE32((uint64_t) x6) << 32 | LE32(x7); - r2->d[3] = LE32((uint64_t) x8) << 32 | LE32(x9); - r2->d[2] = LE32((uint64_t) x10) << 32 | LE32(x11); - r2->d[1] = LE32((uint64_t) x12) << 32 | LE32(x13); - r2->d[0] = LE32((uint64_t) x14) << 32 | LE32(x15); + r1->d[3] = (((uint64_t) x0) << 32) | x1; + r1->d[2] = (((uint64_t) x2) << 32) | x3; + r1->d[1] = (((uint64_t) x4) << 32) | x5; + r1->d[0] = (((uint64_t) x6) << 32) | x7; + r2->d[3] = (((uint64_t) x8) << 32) | x9; + r2->d[2] = (((uint64_t) x10) << 32) | x11; + r2->d[1] = (((uint64_t) x12) << 32) | x13; + r2->d[0] = (((uint64_t) x14) << 32) | x15; over1 = secp256k1_scalar_check_overflow(r1); over2 = secp256k1_scalar_check_overflow(r2); @@ -1036,7 +1034,6 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2 #undef ROTL32 #undef QUARTERROUND -#undef BE32 #undef LE32 #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index f99c741e40..a9a934c43c 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -729,9 +729,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, #ifdef WORDS_BIGENDIAN #define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) -#define BE32(p) (p) #else -#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) #define LE32(p) (p) #endif @@ -790,22 +788,22 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2 x14 += 0; x15 += over_count; - r1->d[7] = LE32(x0); - r1->d[6] = LE32(x1); - r1->d[5] = LE32(x2); - r1->d[4] = LE32(x3); - r1->d[3] = LE32(x4); - r1->d[2] = LE32(x5); - r1->d[1] = LE32(x6); - r1->d[0] = LE32(x7); - r2->d[7] = LE32(x8); - r2->d[6] = LE32(x9); - r2->d[5] = LE32(x10); - r2->d[4] = LE32(x11); - r2->d[3] = LE32(x12); - r2->d[2] = LE32(x13); - r2->d[1] = LE32(x14); - r2->d[0] = LE32(x15); + r1->d[7] = x0; + r1->d[6] = x1; + r1->d[5] = x2; + r1->d[4] = x3; + r1->d[3] = x4; + r1->d[2] = x5; + r1->d[1] = x6; + r1->d[0] = x7; + r2->d[7] = x8; + r2->d[6] = x9; + r2->d[5] = x10; + r2->d[4] = x11; + r2->d[3] = x12; + r2->d[2] = x13; + r2->d[1] = x14; + r2->d[0] = x15; over1 = secp256k1_scalar_check_overflow(r1); over2 = secp256k1_scalar_check_overflow(r2); @@ -815,7 +813,6 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2 #undef ROTL32 #undef QUARTERROUND -#undef BE32 #undef LE32 #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1.c b/src/secp256k1.c index a3f446e507..38c2b0d69e 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -413,6 +413,29 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off *offset += len; } +/* This nonce function is described in BIP-schnorr + * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */ +static int nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + secp256k1_sha256 sha; + (void) counter; + VERIFY_CHECK(counter == 0); + + /* Hash x||msg as per the spec */ + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, key32, 32); + secp256k1_sha256_write(&sha, msg32, 32); + /* Hash in algorithm, which is not in the spec, but may be critical to + * users depending on it to avoid nonce reuse across algorithms. */ + if (algo16 != NULL) { + secp256k1_sha256_write(&sha, algo16, 16); + } + if (data != NULL) { + secp256k1_sha256_write(&sha, data, 32); + } + secp256k1_sha256_finalize(&sha, nonce32); + return 1; +} + static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { unsigned char keydata[112]; unsigned int offset = 0; @@ -443,6 +466,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m return 1; } +const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr = nonce_function_bipschnorr; const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; @@ -685,6 +709,10 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * # include "modules/ecdh/main_impl.h" #endif +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/main_impl.h" #endif diff --git a/src/tests.c b/src/tests.c index 1322fd5dc4..a823e674c8 100644 --- a/src/tests.c +++ b/src/tests.c @@ -5272,6 +5272,10 @@ void run_ecdsa_openssl(void) { # include "modules/ecdh/tests_impl.h" #endif +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/tests_impl.h" +#endif + #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/tests_impl.h" #endif @@ -5385,6 +5389,11 @@ int main(int argc, char **argv) { run_ecdh_tests(); #endif +#ifdef ENABLE_MODULE_SCHNORRSIG + /* Schnorrsig tests */ + run_schnorrsig_tests(); +#endif + /* ecdsa tests */ run_random_pubkeys(); run_ecdsa_der_parse(); From 639a8599ec97121970566c3a1f9e6fb763471c83 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 29 Aug 2019 12:07:02 +0000 Subject: [PATCH 03/25] f use tagged hashes in nonce derivation and signature hash --- src/hash_impl.h | 14 ++++++++ src/modules/schnorrsig/main_impl.h | 25 +++++++++++--- src/modules/schnorrsig/tests_impl.h | 16 ++++++++- src/secp256k1.c | 38 +++++++++++++++++---- src/tests.c | 51 +++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 12 deletions(-) diff --git a/src/hash_impl.h b/src/hash_impl.h index 782f97216c..552eff356b 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -163,6 +163,20 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out memcpy(out32, (const unsigned char*)out, 32); } +/* Initializes a sha256 struct and writes the 64 byte string + * SHA256(tag)||SHA256(tag) into it. The taglen should be less than or equal to + * 64. */ +static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { + unsigned char buf[32]; + secp256k1_sha256_initialize(hash); + secp256k1_sha256_write(hash, tag, taglen); + secp256k1_sha256_finalize(hash, buf); + + secp256k1_sha256_initialize(hash); + secp256k1_sha256_write(hash, buf, 32); + secp256k1_sha256_write(hash, buf, 32); +} + static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { size_t n; unsigned char rkey[64]; diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 739e98b0c3..86e9f50297 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -29,6 +29,21 @@ int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsi return 1; } +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIPSchnorr")||SHA256("BIPSchnorr"). */ +static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x048d9a59ul; + sha->s[1] = 0xfe39fb05ul; + sha->s[2] = 0x28479648ul; + sha->s[3] = 0xe4a660f9ul; + sha->s[4] = 0x814b9e66ul; + sha->s[5] = 0x0469e801ul; + sha->s[6] = 0x83909280ul; + sha->s[7] = 0xb329e454ul; + sha->bytes = 64; +} + int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) { secp256k1_scalar x; secp256k1_scalar e; @@ -61,7 +76,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x); secp256k1_ge_set_gej(&pk, &pkj); - if (!noncefp(buf, msg32, seckey, NULL, (void*)ndata, 0)) { + if (!noncefp(buf, msg32, seckey, (unsigned char *) "BIPSchnorrDerive", (void*)ndata, 0)) { return 0; } secp256k1_scalar_set_b32(&k, buf, NULL); @@ -78,7 +93,9 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_fe_normalize(&r.x); secp256k1_fe_get_b32(&sig->data[0], &r.x); - secp256k1_sha256_initialize(&sha); + + /* tagged hash(r.x, pk, msg32) */ + secp256k1_schnorrsig_sha256_tagged(&sha); secp256k1_sha256_write(&sha, &sig->data[0], 32); secp256k1_eckey_pubkey_serialize(&pk, buf, &buflen, 1); secp256k1_sha256_write(&sha, buf, buflen); @@ -140,7 +157,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_sc return 0; } - secp256k1_sha256_initialize(&sha); + secp256k1_schnorrsig_sha256_tagged(&sha); secp256k1_sha256_write(&sha, &sig->data[0], 32); secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED); secp256k1_sha256_write(&sha, buf, buflen); @@ -203,7 +220,7 @@ static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *s unsigned char buf[33]; size_t buflen = sizeof(buf); secp256k1_sha256 sha; - secp256k1_sha256_initialize(&sha); + secp256k1_schnorrsig_sha256_tagged(&sha); secp256k1_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32); secp256k1_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED); secp256k1_sha256_write(&sha, buf, buflen); diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 2de43af1e3..dc128cb9b2 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -125,6 +125,18 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) { secp256k1_context_destroy(both); } +/* Checks that hash initialized by secp256k1_musig_sha256_tagged has the + * expected state. */ +void test_schnorrsig_sha256_tagged(void) { + char tag[10] = "BIPSchnorr"; + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + + secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); + secp256k1_schnorrsig_sha256_tagged(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); +} + /* Helper function for schnorrsig_bip_vectors * Signs the message and checks that it's the same as expected_sig. */ void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *msg, const unsigned char *expected_sig) { @@ -711,7 +723,9 @@ void run_schnorrsig_tests(void) { test_schnorrsig_serialize(); test_schnorrsig_api(scratch); - test_schnorrsig_bip_vectors(scratch); + test_schnorrsig_sha256_tagged(); + /* Don't fix test vectors until later */ + /* test_schnorrsig_bip_vectors(scratch); */ test_schnorrsig_sign(); test_schnorrsig_sign_verify(scratch); diff --git a/src/secp256k1.c b/src/secp256k1.c index 38c2b0d69e..6254a4cf52 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -413,6 +413,21 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off *offset += len; } +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIPSchnorrDerive")||SHA256("BIPSchnorrDerive"). */ +static void secp256k1_nonce_function_bipschnorr_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x1cd78ec3ul; + sha->s[1] = 0xc4425f87ul; + sha->s[2] = 0xb4f1a9f1ul; + sha->s[3] = 0xa16abd8dul; + sha->s[4] = 0x5a6dea72ul; + sha->s[5] = 0xd28469e3ul; + sha->s[6] = 0x17119b2eul; + sha->s[7] = 0x7bd19a16ul; + sha->bytes = 64; +} + /* This nonce function is described in BIP-schnorr * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */ static int nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { @@ -420,15 +435,24 @@ static int nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char (void) counter; VERIFY_CHECK(counter == 0); - /* Hash x||msg as per the spec */ - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, key32, 32); - secp256k1_sha256_write(&sha, msg32, 32); - /* Hash in algorithm, which is not in the spec, but may be critical to - * users depending on it to avoid nonce reuse across algorithms. */ + /* Tag the hash with algo16 which is important to avoid nonce reuse across + * algorithms. If the this nonce function is used in BIP-schnorr signing as + * defined in the spec, an optimized tagging implementation is used. */ if (algo16 != NULL) { - secp256k1_sha256_write(&sha, algo16, 16); + if (memcmp(algo16, "BIPSchnorrDerive", 16) == 0) { + secp256k1_nonce_function_bipschnorr_sha256_tagged(&sha); + } else { + secp256k1_sha256_initialize_tagged(&sha, algo16, 16); + } + } else { + /* If algo16 is NULL use a 14-bytes tag to rule out collisions with any + * non-NULL algo16 */ + secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) "BIPSchnorrNULL", 14); } + + /* Hash x||msg using the tagged hash as per the spec */ + secp256k1_sha256_write(&sha, key32, 32); + secp256k1_sha256_write(&sha, msg32, 32); if (data != NULL) { secp256k1_sha256_write(&sha, data, 32); } diff --git a/src/tests.c b/src/tests.c index a823e674c8..f05f39c2a7 100644 --- a/src/tests.c +++ b/src/tests.c @@ -443,6 +443,56 @@ void run_sha256_tests(void) { } } +/* Tests for the equality of two sha256 structs. This function only produces a + * correct result if an integer multiple of 64 many bytes have been written + * into the hash functions. */ +void test_sha256_eq(secp256k1_sha256 *sha1, secp256k1_sha256 *sha2) { + unsigned char buf[32] = { 0 }; + unsigned char buf2[32]; + + /* Is buffer fully consumed? */ + CHECK((sha1->bytes & 0x3F) == 0); + + /* Compare the struct excluding the the buffer, because it may be + * uninitialized or already included in the state. */ + CHECK(sha1->bytes == sha2->bytes); + CHECK(memcmp(sha1->s, sha2->s, sizeof(sha1->s)) == 0); + + /* Compare the output */ + secp256k1_sha256_write(sha1, buf, 32); + secp256k1_sha256_write(sha2, buf, 32); + secp256k1_sha256_finalize(sha1, buf); + secp256k1_sha256_finalize(sha2, buf2); + CHECK(memcmp(buf, buf2, 32) == 0); +} + +void run_nonce_function_bipschnorr_tests(void) { + char tag[16] = "BIPSchnorrDerive"; + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + unsigned char nonces[3][32]; + unsigned char msg[32]; + unsigned char key[32]; + + /* Check that hash initialized by + * secp256k1_nonce_function_bipschnorr_sha256_tagged has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); + secp256k1_nonce_function_bipschnorr_sha256_tagged(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that different choices of the algo16 argument result in different + * hashes. */ + memset(msg, 0, sizeof(msg)); + memset(key, 1, sizeof(key)); + CHECK(nonce_function_bipschnorr(nonces[0], msg, key, (unsigned char *) "BIPSchnorrDerive", NULL, 0)); + CHECK(nonce_function_bipschnorr(nonces[1], msg, key, NULL, NULL, 0)); + CHECK(memcmp(nonces[1], nonces[0], sizeof(nonces[1])) != 0); + CHECK(nonce_function_bipschnorr(nonces[2], msg, key, (unsigned char *) "something16chars", NULL, 0)); + CHECK(memcmp(nonces[2], nonces[0], sizeof(nonces[2])) != 0); + CHECK(memcmp(nonces[2], nonces[1], sizeof(nonces[2])) != 0); +} + void run_hmac_sha256_tests(void) { static const char *keys[6] = { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", @@ -5389,6 +5439,7 @@ int main(int argc, char **argv) { run_ecdh_tests(); #endif + run_nonce_function_bipschnorr_tests(); #ifdef ENABLE_MODULE_SCHNORRSIG /* Schnorrsig tests */ run_schnorrsig_tests(); From 2e76c5dc6d6ff4e30aac481820648ae95353abcf Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 29 Aug 2019 12:21:09 +0000 Subject: [PATCH 04/25] f don't allow counter != 0 in nonce function --- include/secp256k1.h | 3 ++- src/secp256k1.c | 5 +++-- src/tests.c | 4 ++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 10eaff1594..d11552a7bb 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -525,7 +525,8 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc /** An implementation of the nonce generation function as defined in BIP-schnorr. * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of - * extra entropy. + * extra entropy. The attempt argument must be 0 or the function will fail and + * return 0. */ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr; diff --git a/src/secp256k1.c b/src/secp256k1.c index 6254a4cf52..bb418f43bf 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -432,9 +432,10 @@ static void secp256k1_nonce_function_bipschnorr_sha256_tagged(secp256k1_sha256 * * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */ static int nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { secp256k1_sha256 sha; - (void) counter; - VERIFY_CHECK(counter == 0); + if (counter != 0) { + return 0; + } /* Tag the hash with algo16 which is important to avoid nonce reuse across * algorithms. If the this nonce function is used in BIP-schnorr signing as * defined in the spec, an optimized tagging implementation is used. */ diff --git a/src/tests.c b/src/tests.c index f05f39c2a7..68a93ea53e 100644 --- a/src/tests.c +++ b/src/tests.c @@ -491,6 +491,10 @@ void run_nonce_function_bipschnorr_tests(void) { CHECK(nonce_function_bipschnorr(nonces[2], msg, key, (unsigned char *) "something16chars", NULL, 0)); CHECK(memcmp(nonces[2], nonces[0], sizeof(nonces[2])) != 0); CHECK(memcmp(nonces[2], nonces[1], sizeof(nonces[2])) != 0); + + /* Check that counter != 0 makes nonce function fail. */ + CHECK(nonce_function_bipschnorr(nonces[0], msg, key, NULL, NULL, 0) == 1); + CHECK(nonce_function_bipschnorr(nonces[0], msg, key, NULL, NULL, 1) == 0); } void run_hmac_sha256_tests(void) { From 7eeb3aa49832015a8aa8caf17a008d263f373fc0 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 27 Aug 2019 14:05:14 +0000 Subject: [PATCH 05/25] f add xonly pubkey struct which is serialized as 32 byte and whose Y coordinate is a quadratic residue --- include/secp256k1.h | 68 +++++++++++++++++++++++++++++++++ src/secp256k1.c | 55 +++++++++++++++++++++++++++ src/tests.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/include/secp256k1.h b/include/secp256k1.h index d11552a7bb..ab394036f7 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -708,6 +708,74 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( size_t n ) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Opaque data structure that holds a parsed and valid "x-only" public key. + * An x-only pubkey encodes a positive point. That is a point whose Y + * coordinate is a quadratic residue. It is serialized using only its X + * coordinate (32 bytes). A secp256k1_xonly_pubkey is also a secp256k1_pubkey + * but the inverse is not true. Therefore, a secp256k1_pubkey must never be + * interpreted as or copied into a secp256k1_xonly_pubkey. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_xonly_pubkey_serialize and + * secp256k1_xonly_pubkey_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_xonly_pubkey; + +/** Parse a 32-byte public key into a xonly_pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * + * Args: ctx: a secp256k1 context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * In: input32: pointer to a serialized xonly public key + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse( + const secp256k1_context* ctx, + secp256k1_xonly_pubkey* pubkey, + const unsigned char *input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a xonly pubkey object into a byte sequence. + * + * Returns: 1 always. + * + * Args: ctx: a secp256k1 context object. + * Out: output32: a pointer to a 32-byte byte array to place the + * serialized key in. + * In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an + * initialized public key. + */ +SECP256K1_API int secp256k1_xonly_pubkey_serialize( + const secp256k1_context* ctx, + unsigned char *output32, + const secp256k1_xonly_pubkey* pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compute the xonly public key for a secret key. Just as ec_pubkey_create this + * function computes the point P by multiplying the seckey (interpreted as a scalar) + * with the generator. The public key corresponds to P if the Y coordinate of P is a + * quadratic residue or -P otherwise. + * + * Returns: 1 if secret was valid, public key stores + * 0 if secret was invalid, try again + * + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: pubkey: pointer to the created xonly public key (cannot be NULL) + * In: seckey: pointer to a 32-byte private key (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_create( + const secp256k1_context* ctx, + secp256k1_xonly_pubkey *pubkey, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + #ifdef __cplusplus } #endif diff --git a/src/secp256k1.c b/src/secp256k1.c index bb418f43bf..41cb7498e3 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -730,6 +730,61 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * return 1; } +/* Converts a point into its absolute value, i.e. keeps it as is if it is + * positive and otherwise negates it. */ +static void secp256k1_ec_pubkey_absolute(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { + secp256k1_ge ge; + secp256k1_pubkey_load(ctx, &ge, pubkey); + if (!secp256k1_fe_is_quad_var(&ge.y)) { + secp256k1_ge_neg(&ge, &ge); + } + secp256k1_pubkey_save(pubkey, &ge); +} + +int secp256k1_xonly_pubkey_create(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *seckey) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(seckey != NULL); + + if (!secp256k1_ec_pubkey_create(ctx, (secp256k1_pubkey *) pubkey, seckey)) { + return 0; + } + secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) pubkey); + return 1; +} + +int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey* pubkey, const unsigned char *input32) { + /* TODO parse directly from 32 byte buffer */ + unsigned char buf[33]; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(input32 != NULL); + + buf[0] = SECP256K1_TAG_PUBKEY_EVEN; + memcpy(&buf[1], input32, 32); + if (!secp256k1_ec_pubkey_parse(ctx, (secp256k1_pubkey *) pubkey, buf, sizeof(buf))) { + return 0; + } + secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) pubkey); + return 1; +} + +int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey* pubkey) { + /* TODO serialize directly into 32 byte buffer */ + unsigned char buf[33]; + size_t outputlen = sizeof(buf); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(output32 != NULL); + + if (!secp256k1_ec_pubkey_serialize(ctx, buf, &outputlen, (secp256k1_pubkey *) pubkey, SECP256K1_EC_COMPRESSED)) { + return 0; + } + memcpy(output32, &buf[1], 32); + return 1; +} + #ifdef ENABLE_MODULE_ECDH # include "modules/ecdh/main_impl.h" #endif diff --git a/src/tests.c b/src/tests.c index 68a93ea53e..801ea798ad 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4268,6 +4268,93 @@ void run_eckey_edge_case_test(void) { secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } +void test_xonly_pubkey(void) { + unsigned char sk[32] = { 0 }; + unsigned char garbage[32]; + secp256k1_pubkey signed_pk; + secp256k1_xonly_pubkey xonly_pk; + secp256k1_xonly_pubkey xonly_pk_tmp; + secp256k1_ge pk1; + secp256k1_ge pk2; + secp256k1_fe y; + unsigned char buf32[32]; + + /* sk = 0 should fail */ + CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 0); + + /* Check that X coordinate of normal pubkey and x-only pubkey matches + * and that due to choice of secret key the Y coordinates are each others + * additive inverse. */ + sk[0] = 6; + CHECK(secp256k1_ec_pubkey_create(ctx, &signed_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 1); + secp256k1_pubkey_load(ctx, &pk1, &signed_pk); + secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk); + CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1); + secp256k1_fe_negate(&y, &pk2.y, 1); + CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); + + /* Serialization and parse roundtrip */ + CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1); + CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); + + /* Can't parse a byte string that's not a valid X coordinate */ + memset(garbage, 0, sizeof(garbage)); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, garbage) == 0); +} + +void test_xonly_pubkey_api(void) { + secp256k1_xonly_pubkey pk; + unsigned char sk[32]; + unsigned char buf32[32]; + + /** setup **/ + 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); + int ecount; + + 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_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_rand256(sk); + ecount = 0; + CHECK(secp256k1_xonly_pubkey_create(none, &pk, sk) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_pubkey_create(sign, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_create(vrfy, &pk, sk) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_xonly_pubkey_create(sign, NULL, sk) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_xonly_pubkey_create(sign, &pk, NULL) == 0); + CHECK(ecount == 4); + + ecount = 0; + CHECK(secp256k1_xonly_pubkey_create(sign, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &pk) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0); + CHECK(ecount == 2); + + ecount = 0; + CHECK(secp256k1_xonly_pubkey_parse(none, &pk, buf32) == 1); + CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_pubkey_parse(none, &pk, NULL) == 0); + CHECK(ecount == 2); + + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); +} + void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { secp256k1_scalar nonce; do { @@ -5438,6 +5525,10 @@ int main(int argc, char **argv) { /* EC key edge cases */ run_eckey_edge_case_test(); + /* Positive key test cases */ + test_xonly_pubkey(); + test_xonly_pubkey_api(); + #ifdef ENABLE_MODULE_ECDH /* ecdh tests */ run_ecdh_tests(); From add8e78542e29c3aab0d462425a4988689cdb331 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Mon, 9 Sep 2019 19:55:56 +0000 Subject: [PATCH 06/25] f use xonly_pubkeys in schnorrsig sign and verify --- include/secp256k1_schnorrsig.h | 8 ++--- src/bench_schnorrsig.c | 19 +++++------ src/modules/schnorrsig/main_impl.h | 52 +++++++++++++++++------------ src/modules/schnorrsig/tests_impl.h | 30 ++++++++--------- 4 files changed, 58 insertions(+), 51 deletions(-) diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h index 77a9f0bc95..01ad74f1bf 100644 --- a/include/secp256k1_schnorrsig.h +++ b/include/secp256k1_schnorrsig.h @@ -88,13 +88,13 @@ SECP256K1_API int secp256k1_schnorrsig_sign( * Args: ctx: a secp256k1 context object, initialized for verification. * In: sig: the signature being verified (cannot be NULL) * msg32: the 32-byte message being verified (cannot be NULL) - * pubkey: pointer to a public key to verify with (cannot be NULL) + * pubkey: pointer to an x-only public key to verify with (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, - const secp256k1_pubkey *pubkey + const secp256k1_xonly_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Verifies a set of Schnorr signatures. @@ -105,7 +105,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( * scratch: scratch space used for the multiexponentiation * In: sig: array of signatures, or NULL if there are no signatures * msg32: array of messages, or NULL if there are no signatures - * pk: array of public keys, or NULL if there are no signatures + * pk: array of x-only public keys, or NULL if there are no signatures * n_sigs: number of signatures in above arrays. Must be smaller than * 2^31 and smaller than half the maximum size_t value. Must be 0 * if above arrays are NULL. @@ -115,7 +115,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch secp256k1_scratch_space *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, - const secp256k1_pubkey *const *pk, + const secp256k1_xonly_pubkey *const *pk, size_t n_sigs ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); diff --git a/src/bench_schnorrsig.c b/src/bench_schnorrsig.c index b68adf5312..b36499f851 100644 --- a/src/bench_schnorrsig.c +++ b/src/bench_schnorrsig.c @@ -44,8 +44,8 @@ void bench_schnorrsig_verify(void* arg) { size_t i; for (i = 0; i < 1000; i++) { - secp256k1_pubkey pk; - CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pk, data->pk[i], 33) == 1); + secp256k1_xonly_pubkey pk; + CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1); CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk)); } } @@ -53,13 +53,13 @@ void bench_schnorrsig_verify(void* arg) { void bench_schnorrsig_verify_n(void* arg) { bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; size_t i, j; - const secp256k1_pubkey **pk = (const secp256k1_pubkey **)malloc(data->n * sizeof(*pk)); + const secp256k1_xonly_pubkey **pk = (const secp256k1_xonly_pubkey **)malloc(data->n * sizeof(*pk)); CHECK(pk != NULL); for (j = 0; j < MAX_SIGS/data->n; j++) { for (i = 0; i < data->n; i++) { - secp256k1_pubkey *pk_nonconst = (secp256k1_pubkey *)malloc(sizeof(*pk_nonconst)); - CHECK(secp256k1_ec_pubkey_parse(data->ctx, pk_nonconst, data->pk[i], 33) == 1); + secp256k1_xonly_pubkey *pk_nonconst = (secp256k1_xonly_pubkey *)malloc(sizeof(*pk_nonconst)); + CHECK(secp256k1_xonly_pubkey_parse(data->ctx, pk_nonconst, data->pk[i]) == 1); pk[i] = pk_nonconst; } CHECK(secp256k1_schnorrsig_verify_batch(data->ctx, data->scratch, data->sigs, data->msgs, pk, data->n)); @@ -84,9 +84,8 @@ int main(void) { unsigned char sk[32]; unsigned char *msg = (unsigned char *)malloc(32); secp256k1_schnorrsig *sig = (secp256k1_schnorrsig *)malloc(sizeof(*sig)); - unsigned char *pk_char = (unsigned char *)malloc(33); - secp256k1_pubkey pk; - size_t pk_len = 33; + unsigned char *pk_char = (unsigned char *)malloc(32); + secp256k1_xonly_pubkey pk; msg[0] = sk[0] = i; msg[1] = sk[1] = i >> 8; msg[2] = sk[2] = i >> 16; @@ -98,8 +97,8 @@ int main(void) { data.msgs[i] = msg; data.sigs[i] = sig; - CHECK(secp256k1_ec_pubkey_create(data.ctx, &pk, sk)); - CHECK(secp256k1_ec_pubkey_serialize(data.ctx, pk_char, &pk_len, &pk, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_xonly_pubkey_create(data.ctx, &pk, sk)); + CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1); CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, sk, NULL, NULL)); } diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 86e9f50297..cd97f33cfc 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -54,8 +54,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_ge r; secp256k1_sha256 sha; int overflow; - unsigned char buf[33]; - size_t buflen = sizeof(buf); + unsigned char buf[32]; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); @@ -76,6 +75,13 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x); secp256k1_ge_set_gej(&pk, &pkj); + /* Because we are signing for a x-only pubkey, the secret key is negated + * before signing if the point corresponding to the secret key is not + * positive. */ + if (!secp256k1_fe_is_quad_var(&pk.y)) { + secp256k1_scalar_negate(&x, &x); + } + if (!noncefp(buf, msg32, seckey, (unsigned char *) "BIPSchnorrDerive", (void*)ndata, 0)) { return 0; } @@ -93,12 +99,12 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_fe_normalize(&r.x); secp256k1_fe_get_b32(&sig->data[0], &r.x); - - /* tagged hash(r.x, pk, msg32) */ + /* tagged hash(r.x, pk.x, msg32) */ secp256k1_schnorrsig_sha256_tagged(&sha); secp256k1_sha256_write(&sha, &sig->data[0], 32); - secp256k1_eckey_pubkey_serialize(&pk, buf, &buflen, 1); - secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_fe_normalize(&pk.x); + secp256k1_fe_get_b32(buf, &pk.x); + secp256k1_sha256_write(&sha, buf, sizeof(buf)); secp256k1_sha256_write(&sha, msg32, 32); secp256k1_sha256_finalize(&sha, buf); @@ -115,14 +121,14 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig /* Helper function for verification and batch verification. * Computes R = sG - eP. */ -static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp256k1_gej *rj, const secp256k1_scalar *s, const secp256k1_scalar *e, const secp256k1_pubkey *pk) { +static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp256k1_gej *rj, const secp256k1_scalar *s, const secp256k1_scalar *e, const secp256k1_xonly_pubkey *pk) { secp256k1_scalar nege; secp256k1_ge pkp; secp256k1_gej pkj; secp256k1_scalar_negate(&nege, e); - if (!secp256k1_pubkey_load(ctx, &pkp, pk)) { + if (!secp256k1_pubkey_load(ctx, &pkp, (secp256k1_pubkey *) pk)) { return 0; } secp256k1_gej_set_ge(&pkj, &pkp); @@ -132,14 +138,13 @@ static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp25 return 1; } -int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk) { +int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_xonly_pubkey *pk) { secp256k1_scalar s; secp256k1_scalar e; secp256k1_gej rj; secp256k1_fe rx; secp256k1_sha256 sha; - unsigned char buf[33]; - size_t buflen = sizeof(buf); + unsigned char buf[32]; int overflow; VERIFY_CHECK(ctx != NULL); @@ -159,8 +164,8 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_sc secp256k1_schnorrsig_sha256_tagged(&sha); secp256k1_sha256_write(&sha, &sig->data[0], 32); - secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED); - secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_xonly_pubkey_serialize(ctx, buf, pk); + secp256k1_sha256_write(&sha, buf, sizeof(buf)); secp256k1_sha256_write(&sha, msg32, 32); secp256k1_sha256_finalize(&sha, buf); secp256k1_scalar_set_b32(&e, buf, NULL); @@ -186,7 +191,7 @@ typedef struct { /* Signature, message, public key tuples to verify */ const secp256k1_schnorrsig *const *sig; const unsigned char *const *msg32; - const secp256k1_pubkey *const *pk; + const secp256k1_xonly_pubkey *const *pk; size_t n_sigs; } secp256k1_schnorrsig_verify_ecmult_context; @@ -217,20 +222,19 @@ static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *s } /* eP */ } else { - unsigned char buf[33]; - size_t buflen = sizeof(buf); + unsigned char buf[32]; secp256k1_sha256 sha; secp256k1_schnorrsig_sha256_tagged(&sha); secp256k1_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32); - secp256k1_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED); - secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_xonly_pubkey_serialize(ecmult_context->ctx, buf, ecmult_context->pk[idx / 2]); + secp256k1_sha256_write(&sha, buf, sizeof(buf)); secp256k1_sha256_write(&sha, ecmult_context->msg32[idx / 2], 32); secp256k1_sha256_finalize(&sha, buf); secp256k1_scalar_set_b32(sc, buf, NULL); secp256k1_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]); - if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, ecmult_context->pk[idx / 2])) { + if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, (secp256k1_pubkey *) ecmult_context->pk[idx / 2])) { return 0; } } @@ -251,7 +255,7 @@ static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *s * pk: array of public keys, or NULL if there are no signatures * n_sigs: number of signatures in above arrays (must be 0 if they are NULL) */ -static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { +static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_xonly_pubkey *const *pk, size_t n_sigs) { size_t i; if (n_sigs > 0) { @@ -265,7 +269,11 @@ static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_con size_t buflen = sizeof(buf); secp256k1_sha256_write(sha, sig[i]->data, 64); secp256k1_sha256_write(sha, msg32[i], 32); - secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED); + /* We use compressed serialization here. If we would use + * xonly_pubkey serialization and a user would wrongly memcpy + * normal secp256k1_pubkeys into xonly_pubkeys then the randomizer + * would be the same for two different pubkeys. */ + secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, (secp256k1_pubkey *) pk[i], SECP256K1_EC_COMPRESSED); secp256k1_sha256_write(sha, buf, buflen); } ecmult_context->ctx = ctx; @@ -313,7 +321,7 @@ static int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned * Seeds a random number generator with the inputs and derives a random number ai for every * signature i. Fails if y-coordinate of any R is not a quadratic residue or if * 0 != -(s1 + a2*s2 + ... + au*su)G + R1 + a2*R2 + ... + au*Ru + e1*P1 + (a2*e2)P2 + ... + (au*eu)Pu. */ -int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_scratch *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { +int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_scratch *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_xonly_pubkey *const *pk, size_t n_sigs) { secp256k1_schnorrsig_verify_ecmult_context ecmult_context; secp256k1_sha256 sha; secp256k1_scalar s; diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index dc128cb9b2..d2b077c039 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -26,11 +26,11 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) { unsigned char sk3[32]; unsigned char msg[32]; unsigned char sig64[64]; - secp256k1_pubkey pk[3]; + secp256k1_xonly_pubkey pk[3]; secp256k1_schnorrsig sig; const secp256k1_schnorrsig *sigptr = &sig; const unsigned char *msgptr = msg; - const secp256k1_pubkey *pkptr = &pk[0]; + const secp256k1_xonly_pubkey *pkptr = &pk[0]; /** setup **/ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); @@ -52,9 +52,9 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) { secp256k1_rand256(sk2); secp256k1_rand256(sk3); secp256k1_rand256(msg); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk1) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk2) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[2], sk3) == 1); + CHECK(secp256k1_xonly_pubkey_create(ctx, &pk[0], sk1) == 1); + CHECK(secp256k1_xonly_pubkey_create(ctx, &pk[1], sk2) == 1); + CHECK(secp256k1_xonly_pubkey_create(ctx, &pk[2], sk3) == 1); /** main test body **/ ecount = 0; @@ -142,13 +142,13 @@ void test_schnorrsig_sha256_tagged(void) { void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *msg, const unsigned char *expected_sig) { secp256k1_schnorrsig sig; unsigned char serialized_sig[64]; - secp256k1_pubkey pk; + secp256k1_xonly_pubkey pk; CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL)); CHECK(secp256k1_schnorrsig_serialize(ctx, serialized_sig, &sig)); CHECK(memcmp(serialized_sig, expected_sig, 64) == 0); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized)); CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &pk)); } @@ -157,11 +157,11 @@ void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const un void test_schnorrsig_bip_vectors_check_verify(secp256k1_scratch_space *scratch, const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig_serialized, int expected) { const unsigned char *msg_arr[1]; const secp256k1_schnorrsig *sig_arr[1]; - const secp256k1_pubkey *pk_arr[1]; - secp256k1_pubkey pk; + const secp256k1_xonly_pubkey *pk_arr[1]; + secp256k1_xonly_pubkey pk; secp256k1_schnorrsig sig; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized)); CHECK(secp256k1_schnorrsig_parse(ctx, &sig, sig_serialized)); sig_arr[0] = &sig; @@ -368,9 +368,9 @@ void test_schnorrsig_bip_vectors(secp256k1_scratch_space *scratch) { 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34 }; - secp256k1_pubkey pk7_parsed; + secp256k1_xonly_pubkey pk7_parsed; /* No need to check the signature of the test vector as parsing the pubkey already fails */ - CHECK(!secp256k1_ec_pubkey_parse(ctx, &pk7_parsed, pk7, 33)); + CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk7_parsed, pk7)); } { /* Test vector 8 */ @@ -667,10 +667,10 @@ void test_schnorrsig_sign_verify(secp256k1_scratch_space *scratch) { size_t i; const secp256k1_schnorrsig *sig_arr[N_SIGS]; const unsigned char *msg_arr[N_SIGS]; - const secp256k1_pubkey *pk_arr[N_SIGS]; - secp256k1_pubkey pk; + const secp256k1_xonly_pubkey *pk_arr[N_SIGS]; + secp256k1_xonly_pubkey pk; - CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk)); + CHECK(secp256k1_xonly_pubkey_create(ctx, &pk, sk)); CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, NULL, NULL, NULL, 0)); From 2e4ed392e1fd8cb7c64787bde9b67ddc0b463e3d Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Mon, 9 Sep 2019 19:56:11 +0000 Subject: [PATCH 07/25] f add tweak functions for xonly_pubkeys --- include/secp256k1.h | 114 ++++++++++++++++++++++ src/modules/schnorrsig/tests_impl.h | 38 ++++++++ src/secp256k1.c | 87 +++++++++++++++-- src/tests.c | 145 +++++++++++++++++++++++++++- 4 files changed, 374 insertions(+), 10 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index ab394036f7..288ff1c5a9 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -776,6 +776,120 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_create( const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey. This + * function optionally outputs a sign bit that can be used to convert + * the secp256k1_xonly_pubkey back into the same secp256k1_pubkey. + * The sign bit is 0 if the input pubkey encodes a positive point (has a Y + * coordinate that is a quadratic residue), otherwise it is 1. + * + * Returns: 1 if the public key was successfully converted + * 0 otherwise + * + * Args: ctx: pointer to a context object + * Out: xonly_pubkey: pointer to an x-only public key object for placing the + * converted public key (cannot be NULL) + * sign: sign bit of the pubkey. Can be used to reconstruct a + * public key from x-only public key (can be NULL) + * In: pubkey: pointer to a public key that is converted (cannot be + * NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( + const secp256k1_context* ctx, + secp256k1_xonly_pubkey *xonly_pubkey, + int *sign, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Convert a secp256k1_xonly_pubkey into a secp256k1_pubkey. If this + * function is used to invert secp256k1_xonly_pubkey_from_pubkey, the + * sign bit must be set to the output of that function. If the sign bit + * is 0 the output pubkey encodes a positive point (has a Y coordinate that is a + * quadratic residue), otherwise it is negative. + * + * Returns: 1 if the public key was successfully converted + * 0 otherwise + * + * Args: ctx: pointer to a context object + * Out: pubkey: pointer to a public key object for placing the + * converted public key (cannot be NULL) + * In: xonly_pubkey: pointer to an x-only public key that is converted + * (cannot be NULL) + * sign: sign bit of the resulting public key (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_to_pubkey( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const secp256k1_xonly_pubkey *xonly_pubkey, + int sign +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak the private key of an x-only pubkey by adding a tweak to it. The public + * key of the resulting private key will be the same as the output of + * secp256k1_xonly_pubkey_tweak_add called with the same tweak and corresponding + * input public key. + * + * If the public key corresponds to a positive point, tweak32 is added to the + * seckey (modulo the group order). If the public key corresponds to a + * negative point, tweak32 is added to the negation of the seckey (modulo the + * group order). + * + * Returns: 1 if the tweak was successfully added to seckey + * 0 if the tweak was out of range or the resulting private key would be + * invalid (only when the tweak is the complement of the private key) or + * seckey is 0. + * + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * In/Out: seckey: pointer to a 32-byte private key + * In: tweak32: pointer to a 32-byte tweak + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_privkey_tweak_add( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak an x-only public key by adding tweak times the generator to it. Note that + * the output is a secp256k1_pubkey and not a secp256k1_xonly_pubkey. + * Returns: 1 if tweak times the generator was successfully added to pubkey + * 0 if the tweak was out of range or the resulting public key would be + * invalid (only when the tweak is the complement of the corresponding + * private key). + * + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL) + * Out: output_pubkey: pointer to a public key object (cannot be NULL) + * In: internal_pubkey: pointer to an x-only public key object to apply the + * tweak to (cannot be NULL) + * tweak32: pointer to a 32-byte tweak (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( + const secp256k1_context* ctx, + secp256k1_pubkey *output_pubkey, + const secp256k1_xonly_pubkey *internal_pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verifies that output_pubkey is the result of calling + * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32. + * + * Returns: 1 if output_pubkey is the result of tweaking the internal_pubkey with + * tweak32 + * 0 otherwise + * + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL) + * In: output_pubkey: pointer to a public key object (cannot be NULL) + * internal_pubkey: pointer to an x-only public key object to apply the + * tweak to (cannot be NULL) + * tweak32: pointer to a 32-byte tweak (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_verify( + const secp256k1_context* ctx, + const secp256k1_pubkey *output_pubkey, + const secp256k1_xonly_pubkey *internal_pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + #ifdef __cplusplus } #endif diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index d2b077c039..49ddb50b84 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -718,6 +718,43 @@ void test_schnorrsig_sign_verify(secp256k1_scratch_space *scratch) { } #undef N_SIGS +void test_schnorrsig_taproot(void) { + unsigned char sk[32]; + secp256k1_xonly_pubkey internal_pk; + unsigned char internal_pk_bytes[32]; + secp256k1_pubkey output_pk; + secp256k1_xonly_pubkey output_pk_pos; + unsigned char output_pk_bytes[32]; + unsigned char tweak[32]; + int sign; + unsigned char msg[32]; + secp256k1_schnorrsig sig; + + /* Create output key */ + secp256k1_rand256(sk); + CHECK(secp256k1_xonly_pubkey_create(ctx, &internal_pk, sk) == 1); + memset(tweak, 1, sizeof(tweak)); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_pk_pos, &sign, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk_pos) == 1); + + /* Key spend */ + secp256k1_rand256(msg); + CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, tweak) == 1); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL) == 1); + /* Verify key spend */ + CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk_pos, output_pk_bytes) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &output_pk_pos) == 1); + + /* Script spend */ + CHECK(secp256k1_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1); + /* Verify script spend */ + CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk_pos, output_pk_bytes) == 1); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(ctx, &output_pk, &output_pk_pos, sign) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, tweak) == 1); +} + void run_schnorrsig_tests(void) { secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024); @@ -728,6 +765,7 @@ void run_schnorrsig_tests(void) { /* test_schnorrsig_bip_vectors(scratch); */ test_schnorrsig_sign(); test_schnorrsig_sign_verify(scratch); + test_schnorrsig_taproot(); secp256k1_scratch_space_destroy(ctx, scratch); } diff --git a/src/secp256k1.c b/src/secp256k1.c index 41cb7498e3..0da4644c9e 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -730,13 +730,20 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * return 1; } -/* Converts a point into its absolute value, i.e. keeps it as is if it is - * positive and otherwise negates it. */ -static void secp256k1_ec_pubkey_absolute(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { - secp256k1_ge ge; +/* Converts the point encoded by a secp256k1_pubkey into its absolute value, + * i.e. keeps it as is if it is positive and otherwise negates it. Sign is set + * to 1 if the input point was negative and set to 0 otherwise. */ +static void secp256k1_ec_pubkey_absolute(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, int *sign) { + secp256k1_ge ge; secp256k1_pubkey_load(ctx, &ge, pubkey); + if (sign != NULL) { + *sign = 0; + } if (!secp256k1_fe_is_quad_var(&ge.y)) { secp256k1_ge_neg(&ge, &ge); + if (sign != NULL) { + *sign = 1; + } } secp256k1_pubkey_save(pubkey, &ge); } @@ -750,7 +757,7 @@ int secp256k1_xonly_pubkey_create(const secp256k1_context* ctx, secp256k1_xonly_ if (!secp256k1_ec_pubkey_create(ctx, (secp256k1_pubkey *) pubkey, seckey)) { return 0; } - secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) pubkey); + secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) pubkey, NULL); return 1; } @@ -766,7 +773,7 @@ int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_p if (!secp256k1_ec_pubkey_parse(ctx, (secp256k1_pubkey *) pubkey, buf, sizeof(buf))) { return 0; } - secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) pubkey); + secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) pubkey, NULL); return 1; } @@ -785,6 +792,74 @@ int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char return 1; } +int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *sign, const secp256k1_pubkey *pubkey) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(xonly_pubkey != NULL); + ARG_CHECK(pubkey != NULL); + + *xonly_pubkey = *(secp256k1_xonly_pubkey *) pubkey; + + secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) xonly_pubkey, sign); + return 1; +} + +int secp256k1_xonly_pubkey_to_pubkey(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_xonly_pubkey *xonly_pubkey, int sign) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(xonly_pubkey != NULL); + + *pubkey = *(secp256k1_pubkey *) xonly_pubkey; + if (sign) { + return secp256k1_ec_pubkey_negate(ctx, pubkey); + } + return 1; +} + +int secp256k1_xonly_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey32, const unsigned char *tweak32) { + secp256k1_ge ge; + secp256k1_pubkey pubkey; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey32 != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, seckey32)) { + return 0; + } + secp256k1_pubkey_load(ctx, &ge, &pubkey); + if (!secp256k1_fe_is_quad_var(&ge.y)) { + if (!secp256k1_ec_privkey_negate(ctx, seckey32)) { + return 0; + } + } + + return secp256k1_ec_privkey_tweak_add(ctx, seckey32, tweak32); +} + +int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(output_pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + *output_pubkey = *(secp256k1_pubkey *)internal_pubkey; + return secp256k1_ec_pubkey_tweak_add(ctx, output_pubkey, tweak32); +} + +int secp256k1_xonly_pubkey_tweak_verify(const secp256k1_context* ctx, const secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_pubkey pk_expected; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(output_pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_xonly_pubkey_tweak_add(ctx, &pk_expected, internal_pubkey, tweak32)) { + return 0; + } + return memcmp(&pk_expected, output_pubkey, sizeof(pk_expected)) == 0; +} + #ifdef ENABLE_MODULE_ECDH # include "modules/ecdh/main_impl.h" #endif diff --git a/src/tests.c b/src/tests.c index 801ea798ad..1d2c8280a3 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4271,12 +4271,14 @@ void run_eckey_edge_case_test(void) { void test_xonly_pubkey(void) { unsigned char sk[32] = { 0 }; unsigned char garbage[32]; - secp256k1_pubkey signed_pk; + secp256k1_pubkey xy_pk; + secp256k1_pubkey xy_pk_tmp; secp256k1_xonly_pubkey xonly_pk; secp256k1_xonly_pubkey xonly_pk_tmp; secp256k1_ge pk1; secp256k1_ge pk2; secp256k1_fe y; + int sign; unsigned char buf32[32]; /* sk = 0 should fail */ @@ -4286,14 +4288,21 @@ void test_xonly_pubkey(void) { * and that due to choice of secret key the Y coordinates are each others * additive inverse. */ sk[0] = 6; - CHECK(secp256k1_ec_pubkey_create(ctx, &signed_pk, sk) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &xy_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 1); - secp256k1_pubkey_load(ctx, &pk1, &signed_pk); + secp256k1_pubkey_load(ctx, &pk1, &xy_pk); secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk); CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1); secp256k1_fe_negate(&y, &pk2.y, 1); CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); + /* Check from_pubkey and to_pubkey */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk_tmp, &sign, &xy_pk) == 1); + CHECK(memcmp(&xonly_pk_tmp, &xonly_pk, sizeof(xonly_pk)) == 0); + CHECK(sign == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(ctx, &xy_pk_tmp, &xonly_pk, sign) == 1); + CHECK(memcmp(&xy_pk_tmp, &xy_pk, sizeof(xy_pk)) == 0); + /* Serialization and parse roundtrip */ CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); @@ -4307,8 +4316,11 @@ void test_xonly_pubkey(void) { void test_xonly_pubkey_api(void) { secp256k1_xonly_pubkey pk; + secp256k1_pubkey xy_pk; unsigned char sk[32]; unsigned char buf32[32]; + unsigned char tweak[32]; + int pk_sign; /** setup **/ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); @@ -4324,6 +4336,8 @@ void test_xonly_pubkey_api(void) { secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); secp256k1_rand256(sk); + secp256k1_rand256(tweak); + ecount = 0; CHECK(secp256k1_xonly_pubkey_create(none, &pk, sk) == 0); CHECK(ecount == 1); @@ -4350,11 +4364,132 @@ void test_xonly_pubkey_api(void) { CHECK(secp256k1_xonly_pubkey_parse(none, &pk, NULL) == 0); CHECK(ecount == 2); + ecount = 0; + CHECK(secp256k1_xonly_privkey_tweak_add(none, sk, tweak) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_privkey_tweak_add(sign, sk, tweak) == 1); + CHECK(secp256k1_xonly_privkey_tweak_add(vrfy, sk, tweak) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_xonly_privkey_tweak_add(sign, NULL, tweak) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_xonly_privkey_tweak_add(sign, sk, NULL) == 0); + CHECK(ecount == 4); + + ecount = 0; + CHECK(secp256k1_xonly_pubkey_tweak_add(none, &xy_pk, &pk, tweak) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &xy_pk, &pk, tweak) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, NULL, &pk, tweak) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, NULL, tweak) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, &pk, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(none, &xy_pk, &pk, tweak) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(sign, &xy_pk, &pk, tweak) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &xy_pk, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, NULL, &pk, tweak) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &xy_pk, NULL, tweak) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &xy_pk, &pk, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_sign, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &pk, &pk_sign, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(vrfy, &pk, &pk_sign, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_sign, &xy_pk) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, NULL, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_sign, NULL) == 0); + CHECK(ecount == 2); + + ecount = 0; + CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, &pk, pk_sign) == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(sign, &xy_pk, &pk, pk_sign) == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(vrfy, &xy_pk, &pk, pk_sign) == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(none, NULL, &pk, pk_sign) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, NULL, pk_sign) == 0); + CHECK(ecount == 2); + secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(vrfy); } +void test_xonly_pubkey_tweak(void) { + unsigned char zeros[32]; + unsigned char overflows[32]; + unsigned char sk[32]; + secp256k1_xonly_pubkey internal_pk; + secp256k1_pubkey output_pk; + unsigned char tweak[32]; + + memset(zeros, 0, sizeof(zeros)); + memset(overflows, 0xff, sizeof(zeros)); + secp256k1_rand256(sk); + CHECK(secp256k1_xonly_pubkey_create(ctx, &internal_pk, sk) == 1); + + memset(tweak, 1, sizeof(tweak)); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, tweak) == 1); + /* Using privkey_tweak_add gives the same result */ + CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, tweak) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, tweak) == 1); + + /* Wrong public key */ + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, (secp256k1_pubkey*) &internal_pk, &internal_pk, tweak) == 0); + + /* Overflowing tweak not allowed */ + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, overflows) == 0); + CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_pk, overflows) == 0); +} + +/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 + * additional pubkeys by calling tweak_add. Then after the pubkeys are + * serialized and parsed, every tweak is verified. */ +#define N_PUBKEYS 32 +void test_xonly_pubkey_tweak_recursive(void) { + unsigned char sk[32]; + secp256k1_xonly_pubkey xonly_pk[N_PUBKEYS]; + unsigned char pk_bytes[N_PUBKEYS][32]; + secp256k1_pubkey xy_pk[N_PUBKEYS - 1]; + unsigned char tweak[N_PUBKEYS - 1][32]; + int sign[N_PUBKEYS]; + int i; + + secp256k1_rand256(sk); + CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk[0], sk) == 1); + /* Add tweaks */ + for (i = 0; i < N_PUBKEYS - 1; i++) { + memset(tweak[i], i + 1, sizeof(tweak[i])); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &xy_pk[i], &xonly_pk[i], tweak[i]) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_bytes[i], &xonly_pk[i]) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk[i + 1], &sign[i + 1], &xy_pk[i]) == 1); + } + CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_bytes[N_PUBKEYS - 1], &xonly_pk[N_PUBKEYS - 1]) == 1); + + /* Verify tweaks */ + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk[N_PUBKEYS - 1], pk_bytes[N_PUBKEYS - 1]) == 1); + for (i = N_PUBKEYS - 2; i >= 0; i--) { + CHECK(secp256k1_xonly_pubkey_to_pubkey(ctx, &xy_pk[i], &xonly_pk[i + 1], sign[i + 1]) == 1); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk[i], pk_bytes[i]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &xy_pk[i], &xonly_pk[i], tweak[i]) == 1); + } +} +#undef N_PUBKEYS + void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { secp256k1_scalar nonce; do { @@ -5525,9 +5660,11 @@ int main(int argc, char **argv) { /* EC key edge cases */ run_eckey_edge_case_test(); - /* Positive key test cases */ + /* xonly key test cases */ test_xonly_pubkey(); test_xonly_pubkey_api(); + test_xonly_pubkey_tweak(); + test_xonly_pubkey_tweak_recursive(); #ifdef ENABLE_MODULE_ECDH /* ecdh tests */ From 84fe42737d9f915a53e3e682ebd11021e24bfd52 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 24 Oct 2019 20:35:10 +0000 Subject: [PATCH 08/25] f address some of pieter's comments --- include/secp256k1.h | 29 +++++++++++++++-------------- include/secp256k1_schnorrsig.h | 15 +++++++-------- src/hash_impl.h | 3 +-- src/modules/schnorrsig/main_impl.h | 4 ++++ 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 288ff1c5a9..36119df5f8 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -447,7 +447,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( /** Verify an ECDSA signature. * * Returns: 1: correct signature - * 0: incorrect or unparseable signature + * 0: incorrect signature * Args: ctx: a secp256k1 context object, initialized for verification. * In: sig: the signature being verified (cannot be NULL) * msg32: the 32-byte message hash being verified (cannot be NULL) @@ -524,9 +524,14 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize( SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; /** An implementation of the nonce generation function as defined in BIP-schnorr. + * * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of - * extra entropy. The attempt argument must be 0 or the function will fail and - * return 0. + * extra entropy. If the data pointer is NULL and this function is used in + * schnorrsig_sign, it produces BIP-schnorr compliant signatures. + * When this function is used in ecdsa_sign, it generates a nonce using an + * analogue of the bip-schnorr nonce generation algorithm, but with tag + * "BIPSchnorrNULL" instead of "BIPSchnorrDerive". + * The attempt argument must be 0 or the function will fail and return 0. */ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr; @@ -710,10 +715,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( /** Opaque data structure that holds a parsed and valid "x-only" public key. * An x-only pubkey encodes a positive point. That is a point whose Y - * coordinate is a quadratic residue. It is serialized using only its X - * coordinate (32 bytes). A secp256k1_xonly_pubkey is also a secp256k1_pubkey - * but the inverse is not true. Therefore, a secp256k1_pubkey must never be - * interpreted as or copied into a secp256k1_xonly_pubkey. + * coordinate is square. It is serialized using only its X coordinate (32 + * bytes). * * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is @@ -758,10 +761,8 @@ SECP256K1_API int secp256k1_xonly_pubkey_serialize( const secp256k1_xonly_pubkey* pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Compute the xonly public key for a secret key. Just as ec_pubkey_create this - * function computes the point P by multiplying the seckey (interpreted as a scalar) - * with the generator. The public key corresponds to P if the Y coordinate of P is a - * quadratic residue or -P otherwise. +/** Compute the xonly public key for a secret key. Same as ec_pubkey_create, but + * for xonly public keys. * * Returns: 1 if secret was valid, public key stores * 0 if secret was invalid, try again @@ -780,7 +781,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_create( * function optionally outputs a sign bit that can be used to convert * the secp256k1_xonly_pubkey back into the same secp256k1_pubkey. * The sign bit is 0 if the input pubkey encodes a positive point (has a Y - * coordinate that is a quadratic residue), otherwise it is 1. + * coordinate that is square), otherwise it is 1. * * Returns: 1 if the public key was successfully converted * 0 otherwise @@ -803,8 +804,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke /** Convert a secp256k1_xonly_pubkey into a secp256k1_pubkey. If this * function is used to invert secp256k1_xonly_pubkey_from_pubkey, the * sign bit must be set to the output of that function. If the sign bit - * is 0 the output pubkey encodes a positive point (has a Y coordinate that is a - * quadratic residue), otherwise it is negative. + * is 0 the output pubkey encodes a positive point (has a Y coordinate that is + * square), otherwise it is negative. * * Returns: 1 if the public key was successfully converted * 0 otherwise diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h index 01ad74f1bf..32a8e3481f 100644 --- a/include/secp256k1_schnorrsig.h +++ b/include/secp256k1_schnorrsig.h @@ -48,8 +48,8 @@ SECP256K1_API int secp256k1_schnorrsig_serialize( * In: in64: pointer to the 64-byte signature to be parsed * * The signature is serialized in the form R||s, where R is a 32-byte public - * key (x-coordinate only; the y-coordinate is considered to be the unique - * y-coordinate satisfying the curve equation that is a quadratic residue) + * key (X coordinate only; the Y coordinate is considered to be the unique + * Y coordinate satisfying the curve equation that is square) * and s is a 32-byte big-endian scalar. * * After the call, sig will always be initialized. If parsing failed or the @@ -103,12 +103,11 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( * * Args: ctx: a secp256k1 context object, initialized for verification. * scratch: scratch space used for the multiexponentiation - * In: sig: array of signatures, or NULL if there are no signatures - * msg32: array of messages, or NULL if there are no signatures - * pk: array of x-only public keys, or NULL if there are no signatures - * n_sigs: number of signatures in above arrays. Must be smaller than - * 2^31 and smaller than half the maximum size_t value. Must be 0 - * if above arrays are NULL. + * In: sig: array of pointers to signatures, or NULL if there are no signatures + * msg32: array of pointers to messages, or NULL if there are no signatures + * pk: array of pointers to x-only public keys, or NULL if there are no signatures + * n_sigs: number of signatures in above arrays. Must be below the + * minimum of 2^31 and SIZE_MAX/2. Must be 0 if above arrays are NULL. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch( const secp256k1_context* ctx, diff --git a/src/hash_impl.h b/src/hash_impl.h index 552eff356b..1ab05cae1d 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -164,8 +164,7 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out } /* Initializes a sha256 struct and writes the 64 byte string - * SHA256(tag)||SHA256(tag) into it. The taglen should be less than or equal to - * 64. */ + * SHA256(tag)||SHA256(tag) into it. */ static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { unsigned char buf[32]; secp256k1_sha256_initialize(hash); diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index cd97f33cfc..6d8d74e6a5 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -83,10 +83,14 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig } if (!noncefp(buf, msg32, seckey, (unsigned char *) "BIPSchnorrDerive", (void*)ndata, 0)) { + memset(sig, 0, sizeof(*sig)); + secp256k1_scalar_clear(&x); return 0; } secp256k1_scalar_set_b32(&k, buf, NULL); if (secp256k1_scalar_is_zero(&k)) { + memset(sig, 0, sizeof(*sig)); + secp256k1_scalar_clear(&x); return 0; } From e28b61c290f4549dfeb94b421310ff68b661fea0 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 24 Oct 2019 21:45:32 +0000 Subject: [PATCH 09/25] f const casting --- src/modules/schnorrsig/main_impl.h | 6 +++--- src/secp256k1.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 6d8d74e6a5..193c2a6486 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -132,7 +132,7 @@ static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp25 secp256k1_scalar_negate(&nege, e); - if (!secp256k1_pubkey_load(ctx, &pkp, (secp256k1_pubkey *) pk)) { + if (!secp256k1_pubkey_load(ctx, &pkp, (const secp256k1_pubkey *) pk)) { return 0; } secp256k1_gej_set_ge(&pkj, &pkp); @@ -238,7 +238,7 @@ static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *s secp256k1_scalar_set_b32(sc, buf, NULL); secp256k1_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]); - if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, (secp256k1_pubkey *) ecmult_context->pk[idx / 2])) { + if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, (const secp256k1_pubkey *) ecmult_context->pk[idx / 2])) { return 0; } } @@ -277,7 +277,7 @@ static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_con * xonly_pubkey serialization and a user would wrongly memcpy * normal secp256k1_pubkeys into xonly_pubkeys then the randomizer * would be the same for two different pubkeys. */ - secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, (secp256k1_pubkey *) pk[i], SECP256K1_EC_COMPRESSED); + secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, (const secp256k1_pubkey *) pk[i], SECP256K1_EC_COMPRESSED); secp256k1_sha256_write(sha, buf, buflen); } ecmult_context->ctx = ctx; diff --git a/src/secp256k1.c b/src/secp256k1.c index 0da4644c9e..90a89c2805 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -785,7 +785,7 @@ int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char ARG_CHECK(pubkey != NULL); ARG_CHECK(output32 != NULL); - if (!secp256k1_ec_pubkey_serialize(ctx, buf, &outputlen, (secp256k1_pubkey *) pubkey, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_ec_pubkey_serialize(ctx, buf, &outputlen, (const secp256k1_pubkey *) pubkey, SECP256K1_EC_COMPRESSED)) { return 0; } memcpy(output32, &buf[1], 32); @@ -797,7 +797,7 @@ int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_x ARG_CHECK(xonly_pubkey != NULL); ARG_CHECK(pubkey != NULL); - *xonly_pubkey = *(secp256k1_xonly_pubkey *) pubkey; + *xonly_pubkey = *(const secp256k1_xonly_pubkey *) pubkey; secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) xonly_pubkey, sign); return 1; @@ -808,7 +808,7 @@ int secp256k1_xonly_pubkey_to_pubkey(const secp256k1_context* ctx, secp256k1_pub ARG_CHECK(pubkey != NULL); ARG_CHECK(xonly_pubkey != NULL); - *pubkey = *(secp256k1_pubkey *) xonly_pubkey; + *pubkey = *(const secp256k1_pubkey *) xonly_pubkey; if (sign) { return secp256k1_ec_pubkey_negate(ctx, pubkey); } @@ -842,7 +842,7 @@ int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pub ARG_CHECK(output_pubkey != NULL); ARG_CHECK(tweak32 != NULL); - *output_pubkey = *(secp256k1_pubkey *)internal_pubkey; + *output_pubkey = *(const secp256k1_pubkey *)internal_pubkey; return secp256k1_ec_pubkey_tweak_add(ctx, output_pubkey, tweak32); } From 5764b2b2b7e9d96c7704364e55c17ed064217398 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 29 Oct 2019 08:38:11 +0000 Subject: [PATCH 10/25] f test that pubkey is zeroed after xonly_pubkey_parse returned 0 --- src/tests.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tests.c b/src/tests.c index 1d2c8280a3..0429217edf 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4270,7 +4270,8 @@ void run_eckey_edge_case_test(void) { void test_xonly_pubkey(void) { unsigned char sk[32] = { 0 }; - unsigned char garbage[32]; + unsigned char ones32[32]; + unsigned char zeros64[64] = { 0 }; secp256k1_pubkey xy_pk; secp256k1_pubkey xy_pk_tmp; secp256k1_xonly_pubkey xonly_pk; @@ -4310,8 +4311,9 @@ void test_xonly_pubkey(void) { CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); /* Can't parse a byte string that's not a valid X coordinate */ - memset(garbage, 0, sizeof(garbage)); - CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, garbage) == 0); + memset(ones32, 0xFF, sizeof(ones32)); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, ones32) == 0); + CHECK(memcmp(&xonly_pk_tmp, zeros64, sizeof(xonly_pk_tmp)) == 0); } void test_xonly_pubkey_api(void) { From 74bb3b4318b4c17b8cb01fa9d42ee776094b1743 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 1 Nov 2019 10:10:08 +0000 Subject: [PATCH 11/25] f don't use secp256k1_pubkeys in xonly_tweak api and instead use is_positive flag --- include/secp256k1.h | 19 ++++-- src/modules/schnorrsig/tests_impl.h | 19 +++--- src/secp256k1.c | 23 ++++--- src/tests.c | 100 +++++++++++++++------------- 4 files changed, 87 insertions(+), 74 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 36119df5f8..e561f7f483 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -849,8 +849,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_privkey_tweak_add const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak an x-only public key by adding tweak times the generator to it. Note that - * the output is a secp256k1_pubkey and not a secp256k1_xonly_pubkey. +/** Tweak an x-only public key by adding tweak times the generator to it. + * * Returns: 1 if tweak times the generator was successfully added to pubkey * 0 if the tweak was out of range or the resulting public key would be * invalid (only when the tweak is the complement of the corresponding @@ -859,18 +859,21 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_privkey_tweak_add * Args: ctx: pointer to a context object initialized for validation * (cannot be NULL) * Out: output_pubkey: pointer to a public key object (cannot be NULL) + * is_positive: pointer to an integer that will be set to 1 if the + * output_pubkey is positive, and 0 otherwise (cannot be NULL) * In: internal_pubkey: pointer to an x-only public key object to apply the * tweak to (cannot be NULL) * tweak32: pointer to a 32-byte tweak (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( const secp256k1_context* ctx, - secp256k1_pubkey *output_pubkey, + secp256k1_xonly_pubkey *output_pubkey, + int *is_positive, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); -/** Verifies that output_pubkey is the result of calling +/** Verifies that output_pubkey and is_positive is the result of calling * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32. * * Returns: 1 if output_pubkey is the result of tweaking the internal_pubkey with @@ -880,16 +883,18 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( * Args: ctx: pointer to a context object initialized for validation * (cannot be NULL) * In: output_pubkey: pointer to a public key object (cannot be NULL) + * is_positive: 1 if output_pubkey is positive and 0 otherwise * internal_pubkey: pointer to an x-only public key object to apply the * tweak to (cannot be NULL) * tweak32: pointer to a 32-byte tweak (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_verify( const secp256k1_context* ctx, - const secp256k1_pubkey *output_pubkey, + const secp256k1_xonly_pubkey *output_pubkey, + int is_positive, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); #ifdef __cplusplus } diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 49ddb50b84..39b355f664 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -722,11 +722,10 @@ void test_schnorrsig_taproot(void) { unsigned char sk[32]; secp256k1_xonly_pubkey internal_pk; unsigned char internal_pk_bytes[32]; - secp256k1_pubkey output_pk; - secp256k1_xonly_pubkey output_pk_pos; + secp256k1_xonly_pubkey output_pk; unsigned char output_pk_bytes[32]; unsigned char tweak[32]; - int sign; + int is_positive; unsigned char msg[32]; secp256k1_schnorrsig sig; @@ -734,25 +733,23 @@ void test_schnorrsig_taproot(void) { secp256k1_rand256(sk); CHECK(secp256k1_xonly_pubkey_create(ctx, &internal_pk, sk) == 1); memset(tweak, 1, sizeof(tweak)); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_pk_pos, &sign, &output_pk) == 1); - CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk_pos) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &is_positive, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1); /* Key spend */ secp256k1_rand256(msg); CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, tweak) == 1); CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL) == 1); /* Verify key spend */ - CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk_pos, output_pk_bytes) == 1); - CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &output_pk_pos) == 1); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &output_pk) == 1); /* Script spend */ CHECK(secp256k1_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1); /* Verify script spend */ - CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk_pos, output_pk_bytes) == 1); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1); CHECK(secp256k1_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(ctx, &output_pk, &output_pk_pos, sign) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, tweak) == 1); } void run_schnorrsig_tests(void) { diff --git a/src/secp256k1.c b/src/secp256k1.c index 90a89c2805..2ee66ba110 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -836,28 +836,35 @@ int secp256k1_xonly_privkey_tweak_add(const secp256k1_context* ctx, unsigned cha return secp256k1_ec_privkey_tweak_add(ctx, seckey32, tweak32); } -int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { +int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_xonly_pubkey *output_pubkey, int *is_positive, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_pubkey pubkey_tmp; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(internal_pubkey != NULL); ARG_CHECK(output_pubkey != NULL); + ARG_CHECK(is_positive != NULL); + ARG_CHECK(internal_pubkey != NULL); ARG_CHECK(tweak32 != NULL); - *output_pubkey = *(const secp256k1_pubkey *)internal_pubkey; - return secp256k1_ec_pubkey_tweak_add(ctx, output_pubkey, tweak32); + pubkey_tmp = *(secp256k1_pubkey *)internal_pubkey; + if(!secp256k1_ec_pubkey_tweak_add(ctx, &pubkey_tmp, tweak32)) { + return 0; + } + return secp256k1_xonly_pubkey_from_pubkey(ctx, output_pubkey, is_positive, &pubkey_tmp); } -int secp256k1_xonly_pubkey_tweak_verify(const secp256k1_context* ctx, const secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { - secp256k1_pubkey pk_expected; +int secp256k1_xonly_pubkey_tweak_verify(const secp256k1_context* ctx, const secp256k1_xonly_pubkey *output_pubkey, int is_positive, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_xonly_pubkey pk_expected; + int is_positive_expected; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(internal_pubkey != NULL); ARG_CHECK(output_pubkey != NULL); ARG_CHECK(tweak32 != NULL); - if (!secp256k1_xonly_pubkey_tweak_add(ctx, &pk_expected, internal_pubkey, tweak32)) { + if (!secp256k1_xonly_pubkey_tweak_add(ctx, &pk_expected, &is_positive_expected, internal_pubkey, tweak32)) { return 0; } - return memcmp(&pk_expected, output_pubkey, sizeof(pk_expected)) == 0; + return memcmp(&pk_expected, output_pubkey, sizeof(pk_expected)) == 0 + && is_positive_expected == is_positive; } #ifdef ENABLE_MODULE_ECDH diff --git a/src/tests.c b/src/tests.c index 0429217edf..01210a2f73 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4318,11 +4318,12 @@ void test_xonly_pubkey(void) { void test_xonly_pubkey_api(void) { secp256k1_xonly_pubkey pk; + secp256k1_xonly_pubkey pk_tweaked; secp256k1_pubkey xy_pk; unsigned char sk[32]; unsigned char buf32[32]; unsigned char tweak[32]; - int pk_sign; + int pk_is_positive; /** setup **/ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); @@ -4378,49 +4379,55 @@ void test_xonly_pubkey_api(void) { CHECK(ecount == 4); ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(none, &xy_pk, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(none, &pk, &pk_is_positive, &pk, tweak) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &xy_pk, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &pk, &pk_is_positive, &pk, tweak) == 0); CHECK(ecount == 2); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, &pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, NULL, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &pk_is_positive, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, NULL, &pk_is_positive, &pk, tweak) == 0); CHECK(ecount == 3); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, NULL, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, NULL, &pk, tweak) == 0); CHECK(ecount == 4); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, &pk, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &pk_is_positive, NULL, tweak) == 0); CHECK(ecount == 5); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &pk_is_positive, &pk, NULL) == 0); + CHECK(ecount == 6); ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &xy_pk, &pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(none, &xy_pk, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk_tweaked, &pk_is_positive, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(none, &pk_tweaked, pk_is_positive, &pk, tweak) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(sign, &xy_pk, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(sign, &pk_tweaked, pk_is_positive, &pk, tweak) == 0); CHECK(ecount == 2); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &xy_pk, &pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, NULL, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, pk_is_positive, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, NULL, pk_is_positive, &pk, tweak) == 0); CHECK(ecount == 3); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &xy_pk, NULL, tweak) == 0); + /* invalid is_positive value */ + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, 2, &pk, tweak) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, pk_is_positive, NULL, tweak) == 0); CHECK(ecount == 4); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &xy_pk, &pk, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, pk_is_positive, &pk, NULL) == 0); CHECK(ecount == 5); + ecount = 0; - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_sign, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &pk, &pk_sign, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(vrfy, &pk, &pk_sign, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_sign, &xy_pk) == 0); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_is_positive, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &pk, &pk_is_positive, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(vrfy, &pk, &pk_is_positive, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_is_positive, &xy_pk) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, NULL, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_sign, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_is_positive, NULL) == 0); CHECK(ecount == 2); ecount = 0; - CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, &pk, pk_sign) == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(sign, &xy_pk, &pk, pk_sign) == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(vrfy, &xy_pk, &pk, pk_sign) == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(none, NULL, &pk, pk_sign) == 0); + CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, &pk, pk_is_positive) == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(sign, &xy_pk, &pk, pk_is_positive) == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(vrfy, &xy_pk, &pk, pk_is_positive) == 1); + CHECK(secp256k1_xonly_pubkey_to_pubkey(none, NULL, &pk, pk_is_positive) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, NULL, pk_sign) == 0); + CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, NULL, pk_is_positive) == 0); CHECK(ecount == 2); secp256k1_context_destroy(none); @@ -4433,7 +4440,9 @@ void test_xonly_pubkey_tweak(void) { unsigned char overflows[32]; unsigned char sk[32]; secp256k1_xonly_pubkey internal_pk; - secp256k1_pubkey output_pk; + secp256k1_xonly_pubkey output_pk; + secp256k1_pubkey xy_pk; + int is_positive; unsigned char tweak[32]; memset(zeros, 0, sizeof(zeros)); @@ -4442,52 +4451,47 @@ void test_xonly_pubkey_tweak(void) { CHECK(secp256k1_xonly_pubkey_create(ctx, &internal_pk, sk) == 1); memset(tweak, 1, sizeof(tweak)); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &is_positive, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, tweak) == 1); /* Using privkey_tweak_add gives the same result */ CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, tweak) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, tweak) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &xy_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_pk, &is_positive, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, tweak) == 1); + /* Wrong is_positive */ + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, !is_positive, &internal_pk, tweak) == 0); /* Wrong public key */ - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, (secp256k1_pubkey*) &internal_pk, &internal_pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &internal_pk, is_positive, &internal_pk, tweak) == 0); /* Overflowing tweak not allowed */ - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, &internal_pk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, overflows) == 0); CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, overflows) == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_pk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &is_positive, &internal_pk, overflows) == 0); } /* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 - * additional pubkeys by calling tweak_add. Then after the pubkeys are - * serialized and parsed, every tweak is verified. */ + * additional pubkeys by calling tweak_add. Then verifies every tweak starting + * from the last pubkey. */ #define N_PUBKEYS 32 void test_xonly_pubkey_tweak_recursive(void) { unsigned char sk[32]; - secp256k1_xonly_pubkey xonly_pk[N_PUBKEYS]; - unsigned char pk_bytes[N_PUBKEYS][32]; - secp256k1_pubkey xy_pk[N_PUBKEYS - 1]; + secp256k1_xonly_pubkey pk[N_PUBKEYS]; + int is_positive[N_PUBKEYS]; unsigned char tweak[N_PUBKEYS - 1][32]; - int sign[N_PUBKEYS]; int i; secp256k1_rand256(sk); - CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk[0], sk) == 1); + CHECK(secp256k1_xonly_pubkey_create(ctx, &pk[0], sk) == 1); /* Add tweaks */ for (i = 0; i < N_PUBKEYS - 1; i++) { memset(tweak[i], i + 1, sizeof(tweak[i])); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &xy_pk[i], &xonly_pk[i], tweak[i]) == 1); - CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_bytes[i], &xonly_pk[i]) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk[i + 1], &sign[i + 1], &xy_pk[i]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &is_positive[i + 1], &pk[i], tweak[i]) == 1); } - CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_bytes[N_PUBKEYS - 1], &xonly_pk[N_PUBKEYS - 1]) == 1); /* Verify tweaks */ - CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk[N_PUBKEYS - 1], pk_bytes[N_PUBKEYS - 1]) == 1); - for (i = N_PUBKEYS - 2; i >= 0; i--) { - CHECK(secp256k1_xonly_pubkey_to_pubkey(ctx, &xy_pk[i], &xonly_pk[i + 1], sign[i + 1]) == 1); - CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk[i], pk_bytes[i]) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &xy_pk[i], &xonly_pk[i], tweak[i]) == 1); + for (i = N_PUBKEYS - 1; i > 0; i--) { + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &pk[i], is_positive[i], &pk[i - 1], tweak[i - 1]) == 1); } } #undef N_PUBKEYS From dfce048bdec171fa76384a28136c59acd80f9b5a Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 1 Nov 2019 10:14:41 +0000 Subject: [PATCH 12/25] f remove xonly_pubkey_to_pubkey --- include/secp256k1.h | 23 ----------------------- src/secp256k1.c | 12 ------------ src/tests.c | 14 +------------- 3 files changed, 1 insertion(+), 48 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index e561f7f483..a304b4487b 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -801,29 +801,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke const secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); -/** Convert a secp256k1_xonly_pubkey into a secp256k1_pubkey. If this - * function is used to invert secp256k1_xonly_pubkey_from_pubkey, the - * sign bit must be set to the output of that function. If the sign bit - * is 0 the output pubkey encodes a positive point (has a Y coordinate that is - * square), otherwise it is negative. - * - * Returns: 1 if the public key was successfully converted - * 0 otherwise - * - * Args: ctx: pointer to a context object - * Out: pubkey: pointer to a public key object for placing the - * converted public key (cannot be NULL) - * In: xonly_pubkey: pointer to an x-only public key that is converted - * (cannot be NULL) - * sign: sign bit of the resulting public key (can be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_to_pubkey( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey, - const secp256k1_xonly_pubkey *xonly_pubkey, - int sign -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - /** Tweak the private key of an x-only pubkey by adding a tweak to it. The public * key of the resulting private key will be the same as the output of * secp256k1_xonly_pubkey_tweak_add called with the same tweak and corresponding diff --git a/src/secp256k1.c b/src/secp256k1.c index 2ee66ba110..81d3de5e23 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -803,18 +803,6 @@ int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_x return 1; } -int secp256k1_xonly_pubkey_to_pubkey(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_xonly_pubkey *xonly_pubkey, int sign) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(xonly_pubkey != NULL); - - *pubkey = *(const secp256k1_pubkey *) xonly_pubkey; - if (sign) { - return secp256k1_ec_pubkey_negate(ctx, pubkey); - } - return 1; -} - int secp256k1_xonly_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey32, const unsigned char *tweak32) { secp256k1_ge ge; secp256k1_pubkey pubkey; diff --git a/src/tests.c b/src/tests.c index 01210a2f73..fc473c3dbe 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4273,7 +4273,6 @@ void test_xonly_pubkey(void) { unsigned char ones32[32]; unsigned char zeros64[64] = { 0 }; secp256k1_pubkey xy_pk; - secp256k1_pubkey xy_pk_tmp; secp256k1_xonly_pubkey xonly_pk; secp256k1_xonly_pubkey xonly_pk_tmp; secp256k1_ge pk1; @@ -4297,12 +4296,10 @@ void test_xonly_pubkey(void) { secp256k1_fe_negate(&y, &pk2.y, 1); CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); - /* Check from_pubkey and to_pubkey */ + /* Test from_pubkey */ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk_tmp, &sign, &xy_pk) == 1); CHECK(memcmp(&xonly_pk_tmp, &xonly_pk, sizeof(xonly_pk)) == 0); CHECK(sign == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(ctx, &xy_pk_tmp, &xonly_pk, sign) == 1); - CHECK(memcmp(&xy_pk_tmp, &xy_pk, sizeof(xy_pk)) == 0); /* Serialization and parse roundtrip */ CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 1); @@ -4421,15 +4418,6 @@ void test_xonly_pubkey_api(void) { CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_is_positive, NULL) == 0); CHECK(ecount == 2); - ecount = 0; - CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, &pk, pk_is_positive) == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(sign, &xy_pk, &pk, pk_is_positive) == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(vrfy, &xy_pk, &pk, pk_is_positive) == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(none, NULL, &pk, pk_is_positive) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_to_pubkey(none, &xy_pk, NULL, pk_is_positive) == 0); - CHECK(ecount == 2); - secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(vrfy); From 2b36bf7db30d399878f8b32abf3fe29039f79809 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 1 Nov 2019 10:18:50 +0000 Subject: [PATCH 13/25] f sign -> is_positive --- include/secp256k1.h | 2 +- src/tests.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index a304b4487b..bbd38eba6d 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -797,7 +797,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_create( SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, - int *sign, + int *is_positive, const secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); diff --git a/src/tests.c b/src/tests.c index fc473c3dbe..5d4d06805f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4278,7 +4278,7 @@ void test_xonly_pubkey(void) { secp256k1_ge pk1; secp256k1_ge pk2; secp256k1_fe y; - int sign; + int is_positive; unsigned char buf32[32]; /* sk = 0 should fail */ @@ -4297,9 +4297,9 @@ void test_xonly_pubkey(void) { CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); /* Test from_pubkey */ - CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk_tmp, &sign, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk_tmp, &is_positive, &xy_pk) == 1); CHECK(memcmp(&xonly_pk_tmp, &xonly_pk, sizeof(xonly_pk)) == 0); - CHECK(sign == 1); + CHECK(is_positive == 1); /* Serialization and parse roundtrip */ CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 1); From 26f95c556a088dc9e83e587d96534429a1974737 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sat, 2 Nov 2019 00:46:03 +0000 Subject: [PATCH 14/25] f feed seckey that is actually signed with (i.e. perhaps negated) into nonce functions --- src/modules/schnorrsig/main_impl.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 193c2a6486..aff767ca73 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -55,6 +55,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_sha256 sha; int overflow; unsigned char buf[32]; + unsigned char seckey_tmp[32]; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); @@ -82,11 +83,15 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_scalar_negate(&x, &x); } - if (!noncefp(buf, msg32, seckey, (unsigned char *) "BIPSchnorrDerive", (void*)ndata, 0)) { + secp256k1_scalar_get_b32(seckey_tmp, &x); + if (!noncefp(buf, msg32, seckey_tmp, (unsigned char *) "BIPSchnorrDerive", (void*)ndata, 0)) { memset(sig, 0, sizeof(*sig)); + memset(seckey_tmp, 0, sizeof(seckey_tmp)); secp256k1_scalar_clear(&x); return 0; } + memset(seckey_tmp, 0, sizeof(seckey_tmp)); + secp256k1_scalar_set_b32(&k, buf, NULL); if (secp256k1_scalar_is_zero(&k)) { memset(sig, 0, sizeof(*sig)); From 538052c95039e84c2f6b2790b826b86765f8d2c3 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sat, 2 Nov 2019 00:46:15 +0000 Subject: [PATCH 15/25] f reenable test vectors --- src/modules/schnorrsig/tests_impl.h | 558 +++++++++++++--------------- 1 file changed, 248 insertions(+), 310 deletions(-) diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 39b355f664..f2502cffa4 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -173,447 +173,386 @@ void test_schnorrsig_bip_vectors_check_verify(secp256k1_scratch_space *scratch, } /* Test vectors according to BIP-schnorr - * (https://github.com/sipa/bips/blob/7f6a73e53c8bbcf2d008ea0546f76433e22094a8/bip-schnorr/test-vectors.csv). + * (https://github.com/sipa/bips/blob/775cb2fd903cbfe459081fda49ada744ef3139be/bip-schnorr/test-vectors.csv). */ void test_schnorrsig_bip_vectors(secp256k1_scratch_space *scratch) { { - /* Test vector 1 */ - const unsigned char sk1[32] = { + /* Test vector 0 */ + const unsigned char sk[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; - const unsigned char pk1[33] = { - 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, - 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, - 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, - 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, - 0x98 + const unsigned char pk[32] = { + 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, + 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, + 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, + 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }; - const unsigned char msg1[32] = { + const unsigned char msg[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - const unsigned char sig1[64] = { - 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, - 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, - 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, - 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, - 0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3, - 0x4D, 0xFF, 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84, - 0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1, - 0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05 - }; - test_schnorrsig_bip_vectors_check_signing(sk1, pk1, msg1, sig1); - test_schnorrsig_bip_vectors_check_verify(scratch, pk1, msg1, sig1, 1); + const unsigned char sig[64] = { + 0x52, 0x8F, 0x74, 0x57, 0x93, 0xE8, 0x47, 0x2C, + 0x03, 0x29, 0x74, 0x2A, 0x46, 0x3F, 0x59, 0xE5, + 0x8F, 0x3A, 0x3F, 0x1A, 0x4A, 0xC0, 0x9C, 0x28, + 0xF6, 0xF8, 0x51, 0x4D, 0x4D, 0x03, 0x22, 0xA2, + 0x58, 0xBD, 0x08, 0x39, 0x8F, 0x82, 0xCF, 0x67, + 0xB8, 0x12, 0xAB, 0x2C, 0x77, 0x17, 0xCE, 0x56, + 0x6F, 0x87, 0x7C, 0x2F, 0x87, 0x95, 0xC8, 0x46, + 0x14, 0x69, 0x78, 0xE8, 0xF0, 0x47, 0x82, 0xAE + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, msg, sig); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 1); } { - /* Test vector 2 */ - const unsigned char sk2[32] = { + /* Test vector 1 */ + const unsigned char sk[32] = { 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF }; - const unsigned char pk2[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }; - const unsigned char msg2[32] = { + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig2[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD - }; - test_schnorrsig_bip_vectors_check_signing(sk2, pk2, msg2, sig2); - test_schnorrsig_bip_vectors_check_verify(scratch, pk2, msg2, sig2, 1); + const unsigned char sig[64] = { + 0x66, 0x7C, 0x2F, 0x77, 0x8E, 0x06, 0x16, 0xE6, + 0x11, 0xBD, 0x0C, 0x14, 0xB8, 0xA6, 0x00, 0xC5, + 0x88, 0x45, 0x51, 0x70, 0x1A, 0x94, 0x9E, 0xF0, + 0xEB, 0xFD, 0x72, 0xD4, 0x52, 0xD6, 0x4E, 0x84, + 0x41, 0x60, 0xBC, 0xFC, 0x3F, 0x46, 0x6E, 0xCB, + 0x8F, 0xAC, 0xD1, 0x9A, 0xDE, 0x57, 0xD8, 0x69, + 0x9D, 0x74, 0xE7, 0x20, 0x7D, 0x78, 0xC6, 0xAE, + 0xDC, 0x37, 0x99, 0xB5, 0x2A, 0x8E, 0x05, 0x98 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, msg, sig); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 1); } { - /* Test vector 3 */ - const unsigned char sk3[32] = { + /* Test vector 2 */ + const unsigned char sk[32] = { 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC7 + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC9 }; - const unsigned char pk3[33] = { - 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, - 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, - 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, - 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, - 0x4B + const unsigned char pk[32] = { + 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, + 0x12, 0x1F, 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, + 0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9, + 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }; - const unsigned char msg3[32] = { + const unsigned char msg[32] = { 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C }; - const unsigned char sig3[64] = { - 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, - 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, - 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, - 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, - 0x00, 0x88, 0x03, 0x71, 0xD0, 0x17, 0x66, 0x93, - 0x5B, 0x92, 0xD2, 0xAB, 0x4C, 0xD5, 0xC8, 0xA2, - 0xA5, 0x83, 0x7E, 0xC5, 0x7F, 0xED, 0x76, 0x60, - 0x77, 0x3A, 0x05, 0xF0, 0xDE, 0x14, 0x23, 0x80 - }; - test_schnorrsig_bip_vectors_check_signing(sk3, pk3, msg3, sig3); - test_schnorrsig_bip_vectors_check_verify(scratch, pk3, msg3, sig3, 1); + const unsigned char sig[64] = { + 0x2D, 0x94, 0x1B, 0x38, 0xE3, 0x26, 0x24, 0xBF, + 0x0A, 0xC7, 0x66, 0x9C, 0x09, 0x71, 0xB9, 0x90, + 0x99, 0x4A, 0xF6, 0xF9, 0xB1, 0x84, 0x26, 0xBF, + 0x4F, 0x4E, 0x7E, 0xC1, 0x0E, 0x6C, 0xDF, 0x38, + 0x6C, 0xF6, 0x46, 0xC6, 0xDD, 0xAF, 0xCF, 0xA7, + 0xF1, 0x99, 0x3E, 0xEB, 0x2E, 0x4D, 0x66, 0x41, + 0x6A, 0xEA, 0xD1, 0xDD, 0xAE, 0x2F, 0x22, 0xD6, + 0x3C, 0xAD, 0x90, 0x14, 0x12, 0xD1, 0x16, 0xC6 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, msg, sig); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 1); + } + { + /* Test vector 3 */ + const unsigned char sk[32] = { + 0x0B, 0x43, 0x2B, 0x26, 0x77, 0x93, 0x73, 0x81, + 0xAE, 0xF0, 0x5B, 0xB0, 0x2A, 0x66, 0xEC, 0xD0, + 0x12, 0x77, 0x30, 0x62, 0xCF, 0x3F, 0xA2, 0x54, + 0x9E, 0x44, 0xF5, 0x8E, 0xD2, 0x40, 0x17, 0x10 + }; + const unsigned char pk[32] = { + 0x25, 0xD1, 0xDF, 0xF9, 0x51, 0x05, 0xF5, 0x25, + 0x3C, 0x40, 0x22, 0xF6, 0x28, 0xA9, 0x96, 0xAD, + 0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A, + 0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17 + }; + const unsigned char msg[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 + }; + const unsigned char sig[64] = { + 0x8B, 0xD2, 0xC1, 0x16, 0x04, 0xB0, 0xA8, 0x7A, + 0x44, 0x3F, 0xCC, 0x2E, 0x5D, 0x90, 0xE5, 0x32, + 0x8F, 0x93, 0x41, 0x61, 0xB1, 0x88, 0x64, 0xFB, + 0x48, 0xCE, 0x10, 0xCB, 0x59, 0xB4, 0x5F, 0xB9, + 0xB5, 0xB2, 0xA0, 0xF1, 0x29, 0xBD, 0x88, 0xF5, + 0xBD, 0xC0, 0x5D, 0x5C, 0x21, 0xE5, 0xC5, 0x71, + 0x76, 0xB9, 0x13, 0x00, 0x23, 0x35, 0x78, 0x4F, + 0x97, 0x77, 0xA2, 0x4B, 0xD3, 0x17, 0xCD, 0x36 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, msg, sig); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 1); } { /* Test vector 4 */ - const unsigned char pk4[33] = { - 0x03, 0xDE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, - 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, - 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, - 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, - 0x34 - }; - const unsigned char msg4[32] = { + const unsigned char pk[32] = { + 0xD6, 0x9C, 0x35, 0x09, 0xBB, 0x99, 0xE4, 0x12, + 0xE6, 0x8B, 0x0F, 0xE8, 0x54, 0x4E, 0x72, 0x83, + 0x7D, 0xFA, 0x30, 0x74, 0x6D, 0x8B, 0xE2, 0xAA, + 0x65, 0x97, 0x5F, 0x29, 0xD2, 0x2D, 0xC7, 0xB9 + }; + const unsigned char msg[32] = { 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 }; - const unsigned char sig4[64] = { + const unsigned char sig[64] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, - 0x02, 0xA8, 0xDC, 0x32, 0xE6, 0x4E, 0x86, 0xA3, - 0x33, 0xF2, 0x0E, 0xF5, 0x6E, 0xAC, 0x9B, 0xA3, - 0x0B, 0x72, 0x46, 0xD6, 0xD2, 0x5E, 0x22, 0xAD, - 0xB8, 0xC6, 0xBE, 0x1A, 0xEB, 0x08, 0xD4, 0x9D + 0xEE, 0x37, 0x4A, 0xC7, 0xFA, 0xE9, 0x27, 0xD3, + 0x34, 0xCC, 0xB1, 0x90, 0xF6, 0xFB, 0x8F, 0xD2, + 0x7A, 0x2D, 0xDC, 0x63, 0x9C, 0xCE, 0xE4, 0x6D, + 0x43, 0xF1, 0x13, 0xA4, 0x03, 0x5A, 0x2C, 0x7F }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk4, msg4, sig4, 1); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 1); } { /* Test vector 5 */ - const unsigned char pk5[33] = { - 0x03, 0x1B, 0x84, 0xC5, 0x56, 0x7B, 0x12, 0x64, - 0x40, 0x99, 0x5D, 0x3E, 0xD5, 0xAA, 0xBA, 0x05, - 0x65, 0xD7, 0x1E, 0x18, 0x34, 0x60, 0x48, 0x19, - 0xFF, 0x9C, 0x17, 0xF5, 0xE9, 0xD5, 0xDD, 0x07, - 0x8F - }; - const unsigned char msg5[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + const unsigned char pk[32] = { + 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, 0x50, + 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, 0x21, + 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87, + 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34 }; - const unsigned char sig5[64] = { - 0x52, 0x81, 0x85, 0x79, 0xAC, 0xA5, 0x97, 0x67, - 0xE3, 0x29, 0x1D, 0x91, 0xB7, 0x6B, 0x63, 0x7B, - 0xEF, 0x06, 0x20, 0x83, 0x28, 0x49, 0x92, 0xF2, - 0xD9, 0x5F, 0x56, 0x4C, 0xA6, 0xCB, 0x4E, 0x35, - 0x30, 0xB1, 0xDA, 0x84, 0x9C, 0x8E, 0x83, 0x04, - 0xAD, 0xC0, 0xCF, 0xE8, 0x70, 0x66, 0x03, 0x34, - 0xB3, 0xCF, 0xC1, 0x8E, 0x82, 0x5E, 0xF1, 0xDB, - 0x34, 0xCF, 0xAE, 0x3D, 0xFC, 0x5D, 0x81, 0x87 - }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk5, msg5, sig5, 1); + secp256k1_xonly_pubkey pk_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk)); } { /* Test vector 6 */ - const unsigned char pk6[33] = { - 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, - 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, - 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, - 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, - 0x4B - }; - const unsigned char msg6[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 + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }; - const unsigned char sig6[64] = { - 0x57, 0x0D, 0xD4, 0xCA, 0x83, 0xD4, 0xE6, 0x31, - 0x7B, 0x8E, 0xE6, 0xBA, 0xE8, 0x34, 0x67, 0xA1, - 0xBF, 0x41, 0x9D, 0x07, 0x67, 0x12, 0x2D, 0xE4, - 0x09, 0x39, 0x44, 0x14, 0xB0, 0x50, 0x80, 0xDC, - 0xE9, 0xEE, 0x5F, 0x23, 0x7C, 0xBD, 0x10, 0x8E, - 0xAB, 0xAE, 0x1E, 0x37, 0x75, 0x9A, 0xE4, 0x7F, - 0x8E, 0x42, 0x03, 0xDA, 0x35, 0x32, 0xEB, 0x28, - 0xDB, 0x86, 0x0F, 0x33, 0xD6, 0x2D, 0x49, 0xBD - }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk6, msg6, sig6, 1); - } - { - /* Test vector 7 */ - const unsigned char pk7[33] = { - 0x03, 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, - 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, - 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, - 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, - 0x34 - }; - secp256k1_xonly_pubkey pk7_parsed; - /* No need to check the signature of the test vector as parsing the pubkey already fails */ - CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk7_parsed, pk7)); - } - { - /* Test vector 8 */ - const unsigned char pk8[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg8[32] = { + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig8[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A, - 0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46, - 0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14, - 0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7 - }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk8, msg8, sig8, 0); + const unsigned char sig[64] = { + 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, + 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, + 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, + 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9, + 0x93, 0x55, 0x54, 0xD1, 0xAA, 0x5F, 0x03, 0x74, + 0xE5, 0xCD, 0xAA, 0xCB, 0x39, 0x25, 0x03, 0x5C, + 0x7C, 0x16, 0x9B, 0x27, 0xC4, 0x42, 0x6D, 0xF0, + 0xA6, 0xB1, 0x9A, 0xF3, 0xBA, 0xEA, 0xB1, 0x38 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } { - /* Test vector 9 */ - const unsigned char pk9[33] = { - 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, - 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, - 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, - 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, - 0x4B - }; - const unsigned char msg9[32] = { - 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, - 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, - 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, - 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + /* Test vector 7 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }; - const unsigned char sig9[64] = { - 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, - 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, - 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, - 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, - 0xD0, 0x92, 0xF9, 0xD8, 0x60, 0xF1, 0x77, 0x6A, - 0x1F, 0x74, 0x12, 0xAD, 0x8A, 0x1E, 0xB5, 0x0D, - 0xAC, 0xCC, 0x22, 0x2B, 0xC8, 0xC0, 0xE2, 0x6B, - 0x20, 0x56, 0xDF, 0x2F, 0x27, 0x3E, 0xFD, 0xEC - }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk9, msg9, sig9, 0); - } - { - /* Test vector 10 */ - const unsigned char pk10[33] = { - 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, - 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, - 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, - 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, - 0x98 - }; - const unsigned char msg10[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig10[64] = { - 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, - 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, - 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, - 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, - 0x8F, 0xCE, 0x56, 0x77, 0xCE, 0x7A, 0x62, 0x3C, - 0xB2, 0x00, 0x11, 0x22, 0x57, 0x97, 0xCE, 0x7A, - 0x8D, 0xE1, 0xDC, 0x6C, 0xCD, 0x4F, 0x75, 0x4A, - 0x47, 0xDA, 0x6C, 0x60, 0x0E, 0x59, 0x54, 0x3C - }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk10, msg10, sig10, 0); + const unsigned char sig[64] = { + 0x10, 0xAC, 0x49, 0xA6, 0xA2, 0xEB, 0xF6, 0x04, + 0x18, 0x9C, 0x5F, 0x40, 0xFC, 0x75, 0xAF, 0x2D, + 0x42, 0xD7, 0x7D, 0xE9, 0xA2, 0x78, 0x27, 0x09, + 0xB1, 0xEB, 0x4E, 0xAF, 0x1C, 0xFE, 0x91, 0x08, + 0xD7, 0x00, 0x3B, 0x70, 0x3A, 0x34, 0x99, 0xD5, + 0xE2, 0x95, 0x29, 0xD3, 0x9B, 0xA0, 0x40, 0xA4, + 0x49, 0x55, 0x12, 0x71, 0x40, 0xF8, 0x1A, 0x8A, + 0x89, 0xA9, 0x6F, 0x99, 0x2A, 0xC0, 0xFE, 0x79 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } { - /* Test vector 11 */ - const unsigned char pk11[33] = { - 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg11[32] = { + /* Test vector 8 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig11[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD - }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk11, msg11, sig11, 0); + const unsigned char sig[64] = { + 0x66, 0x7C, 0x2F, 0x77, 0x8E, 0x06, 0x16, 0xE6, + 0x11, 0xBD, 0x0C, 0x14, 0xB8, 0xA6, 0x00, 0xC5, + 0x88, 0x45, 0x51, 0x70, 0x1A, 0x94, 0x9E, 0xF0, + 0xEB, 0xFD, 0x72, 0xD4, 0x52, 0xD6, 0x4E, 0x84, + 0xBE, 0x9F, 0x43, 0x03, 0xC0, 0xB9, 0x91, 0x34, + 0x70, 0x53, 0x2E, 0x65, 0x21, 0xA8, 0x27, 0x95, + 0x1D, 0x39, 0xF5, 0xC6, 0x31, 0xCF, 0xD9, 0x8C, + 0xE3, 0x9A, 0xC4, 0xD7, 0xA5, 0xA8, 0x3B, 0xA9 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } { - /* Test vector 12 */ - const unsigned char pk12[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg12[32] = { + /* Test vector 9 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig12[64] = { + const unsigned char sig[64] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9E, 0x9D, 0x01, 0xAF, 0x98, 0x8B, 0x5C, 0xED, - 0xCE, 0x47, 0x22, 0x1B, 0xFA, 0x9B, 0x22, 0x27, - 0x21, 0xF3, 0xFA, 0x40, 0x89, 0x15, 0x44, 0x4A, - 0x4B, 0x48, 0x90, 0x21, 0xDB, 0x55, 0x77, 0x5F + 0x99, 0xD2, 0xF0, 0xEB, 0xC2, 0x99, 0x68, 0x08, + 0x20, 0x86, 0x33, 0xCD, 0x99, 0x26, 0xBF, 0x7E, + 0xC3, 0xDA, 0xB7, 0x3D, 0xAA, 0xD3, 0x6E, 0x85, + 0xB3, 0x04, 0x0A, 0x69, 0x8E, 0x6D, 0x1C, 0xE0 }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk12, msg12, sig12, 0); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } { - /* Test vector 13 */ - const unsigned char pk13[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg13[32] = { + /* Test vector 10 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig13[64] = { + const unsigned char sig[64] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xD3, 0x7D, 0xDF, 0x02, 0x54, 0x35, 0x18, 0x36, - 0xD8, 0x4B, 0x1B, 0xD6, 0xA7, 0x95, 0xFD, 0x5D, - 0x52, 0x30, 0x48, 0xF2, 0x98, 0xC4, 0x21, 0x4D, - 0x18, 0x7F, 0xE4, 0x89, 0x29, 0x47, 0xF7, 0x28 + 0x24, 0xE8, 0x1D, 0x89, 0xF0, 0x13, 0x04, 0x69, + 0x5C, 0xE9, 0x43, 0xF7, 0xD5, 0xEB, 0xD0, 0x0E, + 0xF7, 0x26, 0xA0, 0x86, 0x4B, 0x4F, 0xF3, 0x38, + 0x95, 0xB4, 0xE8, 0x6B, 0xEA, 0xDC, 0x54, 0x56 }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk13, msg13, sig13, 0); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } { - /* Test vector 14 */ - const unsigned char pk14[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg14[32] = { + /* Test vector 11 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x14, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig14[64] = { + const unsigned char sig[64] = { 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + 0x41, 0x60, 0xBC, 0xFC, 0x3F, 0x46, 0x6E, 0xCB, + 0x8F, 0xAC, 0xD1, 0x9A, 0xDE, 0x57, 0xD8, 0x69, + 0x9D, 0x74, 0xE7, 0x20, 0x7D, 0x78, 0xC6, 0xAE, + 0xDC, 0x37, 0x99, 0xB5, 0x2A, 0x8E, 0x05, 0x98 }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk14, msg14, sig14, 0); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } { - /* Test vector 15 */ - const unsigned char pk15[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg15[32] = { + /* Test vector 12 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig15[64] = { + const unsigned char sig[64] = { 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, 0xFC, 0x2F, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, + 0x41, 0x60, 0xBC, 0xFC, 0x3F, 0x46, 0x6E, 0xCB, + 0x8F, 0xAC, 0xD1, 0x9A, 0xDE, 0x57, 0xD8, 0x69, + 0x9D, 0x74, 0xE7, 0x20, 0x7D, 0x78, 0xC6, 0xAE, + 0xDC, 0x37, 0x99, 0xB5, 0x2A, 0x8E, 0x05, 0x98 }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk15, msg15, sig15, 0); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } { - /* Test vector 16 */ - const unsigned char pk16[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg16[32] = { + /* Test vector 13 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0x14, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 }; - const unsigned char sig16[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + const unsigned char sig[64] = { + 0x66, 0x7C, 0x2F, 0x77, 0x8E, 0x06, 0x16, 0xE6, + 0x11, 0xBD, 0x0C, 0x14, 0xB8, 0xA6, 0x00, 0xC5, + 0x88, 0x45, 0x51, 0x70, 0x1A, 0x94, 0x9E, 0xF0, + 0xEB, 0xFD, 0x72, 0xD4, 0x52, 0xD6, 0x4E, 0x84, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; - test_schnorrsig_bip_vectors_check_verify(scratch, pk16, msg16, sig16, 0); + test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } } @@ -758,8 +697,7 @@ void run_schnorrsig_tests(void) { test_schnorrsig_serialize(); test_schnorrsig_api(scratch); test_schnorrsig_sha256_tagged(); - /* Don't fix test vectors until later */ - /* test_schnorrsig_bip_vectors(scratch); */ + test_schnorrsig_bip_vectors(scratch); test_schnorrsig_sign(); test_schnorrsig_sign_verify(scratch); test_schnorrsig_taproot(); From 7e4ea975821ba3d897f660e28f86b3f8246d6e55 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sat, 2 Nov 2019 20:02:47 +0000 Subject: [PATCH 16/25] f trigger travis From b5fcf541495d78595c0bcbecdba58219a866b7f3 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sun, 3 Nov 2019 16:40:44 +0000 Subject: [PATCH 17/25] f uninitialized memory in tests --- src/tests.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests.c b/src/tests.c index 5d4d06805f..a882bbfebd 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4318,6 +4318,7 @@ void test_xonly_pubkey_api(void) { secp256k1_xonly_pubkey pk_tweaked; secp256k1_pubkey xy_pk; unsigned char sk[32]; + unsigned char xy_sk[32]; unsigned char buf32[32]; unsigned char tweak[32]; int pk_is_positive; @@ -4337,6 +4338,8 @@ void test_xonly_pubkey_api(void) { secp256k1_rand256(sk); secp256k1_rand256(tweak); + secp256k1_rand256(xy_sk); + CHECK(secp256k1_ec_pubkey_create(sign, &xy_pk, xy_sk) == 1); ecount = 0; CHECK(secp256k1_xonly_pubkey_create(none, &pk, sk) == 0); From affa6e87e972b7d2f48a60b79b9360f8b15db021 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 5 Nov 2019 12:44:14 +0000 Subject: [PATCH 18/25] f rename is_positive in xonly_pubkey api to has_square_y --- include/secp256k1.h | 39 ++++++++++++------------ src/secp256k1.c | 34 ++++++++++----------- src/tests.c | 72 ++++++++++++++++++++++----------------------- 3 files changed, 71 insertions(+), 74 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index bbd38eba6d..25f10e2ef8 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -714,9 +714,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( ) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Opaque data structure that holds a parsed and valid "x-only" public key. - * An x-only pubkey encodes a positive point. That is a point whose Y - * coordinate is square. It is serialized using only its X coordinate (32 - * bytes). + * An x-only pubkey encodes a point whose Y coordinate is square. It is + * serialized using only its X coordinate (32 bytes). See bip-schnorr for more + * information about x-only pubkeys. * * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is @@ -777,11 +777,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_create( const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey. This - * function optionally outputs a sign bit that can be used to convert - * the secp256k1_xonly_pubkey back into the same secp256k1_pubkey. - * The sign bit is 0 if the input pubkey encodes a positive point (has a Y - * coordinate that is square), otherwise it is 1. +/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey. * * Returns: 1 if the public key was successfully converted * 0 otherwise @@ -789,15 +785,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_create( * Args: ctx: pointer to a context object * Out: xonly_pubkey: pointer to an x-only public key object for placing the * converted public key (cannot be NULL) - * sign: sign bit of the pubkey. Can be used to reconstruct a - * public key from x-only public key (can be NULL) + * has_square_y: pointer to an integer that will be set to 1 if the pubkey + * encodes a point with a square Y coordinate, and set to 0 + * otherwise. (can be NULL) * In: pubkey: pointer to a public key that is converted (cannot be * NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, - int *is_positive, + int *has_square_y, const secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); @@ -806,10 +803,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke * secp256k1_xonly_pubkey_tweak_add called with the same tweak and corresponding * input public key. * - * If the public key corresponds to a positive point, tweak32 is added to the - * seckey (modulo the group order). If the public key corresponds to a - * negative point, tweak32 is added to the negation of the seckey (modulo the - * group order). + * If the public key corresponds to a point with square Y, tweak32 is added to + * the seckey (modulo the group order). Otherwise, tweak32 is added to the + * negation of the seckey (modulo the group order). * * Returns: 1 if the tweak was successfully added to seckey * 0 if the tweak was out of range or the resulting private key would be @@ -836,8 +832,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_privkey_tweak_add * Args: ctx: pointer to a context object initialized for validation * (cannot be NULL) * Out: output_pubkey: pointer to a public key object (cannot be NULL) - * is_positive: pointer to an integer that will be set to 1 if the - * output_pubkey is positive, and 0 otherwise (cannot be NULL) + * has_square_y: pointer to an integer that will be set to 1 if the + * output_pubkey has a square Y coordinate, and set to 0 + * otherwise (cannot be NULL) * In: internal_pubkey: pointer to an x-only public key object to apply the * tweak to (cannot be NULL) * tweak32: pointer to a 32-byte tweak (cannot be NULL) @@ -845,12 +842,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_privkey_tweak_add SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( const secp256k1_context* ctx, secp256k1_xonly_pubkey *output_pubkey, - int *is_positive, + int *has_square_y, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); -/** Verifies that output_pubkey and is_positive is the result of calling +/** Verifies that output_pubkey and has_square_y is the result of calling * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32. * * Returns: 1 if output_pubkey is the result of tweaking the internal_pubkey with @@ -860,7 +857,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( * Args: ctx: pointer to a context object initialized for validation * (cannot be NULL) * In: output_pubkey: pointer to a public key object (cannot be NULL) - * is_positive: 1 if output_pubkey is positive and 0 otherwise + * has_square_y: 1 if output_pubkey has a square Y coordinate and 0 otherwise. * internal_pubkey: pointer to an x-only public key object to apply the * tweak to (cannot be NULL) * tweak32: pointer to a 32-byte tweak (cannot be NULL) @@ -868,7 +865,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_verify( const secp256k1_context* ctx, const secp256k1_xonly_pubkey *output_pubkey, - int is_positive, + int has_square_y, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); diff --git a/src/secp256k1.c b/src/secp256k1.c index 81d3de5e23..e1c93928c1 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -730,19 +730,19 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * return 1; } -/* Converts the point encoded by a secp256k1_pubkey into its absolute value, - * i.e. keeps it as is if it is positive and otherwise negates it. Sign is set - * to 1 if the input point was negative and set to 0 otherwise. */ -static void secp256k1_ec_pubkey_absolute(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, int *sign) { +/* Converts the point encoded by a secp256k1_pubkey into its "absolute" value, + * i.e. keeps it as is if it is has a square Y and otherwise negates it. + * has_square_y is set to 1 in the former case and to 0 in the latter case. */ +static void secp256k1_ec_pubkey_absolute(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, int *has_square_y) { secp256k1_ge ge; secp256k1_pubkey_load(ctx, &ge, pubkey); - if (sign != NULL) { - *sign = 0; + if (has_square_y != NULL) { + *has_square_y = 1; } if (!secp256k1_fe_is_quad_var(&ge.y)) { secp256k1_ge_neg(&ge, &ge); - if (sign != NULL) { - *sign = 1; + if (has_square_y != NULL) { + *has_square_y = 0; } } secp256k1_pubkey_save(pubkey, &ge); @@ -792,14 +792,14 @@ int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char return 1; } -int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *sign, const secp256k1_pubkey *pubkey) { +int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *has_square_y, const secp256k1_pubkey *pubkey) { VERIFY_CHECK(ctx != NULL); ARG_CHECK(xonly_pubkey != NULL); ARG_CHECK(pubkey != NULL); *xonly_pubkey = *(const secp256k1_xonly_pubkey *) pubkey; - secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) xonly_pubkey, sign); + secp256k1_ec_pubkey_absolute(ctx, (secp256k1_pubkey *) xonly_pubkey, has_square_y); return 1; } @@ -824,11 +824,11 @@ int secp256k1_xonly_privkey_tweak_add(const secp256k1_context* ctx, unsigned cha return secp256k1_ec_privkey_tweak_add(ctx, seckey32, tweak32); } -int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_xonly_pubkey *output_pubkey, int *is_positive, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { +int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_xonly_pubkey *output_pubkey, int *has_square_y, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { secp256k1_pubkey pubkey_tmp; VERIFY_CHECK(ctx != NULL); ARG_CHECK(output_pubkey != NULL); - ARG_CHECK(is_positive != NULL); + ARG_CHECK(has_square_y != NULL); ARG_CHECK(internal_pubkey != NULL); ARG_CHECK(tweak32 != NULL); @@ -836,23 +836,23 @@ int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_xon if(!secp256k1_ec_pubkey_tweak_add(ctx, &pubkey_tmp, tweak32)) { return 0; } - return secp256k1_xonly_pubkey_from_pubkey(ctx, output_pubkey, is_positive, &pubkey_tmp); + return secp256k1_xonly_pubkey_from_pubkey(ctx, output_pubkey, has_square_y, &pubkey_tmp); } -int secp256k1_xonly_pubkey_tweak_verify(const secp256k1_context* ctx, const secp256k1_xonly_pubkey *output_pubkey, int is_positive, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { +int secp256k1_xonly_pubkey_tweak_verify(const secp256k1_context* ctx, const secp256k1_xonly_pubkey *output_pubkey, int has_square_y, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { secp256k1_xonly_pubkey pk_expected; - int is_positive_expected; + int has_square_y_expected; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(internal_pubkey != NULL); ARG_CHECK(output_pubkey != NULL); ARG_CHECK(tweak32 != NULL); - if (!secp256k1_xonly_pubkey_tweak_add(ctx, &pk_expected, &is_positive_expected, internal_pubkey, tweak32)) { + if (!secp256k1_xonly_pubkey_tweak_add(ctx, &pk_expected, &has_square_y_expected, internal_pubkey, tweak32)) { return 0; } return memcmp(&pk_expected, output_pubkey, sizeof(pk_expected)) == 0 - && is_positive_expected == is_positive; + && has_square_y_expected == has_square_y; } #ifdef ENABLE_MODULE_ECDH diff --git a/src/tests.c b/src/tests.c index a882bbfebd..1e7b592699 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4278,7 +4278,7 @@ void test_xonly_pubkey(void) { secp256k1_ge pk1; secp256k1_ge pk2; secp256k1_fe y; - int is_positive; + int has_square_y; unsigned char buf32[32]; /* sk = 0 should fail */ @@ -4297,9 +4297,9 @@ void test_xonly_pubkey(void) { CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); /* Test from_pubkey */ - CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk_tmp, &is_positive, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk_tmp, &has_square_y, &xy_pk) == 1); CHECK(memcmp(&xonly_pk_tmp, &xonly_pk, sizeof(xonly_pk)) == 0); - CHECK(is_positive == 1); + CHECK(has_square_y == 0); /* Serialization and parse roundtrip */ CHECK(secp256k1_xonly_pubkey_create(ctx, &xonly_pk, sk) == 1); @@ -4321,7 +4321,7 @@ void test_xonly_pubkey_api(void) { unsigned char xy_sk[32]; unsigned char buf32[32]; unsigned char tweak[32]; - int pk_is_positive; + int has_square_y; /** setup **/ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); @@ -4379,46 +4379,46 @@ void test_xonly_pubkey_api(void) { CHECK(ecount == 4); ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(none, &pk, &pk_is_positive, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(none, &pk, &has_square_y, &pk, tweak) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &pk, &pk_is_positive, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &pk, &has_square_y, &pk, tweak) == 0); CHECK(ecount == 2); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &pk_is_positive, &pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, NULL, &pk_is_positive, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &has_square_y, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, NULL, &has_square_y, &pk, tweak) == 0); CHECK(ecount == 3); CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, NULL, &pk, tweak) == 0); CHECK(ecount == 4); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &pk_is_positive, NULL, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &has_square_y, NULL, tweak) == 0); CHECK(ecount == 5); - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &pk_is_positive, &pk, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk, &has_square_y, &pk, NULL) == 0); CHECK(ecount == 6); ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk_tweaked, &pk_is_positive, &pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(none, &pk_tweaked, pk_is_positive, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(vrfy, &pk_tweaked, &has_square_y, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(none, &pk_tweaked, has_square_y, &pk, tweak) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(sign, &pk_tweaked, pk_is_positive, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(sign, &pk_tweaked, has_square_y, &pk, tweak) == 0); CHECK(ecount == 2); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, pk_is_positive, &pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, NULL, pk_is_positive, &pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, has_square_y, &pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, NULL, has_square_y, &pk, tweak) == 0); CHECK(ecount == 3); - /* invalid is_positive value */ + /* invalid has_square_y value */ CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, 2, &pk, tweak) == 0); CHECK(ecount == 3); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, pk_is_positive, NULL, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, has_square_y, NULL, tweak) == 0); CHECK(ecount == 4); - CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, pk_is_positive, &pk, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(vrfy, &pk_tweaked, has_square_y, &pk, NULL) == 0); CHECK(ecount == 5); ecount = 0; - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_is_positive, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &pk, &pk_is_positive, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(vrfy, &pk, &pk_is_positive, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_is_positive, &xy_pk) == 0); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &has_square_y, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &pk, &has_square_y, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(vrfy, &pk, &has_square_y, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &has_square_y, &xy_pk) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, NULL, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &pk_is_positive, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &pk, &has_square_y, NULL) == 0); CHECK(ecount == 2); secp256k1_context_destroy(none); @@ -4433,7 +4433,7 @@ void test_xonly_pubkey_tweak(void) { secp256k1_xonly_pubkey internal_pk; secp256k1_xonly_pubkey output_pk; secp256k1_pubkey xy_pk; - int is_positive; + int has_square_y; unsigned char tweak[32]; memset(zeros, 0, sizeof(zeros)); @@ -4442,23 +4442,23 @@ void test_xonly_pubkey_tweak(void) { CHECK(secp256k1_xonly_pubkey_create(ctx, &internal_pk, sk) == 1); memset(tweak, 1, sizeof(tweak)); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &is_positive, &internal_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &has_square_y, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, has_square_y, &internal_pk, tweak) == 1); /* Using privkey_tweak_add gives the same result */ CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, tweak) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &xy_pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_pk, &is_positive, &xy_pk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_pk, &has_square_y, &xy_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, has_square_y, &internal_pk, tweak) == 1); - /* Wrong is_positive */ - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, !is_positive, &internal_pk, tweak) == 0); + /* Wrong has_square_y */ + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, !has_square_y, &internal_pk, tweak) == 0); /* Wrong public key */ - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &internal_pk, is_positive, &internal_pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &internal_pk, has_square_y, &internal_pk, tweak) == 0); /* Overflowing tweak not allowed */ - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, has_square_y, &internal_pk, overflows) == 0); CHECK(secp256k1_xonly_privkey_tweak_add(ctx, sk, overflows) == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &is_positive, &internal_pk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &has_square_y, &internal_pk, overflows) == 0); } /* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 @@ -4468,7 +4468,7 @@ void test_xonly_pubkey_tweak(void) { void test_xonly_pubkey_tweak_recursive(void) { unsigned char sk[32]; secp256k1_xonly_pubkey pk[N_PUBKEYS]; - int is_positive[N_PUBKEYS]; + int has_square_y[N_PUBKEYS]; unsigned char tweak[N_PUBKEYS - 1][32]; int i; @@ -4477,12 +4477,12 @@ void test_xonly_pubkey_tweak_recursive(void) { /* Add tweaks */ for (i = 0; i < N_PUBKEYS - 1; i++) { memset(tweak[i], i + 1, sizeof(tweak[i])); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &is_positive[i + 1], &pk[i], tweak[i]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &has_square_y[i + 1], &pk[i], tweak[i]) == 1); } /* Verify tweaks */ for (i = N_PUBKEYS - 1; i > 0; i--) { - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &pk[i], is_positive[i], &pk[i - 1], tweak[i - 1]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &pk[i], has_square_y[i], &pk[i - 1], tweak[i - 1]) == 1); } } #undef N_PUBKEYS From 44881b21e3876fd63a4674fdc1375709e31cd694 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 5 Nov 2019 12:56:19 +0000 Subject: [PATCH 19/25] f rename is_positive in schnorrsig module to has_square_y --- src/modules/schnorrsig/main_impl.h | 4 ++-- src/modules/schnorrsig/tests_impl.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index aff767ca73..fc7e60caa9 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -77,8 +77,8 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig secp256k1_ge_set_gej(&pk, &pkj); /* Because we are signing for a x-only pubkey, the secret key is negated - * before signing if the point corresponding to the secret key is not - * positive. */ + * before signing if the point corresponding to the secret key does not + * have a square Y. */ if (!secp256k1_fe_is_quad_var(&pk.y)) { secp256k1_scalar_negate(&x, &x); } diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index f2502cffa4..5cc17d2f58 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -664,7 +664,7 @@ void test_schnorrsig_taproot(void) { secp256k1_xonly_pubkey output_pk; unsigned char output_pk_bytes[32]; unsigned char tweak[32]; - int is_positive; + int has_square_y; unsigned char msg[32]; secp256k1_schnorrsig sig; @@ -672,7 +672,7 @@ void test_schnorrsig_taproot(void) { secp256k1_rand256(sk); CHECK(secp256k1_xonly_pubkey_create(ctx, &internal_pk, sk) == 1); memset(tweak, 1, sizeof(tweak)); - CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &is_positive, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &has_square_y, &internal_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1); /* Key spend */ @@ -688,7 +688,7 @@ void test_schnorrsig_taproot(void) { /* Verify script spend */ CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1); CHECK(secp256k1_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, is_positive, &internal_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_verify(ctx, &output_pk, has_square_y, &internal_pk, tweak) == 1); } void run_schnorrsig_tests(void) { From 9d5373307cfad5fa1b53820d417a8155d2d557dc Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 5 Nov 2019 19:25:49 +0000 Subject: [PATCH 20/25] f add new bip-schnorr test vector 14 --- src/modules/schnorrsig/tests_impl.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 5cc17d2f58..21144de48d 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -554,6 +554,18 @@ void test_schnorrsig_bip_vectors(secp256k1_scratch_space *scratch) { }; test_schnorrsig_bip_vectors_check_verify(scratch, pk, msg, sig, 0); } + { + /* Test vector 14 */ + const unsigned char pk[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, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 + }; + secp256k1_xonly_pubkey pk_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk)); + } } /* Nonce function that returns constant 0 */ From 4743c1b0d078c5646c512b57b6b8d51c2a18d3e1 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 7 Nov 2019 09:02:40 +0000 Subject: [PATCH 21/25] valgrind test --- .travis.yml | 64 ++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/.travis.yml b/.travis.yml index e6678b1b77..e6d55f4fbd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,58 +13,52 @@ env: global: - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no JNI=no SCHNORRSIG=no - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar - matrix: - - SCALAR=32bit RECOVERY=yes - - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - - SCALAR=64bit - - FIELD=64bit RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - - FIELD=64bit ENDOMORPHISM=yes - - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - - FIELD=64bit ASM=x86_64 - - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit ENDOMORPHISM=yes - - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - - BIGNUM=no STATICPRECOMPUTATION=no - - BUILD=distcheck - - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC - - EXTRAFLAGS=CFLAGS=-O0 - - BUILD=check-java JNI=yes ECDH=yes EXPERIMENTAL=yes - - ECMULTGENPRECISION=2 - - ECMULTGENPRECISION=8 matrix: fast_finish: true include: - compiler: clang - env: HOST=i686-linux-gnu ENDOMORPHISM=yes + env: + - DVALGRIND=1 + - CFLAGS=" -fno-omit-frame-pointer -g" + - ASM=no BIGNUM=no EXTRAFLAGS="--disable-openssl-tests" + - EXPERIMENTAL=yes RECOVERY=yes ECDH=yes SCHNORRSIG=yes + - ENDOMORPHISM=no + - TESTRUNS=1 addons: apt: packages: - - gcc-multilib - - libgmp-dev:i386 + - valgrind - compiler: clang - env: HOST=i686-linux-gnu + env: + - DVALGRIND=1 + - CFLAGS="-fno-omit-frame-pointer -g" + - ASM=no BIGNUM=no EXTRAFLAGS="--disable-openssl-tests" + - EXPERIMENTAL=yes RECOVERY=yes ECDH=yes SCHNORRSIG=yes + - ENDOMORPHISM=no + - TESTRUNS=8 addons: apt: packages: - - gcc-multilib - - compiler: gcc - env: HOST=i686-linux-gnu ENDOMORPHISM=yes - addons: - apt: - packages: - - gcc-multilib - - compiler: gcc - env: HOST=i686-linux-gnu + - valgrind + - compiler: clang + env: + - DVALGRIND=1 + - CFLAGS="-fno-omit-frame-pointer -g" + - ASM=no BIGNUM=no EXTRAFLAGS="--disable-openssl-tests" + - EXPERIMENTAL=yes RECOVERY=yes ECDH=yes SCHNORRSIG=yes + - ENDOMORPHISM=no + - TESTRUNS=64 addons: apt: packages: - - gcc-multilib - - libgmp-dev:i386 + - valgrind + before_install: mkdir -p `dirname $GUAVA_JAR` install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 && valgrind --max-stackframe=2500000 ./tests $TESTRUNS && valgrind --max-stackframe=2500000 ./exhaustiv-tests +after_script: + - cat ./config.log From a111b58c5cfadffbe114cb00c7af137304940047 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 5 Nov 2019 10:56:02 +0000 Subject: [PATCH 22/25] Fix ASM setting in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e6d55f4fbd..1e95904cf1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,6 +59,6 @@ before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 && valgrind --max-stackframe=2500000 ./tests $TESTRUNS && valgrind --max-stackframe=2500000 ./exhaustiv-tests + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-asm=$ASM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 && valgrind --max-stackframe=2500000 ./tests $TESTRUNS && valgrind --max-stackframe=2500000 ./exhaustiv-tests after_script: - cat ./config.log From 540ef2df5f7eec84b395b2e413da770c383bc59a Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 7 Nov 2019 15:48:30 +0000 Subject: [PATCH 23/25] switch to gcc --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e95904cf1..2689bdf399 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ addons: apt: packages: libgmp-dev compiler: - - clang - gcc cache: directories: @@ -16,7 +15,7 @@ env: matrix: fast_finish: true include: - - compiler: clang + - compiler: gcc env: - DVALGRIND=1 - CFLAGS=" -fno-omit-frame-pointer -g" @@ -28,7 +27,7 @@ matrix: apt: packages: - valgrind - - compiler: clang + - compiler: gcc env: - DVALGRIND=1 - CFLAGS="-fno-omit-frame-pointer -g" @@ -40,7 +39,7 @@ matrix: apt: packages: - valgrind - - compiler: clang + - compiler: gcc env: - DVALGRIND=1 - CFLAGS="-fno-omit-frame-pointer -g" From 06595901b7bda652427e964f217281cfe0d97a64 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 7 Nov 2019 16:52:36 +0000 Subject: [PATCH 24/25] fix typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2689bdf399..435e4370ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,6 +58,6 @@ before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-asm=$ASM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 && valgrind --max-stackframe=2500000 ./tests $TESTRUNS && valgrind --max-stackframe=2500000 ./exhaustiv-tests + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-asm=$ASM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 && valgrind --max-stackframe=2500000 ./tests $TESTRUNS && valgrind --max-stackframe=2500000 ./exhaustive-tests after_script: - cat ./config.log From 9e8fe70d85052c911b40e596bfcb39ed0c227c59 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 7 Nov 2019 17:22:57 +0000 Subject: [PATCH 25/25] f typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 435e4370ee..4efd12c342 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,6 +58,6 @@ before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-asm=$ASM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 && valgrind --max-stackframe=2500000 ./tests $TESTRUNS && valgrind --max-stackframe=2500000 ./exhaustive-tests + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-asm=$ASM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 && valgrind --max-stackframe=2500000 ./tests $TESTRUNS && valgrind --max-stackframe=2500000 ./exhaustive_tests after_script: - cat ./config.log