18
18
19
19
#define POINTS 32768
20
20
21
+ void help (char * * argv ) {
22
+ printf ("Benchmark EC multiplication algorithms\n" );
23
+ printf ("\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" );
28
+ printf ("\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" );
34
+ }
35
+
21
36
typedef struct {
22
37
/* Setup once in advance */
23
38
secp256k1_context * ctx ;
24
39
secp256k1_scratch_space * scratch ;
25
40
secp256k1_scalar * scalars ;
26
41
secp256k1_ge * pubkeys ;
42
+ secp256k1_gej * pubkeys_gej ;
27
43
secp256k1_scalar * seckeys ;
28
44
secp256k1_gej * expected_output ;
29
45
secp256k1_ecmult_multi_func ecmult_multi ;
@@ -47,6 +63,128 @@ static void hash_into_offset(bench_data* data, size_t x) {
47
63
data -> offset2 = (x * 0x7f6f537b + 0x6a1a8f49 ) % POINTS ;
48
64
}
49
65
66
+ /* Check correctness of the benchmark by computing
67
+ * sum(outputs) ?= (sum(scalars_gen) + sum(seckeys)*sum(scalars))*G */
68
+ static void bench_ecmult_teardown_helper (bench_data * data , size_t * seckey_offset , size_t * scalar_offset , size_t * scalar_gen_offset , int iters ) {
69
+ int i ;
70
+ secp256k1_gej sum_output , tmp ;
71
+ secp256k1_scalar sum_scalars ;
72
+
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 ]);
79
+ }
80
+ if (seckey_offset != NULL ) {
81
+ secp256k1_scalar s = data -> seckeys [(* seckey_offset + i ) % POINTS ];
82
+ secp256k1_scalar_mul (& s , & s , & data -> scalars [(* scalar_offset + i ) % POINTS ]);
83
+ secp256k1_scalar_add (& sum_scalars , & sum_scalars , & s );
84
+ }
85
+ }
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 ));
90
+ }
91
+
92
+ static void bench_ecmult_setup (void * arg ) {
93
+ bench_data * data = (bench_data * )arg ;
94
+ /* Re-randomize offset to ensure that we're using different scalars and
95
+ * group elements in each run. */
96
+ hash_into_offset (data , data -> offset1 );
97
+ }
98
+
99
+ static void bench_ecmult_gen (void * arg , int iters ) {
100
+ bench_data * data = (bench_data * )arg ;
101
+ int i ;
102
+
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 ]);
105
+ }
106
+ }
107
+
108
+ static void bench_ecmult_gen_teardown (void * arg , int iters ) {
109
+ bench_data * data = (bench_data * )arg ;
110
+ bench_ecmult_teardown_helper (data , NULL , NULL , & data -> offset1 , iters );
111
+ }
112
+
113
+ static void bench_ecmult_const (void * arg , int iters ) {
114
+ bench_data * data = (bench_data * )arg ;
115
+ int i ;
116
+
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 );
119
+ }
120
+ }
121
+
122
+ static void bench_ecmult_const_teardown (void * arg , int iters ) {
123
+ bench_data * data = (bench_data * )arg ;
124
+ bench_ecmult_teardown_helper (data , & data -> offset1 , & data -> offset2 , NULL , iters );
125
+ }
126
+
127
+ static void bench_ecmult_1 (void * arg , int iters ) {
128
+ bench_data * data = (bench_data * )arg ;
129
+ int i ;
130
+
131
+ for (i = 0 ; i < iters ; ++ i ) {
132
+ secp256k1_ecmult (& data -> ctx -> ecmult_ctx , & data -> output [i ], & data -> pubkeys_gej [(data -> offset1 + i ) % POINTS ], & data -> scalars [(data -> offset2 + i ) % POINTS ], NULL );
133
+ }
134
+ }
135
+
136
+ static void bench_ecmult_1_teardown (void * arg , int iters ) {
137
+ bench_data * data = (bench_data * )arg ;
138
+ bench_ecmult_teardown_helper (data , & data -> offset1 , & data -> offset2 , NULL , iters );
139
+ }
140
+
141
+ static void bench_ecmult_1g (void * arg , int iters ) {
142
+ bench_data * data = (bench_data * )arg ;
143
+ secp256k1_scalar zero ;
144
+ int i ;
145
+
146
+ secp256k1_scalar_set_int (& zero , 0 );
147
+ for (i = 0 ; i < iters ; ++ i ) {
148
+ secp256k1_ecmult (& data -> ctx -> ecmult_ctx , & data -> output [i ], NULL , & zero , & data -> scalars [(data -> offset1 + i ) % POINTS ]);
149
+ }
150
+ }
151
+
152
+ static void bench_ecmult_1g_teardown (void * arg , int iters ) {
153
+ bench_data * data = (bench_data * )arg ;
154
+ bench_ecmult_teardown_helper (data , NULL , NULL , & data -> offset1 , iters );
155
+ }
156
+
157
+ static void bench_ecmult_2g (void * arg , int iters ) {
158
+ bench_data * data = (bench_data * )arg ;
159
+ int i ;
160
+
161
+ for (i = 0 ; i < iters /2 ; ++ i ) {
162
+ secp256k1_ecmult (& data -> ctx -> ecmult_ctx , & data -> output [i ], & data -> pubkeys_gej [(data -> offset1 + i ) % POINTS ], & data -> scalars [(data -> offset2 + i ) % POINTS ], & data -> scalars [(data -> offset1 + i ) % POINTS ]);
163
+ }
164
+ }
165
+
166
+ static void bench_ecmult_2g_teardown (void * arg , int iters ) {
167
+ bench_data * data = (bench_data * )arg ;
168
+ bench_ecmult_teardown_helper (data , & data -> offset1 , & data -> offset2 , & data -> offset1 , iters /2 );
169
+ }
170
+
171
+ static void run_ecmult_bench (bench_data * data , int iters ) {
172
+ char str [32 ];
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 );
177
+ /* ecmult with non generator point */
178
+ sprintf (str , "ecmult 1" );
179
+ run_benchmark (str , bench_ecmult_1 , bench_ecmult_setup , bench_ecmult_1_teardown , data , 10 , iters );
180
+ /* ecmult with generator point */
181
+ sprintf (str , "ecmult 1g" );
182
+ run_benchmark (str , bench_ecmult_1g , bench_ecmult_setup , bench_ecmult_1g_teardown , data , 10 , iters );
183
+ /* ecmult with generator and non-generator point. The reported time is per point. */
184
+ sprintf (str , "ecmult 2g" );
185
+ run_benchmark (str , bench_ecmult_2g , bench_ecmult_setup , bench_ecmult_2g_teardown , data , 10 , 2 * iters );
186
+ }
187
+
50
188
static int bench_ecmult_multi_callback (secp256k1_scalar * sc , secp256k1_ge * ge , size_t idx , void * arg ) {
51
189
bench_data * data = (bench_data * )arg ;
52
190
if (data -> includes_g ) ++ idx ;
@@ -139,55 +277,65 @@ static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_
139
277
int main (int argc , char * * argv ) {
140
278
bench_data data ;
141
279
int i , p ;
142
- secp256k1_gej * pubkeys_gej ;
143
280
size_t scratch_size ;
144
281
145
282
int iters = get_iters (10000 );
146
283
147
- data .ctx = secp256k1_context_create (SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY );
148
- scratch_size = secp256k1_strauss_scratch_size (POINTS ) + STRAUSS_SCRATCH_OBJECTS * 16 ;
149
- data .scratch = secp256k1_scratch_space_create (data .ctx , scratch_size );
150
284
data .ecmult_multi = secp256k1_ecmult_multi_var ;
151
285
152
286
if (argc > 1 ) {
153
- if (have_flag (argc , argv , "pippenger_wnaf" )) {
287
+ if (have_flag (argc , argv , "-h" )
288
+ || have_flag (argc , argv , "--help" )
289
+ || have_flag (argc , argv , "help" )) {
290
+ help (argv );
291
+ return 1 ;
292
+ } else if (have_flag (argc , argv , "pippenger_wnaf" )) {
154
293
printf ("Using pippenger_wnaf:\n" );
155
294
data .ecmult_multi = secp256k1_ecmult_pippenger_batch_single ;
156
295
} else if (have_flag (argc , argv , "strauss_wnaf" )) {
157
296
printf ("Using strauss_wnaf:\n" );
158
297
data .ecmult_multi = secp256k1_ecmult_strauss_batch_single ;
159
298
} else if (have_flag (argc , argv , "simple" )) {
160
299
printf ("Using simple algorithm:\n" );
161
- data .ecmult_multi = secp256k1_ecmult_multi_var ;
162
- secp256k1_scratch_space_destroy (data .ctx , data .scratch );
163
- data .scratch = NULL ;
164
300
} else {
165
- fprintf (stderr , "%s: unrecognized argument '%s'.\n" , argv [0 ], argv [1 ]);
166
- fprintf ( stderr , "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n" );
301
+ fprintf (stderr , "%s: unrecognized argument '%s'.\n\n " , argv [0 ], argv [1 ]);
302
+ help ( argv );
167
303
return 1 ;
168
304
}
169
305
}
170
306
307
+ data .ctx = secp256k1_context_create (SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY );
308
+ scratch_size = secp256k1_strauss_scratch_size (POINTS ) + STRAUSS_SCRATCH_OBJECTS * 16 ;
309
+ if (!have_flag (argc , argv , "simple" )) {
310
+ data .scratch = secp256k1_scratch_space_create (data .ctx , scratch_size );
311
+ } else {
312
+ data .scratch = NULL ;
313
+ }
314
+
171
315
/* Allocate stuff */
172
316
data .scalars = malloc (sizeof (secp256k1_scalar ) * POINTS );
173
317
data .seckeys = malloc (sizeof (secp256k1_scalar ) * POINTS );
174
318
data .pubkeys = malloc (sizeof (secp256k1_ge ) * POINTS );
319
+ data .pubkeys_gej = malloc (sizeof (secp256k1_gej ) * POINTS );
175
320
data .expected_output = malloc (sizeof (secp256k1_gej ) * (iters + 1 ));
176
321
data .output = malloc (sizeof (secp256k1_gej ) * (iters + 1 ));
177
322
178
323
/* Generate a set of scalars, and private/public keypairs. */
179
- pubkeys_gej = malloc (sizeof (secp256k1_gej ) * POINTS );
180
- secp256k1_gej_set_ge (& pubkeys_gej [0 ], & secp256k1_ge_const_g );
324
+ secp256k1_gej_set_ge (& data .pubkeys_gej [0 ], & secp256k1_ge_const_g );
181
325
secp256k1_scalar_set_int (& data .seckeys [0 ], 1 );
182
326
for (i = 0 ; i < POINTS ; ++ i ) {
183
327
generate_scalar (i , & data .scalars [i ]);
184
328
if (i ) {
185
- secp256k1_gej_double_var (& pubkeys_gej [i ], & pubkeys_gej [i - 1 ], NULL );
329
+ secp256k1_gej_double_var (& data . pubkeys_gej [i ], & data . pubkeys_gej [i - 1 ], NULL );
186
330
secp256k1_scalar_add (& data .seckeys [i ], & data .seckeys [i - 1 ], & data .seckeys [i - 1 ]);
187
331
}
188
332
}
189
- secp256k1_ge_set_all_gej_var (data .pubkeys , pubkeys_gej , POINTS );
190
- free (pubkeys_gej );
333
+ secp256k1_ge_set_all_gej_var (data .pubkeys , data .pubkeys_gej , POINTS );
334
+
335
+
336
+ /* Initialize offset1 and offset2 */
337
+ hash_into_offset (& data , 0 );
338
+ run_ecmult_bench (& data , iters );
191
339
192
340
for (i = 1 ; i <= 8 ; ++ i ) {
193
341
run_ecmult_multi_bench (& data , i , 1 , iters );
@@ -210,6 +358,7 @@ int main(int argc, char **argv) {
210
358
secp256k1_context_destroy (data .ctx );
211
359
free (data .scalars );
212
360
free (data .pubkeys );
361
+ free (data .pubkeys_gej );
213
362
free (data .seckeys );
214
363
free (data .output );
215
364
free (data .expected_output );
0 commit comments