@@ -64,7 +64,7 @@ static void secp256k1_silentpayments_calculate_input_hash(unsigned char *input_h
64
64
secp256k1_sha256_finalize (& hash , input_hash );
65
65
}
66
66
67
- static void secp256k1_silentpayments_create_shared_secret (unsigned char * shared_secret33 , const secp256k1_scalar * secret_component , const secp256k1_ge * public_component ) {
67
+ static void secp256k1_silentpayments_create_shared_secret (const secp256k1_context * ctx , unsigned char * shared_secret33 , const secp256k1_scalar * secret_component , const secp256k1_ge * public_component ) {
68
68
secp256k1_gej ss_j ;
69
69
secp256k1_ge ss ;
70
70
size_t len ;
@@ -73,6 +73,7 @@ static void secp256k1_silentpayments_create_shared_secret(unsigned char *shared_
73
73
/* Compute shared_secret = tweaked_secret_component * Public_component */
74
74
secp256k1_ecmult_const (& ss_j , public_component , secret_component );
75
75
secp256k1_ge_set_gej (& ss , & ss_j );
76
+ secp256k1_declassify (ctx , & ss , sizeof (ss ));
76
77
/* This can only fail if the shared secret is the point at infinity, which should be
77
78
* impossible at this point, considering we have already validated the public key and
78
79
* the secret key being used
@@ -132,16 +133,26 @@ static int secp256k1_silentpayments_create_output_pubkey(const secp256k1_context
132
133
* B_spend + t_k*G is the point at infinity.
133
134
*/
134
135
secp256k1_silentpayments_create_t_k (& t_k_scalar , shared_secret33 , k );
135
- ret = secp256k1_pubkey_load (ctx , & P_output_ge , recipient_spend_pubkey );
136
- ret &= secp256k1_eckey_pubkey_tweak_add (& P_output_ge , & t_k_scalar );
136
+ if (!secp256k1_pubkey_load (ctx , & P_output_ge , recipient_spend_pubkey )) {
137
+ secp256k1_scalar_clear (& t_k_scalar );
138
+ return 0 ;
139
+ }
140
+ ret = secp256k1_eckey_pubkey_tweak_add (& P_output_ge , & t_k_scalar );
141
+ /* tweak add only fails if t_k_scalar is equal to the dlog of P_output_ge, but t_k_scalar is the output of a collision resistant hash function. */
142
+ /* TODO: consider declassify ret */
143
+ /* TODO: but we don't want to imply this can never happen */
144
+ VERIFY_CHECK (ret );
145
+ #ifndef VERIFY
146
+ (void ) ret ;
147
+ #endif
137
148
secp256k1_xonly_pubkey_save (P_output_xonly , & P_output_ge );
138
149
139
150
/* While not technically "secret" data, explicitly clear t_k since leaking this would allow an attacker
140
151
* to identify the resulting transaction as a silent payments transaction and potentially link the transaction
141
152
* back to the silent payment address
142
153
*/
143
154
secp256k1_scalar_clear (& t_k_scalar );
144
- return ret ;
155
+ return 1 ;
145
156
}
146
157
147
158
int secp256k1_silentpayments_sender_create_outputs (
@@ -163,7 +174,7 @@ int secp256k1_silentpayments_sender_create_outputs(
163
174
unsigned char shared_secret [33 ];
164
175
secp256k1_silentpayments_recipient last_recipient ;
165
176
int overflow = 0 ;
166
- int ret = 1 ;
177
+ int ret ;
167
178
168
179
/* Sanity check inputs. */
169
180
VERIFY_CHECK (ctx != NULL );
@@ -191,34 +202,55 @@ int secp256k1_silentpayments_sender_create_outputs(
191
202
/* Compute input private keys sum: a_sum = a_1 + a_2 + ... + a_n */
192
203
a_sum_scalar = secp256k1_scalar_zero ;
193
204
for (i = 0 ; i < n_plain_seckeys ; i ++ ) {
194
- /* TODO: in other places where _set_b32_seckey is called, its normally followed by a _cmov call
195
- * Do we need that here and if so, is it better to call it after the loop is finished?
196
- */
197
- ret &= secp256k1_scalar_set_b32_seckey (& addend , plain_seckeys [i ]);
205
+ ret = secp256k1_scalar_set_b32_seckey (& addend , plain_seckeys [i ]);
206
+ /* TODO: We can declassify return value, because scalar set only fails if the seckey is invalid */
207
+ secp256k1_declassify (ctx , & ret , sizeof (ret ));
208
+ if (!ret ) {
209
+ /* TODO: clear a_sum_scalar */
210
+ printf ("b\n" );
211
+ return 0 ;
212
+ }
198
213
secp256k1_scalar_add (& a_sum_scalar , & a_sum_scalar , & addend );
199
214
}
200
215
/* private keys used for taproot outputs have to be negated if they resulted in an odd point */
201
216
for (i = 0 ; i < n_taproot_seckeys ; i ++ ) {
202
217
secp256k1_ge addend_point ;
203
- /* TODO: why don't we need _cmov here after calling keypair_load? Because the ret is declassified? */
204
- ret &= secp256k1_keypair_load (ctx , & addend , & addend_point , taproot_seckeys [i ]);
218
+ ret = secp256k1_keypair_load (ctx , & addend , & addend_point , taproot_seckeys [i ]);
219
+ /* TODO: we can declassify return value */
220
+ if (!ret ) {
221
+ /* TODO: clear a_sum_scalar */
222
+ printf ("a\n" );
223
+ return 0 ;
224
+ }
225
+ secp256k1_declassify (ctx , & ret , sizeof (ret ));
205
226
if (secp256k1_fe_is_odd (& addend_point .y )) {
206
227
secp256k1_scalar_negate (& addend , & addend );
207
228
}
208
229
secp256k1_scalar_add (& a_sum_scalar , & a_sum_scalar , & addend );
209
230
}
210
231
/* If there are any failures in loading/summing up the secret keys, fail early */
211
- if (!ret || secp256k1_scalar_is_zero (& a_sum_scalar )) {
232
+ /* TODO: can we declassify this? */
233
+ /* Yes: We assume the adversary has access to a_sum_scalar*G */
234
+ ret = secp256k1_scalar_is_zero (& a_sum_scalar );
235
+ secp256k1_declassify (ctx , & ret , sizeof (ret ));
236
+ if (ret ) {
237
+ printf ("z\n" );
212
238
return 0 ;
213
239
}
214
240
/* Compute input_hash = hash(outpoint_L || (a_sum * G)) */
215
241
secp256k1_ecmult_gen (& ctx -> ecmult_gen_ctx , & A_sum_gej , & a_sum_scalar );
216
242
secp256k1_ge_set_gej (& A_sum_ge , & A_sum_gej );
243
+ /* TODO: comment */
244
+ secp256k1_declassify (ctx , & A_sum_ge , sizeof (A_sum_ge ));
217
245
218
246
/* Calculate the input hash and tweak a_sum, i.e., a_sum_tweaked = a_sum * input_hash */
219
247
secp256k1_silentpayments_calculate_input_hash (input_hash , outpoint_smallest36 , & A_sum_ge );
220
248
secp256k1_scalar_set_b32 (& input_hash_scalar , input_hash , & overflow );
221
- ret &= !overflow ;
249
+ /* TODO: consider VERIFY_CHECK ??? */
250
+ if (overflow ) {
251
+ printf ("y\n" );
252
+ return 0 ;
253
+ }
222
254
secp256k1_scalar_mul (& a_sum_scalar , & a_sum_scalar , & input_hash_scalar );
223
255
secp256k1_silentpayments_recipient_sort (ctx , recipients , n_recipients );
224
256
last_recipient = * recipients [0 ];
@@ -231,12 +263,15 @@ int secp256k1_silentpayments_sender_create_outputs(
231
263
* the public key is valid.
232
264
*/
233
265
secp256k1_ge pk ;
234
- ret &= secp256k1_pubkey_load (ctx , & pk , & recipients [i ]-> scan_pubkey );
235
- if (!ret ) break ;
236
- secp256k1_silentpayments_create_shared_secret (shared_secret , & a_sum_scalar , & pk );
266
+ if (!secp256k1_pubkey_load (ctx , & pk , & recipients [i ]-> scan_pubkey )) break ;
267
+ secp256k1_silentpayments_create_shared_secret (ctx , shared_secret , & a_sum_scalar , & pk );
237
268
k = 0 ;
238
269
}
239
- ret &= secp256k1_silentpayments_create_output_pubkey (ctx , generated_outputs [recipients [i ]-> index ], shared_secret , & recipients [i ]-> spend_pubkey , k );
270
+ if (!secp256k1_silentpayments_create_output_pubkey (ctx , generated_outputs [recipients [i ]-> index ], shared_secret , & recipients [i ]-> spend_pubkey , k )) {
271
+ /* TODO: clean up */
272
+ printf ("x\n" );
273
+ return 0 ;
274
+ }
240
275
k ++ ;
241
276
last_recipient = * recipients [i ];
242
277
}
@@ -249,7 +284,7 @@ int secp256k1_silentpayments_sender_create_outputs(
249
284
* and potentially link the transaction back to a silent payment address
250
285
*/
251
286
memset (& shared_secret , 0 , sizeof (shared_secret ));
252
- return ret ;
287
+ return 1 ;
253
288
}
254
289
255
290
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/Label". */
@@ -471,12 +506,21 @@ int secp256k1_silentpayments_recipient_scan_outputs(
471
506
* Recall: a scan key isnt really "secret" data in that leaking the scan key will only leak privacy
472
507
* In this respect, a scan key is functionally equivalent to an xpub
473
508
*/
474
- ret &= secp256k1_scalar_set_b32_seckey (& rsk_scalar , recipient_scan_key );
475
- ret &= secp256k1_silentpayments_recipient_public_data_load_pubkey (ctx , & A_sum , public_data );
476
- ret &= secp256k1_pubkey_load (ctx , & A_sum_ge , & A_sum );
477
- ret &= secp256k1_pubkey_load (ctx , & recipient_spend_pubkey_ge , recipient_spend_pubkey );
478
- /* If there is something wrong with the recipient scan key, recipient spend pubkey, or the public data, return early */
509
+ /* If there is something wrong with the recipient scan key, recipient spend pubkey, or the public data, then return */
510
+ ret = secp256k1_scalar_set_b32_seckey (& rsk_scalar , recipient_scan_key );
511
+ /* TODO: only fails in case of invalid key */
512
+ secp256k1_declassify (ctx , & ret , sizeof (ret ));
479
513
if (!ret ) {
514
+ /* consider clearing */
515
+ return 0 ;
516
+ }
517
+ if (!secp256k1_silentpayments_recipient_public_data_load_pubkey (ctx , & A_sum , public_data )) {
518
+ return 0 ;
519
+ }
520
+ if (!secp256k1_pubkey_load (ctx , & A_sum_ge , & A_sum )) {
521
+ return 0 ;
522
+ }
523
+ if (!secp256k1_pubkey_load (ctx , & recipient_spend_pubkey_ge , recipient_spend_pubkey )) {
480
524
return 0 ;
481
525
}
482
526
combined = (int )public_data -> data [0 ];
@@ -487,10 +531,12 @@ int secp256k1_silentpayments_recipient_scan_outputs(
487
531
488
532
secp256k1_silentpayments_recipient_public_data_load_input_hash (input_hash , public_data );
489
533
secp256k1_scalar_set_b32 (& input_hash_scalar , input_hash , & overflow );
534
+ if (overflow ) {
535
+ return 0 ;
536
+ }
490
537
secp256k1_scalar_mul (& rsk_scalar , & rsk_scalar , & input_hash_scalar );
491
- ret &= !overflow ;
492
538
}
493
- secp256k1_silentpayments_create_shared_secret (shared_secret , & rsk_scalar , & A_sum_ge );
539
+ secp256k1_silentpayments_create_shared_secret (ctx , shared_secret , & rsk_scalar , & A_sum_ge );
494
540
495
541
found_idx = 0 ;
496
542
n_found = 0 ;
@@ -503,7 +549,8 @@ int secp256k1_silentpayments_recipient_scan_outputs(
503
549
/* Calculate P_output = B_spend + t_k * G
504
550
* This can fail if t_k overflows the curver order, but this is statistically improbable
505
551
*/
506
- ret &= secp256k1_eckey_pubkey_tweak_add (& P_output_ge , & t_k_scalar );
552
+ ret = secp256k1_eckey_pubkey_tweak_add (& P_output_ge , & t_k_scalar );
553
+ VERIFY_CHECK (ret );
507
554
found = 0 ;
508
555
secp256k1_xonly_pubkey_save (& P_output_xonly , & P_output_ge );
509
556
for (i = 0 ; i < n_tx_outputs ; i ++ ) {
@@ -560,7 +607,9 @@ int secp256k1_silentpayments_recipient_scan_outputs(
560
607
* created by hashing data, practically speaking this would only happen if an attacker
561
608
* tricked us into using a particular label_tweak (deviating from the protocol).
562
609
*/
563
- ret &= secp256k1_ec_seckey_tweak_add (ctx , found_outputs [n_found ]-> tweak , label_tweak );
610
+ ret = secp256k1_ec_seckey_tweak_add (ctx , found_outputs [n_found ]-> tweak , label_tweak );
611
+ /* TODO: do we really want to do that */
612
+ VERIFY_CHECK (ret );
564
613
secp256k1_pubkey_save (& found_outputs [n_found ]-> label , & label_ge );
565
614
} else {
566
615
found_outputs [n_found ]-> found_with_label = 0 ;
@@ -609,7 +658,7 @@ int secp256k1_silentpayments_recipient_create_shared_secret(const secp256k1_cont
609
658
if (!ret ) {
610
659
return 0 ;
611
660
}
612
- secp256k1_silentpayments_create_shared_secret (shared_secret33 , & rsk , & A_tweaked_ge );
661
+ secp256k1_silentpayments_create_shared_secret (ctx , shared_secret33 , & rsk , & A_tweaked_ge );
613
662
614
663
/* Explicitly clear secrets */
615
664
secp256k1_scalar_clear (& rsk );
0 commit comments