22 printf(
"Benchmark EC multiplication algorithms\n");
24 printf(
"Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n",
argv[0]);
25 printf(
"The output shows the number of multiplied and summed points right after the\n");
26 printf(
"function name. The letter 'g' indicates that one of the points is the generator.\n");
27 printf(
"The benchmarks are divided by the number of points.\n");
29 printf(
"default (ecmult_multi): picks pippenger_wnaf or strauss_wnaf depending on the\n");
30 printf(
" batch size\n");
31 printf(
"pippenger_wnaf: for all batch sizes\n");
32 printf(
"strauss_wnaf: for all batch sizes\n");
33 printf(
"simple: multiply and sum each point individually\n");
61static void hash_into_offset(
bench_data* data,
size_t x) {
62 data->offset1 = (x * 0x537b7f6f + 0x8f66a481) %
POINTS;
63 data->offset2 = (x * 0x7f6f537b + 0x6a1a8f49) %
POINTS;
68static void bench_ecmult_teardown_helper(
bench_data* data,
size_t* seckey_offset,
size_t* scalar_offset,
size_t* scalar_gen_offset,
int iters) {
73 secp256k1_gej_set_infinity(&sum_output);
74 secp256k1_scalar_clear(&sum_scalars);
75 for (i = 0; i < iters; ++i) {
76 secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL);
77 if (scalar_gen_offset != NULL) {
78 secp256k1_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) %
POINTS]);
80 if (seckey_offset != NULL) {
82 secp256k1_scalar_mul(&
s, &
s, &data->scalars[(*scalar_offset+i) %
POINTS]);
83 secp256k1_scalar_add(&sum_scalars, &sum_scalars, &
s);
86 secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars);
87 secp256k1_gej_neg(&tmp, &tmp);
88 secp256k1_gej_add_var(&tmp, &tmp, &sum_output, NULL);
89 CHECK(secp256k1_gej_is_infinity(&tmp));
92static void bench_ecmult_setup(
void* arg) {
96 hash_into_offset(data, data->offset1);
99static void bench_ecmult_gen(
void* arg,
int iters) {
103 for (i = 0; i < iters; ++i) {
104 secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) %
POINTS]);
108static void bench_ecmult_gen_teardown(
void* arg,
int iters) {
110 bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters);
113static void bench_ecmult_const(
void* arg,
int iters) {
117 for (i = 0; i < iters; ++i) {
118 secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) %
POINTS], &data->scalars[(data->offset2+i) %
POINTS], 256);
122static void bench_ecmult_const_teardown(
void* arg,
int iters) {
124 bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters);
127static void bench_ecmult_1p(
void* arg,
int iters) {
131 for (i = 0; i < iters; ++i) {
132 secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) %
POINTS], &data->scalars[(data->offset2+i) %
POINTS], NULL);
136static void bench_ecmult_1p_teardown(
void* arg,
int iters) {
138 bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters);
141static void bench_ecmult_0p_g(
void* arg,
int iters) {
146 secp256k1_scalar_set_int(&zero, 0);
147 for (i = 0; i < iters; ++i) {
148 secp256k1_ecmult(&data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) %
POINTS]);
152static void bench_ecmult_0p_g_teardown(
void* arg,
int iters) {
154 bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters);
157static void bench_ecmult_1p_g(
void* arg,
int iters) {
161 for (i = 0; i < iters/2; ++i) {
162 secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) %
POINTS], &data->scalars[(data->offset2+i) %
POINTS], &data->scalars[(data->offset1+i) %
POINTS]);
166static void bench_ecmult_1p_g_teardown(
void* arg,
int iters) {
168 bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, &data->offset1, iters/2);
171static void run_ecmult_bench(
bench_data* data,
int iters) {
173 sprintf(str,
"ecmult_gen");
174 run_benchmark(str, bench_ecmult_gen, bench_ecmult_setup, bench_ecmult_gen_teardown, data, 10, iters);
175 sprintf(str,
"ecmult_const");
176 run_benchmark(str, bench_ecmult_const, bench_ecmult_setup, bench_ecmult_const_teardown, data, 10, iters);
178 sprintf(str,
"ecmult_1p");
179 run_benchmark(str, bench_ecmult_1p, bench_ecmult_setup, bench_ecmult_1p_teardown, data, 10, iters);
181 sprintf(str,
"ecmult_0p_g");
182 run_benchmark(str, bench_ecmult_0p_g, bench_ecmult_setup, bench_ecmult_0p_g_teardown, data, 10, iters);
184 sprintf(str,
"ecmult_1p_g");
185 run_benchmark(str, bench_ecmult_1p_g, bench_ecmult_setup, bench_ecmult_1p_g_teardown, data, 10, 2*iters);
190 if (data->includes_g) ++idx;
192 *sc = data->scalars[data->offset1];
193 *ge = secp256k1_ge_const_g;
195 *sc = data->scalars[(data->offset1 + idx) %
POINTS];
196 *ge = data->pubkeys[(data->offset2 + idx - 1) %
POINTS];
201static void bench_ecmult_multi(
void* arg,
int iters) {
206 int count = data->count;
207 iters = iters / data->count;
209 for (iter = 0; iter < iters; ++iter) {
210 data->ecmult_multi(&data->ctx->error_callback, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_ecmult_multi_callback, arg,
count - includes_g);
212 data->offset2 = (data->offset2 +
count - 1) %
POINTS;
216static void bench_ecmult_multi_setup(
void* arg) {
218 hash_into_offset(data, data->count);
221static void bench_ecmult_multi_teardown(
void* arg,
int iters) {
224 iters = iters / data->
count;
226 for (iter = 0; iter < iters; ++iter) {
228 secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL);
229 CHECK(secp256k1_gej_is_infinity(&tmp));
235 unsigned char c[10] = {
'e',
'c',
'm',
'u',
'l',
't', 0, 0, 0, 0};
236 unsigned char buf[32];
242 secp256k1_sha256_initialize(&sha256);
243 secp256k1_sha256_write(&sha256, c,
sizeof(c));
244 secp256k1_sha256_finalize(&sha256,
buf);
249static void run_ecmult_multi_bench(
bench_data* data,
size_t count,
int includes_g,
int num_iters) {
252 size_t iters = 1 + num_iters /
count;
256 data->includes_g = includes_g;
259 hash_into_offset(data, data->count);
260 for (iter = 0; iter < iters; ++iter) {
264 for (i = 0; i + 1 <
count; ++i) {
265 secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) %
POINTS], &data->scalars[(data->offset1++) %
POINTS]);
266 secp256k1_scalar_add(&total, &total, &tmp);
268 secp256k1_scalar_negate(&total, &total);
269 secp256k1_ecmult(&data->expected_output[iter], NULL, &zero, &total);
274 sprintf(str,
"ecmult_multi_%ip_g", (
int)
count - 1);
276 sprintf(str,
"ecmult_multi_%ip", (
int)
count);
278 run_benchmark(str, bench_ecmult_multi, bench_ecmult_multi_setup, bench_ecmult_multi_teardown, data, 10,
count * iters);
288 data.ecmult_multi = secp256k1_ecmult_multi_var;
297 printf(
"Using pippenger_wnaf:\n");
298 data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
300 printf(
"Using strauss_wnaf:\n");
301 data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
303 printf(
"Using simple algorithm:\n");
305 fprintf(stderr,
"%s: unrecognized argument '%s'.\n\n",
argv[0],
argv[1]);
324 data.expected_output = malloc(
sizeof(
secp256k1_gej) * (iters + 1));
328 secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g);
329 secp256k1_scalar_set_int(&data.seckeys[0], 1);
330 for (i = 0; i <
POINTS; ++i) {
331 generate_scalar(i, &data.scalars[i]);
333 secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL);
334 secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
337 secp256k1_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej,
POINTS);
342 hash_into_offset(&data, 0);
343 run_ecmult_bench(&data, iters);
345 for (i = 1; i <= 8; ++i) {
346 run_ecmult_multi_bench(&data, i, 1, iters);
353 for (
p = 0;
p <= 11; ++
p) {
354 for (i = 9; i <= 16; ++i) {
355 run_ecmult_multi_bench(&data, i <<
p, 1, iters);
360 if (data.scratch != NULL) {
366 free(data.pubkeys_gej);
369 free(data.expected_output);
void print_output_table_header_row(void)
int have_flag(int argc, char **argv, char *flag)
int get_iters(int default_iters)
void run_benchmark(char *name, void(*benchmark)(void *, int), void(*setup)(void *), void(*teardown)(void *, int), void *data, int count, int iter)
#define STRAUSS_SCRATCH_OBJECTS
int(* secp256k1_ecmult_multi_func)(const secp256k1_callback *error_callback, secp256k1_scratch *, secp256k1_gej *, const secp256k1_scalar *, secp256k1_ecmult_multi_callback cb, void *, size_t)
constexpr const char sha256[]
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0)
SECP256K1_API void secp256k1_context_destroy(secp256k1_context *ctx) SECP256K1_ARG_NONNULL(1)
#define SECP256K1_CONTEXT_SIGN
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space * secp256k1_scratch_space_create(const secp256k1_context *ctx, size_t size) SECP256K1_ARG_NONNULL(1)
SECP256K1_API secp256k1_context * secp256k1_context_create(unsigned int flags) SECP256K1_WARN_UNUSED_RESULT
SECP256K1_API void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space *scratch) SECP256K1_ARG_NONNULL(1)
#define SECP256K1_CONTEXT_VERIFY
secp256k1_scalar * seckeys
secp256k1_gej * pubkeys_gej
secp256k1_ecmult_multi_func ecmult_multi
secp256k1_scratch_space * scratch
secp256k1_scalar * scalars
secp256k1_gej * expected_output