Skip to content

Commit d3fbae5

Browse files
committed
batch, extrakeys: Add benchmark for batch verify and tweak_add_check
This commit adds benchmarks for Schnorr signature batch verification,Tweaked pubkey check batch verification, and Tweaked pubkey check (single verification). For batch verify benchmark, the number of sigs (or checks) in the batch varies from 1 to SECP256K1_BENCH_ITERS with a 20% increment.
1 parent 8a77b2c commit d3fbae5

File tree

4 files changed

+228
-15
lines changed

4 files changed

+228
-15
lines changed

src/bench.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,33 @@ void help(int default_iters) {
3434
printf("Usage: ./bench [args]\n");
3535
printf("By default, all benchmarks will be run.\n");
3636
printf("args:\n");
37-
printf(" help : display this help and exit\n");
38-
printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
39-
printf(" ecdsa_sign : ECDSA siging algorithm\n");
40-
printf(" ecdsa_verify : ECDSA verification algorithm\n");
37+
printf(" help : display this help and exit\n");
38+
printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
39+
printf(" ecdsa_sign : ECDSA siging algorithm\n");
40+
printf(" ecdsa_verify : ECDSA verification algorithm\n");
4141

4242
#ifdef ENABLE_MODULE_RECOVERY
43-
printf(" ecdsa_recover : ECDSA public key recovery algorithm\n");
43+
printf(" ecdsa_recover : ECDSA public key recovery algorithm\n");
4444
#endif
4545

4646
#ifdef ENABLE_MODULE_ECDH
47-
printf(" ecdh : ECDH key exchange algorithm\n");
47+
printf(" ecdh : ECDH key exchange algorithm\n");
4848
#endif
4949

5050
#ifdef ENABLE_MODULE_SCHNORRSIG
51-
printf(" schnorrsig : all Schnorr signature algorithms (sign, verify)\n");
52-
printf(" schnorrsig_sign : Schnorr sigining algorithm\n");
53-
printf(" schnorrsig_verify : Schnorr verification algorithm\n");
51+
printf(" schnorrsig : all Schnorr signature algorithms (sign, verify)\n");
52+
printf(" schnorrsig_sign : Schnorr sigining algorithm\n");
53+
printf(" schnorrsig_verify : Schnorr verification algorithm\n");
54+
# ifdef ENABLE_MODULE_BATCH
55+
printf(" schnorrsig_batch_verify : Batch verification of Schnorr signatures\n");
56+
# endif
57+
#endif
58+
59+
#ifdef ENABLE_MODULE_EXTRAKEYS
60+
printf(" tweak_add_check : Checks if tweaked x-only pubkey is valid\n");
61+
# ifdef ENABLE_MODULE_BATCH
62+
printf(" tweak_check_batch_verify : Batch verification of tweaked x-only pubkeys check\n");
63+
# endif
5464
#endif
5565

5666
printf("\n");
@@ -129,6 +139,10 @@ static void bench_sign_run(void* arg, int iters) {
129139
# include "modules/recovery/bench_impl.h"
130140
#endif
131141

142+
#ifdef ENABLE_MODULE_EXTRAKEYS
143+
# include "modules/extrakeys/bench_impl.h"
144+
#endif
145+
132146
#ifdef ENABLE_MODULE_SCHNORRSIG
133147
# include "modules/schnorrsig/bench_impl.h"
134148
#endif
@@ -145,7 +159,7 @@ int main(int argc, char** argv) {
145159

146160
/* Check for invalid user arguments */
147161
char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
148-
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign"};
162+
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "batch_verify", "schnorrsig_batch_verify", "extrakeys", "tweak_add_check", "tweak_check_batch_verify"};
149163
size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
150164
int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
151165

@@ -164,23 +178,31 @@ int main(int argc, char** argv) {
164178

165179
/* Check if the user tries to benchmark optional module without building it */
166180
#ifndef ENABLE_MODULE_ECDH
167-
if (have_flag(argc, argv, "ecdh")) {
181+
if (have_flag(argc, argv, "ecdh")) {
168182
fprintf(stderr, "./bench: ECDH module not enabled.\n");
169183
fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n");
170184
return 1;
171185
}
172186
#endif
173187

174188
#ifndef ENABLE_MODULE_RECOVERY
175-
if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
189+
if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
176190
fprintf(stderr, "./bench: Public key recovery module not enabled.\n");
177191
fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n");
178192
return 1;
179193
}
180194
#endif
181195

182196
#ifndef ENABLE_MODULE_SCHNORRSIG
183-
if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
197+
if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
198+
fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n");
199+
fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n");
200+
return 1;
201+
}
202+
#endif
203+
204+
#ifndef ENABLE_MODULE_BATCH
205+
if (have_flag(argc, argv, "batch_verify") || have_flag(argc, argv, "schnorrsig_batch_verify") || have_flag(argc, argv, "tweak_check_batch_verify")) {
184206
fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n");
185207
fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n");
186208
return 1;
@@ -225,6 +247,11 @@ int main(int argc, char** argv) {
225247
run_recovery_bench(iters, argc, argv);
226248
#endif
227249

250+
#ifdef ENABLE_MODULE_EXTRAKEYS
251+
/* Extrakeys benchmarks */
252+
run_extrakeys_bench(iters, argc, argv);
253+
#endif
254+
228255
#ifdef ENABLE_MODULE_SCHNORRSIG
229256
/* Schnorr signature benchmarks */
230257
run_schnorrsig_bench(iters, argc, argv);

src/bench.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void
120120
sum += total;
121121
}
122122
/* ',' is used as a column delimiter */
123-
printf("%-30s, ", name);
123+
printf("%-35s, ", name);
124124
print_number(min * FP_MULT / iter);
125125
printf(" , ");
126126
print_number(((sum * FP_MULT) / count) / iter);
@@ -181,7 +181,7 @@ void print_output_table_header_row(void) {
181181
char* min_str = " Min(us) "; /* center alignment */
182182
char* avg_str = " Avg(us) ";
183183
char* max_str = " Max(us) ";
184-
printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str);
184+
printf("%-35s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str);
185185
printf("\n");
186186
}
187187

src/modules/extrakeys/bench_impl.h

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
2+
#ifndef SECP256K1_MODULE_EXTRAKEYS_BENCH_H
3+
#define SECP256K1_MODULE_EXTRAKEYS_BENCH_H
4+
5+
#include "../../../include/secp256k1_extrakeys.h"
6+
#ifdef ENABLE_MODULE_BATCH
7+
# include "../../../include/secp256k1_batch.h"
8+
# include "../../../include/secp256k1_tweak_check_batch.h"
9+
#endif
10+
11+
typedef struct {
12+
secp256k1_context *ctx;
13+
#ifdef ENABLE_MODULE_BATCH
14+
secp256k1_batch *batch;
15+
/* number of tweak checks to batch verify.
16+
* it varies from 1 to iters with 20% increments */
17+
int n;
18+
#endif
19+
20+
const secp256k1_keypair **keypairs;
21+
const unsigned char **pks;
22+
const unsigned char **tweaked_pks;
23+
const int **tweaked_pk_parities;
24+
const unsigned char **tweaks;
25+
} bench_tweak_check_data;
26+
27+
void bench_xonly_pubkey_tweak_add_check(void* arg, int iters) {
28+
bench_tweak_check_data *data = (bench_tweak_check_data *)arg;
29+
int i;
30+
31+
for (i = 0; i < iters; i++) {
32+
secp256k1_xonly_pubkey pk;
33+
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pks[i]) == 1);
34+
CHECK(secp256k1_xonly_pubkey_tweak_add_check(data->ctx, data->tweaked_pks[i], *data->tweaked_pk_parities[i], &pk, data->tweaks[i]) == 1);
35+
}
36+
}
37+
38+
#ifdef ENABLE_MODULE_BATCH
39+
void bench_xonly_pubkey_tweak_add_check_n(void* arg, int iters) {
40+
bench_tweak_check_data *data = (bench_tweak_check_data *)arg;
41+
int i, j;
42+
43+
for (j = 0; j < iters/data->n; j++) {
44+
for (i = 0; i < data->n; i++) {
45+
secp256k1_xonly_pubkey pk;
46+
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pks[j+i]) == 1);
47+
CHECK(secp256k1_batch_usable(data->ctx, data->batch) == 1);
48+
CHECK(secp256k1_batch_add_xonlypub_tweak_check(data->ctx, data->batch, data->tweaked_pks[j+i], *data->tweaked_pk_parities[j+i], &pk, data->tweaks[j+i]) == 1);
49+
}
50+
CHECK(secp256k1_batch_verify(data->ctx, data->batch) == 1);
51+
}
52+
}
53+
#endif
54+
55+
void run_extrakeys_bench(int iters, int argc, char** argv) {
56+
int i;
57+
bench_tweak_check_data data;
58+
int d = argc == 1;
59+
60+
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
61+
data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *));
62+
data.pks = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
63+
data.tweaked_pks = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
64+
data.tweaked_pk_parities = (const int **)malloc(iters * sizeof(int *));
65+
data.tweaks = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
66+
#ifdef ENABLE_MODULE_BATCH
67+
data.batch = secp256k1_batch_create(data.ctx, iters, NULL);
68+
CHECK(data.batch != NULL);
69+
#endif
70+
71+
for (i = 0; i < iters; i++) {
72+
unsigned char sk[32];
73+
unsigned char *tweaked_pk_char = (unsigned char *)malloc(32);
74+
int *tweaked_pk_parity = (int *)malloc(sizeof(int)); /*todo: use sizeof(*twk_parity) instead?*/
75+
unsigned char *tweak = (unsigned char *)malloc(32);
76+
secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair));
77+
unsigned char *pk_char = (unsigned char *)malloc(32);
78+
secp256k1_xonly_pubkey pk;
79+
secp256k1_pubkey output_pk;
80+
secp256k1_xonly_pubkey output_pk_xonly;
81+
tweak[0] = sk[0] = i;
82+
tweak[1] = sk[1] = i >> 8;
83+
tweak[2] = sk[2] = i >> 16;
84+
tweak[3] = sk[3] = i >> 24;
85+
memset(&tweak[4], 't', 28);
86+
memset(&sk[4], 's', 28);
87+
88+
data.keypairs[i] = keypair;
89+
data.pks[i] = pk_char;
90+
data.tweaked_pks[i] = tweaked_pk_char;
91+
data.tweaked_pk_parities[i] = tweaked_pk_parity;
92+
data.tweaks[i] = tweak;
93+
94+
CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
95+
CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
96+
CHECK(secp256k1_xonly_pubkey_tweak_add(data.ctx, &output_pk, &pk, tweak));
97+
CHECK(secp256k1_xonly_pubkey_from_pubkey(data.ctx, &output_pk_xonly, tweaked_pk_parity, &output_pk));
98+
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, tweaked_pk_char, &output_pk_xonly) == 1);
99+
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
100+
}
101+
102+
if (d || have_flag(argc, argv, "extrakeys") || have_flag(argc, argv, "tweak_add_check")) run_benchmark("tweak_add_check", bench_xonly_pubkey_tweak_add_check, NULL, NULL, (void *) &data, 10, iters);
103+
#ifdef ENABLE_MODULE_BATCH
104+
if (d || have_flag(argc, argv, "extrakeys") || have_flag(argc, argv, "batch_verify") || have_flag(argc, argv, "tweak_check_batch_verify")) {
105+
for (i = 1; i <= iters; i = (int)(i*1.2 + 1)) {
106+
char name[64];
107+
int divisible_iters;
108+
sprintf(name, "tweak_check_batch_verify_%d", (int) i);
109+
110+
data.n = i;
111+
divisible_iters = iters - (iters % data.n);
112+
run_benchmark(name, bench_xonly_pubkey_tweak_add_check_n, NULL, NULL, (void *) &data, 3, divisible_iters);
113+
fflush(stdout);
114+
}
115+
}
116+
#endif
117+
118+
for (i = 0; i < iters; i++) {
119+
free((void *)data.keypairs[i]);
120+
free((void *)data.pks[i]);
121+
free((void *)data.tweaked_pks[i]);
122+
free((void *)data.tweaked_pk_parities[i]);
123+
free((void *)data.tweaks[i]);
124+
}
125+
126+
/* Casting to (void *) avoids a stupid warning in MSVC. */
127+
free((void *)data.keypairs);
128+
free((void *)data.pks);
129+
free((void *)data.tweaked_pks);
130+
free((void *)data.tweaked_pk_parities);
131+
free((void *)data.tweaks);
132+
133+
#ifdef ENABLE_MODULE_BATCH
134+
secp256k1_batch_destroy(data.ctx, data.batch);
135+
#endif
136+
secp256k1_context_destroy(data.ctx);
137+
}
138+
139+
#endif /* SECP256K1_MODULE_EXTRAKEYS_BENCH_H */

src/modules/schnorrsig/bench_impl.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@
88
#define SECP256K1_MODULE_SCHNORRSIG_BENCH_H
99

1010
#include "../../../include/secp256k1_schnorrsig.h"
11+
#ifdef ENABLE_MODULE_BATCH
12+
# include "../../../include/secp256k1_batch.h"
13+
# include "../../../include/secp256k1_schnorrsig_batch.h"
14+
#endif
1115

1216
#define MSGLEN 32
1317

1418
typedef struct {
1519
secp256k1_context *ctx;
20+
#ifdef ENABLE_MODULE_BATCH
21+
secp256k1_batch *batch;
22+
/* number of signatures to batch verify.
23+
* it varies from 1 to iters with 20% increments */
1624
int n;
25+
#endif
1726

1827
const secp256k1_keypair **keypairs;
1928
const unsigned char **pk;
@@ -45,6 +54,23 @@ void bench_schnorrsig_verify(void* arg, int iters) {
4554
}
4655
}
4756

57+
#ifdef ENABLE_MODULE_BATCH
58+
void bench_schnorrsig_verify_n(void* arg, int iters) {
59+
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
60+
int i, j;
61+
62+
for (j = 0; j < iters/data->n; j++) {
63+
for (i = 0; i < data->n; i++) {
64+
secp256k1_xonly_pubkey pk;
65+
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[j+i]) == 1);
66+
CHECK(secp256k1_batch_usable(data->ctx, data->batch) == 1);
67+
CHECK(secp256k1_batch_add_schnorrsig(data->ctx, data->batch, data->sigs[j+i], data->msgs[j+i], MSGLEN, &pk) == 1);
68+
}
69+
CHECK(secp256k1_batch_verify(data->ctx, data->batch) == 1);
70+
}
71+
}
72+
#endif
73+
4874
void run_schnorrsig_bench(int iters, int argc, char** argv) {
4975
int i;
5076
bench_schnorrsig_data data;
@@ -55,6 +81,10 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) {
5581
data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
5682
data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
5783
data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
84+
#ifdef ENABLE_MODULE_BATCH
85+
data.batch = secp256k1_batch_create(data.ctx, 2*iters, NULL);
86+
CHECK(data.batch != NULL);
87+
#endif
5888

5989
CHECK(MSGLEN >= 4);
6090
for (i = 0; i < iters; i++) {
@@ -84,6 +114,20 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) {
84114

85115
if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "schnorrsig_sign")) run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters);
86116
if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "schnorrsig_verify")) run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters);
117+
#ifdef ENABLE_MODULE_BATCH
118+
if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "batch_verify") || have_flag(argc, argv, "schnorrsig_batch_verify")) {
119+
for (i = 1; i <= iters; i = (int)(i*1.2 + 1)) {
120+
char name[64];
121+
int divisible_iters;
122+
sprintf(name, "schnorrsig_batch_verify_%d", (int) i);
123+
124+
data.n = i;
125+
divisible_iters = iters - (iters % data.n);
126+
run_benchmark(name, bench_schnorrsig_verify_n, NULL, NULL, (void *) &data, 3, divisible_iters);
127+
fflush(stdout);
128+
}
129+
}
130+
#endif
87131

88132
for (i = 0; i < iters; i++) {
89133
free((void *)data.keypairs[i]);
@@ -98,6 +142,9 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) {
98142
free((void *)data.msgs);
99143
free((void *)data.sigs);
100144

145+
#ifdef ENABLE_MODULE_BATCH
146+
secp256k1_batch_destroy(data.ctx, data.batch);
147+
#endif
101148
secp256k1_context_destroy(data.ctx);
102149
}
103150

0 commit comments

Comments
 (0)