Bitcoin ABC 0.30.5
P2P Digital Currency
tests_exhaustive_impl.h
Go to the documentation of this file.
1/***********************************************************************
2 * Copyright (c) 2020 Pieter Wuille *
3 * Distributed under the MIT software license, see the accompanying *
4 * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
5 ***********************************************************************/
6
7#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
8#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
9
12
13static const unsigned char invalid_pubkey_bytes[][32] = {
14 /* 0 */
15 {
16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
18 },
19 /* 2 */
20 {
21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
23 },
24 /* order */
25 {
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28 ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 24) & 0xFF,
29 ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 16) & 0xFF,
30 ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 8) & 0xFF,
31 (EXHAUSTIVE_TEST_ORDER + 0UL) & 0xFF
32 },
33 /* order + 1 */
34 {
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 24) & 0xFF,
38 ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 16) & 0xFF,
39 ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 8) & 0xFF,
40 (EXHAUSTIVE_TEST_ORDER + 1UL) & 0xFF
41 },
42 /* field size */
43 {
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F
46 },
47 /* field size + 1 (note that 1 is legal) */
48 {
49 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
50 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30
51 },
52 /* 2^256 - 1 */
53 {
54 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
55 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
56 }
57};
58
59#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0]))
60
61static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg,
62 size_t msglen,
63 const unsigned char *key32, const unsigned char *xonly_pk32,
64 const unsigned char *algo, size_t algolen,
65 void* data) {
67 int *idata = data;
68 (void)msg;
69 (void)msglen;
70 (void)key32;
71 (void)xonly_pk32;
72 (void)algo;
73 (void)algolen;
74 secp256k1_scalar_set_int(&s, *idata);
75 secp256k1_scalar_get_b32(nonce32, &s);
76 return 1;
77}
78
79static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) {
80 int d;
81 uint64_t iter = 0;
82 /* Iterate over the possible public keys to verify against (through their corresponding DL d). */
83 for (d = 1; d <= EXHAUSTIVE_TEST_ORDER / 2; ++d) {
84 int actual_d;
85 unsigned k;
86 unsigned char pk32[32];
87 memcpy(pk32, xonly_pubkey_bytes[d - 1], 32);
88 actual_d = parities[d - 1] ? EXHAUSTIVE_TEST_ORDER - d : d;
89 /* Iterate over the possible valid first 32 bytes in the signature, through their corresponding DL k.
90 Values above EXHAUSTIVE_TEST_ORDER/2 refer to the entries in invalid_pubkey_bytes. */
91 for (k = 1; k <= EXHAUSTIVE_TEST_ORDER / 2 + NUM_INVALID_KEYS; ++k) {
92 unsigned char sig64[64];
93 int actual_k = -1;
94 int e_done[EXHAUSTIVE_TEST_ORDER] = {0};
95 int e_count_done = 0;
96 if (skip_section(&iter)) continue;
97 if (k <= EXHAUSTIVE_TEST_ORDER / 2) {
98 memcpy(sig64, xonly_pubkey_bytes[k - 1], 32);
99 actual_k = parities[k - 1] ? EXHAUSTIVE_TEST_ORDER - k : k;
100 } else {
101 memcpy(sig64, invalid_pubkey_bytes[k - 1 - EXHAUSTIVE_TEST_ORDER / 2], 32);
102 }
103 /* Randomly generate messages until all challenges have been hit. */
104 while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
106 unsigned char msg32[32];
108 secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32);
109 /* Only do work if we hit a challenge we haven't tried before. */
110 if (!e_done[e]) {
111 /* Iterate over the possible valid last 32 bytes in the signature.
112 0..order=that s value; order+1=random bytes */
113 int count_valid = 0, s;
114 for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) {
115 int expect_valid, valid;
116 if (s <= EXHAUSTIVE_TEST_ORDER) {
119 secp256k1_scalar_get_b32(sig64 + 32, &s_s);
120 expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER &&
121 (s_s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER);
122 } else {
123 secp256k1_testrand256(sig64 + 32);
124 expect_valid = 0;
125 }
126 valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]);
127 CHECK(valid == expect_valid);
128 count_valid += valid;
129 }
130 /* Exactly one s value must verify, unless R is illegal. */
131 CHECK(count_valid == (actual_k != -1));
132 /* Don't retry other messages that result in the same challenge. */
133 e_done[e] = 1;
134 ++e_count_done;
135 }
136 }
137 }
138 }
139}
140
141static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) {
142 int d, k;
143 uint64_t iter = 0;
145
146 /* Loop over keys. */
147 for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) {
148 int actual_d = d;
149 if (parities[d - 1]) actual_d = EXHAUSTIVE_TEST_ORDER - d;
150 /* Loop over nonces. */
151 for (k = 1; k < EXHAUSTIVE_TEST_ORDER; ++k) {
152 int e_done[EXHAUSTIVE_TEST_ORDER] = {0};
153 int e_count_done = 0;
154 unsigned char msg32[32];
155 unsigned char sig64[64];
156 int actual_k = k;
157 if (skip_section(&iter)) continue;
159 extraparams.ndata = &k;
160 if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k;
161 /* Generate random messages until all challenges have been tried. */
162 while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
165 secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]);
166 /* Only do work if we hit a challenge we haven't tried before. */
167 if (!e_done[e]) {
168 secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER;
169 unsigned char expected_s_bytes[32];
170 secp256k1_scalar_get_b32(expected_s_bytes, &expected_s);
171 /* Invoke the real function to construct a signature. */
172 CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams));
173 /* The first 32 bytes must match the xonly pubkey for the specified k. */
174 CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0);
175 /* The last 32 bytes must match the expected s value. */
176 CHECK(secp256k1_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0);
177 /* Don't retry other messages that result in the same challenge. */
178 e_done[e] = 1;
179 ++e_count_done;
180 }
181 }
182 }
183 }
184}
185
189 int parity[EXHAUSTIVE_TEST_ORDER - 1];
190 unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32];
191 unsigned i;
192
193 /* Verify that all invalid_pubkey_bytes are actually invalid. */
194 for (i = 0; i < NUM_INVALID_KEYS; ++i) {
197 }
198
199 /* Construct keypairs and xonly-pubkeys for the entire group. */
200 for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) {
201 secp256k1_scalar scalar_i;
202 unsigned char buf[32];
203 secp256k1_scalar_set_int(&scalar_i, i);
204 secp256k1_scalar_get_b32(buf, &scalar_i);
205 CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf));
206 CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1]));
207 CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1]));
208 }
209
210 test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity);
211 test_exhaustive_schnorrsig_verify(ctx, xonly_pubkey, xonly_pubkey_bytes, parity);
212}
213
214#endif
secp256k1_context * ctx
static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v)
Set a scalar to an unsigned integer.
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar *a)
Convert a scalar to a byte array.
static void secp256k1_schnorrsig_challenge(secp256k1_scalar *e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32)
Definition: main_impl.h:109
static void test_exhaustive_schnorrsig(const secp256k1_context *ctx)
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data)
static const unsigned char invalid_pubkey_bytes[][32]
#define NUM_INVALID_KEYS
static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey *pubkeys, unsigned char(*xonly_pubkey_bytes)[32], const int *parities)
static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char(*xonly_pubkey_bytes)[32], const secp256k1_keypair *keypairs, const int *parities)
static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2, size_t n)
Semantics like memcmp.
Definition: util.h:224
#define CHECK(cond)
Definition: util.h:53
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)
Serialize an xonly_pubkey object into a 32-byte sequence.
Definition: main_impl.h:43
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(const secp256k1_context *ctx, secp256k1_keypair *keypair, const unsigned char *seckey) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Compute the keypair for a secret key.
Definition: main_impl.h:197
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(const secp256k1_context *ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4)
Get the x-only public key from a keypair.
Definition: main_impl.h:235
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)
Parse a 32-byte sequence into a xonly_pubkey object.
Definition: main_impl.h:21
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT
SECP256K1_API int secp256k1_schnorrsig_sign_custom(const secp256k1_context *ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5)
Create a Schnorr signature with a more flexible API.
Definition: main_impl.h:192
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(const secp256k1_context *ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_xonly_pubkey *pubkey) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5)
Verify a Schnorr signature.
Definition: main_impl.h:207
Opaque data structure that holds a keypair consisting of a secret and a public key.
A scalar modulo the group order of the secp256k1 curve.
Definition: scalar_4x64.h:13
Data structure that contains additional arguments for schnorrsig_sign_custom.
secp256k1_nonce_function_hardened noncefp
Opaque data structure that holds a parsed and valid "x-only" public key.
static void secp256k1_testrand256(unsigned char *b32)
Generate a pseudorandom 32-byte array.
static SECP256K1_INLINE int skip_section(uint64_t *iter)
#define EXHAUSTIVE_TEST_ORDER