@@ -137,9 +137,184 @@ void test_xonly_pubkey(void) {
137
137
secp256k1_context_destroy (verify );
138
138
}
139
139
140
+ void test_xonly_pubkey_tweak (void ) {
141
+ unsigned char zeros64 [64 ] = { 0 };
142
+ unsigned char overflows [32 ];
143
+ unsigned char sk [32 ];
144
+ secp256k1_pubkey internal_pk ;
145
+ secp256k1_xonly_pubkey internal_xonly_pk ;
146
+ secp256k1_pubkey output_pk ;
147
+ int pk_parity ;
148
+ unsigned char tweak [32 ];
149
+ int i ;
150
+
151
+ int ecount ;
152
+ secp256k1_context * none = api_test_context (SECP256K1_CONTEXT_NONE , & ecount );
153
+ secp256k1_context * sign = api_test_context (SECP256K1_CONTEXT_SIGN , & ecount );
154
+ secp256k1_context * verify = api_test_context (SECP256K1_CONTEXT_VERIFY , & ecount );
155
+
156
+ memset (overflows , 0xff , sizeof (overflows ));
157
+ secp256k1_rand256 (tweak );
158
+ secp256k1_rand256 (sk );
159
+ CHECK (secp256k1_ec_pubkey_create (ctx , & internal_pk , sk ) == 1 );
160
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (none , & internal_xonly_pk , & pk_parity , & internal_pk ) == 1 );
161
+
162
+ ecount = 0 ;
163
+ CHECK (secp256k1_xonly_pubkey_tweak_add (none , & output_pk , & internal_xonly_pk , tweak ) == 0 );
164
+ CHECK (ecount == 1 );
165
+ CHECK (secp256k1_xonly_pubkey_tweak_add (sign , & output_pk , & internal_xonly_pk , tweak ) == 0 );
166
+ CHECK (ecount == 2 );
167
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , tweak ) == 1 );
168
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , NULL , & internal_xonly_pk , tweak ) == 0 );
169
+ CHECK (ecount == 3 );
170
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , NULL , tweak ) == 0 );
171
+ CHECK (ecount == 4 );
172
+ /* NULL internal_xonly_pk zeroes the output_pk */
173
+ CHECK (memcmp (& output_pk , zeros64 , sizeof (output_pk )) == 0 );
174
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , NULL ) == 0 );
175
+ CHECK (ecount == 5 );
176
+ /* NULL tweak zeroes the output_pk */
177
+ CHECK (memcmp (& output_pk , zeros64 , sizeof (output_pk )) == 0 );
178
+
179
+ /* Invalid tweak zeroes the output_pk */
180
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , overflows ) == 0 );
181
+ CHECK (memcmp (& output_pk , zeros64 , sizeof (output_pk )) == 0 );
182
+
183
+ /* A zero tweak is fine */
184
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , zeros64 ) == 1 );
185
+
186
+ /* Fails if the resulting key was infinity */
187
+ for (i = 0 ; i < count ; i ++ ) {
188
+ secp256k1_scalar scalar_tweak ;
189
+ /* Because sk may be negated before adding, we need to try with tweak =
190
+ * sk as well as tweak = -sk. */
191
+ secp256k1_scalar_set_b32 (& scalar_tweak , sk , NULL );
192
+ secp256k1_scalar_negate (& scalar_tweak , & scalar_tweak );
193
+ secp256k1_scalar_get_b32 (tweak , & scalar_tweak );
194
+ CHECK ((secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , sk ) == 0 )
195
+ || (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , tweak ) == 0 ));
196
+ CHECK (memcmp (& output_pk , zeros64 , sizeof (output_pk )) == 0 );
197
+ }
198
+
199
+ /* Invalid pk with a valid tweak */
200
+ memset (& internal_xonly_pk , 0 , sizeof (internal_xonly_pk ));
201
+ secp256k1_rand256 (tweak );
202
+ ecount = 0 ;
203
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , tweak ) == 0 );
204
+ CHECK (ecount == 1 );
205
+ CHECK (memcmp (& output_pk , zeros64 , sizeof (output_pk )) == 0 );
206
+
207
+ secp256k1_context_destroy (none );
208
+ secp256k1_context_destroy (sign );
209
+ secp256k1_context_destroy (verify );
210
+ }
211
+
212
+ void test_xonly_pubkey_tweak_check (void ) {
213
+ unsigned char zeros64 [64 ] = { 0 };
214
+ unsigned char overflows [32 ];
215
+ unsigned char sk [32 ];
216
+ secp256k1_pubkey internal_pk ;
217
+ secp256k1_xonly_pubkey internal_xonly_pk ;
218
+ secp256k1_pubkey output_pk ;
219
+ secp256k1_xonly_pubkey output_xonly_pk ;
220
+ unsigned char output_pk32 [32 ];
221
+ unsigned char buf32 [32 ];
222
+ int pk_parity ;
223
+ unsigned char tweak [32 ];
224
+
225
+ int ecount ;
226
+ secp256k1_context * none = api_test_context (SECP256K1_CONTEXT_NONE , & ecount );
227
+ secp256k1_context * sign = api_test_context (SECP256K1_CONTEXT_SIGN , & ecount );
228
+ secp256k1_context * verify = api_test_context (SECP256K1_CONTEXT_VERIFY , & ecount );
229
+
230
+ memset (overflows , 0xff , sizeof (overflows ));
231
+ secp256k1_rand256 (tweak );
232
+ secp256k1_rand256 (sk );
233
+ CHECK (secp256k1_ec_pubkey_create (ctx , & internal_pk , sk ) == 1 );
234
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (none , & internal_xonly_pk , & pk_parity , & internal_pk ) == 1 );
235
+
236
+ ecount = 0 ;
237
+ CHECK (secp256k1_xonly_pubkey_tweak_add (verify , & output_pk , & internal_xonly_pk , tweak ) == 1 );
238
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (verify , & output_xonly_pk , & pk_parity , & output_pk ) == 1 );
239
+ CHECK (secp256k1_xonly_pubkey_serialize (ctx , buf32 , & output_xonly_pk ) == 1 );
240
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (none , buf32 , pk_parity , & internal_xonly_pk , tweak ) == 0 );
241
+ CHECK (ecount == 1 );
242
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (sign , buf32 , pk_parity , & internal_xonly_pk , tweak ) == 0 );
243
+ CHECK (ecount == 2 );
244
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (verify , buf32 , pk_parity , & internal_xonly_pk , tweak ) == 1 );
245
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (verify , NULL , pk_parity , & internal_xonly_pk , tweak ) == 0 );
246
+ CHECK (ecount == 3 );
247
+ /* invalid pk_parity value */
248
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (verify , buf32 , 2 , & internal_xonly_pk , tweak ) == 0 );
249
+ CHECK (ecount == 3 );
250
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (verify , buf32 , pk_parity , NULL , tweak ) == 0 );
251
+ CHECK (ecount == 4 );
252
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (verify , buf32 , pk_parity , & internal_xonly_pk , NULL ) == 0 );
253
+ CHECK (ecount == 5 );
254
+
255
+ memset (tweak , 1 , sizeof (tweak ));
256
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (ctx , & internal_xonly_pk , NULL , & internal_pk ) == 1 );
257
+ CHECK (secp256k1_xonly_pubkey_tweak_add (ctx , & output_pk , & internal_xonly_pk , tweak ) == 1 );
258
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (ctx , & output_xonly_pk , & pk_parity , & output_pk ) == 1 );
259
+ CHECK (secp256k1_xonly_pubkey_serialize (ctx , output_pk32 , & output_xonly_pk ) == 1 );
260
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (ctx , output_pk32 , pk_parity , & internal_xonly_pk , tweak ) == 1 );
261
+
262
+ /* Wrong pk_parity */
263
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (ctx , output_pk32 , !pk_parity , & internal_xonly_pk , tweak ) == 0 );
264
+ /* Wrong public key */
265
+ CHECK (secp256k1_xonly_pubkey_serialize (ctx , buf32 , & internal_xonly_pk ) == 1 );
266
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (ctx , buf32 , pk_parity , & internal_xonly_pk , tweak ) == 0 );
267
+
268
+ /* Overflowing tweak not allowed */
269
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (ctx , output_pk32 , pk_parity , & internal_xonly_pk , overflows ) == 0 );
270
+ CHECK (secp256k1_xonly_pubkey_tweak_add (ctx , & output_pk , & internal_xonly_pk , overflows ) == 0 );
271
+ CHECK (memcmp (& output_pk , zeros64 , sizeof (output_pk )) == 0 );
272
+ CHECK (ecount == 5 );
273
+
274
+ secp256k1_context_destroy (none );
275
+ secp256k1_context_destroy (sign );
276
+ secp256k1_context_destroy (verify );
277
+ }
278
+
279
+ /* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
280
+ * additional pubkeys by calling tweak_add. Then verifies every tweak starting
281
+ * from the last pubkey. */
282
+ #define N_PUBKEYS 32
283
+ void test_xonly_pubkey_tweak_recursive (void ) {
284
+ unsigned char sk [32 ];
285
+ secp256k1_pubkey pk [N_PUBKEYS ];
286
+ unsigned char pk_serialized [32 ];
287
+ unsigned char tweak [N_PUBKEYS - 1 ][32 ];
288
+ int i ;
289
+
290
+ secp256k1_rand256 (sk );
291
+ CHECK (secp256k1_ec_pubkey_create (ctx , & pk [0 ], sk ) == 1 );
292
+ /* Add tweaks */
293
+ for (i = 0 ; i < N_PUBKEYS - 1 ; i ++ ) {
294
+ secp256k1_xonly_pubkey xonly_pk ;
295
+ memset (tweak [i ], i + 1 , sizeof (tweak [i ]));
296
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (ctx , & xonly_pk , NULL , & pk [i ]) == 1 );
297
+ CHECK (secp256k1_xonly_pubkey_tweak_add (ctx , & pk [i + 1 ], & xonly_pk , tweak [i ]) == 1 );
298
+ }
299
+
300
+ /* Verify tweaks */
301
+ for (i = N_PUBKEYS - 1 ; i > 0 ; i -- ) {
302
+ secp256k1_xonly_pubkey xonly_pk ;
303
+ int pk_parity ;
304
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (ctx , & xonly_pk , & pk_parity , & pk [i ]) == 1 );
305
+ CHECK (secp256k1_xonly_pubkey_serialize (ctx , pk_serialized , & xonly_pk ) == 1 );
306
+ CHECK (secp256k1_xonly_pubkey_from_pubkey (ctx , & xonly_pk , NULL , & pk [i - 1 ]) == 1 );
307
+ CHECK (secp256k1_xonly_pubkey_tweak_add_check (ctx , pk_serialized , pk_parity , & xonly_pk , tweak [i - 1 ]) == 1 );
308
+ }
309
+ }
310
+ #undef N_PUBKEYS
311
+
140
312
void run_extrakeys_tests (void ) {
141
313
/* xonly key test cases */
142
314
test_xonly_pubkey ();
315
+ test_xonly_pubkey_tweak ();
316
+ test_xonly_pubkey_tweak_check ();
317
+ test_xonly_pubkey_tweak_recursive ();
143
318
}
144
319
145
320
#endif
0 commit comments