22static void help(
char **argv,
int default_iters) {
23 printf(
"Benchmark EC multiplication algorithms\n");
25 printf(
"The default number of iterations for each benchmark is %d. This can be\n", default_iters);
26 printf(
"customized using the SECP256K1_BENCH_ITERS environment variable.\n");
28 printf(
"Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n", argv[0]);
29 printf(
"The output shows the number of multiplied and summed points right after the\n");
30 printf(
"function name. The letter 'g' indicates that one of the points is the generator.\n");
31 printf(
"The benchmarks are divided by the number of points.\n");
33 printf(
"default (ecmult_multi): picks pippenger_wnaf or strauss_wnaf depending on the\n");
34 printf(
" batch size\n");
35 printf(
"pippenger_wnaf: for all batch sizes\n");
36 printf(
"strauss_wnaf: for all batch sizes\n");
37 printf(
"simple: multiply and sum each point individually\n");
67 data->offset1 = (x * 0x537b7f6f + 0x8f66a481) %
POINTS;
68 data->offset2 = (x * 0x7f6f537b + 0x6a1a8f49) %
POINTS;
78 secp256k1_gej_set_infinity(&sum_output);
79 secp256k1_scalar_set_int(&sum_scalars, 0);
80 for (i = 0; i < iters; ++i) {
81 secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL);
82 if (scalar_gen_offset != NULL) {
83 secp256k1_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) %
POINTS]);
85 if (seckey_offset != NULL) {
87 secp256k1_scalar_mul(&s, &s, &data->scalars[(*scalar_offset+i) %
POINTS]);
88 secp256k1_scalar_add(&sum_scalars, &sum_scalars, &s);
91 secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars);
92 CHECK(secp256k1_gej_eq_var(&tmp, &sum_output));
106 for (i = 0; i < iters; ++i) {
107 secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) %
POINTS]);
120 for (i = 0; i < iters; ++i) {
121 secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) %
POINTS], &data->scalars[(data->offset2+i) %
POINTS]);
134 for (i = 0; i < iters; ++i) {
137 int known_on_curve = 1;
138 secp256k1_ecmult_const_xonly(&data->output_xonly[i], &pubkey->
x, NULL, scalar, known_on_curve);
147 for (i = 0; i < iters; ++i) {
151 secp256k1_ecmult(&expected_gej, pubkey_gej, scalar, NULL);
152 CHECK(secp256k1_gej_eq_x_var(&data->output_xonly[i], &expected_gej));
160 for (i = 0; i < iters; ++i) {
161 secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) %
POINTS], &data->scalars[(data->offset2+i) %
POINTS], NULL);
174 for (i = 0; i < iters; ++i) {
175 secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) %
POINTS]);
188 for (i = 0; i < iters/2; ++i) {
189 secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) %
POINTS], &data->scalars[(data->offset2+i) %
POINTS], &data->scalars[(data->offset1+i) %
POINTS]);
200 sprintf(str,
"ecmult_gen");
202 sprintf(str,
"ecmult_const");
204 sprintf(str,
"ecmult_const_xonly");
207 sprintf(str,
"ecmult_1p");
210 sprintf(str,
"ecmult_0p_g");
213 sprintf(str,
"ecmult_1p_g");
219 if (data->includes_g) ++idx;
221 *sc = data->scalars[data->offset1];
222 *ge = secp256k1_ge_const_g;
224 *sc = data->scalars[(data->offset1 + idx) %
POINTS];
225 *ge = data->pubkeys[(data->offset2 + idx - 1) %
POINTS];
233 int includes_g = data->includes_g;
235 int count = data->count;
236 iters = iters / data->count;
238 for (iter = 0; iter < iters; ++iter) {
239 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);
240 data->offset1 = (data->offset1 + count) %
POINTS;
241 data->offset2 = (data->offset2 + count - 1) %
POINTS;
253 iters = iters / data->count;
255 for (iter = 0; iter < iters; ++iter) {
257 secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL);
258 CHECK(secp256k1_gej_is_infinity(&tmp));
264 unsigned char c[10] = {
'e',
'c',
'm',
'u',
'l',
't', 0, 0, 0, 0};
265 unsigned char buf[32];
274 secp256k1_scalar_set_b32(scalar, buf, &overflow);
280 size_t iters = 1 + num_iters / count;
284 data->includes_g = includes_g;
288 for (iter = 0; iter < iters; ++iter) {
292 for (i = 0; i + 1 < count; ++i) {
293 secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) %
POINTS], &data->scalars[(data->offset1++) %
POINTS]);
294 secp256k1_scalar_add(&total, &total, &tmp);
296 secp256k1_scalar_negate(&total, &total);
297 secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total);
302 sprintf(str,
"ecmult_multi_%ip_g", (
int)count - 1);
304 sprintf(str,
"ecmult_multi_%ip", (
int)count);
309int main(
int argc,
char **argv) {
314 int default_iters = 10000;
317 help(argv, default_iters);
321 data.ecmult_multi = secp256k1_ecmult_multi_var;
327 help(argv, default_iters);
329 }
else if(
have_flag(argc, argv,
"pippenger_wnaf")) {
330 printf(
"Using pippenger_wnaf:\n");
331 data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
332 }
else if(
have_flag(argc, argv,
"strauss_wnaf")) {
333 printf(
"Using strauss_wnaf:\n");
334 data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
335 }
else if(
have_flag(argc, argv,
"simple")) {
336 printf(
"Using simple algorithm:\n");
338 fprintf(stderr,
"%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]);
339 help(argv, default_iters);
347 data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
357 data.expected_output = malloc(
sizeof(
secp256k1_gej) * (iters + 1));
359 data.output_xonly = malloc(
sizeof(
secp256k1_fe) * (iters + 1));
362 secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g);
363 secp256k1_scalar_set_int(&data.seckeys[0], 1);
364 for (i = 0; i <
POINTS; ++i) {
367 secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL);
368 secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
371 secp256k1_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej,
POINTS);
379 for (i = 1; i <= 8; ++i) {
387 for (p = 0; p <= 11; ++p) {
388 for (i = 9; i <= 16; ++i) {
393 printf(
"Skipping some benchmarks due to SECP256K1_BENCH_ITERS <= 2\n");
396 if (data.scratch != NULL) {
397 secp256k1_scratch_space_destroy(data.ctx, data.scratch);
402 free(data.pubkeys_gej);
404 free(data.output_xonly);
406 free(data.expected_output);
int main(int argc, char **argv)
static void bench_ecmult_const(void *arg, int iters)
static void bench_ecmult_gen_teardown(void *arg, int iters)
static int bench_ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *ge, size_t idx, void *arg)
static void bench_ecmult_teardown_helper(bench_data *data, size_t *seckey_offset, size_t *scalar_offset, size_t *scalar_gen_offset, int iters)
static void bench_ecmult_const_xonly(void *arg, int iters)
static void bench_ecmult_setup(void *arg)
static void bench_ecmult_gen(void *arg, int iters)
static void generate_scalar(uint32_t num, secp256k1_scalar *scalar)
static void bench_ecmult_const_teardown(void *arg, int iters)
static void bench_ecmult_multi_setup(void *arg)
static void bench_ecmult_1p_g_teardown(void *arg, int iters)
static void bench_ecmult_1p(void *arg, int iters)
static void bench_ecmult_const_xonly_teardown(void *arg, int iters)
static void bench_ecmult_1p_teardown(void *arg, int iters)
static void bench_ecmult_multi(void *arg, int iters)
static void hash_into_offset(bench_data *data, size_t x)
static void bench_ecmult_0p_g_teardown(void *arg, int iters)
static void run_ecmult_bench(bench_data *data, int iters)
static void bench_ecmult_1p_g(void *arg, int iters)
static void bench_ecmult_0p_g(void *arg, int iters)
static void bench_ecmult_multi_teardown(void *arg, int iters)
static void run_ecmult_multi_bench(bench_data *data, size_t count, int includes_g, int num_iters)
#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)
#define CHECK(cond)
Unconditional failure on condition failure.
Internal SHA-256 implementation.
struct secp256k1_scratch_space_struct secp256k1_scratch_space
static void help(int default_iters)
static int get_iters(int default_iters)
static void print_output_table_header_row(void)
static void run_benchmark(char *name, void(*benchmark)(void *, int), void(*setup)(void *), void(*teardown)(void *, int), void *data, int count, int iter)
static int have_flag(int argc, char **argv, char *flag)
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash)
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32)
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size)
SECP256K1_API void secp256k1_context_destroy(secp256k1_context *ctx) SECP256K1_ARG_NONNULL(1)
Destroy a secp256k1 context object (created in dynamically allocated memory).
struct secp256k1_context_struct secp256k1_context
Unless explicitly stated all pointer arguments must not be NULL.
SECP256K1_API secp256k1_context * secp256k1_context_create(unsigned int flags) SECP256K1_WARN_UNUSED_RESULT
Create a secp256k1 context object (in dynamically allocated memory).
#define SECP256K1_CONTEXT_NONE
Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size,...
secp256k1_scalar * seckeys
secp256k1_gej * pubkeys_gej
secp256k1_ecmult_multi_func ecmult_multi
secp256k1_scratch_space * scratch
secp256k1_fe * output_xonly
secp256k1_scalar * scalars
secp256k1_gej * expected_output
This field implementation represents the value as 10 uint32_t limbs in base 2^26.
A group element in affine coordinates on the secp256k1 curve, or occasionally on an isomorphic curve ...
A group element of the secp256k1 curve, in jacobian coordinates.
A scalar modulo the group order of the secp256k1 curve.