Skip to content

Commit 2f0954e

Browse files
committed
silentpayments: tweak spend pubkey using ecmult_gen_var (~25% scanning speedup for small N)
Note that the tweak t_k is not considered a long-term secret, so using variable-time functions for calculating P_k = B_spend + t_k * G seems fine. This leads to a ~25% scanning speedup if the number of outputs is small (N <= 10): master: ``` $ ./build/bin/bench silentpayments_scan_nomatch Benchmark , Min(us) , Avg(us) , Max(us) silentpayments_scan_nomatch_N=2 , 39.3 , 39.3 , 39.3 silentpayments_scan_nomatch_N=5 , 40.4 , 40.4 , 40.4 silentpayments_scan_nomatch_N=10 , 43.3 , 43.3 , 43.3 silentpayments_scan_nomatch_N=100 , 89.0 , 89.6 , 91.0 silentpayments_scan_nomatch_N=1000 , 560.0 , 563.0 , 568.0 silentpayments_scan_nomatch_N=2323 , 1254.0 , 1259.0 , 1271.0 silentpayments_scan_nomatch_N=23250 , 12196.0 , 12209.0 , 12228.0 ``` PR branch (using ecmult_gen_var for calculating t_k * G): ``` $ ./build/bin/bench silentpayments_scan_nomatch Benchmark , Min(us) , Avg(us) , Max(us) silentpayments_scan_nomatch_N=2 , 30.5 , 30.5 , 30.5 silentpayments_scan_nomatch_N=5 , 31.7 , 31.7 , 31.7 silentpayments_scan_nomatch_N=10 , 34.6 , 34.6 , 34.6 silentpayments_scan_nomatch_N=100 , 80.0 , 81.2 , 85.0 silentpayments_scan_nomatch_N=1000 , 550.0 , 552.0 , 554.0 silentpayments_scan_nomatch_N=2323 , 1239.0 , 1244.0 , 1253.0 silentpayments_scan_nomatch_N=23250 , 12164.0 , 12182.0 , 12214.0 ``` Speedups: N=2: ~28.85% N=5: ~27.44% N=10: ~25.14% N=100: ~10.34% N=1000: ~1.99%
1 parent 53ca31a commit 2f0954e

1 file changed

Lines changed: 16 additions & 3 deletions

File tree

src/modules/silentpayments/main_impl.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include "../../../include/secp256k1_silentpayments.h"
1212

1313
#include "../../eckey.h"
14-
#include "../../ecmult.h"
1514
#include "../../ecmult_const.h"
1615
#include "../../ecmult_gen.h"
1716
#include "../../group.h"
@@ -148,6 +147,20 @@ static int secp256k1_silentpayments_create_output_tweak(const secp256k1_context
148147
return (!secp256k1_scalar_is_zero(t_k_scalar)) & (!overflow);
149148
}
150149

150+
/* faster variant of _eckey_pubkey_tweak_add, taking advantage of variable-time generator point multiplication */
151+
static int secp256k1_silentpayments_pubkey_tweak_add(secp256k1_ge *pubkey, const secp256k1_scalar *tweak) {
152+
secp256k1_gej tweak_g_gej, tweaked_pubkey_gej;
153+
154+
secp256k1_ecmult_gen_var_gej(&tweak_g_gej, tweak);
155+
secp256k1_gej_add_ge_var(&tweaked_pubkey_gej, &tweak_g_gej, pubkey, NULL);
156+
if (secp256k1_gej_is_infinity(&tweaked_pubkey_gej)) {
157+
return 0;
158+
}
159+
secp256k1_ge_set_gej_var(pubkey, &tweaked_pubkey_gej);
160+
161+
return 1;
162+
}
163+
151164
static int secp256k1_silentpayments_create_output_pubkey(const secp256k1_context *ctx, secp256k1_xonly_pubkey *output_xonly, const unsigned char *shared_secret33, const secp256k1_pubkey *spend_pubkey, uint32_t k) {
152165
secp256k1_ge output_ge;
153166
secp256k1_scalar t_k_scalar;
@@ -171,7 +184,7 @@ static int secp256k1_silentpayments_create_output_pubkey(const secp256k1_context
171184
* to protect against this function being called with malicious inputs, i.e.,
172185
* spend_pubkey = -(_create_output_tweak(shared_secret33, k))*G
173186
*/
174-
if (!secp256k1_eckey_pubkey_tweak_add(&output_ge, &t_k_scalar)) {
187+
if (!secp256k1_silentpayments_pubkey_tweak_add(&output_ge, &t_k_scalar)) {
175188
secp256k1_scalar_clear(&t_k_scalar);
176189
return 0;
177190
}
@@ -701,7 +714,7 @@ int secp256k1_silentpayments_recipient_scan_outputs(
701714
/* Calculate unlabeled_output = unlabeled_spend_pubkey + t_k * G.
702715
* This can fail if t_k * G is the negation of unlabeled_spend_pubkey, but this happens only with negligible
703716
* probability for honestly created unlabeled_spend_pubkey as t_k is the output of a hash function. */
704-
if (!secp256k1_eckey_pubkey_tweak_add(&unlabeled_output_ge, &t_k_scalar)) {
717+
if (!secp256k1_silentpayments_pubkey_tweak_add(&unlabeled_output_ge, &t_k_scalar)) {
705718
/* Leaking these values would break indistinguishability of the transaction, so clear them. */
706719
secp256k1_scalar_clear(&t_k_scalar);
707720
secp256k1_memclear_explicit(&shared_secret, sizeof(shared_secret));

0 commit comments

Comments
 (0)