Line data Source code
1 : /* bench-slope.c - for libgcrypt
2 : * Copyright (C) 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3 : *
4 : * This file is part of Libgcrypt.
5 : *
6 : * Libgcrypt is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser general Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Libgcrypt is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #ifdef HAVE_CONFIG_H
21 : #include <config.h>
22 : #endif
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <stdarg.h>
26 : #include <assert.h>
27 : #include <time.h>
28 :
29 : #ifdef _GCRYPT_IN_LIBGCRYPT
30 : # include "../src/gcrypt-int.h"
31 : # include "../compat/libcompat.h"
32 : #else
33 : # include <gcrypt.h>
34 : #endif
35 :
36 : #ifndef STR
37 : #define STR(v) #v
38 : #define STR2(v) STR(v)
39 : #endif
40 :
41 : #define PGM "bench-slope"
42 :
43 : static int verbose;
44 : static int csv_mode;
45 : static int unaligned_mode;
46 : static int num_measurement_repetitions;
47 :
48 : /* CPU Ghz value provided by user, allows constructing cycles/byte and other
49 : results. */
50 : static double cpu_ghz = -1;
51 :
52 : /* Whether we are running as part of the regression test suite. */
53 : static int in_regression_test;
54 :
55 : /* The name of the currently printed section. */
56 : static char *current_section_name;
57 : /* The name of the currently printed algorithm. */
58 : static char *current_algo_name;
59 : /* The name of the currently printed mode. */
60 : static char *current_mode_name;
61 :
62 :
63 : /*************************************** Default parameters for measurements. */
64 :
65 : /* Start at small buffer size, to get reasonable timer calibration for fast
66 : * implementations (AES-NI etc). Sixteen selected to support the largest block
67 : * size of current set cipher blocks. */
68 : #define BUF_START_SIZE 16
69 :
70 : /* From ~0 to ~4kbytes give comparable results with results from academia
71 : * (SUPERCOP). */
72 : #define BUF_END_SIZE (BUF_START_SIZE + 4096)
73 :
74 : /* With 128 byte steps, we get (4096)/64 = 64 data points. */
75 : #define BUF_STEP_SIZE 64
76 :
77 : /* Number of repeated measurements at each data point. The median of these
78 : * measurements is selected as data point further analysis. */
79 : #define NUM_MEASUREMENT_REPETITIONS 64
80 :
81 : /**************************************************** High-resolution timers. */
82 :
83 : /* This benchmarking module needs needs high resolution timer. */
84 : #undef NO_GET_NSEC_TIME
85 : #if defined(_WIN32)
86 : struct nsec_time
87 : {
88 : LARGE_INTEGER perf_count;
89 : };
90 :
91 : static void
92 : get_nsec_time (struct nsec_time *t)
93 : {
94 : BOOL ok;
95 :
96 : ok = QueryPerformanceCounter (&t->perf_count);
97 : assert (ok);
98 : }
99 :
100 : static double
101 : get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
102 : {
103 : static double nsecs_per_count = 0.0;
104 : double nsecs;
105 :
106 : if (nsecs_per_count == 0.0)
107 : {
108 : LARGE_INTEGER perf_freq;
109 : BOOL ok;
110 :
111 : /* Get counts per second. */
112 : ok = QueryPerformanceFrequency (&perf_freq);
113 : assert (ok);
114 :
115 : nsecs_per_count = 1.0 / perf_freq.QuadPart;
116 : nsecs_per_count *= 1000000.0 * 1000.0; /* sec => nsec */
117 :
118 : assert (nsecs_per_count > 0.0);
119 : }
120 :
121 : nsecs = end->perf_count.QuadPart - start->perf_count.QuadPart; /* counts */
122 : nsecs *= nsecs_per_count; /* counts * (nsecs / count) => nsecs */
123 :
124 : return nsecs;
125 : }
126 : #elif defined(HAVE_CLOCK_GETTIME)
127 : struct nsec_time
128 : {
129 : struct timespec ts;
130 : };
131 :
132 : static void
133 29065692 : get_nsec_time (struct nsec_time *t)
134 : {
135 : int err;
136 :
137 29065692 : err = clock_gettime (CLOCK_REALTIME, &t->ts);
138 29065692 : assert (err == 0);
139 29065692 : }
140 :
141 : static double
142 29007733 : get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
143 : {
144 : double nsecs;
145 :
146 29007733 : nsecs = end->ts.tv_sec - start->ts.tv_sec;
147 29007733 : nsecs *= 1000000.0 * 1000.0; /* sec => nsec */
148 :
149 : /* This way we don't have to care if tv_nsec unsigned or signed. */
150 29007733 : if (end->ts.tv_nsec >= start->ts.tv_nsec)
151 15352845 : nsecs += end->ts.tv_nsec - start->ts.tv_nsec;
152 : else
153 13654888 : nsecs -= start->ts.tv_nsec - end->ts.tv_nsec;
154 :
155 29007733 : return nsecs;
156 : }
157 : #elif defined(HAVE_GETTIMEOFDAY)
158 : struct nsec_time
159 : {
160 : struct timeval tv;
161 : };
162 :
163 : static void
164 : get_nsec_time (struct nsec_time *t)
165 : {
166 : int err;
167 :
168 : err = gettimeofday (&t->tv, NULL);
169 : assert (err == 0);
170 : }
171 :
172 : static double
173 : get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
174 : {
175 : double nsecs;
176 :
177 : nsecs = end->tv.tv_sec - start->tv.tv_sec;
178 : nsecs *= 1000000; /* sec => µsec */
179 :
180 : /* This way we don't have to care if tv_usec unsigned or signed. */
181 : if (end->tv.tv_usec >= start->tv.tv_usec)
182 : nsecs += end->tv.tv_usec - start->tv.tv_usec;
183 : else
184 : nsecs -= start->tv.tv_usec - end->tv.tv_usec;
185 :
186 : nsecs *= 1000; /* µsec => nsec */
187 :
188 : return nsecs;
189 : }
190 : #else
191 : #define NO_GET_NSEC_TIME 1
192 : #endif
193 :
194 :
195 : /* If no high resolution timer found, provide dummy bench-slope. */
196 : #ifdef NO_GET_NSEC_TIME
197 :
198 :
199 : int
200 : main (void)
201 : {
202 : /* No nsec timer => SKIP test. */
203 : return 77;
204 : }
205 :
206 :
207 : #else /* !NO_GET_NSEC_TIME */
208 :
209 :
210 : /********************************************** Slope benchmarking framework. */
211 :
212 : struct bench_obj
213 : {
214 : const struct bench_ops *ops;
215 :
216 : unsigned int num_measure_repetitions;
217 : unsigned int min_bufsize;
218 : unsigned int max_bufsize;
219 : unsigned int step_size;
220 :
221 : void *priv;
222 : };
223 :
224 : typedef int (*const bench_initialize_t) (struct bench_obj * obj);
225 : typedef void (*const bench_finalize_t) (struct bench_obj * obj);
226 : typedef void (*const bench_do_run_t) (struct bench_obj * obj, void *buffer,
227 : size_t buflen);
228 :
229 : struct bench_ops
230 : {
231 : bench_initialize_t initialize;
232 : bench_finalize_t finalize;
233 : bench_do_run_t do_run;
234 : };
235 :
236 :
237 : double
238 402 : get_slope (double (*const get_x) (unsigned int idx, void *priv),
239 : void *get_x_priv, double y_points[], unsigned int npoints,
240 : double *overhead)
241 : {
242 : double sumx, sumy, sumx2, sumy2, sumxy;
243 : unsigned int i;
244 : double b, a;
245 :
246 402 : sumx = sumy = sumx2 = sumy2 = sumxy = 0;
247 :
248 25905 : for (i = 0; i < npoints; i++)
249 : {
250 : double x, y;
251 :
252 25503 : x = get_x (i, get_x_priv); /* bytes */
253 25503 : y = y_points[i]; /* nsecs */
254 :
255 25503 : sumx += x;
256 25503 : sumy += y;
257 25503 : sumx2 += x * x;
258 : /*sumy2 += y * y;*/
259 25503 : sumxy += x * y;
260 : }
261 :
262 402 : b = (npoints * sumxy - sumx * sumy) / (npoints * sumx2 - sumx * sumx);
263 402 : a = (sumy - b * sumx) / npoints;
264 :
265 402 : if (overhead)
266 402 : *overhead = a; /* nsecs */
267 :
268 402 : return b; /* nsecs per byte */
269 : }
270 :
271 :
272 : double
273 25503 : get_bench_obj_point_x (unsigned int idx, void *priv)
274 : {
275 25503 : struct bench_obj *obj = priv;
276 25503 : return (double) (obj->min_bufsize + (idx * obj->step_size));
277 : }
278 :
279 :
280 : unsigned int
281 402 : get_num_measurements (struct bench_obj *obj)
282 : {
283 402 : unsigned int buf_range = obj->max_bufsize - obj->min_bufsize;
284 402 : unsigned int num = buf_range / obj->step_size + 1;
285 :
286 1206 : while (obj->min_bufsize + (num * obj->step_size) > obj->max_bufsize)
287 402 : num--;
288 :
289 402 : return num + 1;
290 : }
291 :
292 :
293 : static int
294 28979 : double_cmp (const void *_a, const void *_b)
295 : {
296 : const double *a, *b;
297 :
298 28979 : a = _a;
299 28979 : b = _b;
300 :
301 28979 : if (*a > *b)
302 16957 : return 1;
303 12022 : if (*a < *b)
304 11941 : return -1;
305 81 : return 0;
306 : }
307 :
308 :
309 : double
310 28979 : do_bench_obj_measurement (struct bench_obj *obj, void *buffer, size_t buflen,
311 : double *measurement_raw,
312 : unsigned int loop_iterations)
313 : {
314 28979 : const unsigned int num_repetitions = obj->num_measure_repetitions;
315 28979 : const bench_do_run_t do_run = obj->ops->do_run;
316 : struct nsec_time start, end;
317 : unsigned int rep, loop;
318 : double res;
319 :
320 28979 : if (num_repetitions < 1 || loop_iterations < 1)
321 0 : return 0.0;
322 :
323 86937 : for (rep = 0; rep < num_repetitions; rep++)
324 : {
325 57958 : get_nsec_time (&start);
326 :
327 555946 : for (loop = 0; loop < loop_iterations; loop++)
328 497988 : do_run (obj, buffer, buflen);
329 :
330 57958 : get_nsec_time (&end);
331 :
332 57958 : measurement_raw[rep] = get_time_nsec_diff (&start, &end);
333 : }
334 :
335 : /* Return median of repeated measurements. */
336 28979 : qsort (measurement_raw, num_repetitions, sizeof (measurement_raw[0]),
337 : double_cmp);
338 :
339 28979 : if (num_repetitions % 2 == 1)
340 0 : return measurement_raw[num_repetitions / 2];
341 :
342 57958 : res = measurement_raw[num_repetitions / 2]
343 28979 : + measurement_raw[num_repetitions / 2 - 1];
344 28979 : return res / 2;
345 : }
346 :
347 :
348 : unsigned int
349 402 : adjust_loop_iterations_to_timer_accuracy (struct bench_obj *obj, void *buffer,
350 : double *measurement_raw)
351 : {
352 402 : const double increase_thres = 3.0;
353 : double tmp, nsecs;
354 : unsigned int loop_iterations;
355 : unsigned int test_bufsize;
356 :
357 402 : test_bufsize = obj->min_bufsize;
358 402 : if (test_bufsize == 0)
359 0 : test_bufsize += obj->step_size;
360 :
361 402 : loop_iterations = 0;
362 : do
363 : {
364 : /* Increase loop iterations until we get other results than zero. */
365 804 : nsecs =
366 402 : do_bench_obj_measurement (obj, buffer, test_bufsize,
367 : measurement_raw, ++loop_iterations);
368 : }
369 402 : while (nsecs < 1.0 - 0.1);
370 : do
371 : {
372 : /* Increase loop iterations until we get reasonable increase for elapsed time. */
373 6148 : tmp =
374 3074 : do_bench_obj_measurement (obj, buffer, test_bufsize,
375 : measurement_raw, ++loop_iterations);
376 : }
377 3074 : while (tmp < nsecs * (increase_thres - 0.1));
378 :
379 402 : return loop_iterations;
380 : }
381 :
382 :
383 : /* Benchmark and return linear regression slope in nanoseconds per byte. */
384 : double
385 402 : do_slope_benchmark (struct bench_obj *obj)
386 : {
387 : unsigned int num_measurements;
388 402 : double *measurements = NULL;
389 402 : double *measurement_raw = NULL;
390 : double slope, overhead;
391 : unsigned int loop_iterations, midx, i;
392 402 : unsigned char *real_buffer = NULL;
393 : unsigned char *buffer;
394 : size_t cur_bufsize;
395 : int err;
396 :
397 402 : err = obj->ops->initialize (obj);
398 402 : if (err < 0)
399 0 : return -1;
400 :
401 402 : num_measurements = get_num_measurements (obj);
402 402 : measurements = calloc (num_measurements, sizeof (*measurements));
403 402 : if (!measurements)
404 0 : goto err_free;
405 :
406 402 : measurement_raw =
407 402 : calloc (obj->num_measure_repetitions, sizeof (*measurement_raw));
408 402 : if (!measurement_raw)
409 0 : goto err_free;
410 :
411 804 : if (num_measurements < 1 || obj->num_measure_repetitions < 1 ||
412 804 : obj->max_bufsize < 1 || obj->min_bufsize > obj->max_bufsize)
413 : goto err_free;
414 :
415 402 : real_buffer = malloc (obj->max_bufsize + 128 + unaligned_mode);
416 402 : if (!real_buffer)
417 0 : goto err_free;
418 : /* Get aligned buffer */
419 402 : buffer = real_buffer;
420 402 : buffer += 128 - ((real_buffer - (unsigned char *) 0) & (128 - 1));
421 402 : if (unaligned_mode)
422 0 : buffer += unaligned_mode; /* Make buffer unaligned */
423 :
424 1576514 : for (i = 0; i < obj->max_bufsize; i++)
425 1576112 : buffer[i] = 0x55 ^ (-i);
426 :
427 : /* Adjust number of loop iterations up to timer accuracy. */
428 402 : loop_iterations = adjust_loop_iterations_to_timer_accuracy (obj, buffer,
429 : measurement_raw);
430 :
431 : /* Perform measurements */
432 26307 : for (midx = 0, cur_bufsize = obj->min_bufsize;
433 25503 : cur_bufsize <= obj->max_bufsize; cur_bufsize += obj->step_size, midx++)
434 : {
435 51006 : measurements[midx] =
436 25503 : do_bench_obj_measurement (obj, buffer, cur_bufsize, measurement_raw,
437 : loop_iterations);
438 25503 : measurements[midx] /= loop_iterations;
439 : }
440 :
441 402 : assert (midx == num_measurements);
442 :
443 402 : slope =
444 : get_slope (&get_bench_obj_point_x, obj, measurements, num_measurements,
445 : &overhead);
446 :
447 402 : free (measurement_raw);
448 402 : free (measurements);
449 402 : free (real_buffer);
450 402 : obj->ops->finalize (obj);
451 :
452 402 : return slope;
453 :
454 : err_free:
455 0 : if (measurement_raw)
456 0 : free (measurement_raw);
457 0 : if (measurements)
458 0 : free (measurements);
459 0 : if (real_buffer)
460 0 : free (real_buffer);
461 0 : obj->ops->finalize (obj);
462 :
463 0 : return -1;
464 : }
465 :
466 :
467 : /********************************************************** Printing results. */
468 :
469 : static void
470 785 : double_to_str (char *out, size_t outlen, double value)
471 : {
472 : const char *fmt;
473 :
474 785 : if (value < 1.0)
475 52 : fmt = "%.3f";
476 733 : else if (value < 100.0)
477 491 : fmt = "%.2f";
478 : else
479 242 : fmt = "%.1f";
480 :
481 785 : snprintf (out, outlen, fmt, value);
482 785 : }
483 :
484 : static void
485 0 : bench_print_result_csv (double nsecs_per_byte)
486 : {
487 : double cycles_per_byte, mbytes_per_sec;
488 : char nsecpbyte_buf[16];
489 : char mbpsec_buf[16];
490 : char cpbyte_buf[16];
491 :
492 0 : *cpbyte_buf = 0;
493 :
494 0 : double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
495 :
496 : /* If user didn't provide CPU speed, we cannot show cycles/byte results. */
497 0 : if (cpu_ghz > 0.0)
498 : {
499 0 : cycles_per_byte = nsecs_per_byte * cpu_ghz;
500 0 : double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
501 : }
502 :
503 0 : mbytes_per_sec =
504 0 : (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
505 0 : double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
506 :
507 : /* We print two empty fields to allow for future enhancements. */
508 0 : printf ("%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B\n",
509 : current_section_name,
510 0 : current_algo_name? current_algo_name : "",
511 0 : current_mode_name? current_mode_name : "",
512 : nsecpbyte_buf,
513 : mbpsec_buf,
514 : cpbyte_buf);
515 :
516 0 : }
517 :
518 : static void
519 383 : bench_print_result_std (double nsecs_per_byte)
520 : {
521 : double cycles_per_byte, mbytes_per_sec;
522 : char nsecpbyte_buf[16];
523 : char mbpsec_buf[16];
524 : char cpbyte_buf[16];
525 :
526 383 : double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
527 :
528 : /* If user didn't provide CPU speed, we cannot show cycles/byte results. */
529 383 : if (cpu_ghz > 0.0)
530 : {
531 0 : cycles_per_byte = nsecs_per_byte * cpu_ghz;
532 0 : double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
533 : }
534 : else
535 383 : strcpy (cpbyte_buf, "-");
536 :
537 383 : mbytes_per_sec =
538 383 : (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
539 383 : double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
540 :
541 383 : printf ("%9s ns/B %9s MiB/s %9s c/B\n",
542 : nsecpbyte_buf, mbpsec_buf, cpbyte_buf);
543 383 : }
544 :
545 : static void
546 383 : bench_print_result (double nsecs_per_byte)
547 : {
548 383 : if (csv_mode)
549 0 : bench_print_result_csv (nsecs_per_byte);
550 : else
551 383 : bench_print_result_std (nsecs_per_byte);
552 383 : }
553 :
554 : static void
555 4 : bench_print_section (const char *section_name, const char *print_name)
556 : {
557 4 : if (csv_mode)
558 : {
559 0 : gcry_free (current_section_name);
560 0 : current_section_name = gcry_xstrdup (section_name);
561 : }
562 : else
563 4 : printf ("%s:\n", print_name);
564 4 : }
565 :
566 : static void
567 26 : bench_print_header (int algo_width, const char *algo_name)
568 : {
569 26 : if (csv_mode)
570 : {
571 0 : gcry_free (current_algo_name);
572 0 : current_algo_name = gcry_xstrdup (algo_name);
573 : }
574 : else
575 : {
576 26 : if (algo_width < 0)
577 0 : printf (" %-*s | ", -algo_width, algo_name);
578 : else
579 26 : printf (" %-*s | ", algo_width, algo_name);
580 26 : printf ("%14s %15s %13s\n", "nanosecs/byte", "mebibytes/sec",
581 : "cycles/byte");
582 : }
583 26 : }
584 :
585 : static void
586 83 : bench_print_algo (int algo_width, const char *algo_name)
587 : {
588 83 : if (csv_mode)
589 : {
590 0 : gcry_free (current_algo_name);
591 0 : current_algo_name = gcry_xstrdup (algo_name);
592 : }
593 : else
594 : {
595 83 : if (algo_width < 0)
596 83 : printf (" %-*s | ", -algo_width, algo_name);
597 : else
598 0 : printf (" %-*s | ", algo_width, algo_name);
599 : }
600 83 : }
601 :
602 : static void
603 319 : bench_print_mode (int width, const char *mode_name)
604 : {
605 319 : if (csv_mode)
606 : {
607 0 : gcry_free (current_mode_name);
608 0 : current_mode_name = gcry_xstrdup (mode_name);
609 : }
610 : else
611 : {
612 319 : if (width < 0)
613 0 : printf (" %-*s | ", -width, mode_name);
614 : else
615 319 : printf (" %*s | ", width, mode_name);
616 319 : fflush (stdout);
617 : }
618 319 : }
619 :
620 : static void
621 27 : bench_print_footer (int algo_width)
622 : {
623 27 : if (!csv_mode)
624 27 : printf (" %-*s =\n", algo_width, "");
625 27 : }
626 :
627 :
628 : /********************************************************* Cipher benchmarks. */
629 :
630 : struct bench_cipher_mode
631 : {
632 : int mode;
633 : const char *name;
634 : struct bench_ops *ops;
635 :
636 : int algo;
637 : };
638 :
639 :
640 : static int
641 319 : bench_encrypt_init (struct bench_obj *obj)
642 : {
643 319 : struct bench_cipher_mode *mode = obj->priv;
644 : gcry_cipher_hd_t hd;
645 : int err, keylen;
646 :
647 319 : obj->min_bufsize = BUF_START_SIZE;
648 319 : obj->max_bufsize = BUF_END_SIZE;
649 319 : obj->step_size = BUF_STEP_SIZE;
650 319 : obj->num_measure_repetitions = num_measurement_repetitions;
651 :
652 319 : err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0);
653 319 : if (err)
654 : {
655 0 : fprintf (stderr, PGM ": error opening cipher `%s'\n",
656 : gcry_cipher_algo_name (mode->algo));
657 0 : exit (1);
658 : }
659 :
660 319 : keylen = gcry_cipher_get_algo_keylen (mode->algo);
661 319 : if (keylen)
662 : {
663 319 : char key[keylen];
664 : int i;
665 :
666 7289 : for (i = 0; i < keylen; i++)
667 6970 : key[i] = 0x33 ^ (11 - i);
668 :
669 319 : err = gcry_cipher_setkey (hd, key, keylen);
670 319 : if (err)
671 : {
672 0 : fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n",
673 : gpg_strerror (err));
674 0 : gcry_cipher_close (hd);
675 0 : exit (1);
676 : }
677 : }
678 : else
679 : {
680 0 : fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
681 : gcry_cipher_algo_name (mode->algo));
682 0 : gcry_cipher_close (hd);
683 0 : exit (1);
684 : }
685 :
686 319 : obj->priv = hd;
687 :
688 319 : return 0;
689 : }
690 :
691 : static void
692 319 : bench_encrypt_free (struct bench_obj *obj)
693 : {
694 319 : gcry_cipher_hd_t hd = obj->priv;
695 :
696 319 : gcry_cipher_close (hd);
697 319 : }
698 :
699 : static void
700 176316 : bench_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
701 : {
702 176316 : gcry_cipher_hd_t hd = obj->priv;
703 : int err;
704 :
705 176316 : err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
706 176316 : if (err)
707 : {
708 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
709 : gpg_strerror (err));
710 0 : gcry_cipher_close (hd);
711 0 : exit (1);
712 : }
713 176316 : }
714 :
715 : static void
716 149450 : bench_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
717 : {
718 149450 : gcry_cipher_hd_t hd = obj->priv;
719 : int err;
720 :
721 149450 : err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
722 149450 : if (err)
723 : {
724 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
725 : gpg_strerror (err));
726 0 : gcry_cipher_close (hd);
727 0 : exit (1);
728 : }
729 149450 : }
730 :
731 : static struct bench_ops encrypt_ops = {
732 : &bench_encrypt_init,
733 : &bench_encrypt_free,
734 : &bench_encrypt_do_bench
735 : };
736 :
737 : static struct bench_ops decrypt_ops = {
738 : &bench_encrypt_init,
739 : &bench_encrypt_free,
740 : &bench_decrypt_do_bench
741 : };
742 :
743 :
744 : static void
745 18490 : bench_ccm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
746 : {
747 18490 : gcry_cipher_hd_t hd = obj->priv;
748 : int err;
749 : char tag[8];
750 18490 : char nonce[11] = { 0x80, 0x01, };
751 : u64 params[3];
752 :
753 18490 : gcry_cipher_setiv (hd, nonce, sizeof (nonce));
754 :
755 : /* Set CCM lengths */
756 18490 : params[0] = buflen;
757 18490 : params[1] = 0; /*aadlen */
758 18490 : params[2] = sizeof (tag);
759 18490 : err =
760 18490 : gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
761 18490 : if (err)
762 : {
763 0 : fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
764 : gpg_strerror (err));
765 0 : gcry_cipher_close (hd);
766 0 : exit (1);
767 : }
768 :
769 18490 : err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
770 18490 : if (err)
771 : {
772 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
773 : gpg_strerror (err));
774 0 : gcry_cipher_close (hd);
775 0 : exit (1);
776 : }
777 :
778 18490 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
779 18490 : if (err)
780 : {
781 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
782 : gpg_strerror (err));
783 0 : gcry_cipher_close (hd);
784 0 : exit (1);
785 : }
786 18490 : }
787 :
788 : static void
789 10388 : bench_ccm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
790 : {
791 10388 : gcry_cipher_hd_t hd = obj->priv;
792 : int err;
793 10388 : char tag[8] = { 0, };
794 10388 : char nonce[11] = { 0x80, 0x01, };
795 : u64 params[3];
796 :
797 10388 : gcry_cipher_setiv (hd, nonce, sizeof (nonce));
798 :
799 : /* Set CCM lengths */
800 10388 : params[0] = buflen;
801 10388 : params[1] = 0; /*aadlen */
802 10388 : params[2] = sizeof (tag);
803 10388 : err =
804 10388 : gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
805 10388 : if (err)
806 : {
807 0 : fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
808 : gpg_strerror (err));
809 0 : gcry_cipher_close (hd);
810 0 : exit (1);
811 : }
812 :
813 10388 : err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
814 10388 : if (err)
815 : {
816 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
817 : gpg_strerror (err));
818 0 : gcry_cipher_close (hd);
819 0 : exit (1);
820 : }
821 :
822 10388 : err = gcry_cipher_checktag (hd, tag, sizeof (tag));
823 10388 : if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
824 10388 : err = gpg_error (GPG_ERR_NO_ERROR);
825 10388 : if (err)
826 : {
827 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
828 : gpg_strerror (err));
829 0 : gcry_cipher_close (hd);
830 0 : exit (1);
831 : }
832 10388 : }
833 :
834 : static void
835 9034 : bench_ccm_authenticate_do_bench (struct bench_obj *obj, void *buf,
836 : size_t buflen)
837 : {
838 9034 : gcry_cipher_hd_t hd = obj->priv;
839 : int err;
840 9034 : char tag[8] = { 0, };
841 9034 : char nonce[11] = { 0x80, 0x01, };
842 : u64 params[3];
843 9034 : char data = 0xff;
844 :
845 9034 : gcry_cipher_setiv (hd, nonce, sizeof (nonce));
846 :
847 : /* Set CCM lengths */
848 9034 : params[0] = sizeof (data); /*datalen */
849 9034 : params[1] = buflen; /*aadlen */
850 9034 : params[2] = sizeof (tag);
851 9034 : err =
852 9034 : gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
853 9034 : if (err)
854 : {
855 0 : fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
856 : gpg_strerror (err));
857 0 : gcry_cipher_close (hd);
858 0 : exit (1);
859 : }
860 :
861 9034 : err = gcry_cipher_authenticate (hd, buf, buflen);
862 9034 : if (err)
863 : {
864 0 : fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
865 : gpg_strerror (err));
866 0 : gcry_cipher_close (hd);
867 0 : exit (1);
868 : }
869 :
870 9034 : err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
871 9034 : if (err)
872 : {
873 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
874 : gpg_strerror (err));
875 0 : gcry_cipher_close (hd);
876 0 : exit (1);
877 : }
878 :
879 9034 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
880 9034 : if (err)
881 : {
882 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
883 : gpg_strerror (err));
884 0 : gcry_cipher_close (hd);
885 0 : exit (1);
886 : }
887 9034 : }
888 :
889 : static struct bench_ops ccm_encrypt_ops = {
890 : &bench_encrypt_init,
891 : &bench_encrypt_free,
892 : &bench_ccm_encrypt_do_bench
893 : };
894 :
895 : static struct bench_ops ccm_decrypt_ops = {
896 : &bench_encrypt_init,
897 : &bench_encrypt_free,
898 : &bench_ccm_decrypt_do_bench
899 : };
900 :
901 : static struct bench_ops ccm_authenticate_ops = {
902 : &bench_encrypt_init,
903 : &bench_encrypt_free,
904 : &bench_ccm_authenticate_do_bench
905 : };
906 :
907 :
908 : static void
909 30158 : bench_aead_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
910 : const char *nonce, size_t noncelen)
911 : {
912 30158 : gcry_cipher_hd_t hd = obj->priv;
913 : int err;
914 : char tag[16];
915 :
916 30158 : gcry_cipher_setiv (hd, nonce, noncelen);
917 :
918 30158 : gcry_cipher_final (hd);
919 30158 : err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
920 30158 : if (err)
921 : {
922 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
923 : gpg_strerror (err));
924 0 : gcry_cipher_close (hd);
925 0 : exit (1);
926 : }
927 :
928 30158 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
929 30158 : if (err)
930 : {
931 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
932 : gpg_strerror (err));
933 0 : gcry_cipher_close (hd);
934 0 : exit (1);
935 : }
936 30158 : }
937 :
938 : static void
939 18040 : bench_aead_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
940 : const char *nonce, size_t noncelen)
941 : {
942 18040 : gcry_cipher_hd_t hd = obj->priv;
943 : int err;
944 18040 : char tag[16] = { 0, };
945 :
946 18040 : gcry_cipher_setiv (hd, nonce, noncelen);
947 :
948 18040 : gcry_cipher_final (hd);
949 18040 : err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
950 18040 : if (err)
951 : {
952 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
953 : gpg_strerror (err));
954 0 : gcry_cipher_close (hd);
955 0 : exit (1);
956 : }
957 :
958 18040 : err = gcry_cipher_checktag (hd, tag, sizeof (tag));
959 18040 : if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
960 18040 : err = gpg_error (GPG_ERR_NO_ERROR);
961 18040 : if (err)
962 : {
963 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
964 : gpg_strerror (err));
965 0 : gcry_cipher_close (hd);
966 0 : exit (1);
967 : }
968 18040 : }
969 :
970 : static void
971 19884 : bench_aead_authenticate_do_bench (struct bench_obj *obj, void *buf,
972 : size_t buflen, const char *nonce,
973 : size_t noncelen)
974 : {
975 19884 : gcry_cipher_hd_t hd = obj->priv;
976 : int err;
977 19884 : char tag[16] = { 0, };
978 19884 : char data = 0xff;
979 :
980 19884 : err = gcry_cipher_setiv (hd, nonce, noncelen);
981 19884 : if (err)
982 : {
983 0 : fprintf (stderr, PGM ": gcry_cipher_setiv failed: %s\n",
984 : gpg_strerror (err));
985 0 : gcry_cipher_close (hd);
986 0 : exit (1);
987 : }
988 :
989 19884 : err = gcry_cipher_authenticate (hd, buf, buflen);
990 19884 : if (err)
991 : {
992 0 : fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
993 : gpg_strerror (err));
994 0 : gcry_cipher_close (hd);
995 0 : exit (1);
996 : }
997 :
998 19884 : gcry_cipher_final (hd);
999 19884 : err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
1000 19884 : if (err)
1001 : {
1002 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1003 : gpg_strerror (err));
1004 0 : gcry_cipher_close (hd);
1005 0 : exit (1);
1006 : }
1007 :
1008 19884 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1009 19884 : if (err)
1010 : {
1011 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1012 : gpg_strerror (err));
1013 0 : gcry_cipher_close (hd);
1014 0 : exit (1);
1015 : }
1016 19884 : }
1017 :
1018 :
1019 : static void
1020 16202 : bench_gcm_encrypt_do_bench (struct bench_obj *obj, void *buf,
1021 : size_t buflen)
1022 : {
1023 16202 : char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1024 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1025 16202 : bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1026 16202 : }
1027 :
1028 : static void
1029 9474 : bench_gcm_decrypt_do_bench (struct bench_obj *obj, void *buf,
1030 : size_t buflen)
1031 : {
1032 9474 : char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1033 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1034 9474 : bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1035 9474 : }
1036 :
1037 : static void
1038 9766 : bench_gcm_authenticate_do_bench (struct bench_obj *obj, void *buf,
1039 : size_t buflen)
1040 : {
1041 9766 : char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1042 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1043 9766 : bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1044 9766 : }
1045 :
1046 : static struct bench_ops gcm_encrypt_ops = {
1047 : &bench_encrypt_init,
1048 : &bench_encrypt_free,
1049 : &bench_gcm_encrypt_do_bench
1050 : };
1051 :
1052 : static struct bench_ops gcm_decrypt_ops = {
1053 : &bench_encrypt_init,
1054 : &bench_encrypt_free,
1055 : &bench_gcm_decrypt_do_bench
1056 : };
1057 :
1058 : static struct bench_ops gcm_authenticate_ops = {
1059 : &bench_encrypt_init,
1060 : &bench_encrypt_free,
1061 : &bench_gcm_authenticate_do_bench
1062 : };
1063 :
1064 :
1065 : static void
1066 12394 : bench_ocb_encrypt_do_bench (struct bench_obj *obj, void *buf,
1067 : size_t buflen)
1068 : {
1069 12394 : char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1070 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1071 : 0x00, 0x00, 0x01 };
1072 12394 : bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1073 12394 : }
1074 :
1075 : static void
1076 7886 : bench_ocb_decrypt_do_bench (struct bench_obj *obj, void *buf,
1077 : size_t buflen)
1078 : {
1079 7886 : char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1080 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1081 : 0x00, 0x00, 0x01 };
1082 7886 : bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1083 7886 : }
1084 :
1085 : static void
1086 9578 : bench_ocb_authenticate_do_bench (struct bench_obj *obj, void *buf,
1087 : size_t buflen)
1088 : {
1089 9578 : char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1090 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1091 : 0x00, 0x00, 0x01 };
1092 9578 : bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1093 9578 : }
1094 :
1095 : static struct bench_ops ocb_encrypt_ops = {
1096 : &bench_encrypt_init,
1097 : &bench_encrypt_free,
1098 : &bench_ocb_encrypt_do_bench
1099 : };
1100 :
1101 : static struct bench_ops ocb_decrypt_ops = {
1102 : &bench_encrypt_init,
1103 : &bench_encrypt_free,
1104 : &bench_ocb_decrypt_do_bench
1105 : };
1106 :
1107 : static struct bench_ops ocb_authenticate_ops = {
1108 : &bench_encrypt_init,
1109 : &bench_encrypt_free,
1110 : &bench_ocb_authenticate_do_bench
1111 : };
1112 :
1113 :
1114 : static void
1115 1562 : bench_poly1305_encrypt_do_bench (struct bench_obj *obj, void *buf,
1116 : size_t buflen)
1117 : {
1118 1562 : char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1119 1562 : bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1120 1562 : }
1121 :
1122 : static void
1123 680 : bench_poly1305_decrypt_do_bench (struct bench_obj *obj, void *buf,
1124 : size_t buflen)
1125 : {
1126 680 : char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1127 680 : bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1128 680 : }
1129 :
1130 : static void
1131 540 : bench_poly1305_authenticate_do_bench (struct bench_obj *obj, void *buf,
1132 : size_t buflen)
1133 : {
1134 540 : char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1135 540 : bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1136 540 : }
1137 :
1138 : static struct bench_ops poly1305_encrypt_ops = {
1139 : &bench_encrypt_init,
1140 : &bench_encrypt_free,
1141 : &bench_poly1305_encrypt_do_bench
1142 : };
1143 :
1144 : static struct bench_ops poly1305_decrypt_ops = {
1145 : &bench_encrypt_init,
1146 : &bench_encrypt_free,
1147 : &bench_poly1305_decrypt_do_bench
1148 : };
1149 :
1150 : static struct bench_ops poly1305_authenticate_ops = {
1151 : &bench_encrypt_init,
1152 : &bench_encrypt_free,
1153 : &bench_poly1305_authenticate_do_bench
1154 : };
1155 :
1156 :
1157 : static struct bench_cipher_mode cipher_modes[] = {
1158 : {GCRY_CIPHER_MODE_ECB, "ECB enc", &encrypt_ops},
1159 : {GCRY_CIPHER_MODE_ECB, "ECB dec", &decrypt_ops},
1160 : {GCRY_CIPHER_MODE_CBC, "CBC enc", &encrypt_ops},
1161 : {GCRY_CIPHER_MODE_CBC, "CBC dec", &decrypt_ops},
1162 : {GCRY_CIPHER_MODE_CFB, "CFB enc", &encrypt_ops},
1163 : {GCRY_CIPHER_MODE_CFB, "CFB dec", &decrypt_ops},
1164 : {GCRY_CIPHER_MODE_OFB, "OFB enc", &encrypt_ops},
1165 : {GCRY_CIPHER_MODE_OFB, "OFB dec", &decrypt_ops},
1166 : {GCRY_CIPHER_MODE_CTR, "CTR enc", &encrypt_ops},
1167 : {GCRY_CIPHER_MODE_CTR, "CTR dec", &decrypt_ops},
1168 : {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops},
1169 : {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops},
1170 : {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops},
1171 : {GCRY_CIPHER_MODE_GCM, "GCM enc", &gcm_encrypt_ops},
1172 : {GCRY_CIPHER_MODE_GCM, "GCM dec", &gcm_decrypt_ops},
1173 : {GCRY_CIPHER_MODE_GCM, "GCM auth", &gcm_authenticate_ops},
1174 : {GCRY_CIPHER_MODE_OCB, "OCB enc", &ocb_encrypt_ops},
1175 : {GCRY_CIPHER_MODE_OCB, "OCB dec", &ocb_decrypt_ops},
1176 : {GCRY_CIPHER_MODE_OCB, "OCB auth", &ocb_authenticate_ops},
1177 : {GCRY_CIPHER_MODE_POLY1305, "POLY1305 enc", &poly1305_encrypt_ops},
1178 : {GCRY_CIPHER_MODE_POLY1305, "POLY1305 dec", &poly1305_decrypt_ops},
1179 : {GCRY_CIPHER_MODE_POLY1305, "POLY1305 auth", &poly1305_authenticate_ops},
1180 : {0},
1181 : };
1182 :
1183 :
1184 : static void
1185 528 : cipher_bench_one (int algo, struct bench_cipher_mode *pmode)
1186 : {
1187 528 : struct bench_cipher_mode mode = *pmode;
1188 528 : struct bench_obj obj = { 0 };
1189 : double result;
1190 : unsigned int blklen;
1191 :
1192 528 : mode.algo = algo;
1193 :
1194 : /* Check if this mode is ok */
1195 528 : blklen = gcry_cipher_get_algo_blklen (algo);
1196 528 : if (!blklen)
1197 209 : return;
1198 :
1199 : /* Stream cipher? Only test with "ECB" and POLY1305. */
1200 608 : if (blklen == 1 && (mode.mode != GCRY_CIPHER_MODE_ECB &&
1201 80 : mode.mode != GCRY_CIPHER_MODE_POLY1305))
1202 68 : return;
1203 460 : if (blklen == 1 && mode.mode == GCRY_CIPHER_MODE_ECB)
1204 : {
1205 8 : mode.mode = GCRY_CIPHER_MODE_STREAM;
1206 8 : mode.name = mode.ops == &encrypt_ops ? "STREAM enc" : "STREAM dec";
1207 : }
1208 :
1209 : /* Poly1305 has restriction for cipher algorithm */
1210 460 : if (mode.mode == GCRY_CIPHER_MODE_POLY1305 && algo != GCRY_CIPHER_CHACHA20)
1211 69 : return;
1212 :
1213 : /* CCM has restrictions for block-size */
1214 391 : if (mode.mode == GCRY_CIPHER_MODE_CCM && blklen != GCRY_CCM_BLOCK_LEN)
1215 24 : return;
1216 :
1217 : /* GCM has restrictions for block-size */
1218 367 : if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN)
1219 24 : return;
1220 :
1221 : /* Our OCB implementaion has restrictions for block-size. */
1222 343 : if (mode.mode == GCRY_CIPHER_MODE_OCB && blklen != 16)
1223 24 : return;
1224 :
1225 319 : bench_print_mode (14, mode.name);
1226 :
1227 319 : obj.ops = mode.ops;
1228 319 : obj.priv = &mode;
1229 :
1230 319 : result = do_slope_benchmark (&obj);
1231 :
1232 319 : bench_print_result (result);
1233 : }
1234 :
1235 :
1236 : static void
1237 24 : _cipher_bench (int algo)
1238 : {
1239 : const char *algoname;
1240 : int i;
1241 :
1242 24 : algoname = gcry_cipher_algo_name (algo);
1243 :
1244 24 : bench_print_header (14, algoname);
1245 :
1246 552 : for (i = 0; cipher_modes[i].mode; i++)
1247 528 : cipher_bench_one (algo, &cipher_modes[i]);
1248 :
1249 24 : bench_print_footer (14);
1250 24 : }
1251 :
1252 :
1253 : void
1254 1 : cipher_bench (char **argv, int argc)
1255 : {
1256 : int i, algo;
1257 :
1258 1 : bench_print_section ("cipher", "Cipher");
1259 :
1260 1 : if (argv && argc)
1261 : {
1262 0 : for (i = 0; i < argc; i++)
1263 : {
1264 0 : algo = gcry_cipher_map_name (argv[i]);
1265 0 : if (algo)
1266 0 : _cipher_bench (algo);
1267 : }
1268 : }
1269 : else
1270 : {
1271 400 : for (i = 1; i < 400; i++)
1272 399 : if (!gcry_cipher_test_algo (i))
1273 24 : _cipher_bench (i);
1274 : }
1275 1 : }
1276 :
1277 :
1278 : /*********************************************************** Hash benchmarks. */
1279 :
1280 : struct bench_hash_mode
1281 : {
1282 : const char *name;
1283 : struct bench_ops *ops;
1284 :
1285 : int algo;
1286 : };
1287 :
1288 :
1289 : static int
1290 25 : bench_hash_init (struct bench_obj *obj)
1291 : {
1292 25 : struct bench_hash_mode *mode = obj->priv;
1293 : gcry_md_hd_t hd;
1294 : int err;
1295 :
1296 25 : obj->min_bufsize = BUF_START_SIZE;
1297 25 : obj->max_bufsize = BUF_END_SIZE;
1298 25 : obj->step_size = BUF_STEP_SIZE;
1299 25 : obj->num_measure_repetitions = num_measurement_repetitions;
1300 :
1301 25 : err = gcry_md_open (&hd, mode->algo, 0);
1302 25 : if (err)
1303 : {
1304 0 : fprintf (stderr, PGM ": error opening hash `%s'\n",
1305 : gcry_md_algo_name (mode->algo));
1306 0 : exit (1);
1307 : }
1308 :
1309 25 : obj->priv = hd;
1310 :
1311 25 : return 0;
1312 : }
1313 :
1314 : static void
1315 25 : bench_hash_free (struct bench_obj *obj)
1316 : {
1317 25 : gcry_md_hd_t hd = obj->priv;
1318 :
1319 25 : gcry_md_close (hd);
1320 25 : }
1321 :
1322 : static void
1323 34498 : bench_hash_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1324 : {
1325 34498 : gcry_md_hd_t hd = obj->priv;
1326 :
1327 34498 : gcry_md_reset (hd);
1328 34498 : gcry_md_write (hd, buf, buflen);
1329 34498 : gcry_md_final (hd);
1330 34498 : }
1331 :
1332 : static struct bench_ops hash_ops = {
1333 : &bench_hash_init,
1334 : &bench_hash_free,
1335 : &bench_hash_do_bench
1336 : };
1337 :
1338 :
1339 : static struct bench_hash_mode hash_modes[] = {
1340 : {"", &hash_ops},
1341 : {0},
1342 : };
1343 :
1344 :
1345 : static void
1346 25 : hash_bench_one (int algo, struct bench_hash_mode *pmode)
1347 : {
1348 25 : struct bench_hash_mode mode = *pmode;
1349 25 : struct bench_obj obj = { 0 };
1350 : double result;
1351 :
1352 25 : mode.algo = algo;
1353 :
1354 25 : if (mode.name[0] == '\0')
1355 25 : bench_print_algo (-14, gcry_md_algo_name (algo));
1356 : else
1357 0 : bench_print_algo (14, mode.name);
1358 :
1359 25 : obj.ops = mode.ops;
1360 25 : obj.priv = &mode;
1361 :
1362 25 : result = do_slope_benchmark (&obj);
1363 :
1364 25 : bench_print_result (result);
1365 25 : }
1366 :
1367 : static void
1368 25 : _hash_bench (int algo)
1369 : {
1370 : int i;
1371 :
1372 50 : for (i = 0; hash_modes[i].name; i++)
1373 25 : hash_bench_one (algo, &hash_modes[i]);
1374 25 : }
1375 :
1376 : void
1377 1 : hash_bench (char **argv, int argc)
1378 : {
1379 : int i, algo;
1380 :
1381 1 : bench_print_section ("hash", "Hash");
1382 1 : bench_print_header (14, "");
1383 :
1384 1 : if (argv && argc)
1385 : {
1386 0 : for (i = 0; i < argc; i++)
1387 : {
1388 0 : algo = gcry_md_map_name (argv[i]);
1389 0 : if (algo)
1390 0 : _hash_bench (algo);
1391 : }
1392 : }
1393 : else
1394 : {
1395 400 : for (i = 1; i < 400; i++)
1396 399 : if (!gcry_md_test_algo (i))
1397 25 : _hash_bench (i);
1398 : }
1399 :
1400 1 : bench_print_footer (14);
1401 1 : }
1402 :
1403 :
1404 : /************************************************************ MAC benchmarks. */
1405 :
1406 : struct bench_mac_mode
1407 : {
1408 : const char *name;
1409 : struct bench_ops *ops;
1410 :
1411 : int algo;
1412 : };
1413 :
1414 :
1415 : static int
1416 39 : bench_mac_init (struct bench_obj *obj)
1417 : {
1418 39 : struct bench_mac_mode *mode = obj->priv;
1419 : gcry_mac_hd_t hd;
1420 : int err;
1421 : unsigned int keylen;
1422 : void *key;
1423 :
1424 39 : obj->min_bufsize = BUF_START_SIZE;
1425 39 : obj->max_bufsize = BUF_END_SIZE;
1426 39 : obj->step_size = BUF_STEP_SIZE;
1427 39 : obj->num_measure_repetitions = num_measurement_repetitions;
1428 :
1429 39 : keylen = gcry_mac_get_algo_keylen (mode->algo);
1430 39 : if (keylen == 0)
1431 0 : keylen = 32;
1432 39 : key = malloc (keylen);
1433 39 : if (!key)
1434 : {
1435 0 : fprintf (stderr, PGM ": couldn't allocate %d bytes\n", keylen);
1436 0 : exit (1);
1437 : }
1438 39 : memset(key, 42, keylen);
1439 :
1440 39 : err = gcry_mac_open (&hd, mode->algo, 0, NULL);
1441 39 : if (err)
1442 : {
1443 0 : fprintf (stderr, PGM ": error opening mac `%s'\n",
1444 : gcry_mac_algo_name (mode->algo));
1445 0 : free (key);
1446 0 : exit (1);
1447 : }
1448 :
1449 39 : err = gcry_mac_setkey (hd, key, keylen);
1450 39 : if (err)
1451 : {
1452 0 : fprintf (stderr, PGM ": error setting key for mac `%s'\n",
1453 : gcry_mac_algo_name (mode->algo));
1454 0 : free (key);
1455 0 : exit (1);
1456 : }
1457 :
1458 39 : switch (mode->algo)
1459 : {
1460 : default:
1461 34 : break;
1462 : case GCRY_MAC_POLY1305_AES:
1463 : case GCRY_MAC_POLY1305_CAMELLIA:
1464 : case GCRY_MAC_POLY1305_TWOFISH:
1465 : case GCRY_MAC_POLY1305_SERPENT:
1466 : case GCRY_MAC_POLY1305_SEED:
1467 5 : gcry_mac_setiv (hd, key, 16);
1468 5 : break;
1469 : }
1470 :
1471 39 : obj->priv = hd;
1472 :
1473 39 : free (key);
1474 39 : return 0;
1475 : }
1476 :
1477 : static void
1478 39 : bench_mac_free (struct bench_obj *obj)
1479 : {
1480 39 : gcry_mac_hd_t hd = obj->priv;
1481 :
1482 39 : gcry_mac_close (hd);
1483 39 : }
1484 :
1485 : static void
1486 25506 : bench_mac_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1487 : {
1488 25506 : gcry_mac_hd_t hd = obj->priv;
1489 : size_t bs;
1490 : char b;
1491 :
1492 25506 : gcry_mac_reset (hd);
1493 25506 : gcry_mac_write (hd, buf, buflen);
1494 25506 : bs = sizeof(b);
1495 25506 : gcry_mac_read (hd, &b, &bs);
1496 25506 : }
1497 :
1498 : static struct bench_ops mac_ops = {
1499 : &bench_mac_init,
1500 : &bench_mac_free,
1501 : &bench_mac_do_bench
1502 : };
1503 :
1504 :
1505 : static struct bench_mac_mode mac_modes[] = {
1506 : {"", &mac_ops},
1507 : {0},
1508 : };
1509 :
1510 :
1511 : static void
1512 39 : mac_bench_one (int algo, struct bench_mac_mode *pmode)
1513 : {
1514 39 : struct bench_mac_mode mode = *pmode;
1515 39 : struct bench_obj obj = { 0 };
1516 : double result;
1517 :
1518 39 : mode.algo = algo;
1519 :
1520 39 : if (mode.name[0] == '\0')
1521 39 : bench_print_algo (-18, gcry_mac_algo_name (algo));
1522 : else
1523 0 : bench_print_algo (18, mode.name);
1524 :
1525 39 : obj.ops = mode.ops;
1526 39 : obj.priv = &mode;
1527 :
1528 39 : result = do_slope_benchmark (&obj);
1529 :
1530 39 : bench_print_result (result);
1531 39 : }
1532 :
1533 : static void
1534 39 : _mac_bench (int algo)
1535 : {
1536 : int i;
1537 :
1538 78 : for (i = 0; mac_modes[i].name; i++)
1539 39 : mac_bench_one (algo, &mac_modes[i]);
1540 39 : }
1541 :
1542 : void
1543 1 : mac_bench (char **argv, int argc)
1544 : {
1545 : int i, algo;
1546 :
1547 1 : bench_print_section ("mac", "MAC");
1548 1 : bench_print_header (18, "");
1549 :
1550 1 : if (argv && argc)
1551 : {
1552 0 : for (i = 0; i < argc; i++)
1553 : {
1554 0 : algo = gcry_mac_map_name (argv[i]);
1555 0 : if (algo)
1556 0 : _mac_bench (algo);
1557 : }
1558 : }
1559 : else
1560 : {
1561 600 : for (i = 1; i < 600; i++)
1562 599 : if (!gcry_mac_test_algo (i))
1563 39 : _mac_bench (i);
1564 : }
1565 :
1566 1 : bench_print_footer (18);
1567 1 : }
1568 :
1569 :
1570 : /************************************************************ KDF benchmarks. */
1571 :
1572 : struct bench_kdf_mode
1573 : {
1574 : struct bench_ops *ops;
1575 :
1576 : int algo;
1577 : int subalgo;
1578 : };
1579 :
1580 :
1581 : static int
1582 19 : bench_kdf_init (struct bench_obj *obj)
1583 : {
1584 19 : struct bench_kdf_mode *mode = obj->priv;
1585 :
1586 19 : if (mode->algo == GCRY_KDF_PBKDF2)
1587 : {
1588 19 : obj->min_bufsize = 2;
1589 19 : obj->max_bufsize = 2 * 32;
1590 19 : obj->step_size = 2;
1591 : }
1592 :
1593 19 : obj->num_measure_repetitions = num_measurement_repetitions;
1594 :
1595 19 : return 0;
1596 : }
1597 :
1598 : static void
1599 19 : bench_kdf_free (struct bench_obj *obj)
1600 : {
1601 : (void)obj;
1602 19 : }
1603 :
1604 : static void
1605 6224 : bench_kdf_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1606 : {
1607 6224 : struct bench_kdf_mode *mode = obj->priv;
1608 : char keybuf[16];
1609 :
1610 : (void)buf;
1611 :
1612 6224 : if (mode->algo == GCRY_KDF_PBKDF2)
1613 : {
1614 6224 : gcry_kdf_derive("qwerty", 6, mode->algo, mode->subalgo, "01234567", 8,
1615 : buflen, sizeof(keybuf), keybuf);
1616 : }
1617 6224 : }
1618 :
1619 : static struct bench_ops kdf_ops = {
1620 : &bench_kdf_init,
1621 : &bench_kdf_free,
1622 : &bench_kdf_do_bench
1623 : };
1624 :
1625 :
1626 : static void
1627 25 : kdf_bench_one (int algo, int subalgo)
1628 : {
1629 25 : struct bench_kdf_mode mode = { &kdf_ops };
1630 25 : struct bench_obj obj = { 0 };
1631 : double nsecs_per_iteration;
1632 : double cycles_per_iteration;
1633 : char algo_name[32];
1634 : char nsecpiter_buf[16];
1635 : char cpiter_buf[16];
1636 :
1637 25 : mode.algo = algo;
1638 25 : mode.subalgo = subalgo;
1639 :
1640 25 : switch (subalgo)
1641 : {
1642 : case GCRY_MD_CRC32:
1643 : case GCRY_MD_CRC32_RFC1510:
1644 : case GCRY_MD_CRC24_RFC2440:
1645 : case GCRY_MD_MD4:
1646 : /* Skip CRC32s. */
1647 10 : return;
1648 : }
1649 :
1650 21 : if (gcry_md_get_algo_dlen (subalgo) == 0)
1651 : {
1652 : /* Skip XOFs */
1653 2 : return;
1654 : }
1655 :
1656 19 : *algo_name = 0;
1657 :
1658 19 : if (algo == GCRY_KDF_PBKDF2)
1659 : {
1660 19 : snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
1661 : gcry_md_algo_name (subalgo));
1662 : }
1663 :
1664 19 : bench_print_algo (-24, algo_name);
1665 :
1666 19 : obj.ops = mode.ops;
1667 19 : obj.priv = &mode;
1668 :
1669 19 : nsecs_per_iteration = do_slope_benchmark (&obj);
1670 :
1671 19 : strcpy(cpiter_buf, csv_mode ? "" : "-");
1672 :
1673 19 : double_to_str (nsecpiter_buf, sizeof (nsecpiter_buf), nsecs_per_iteration);
1674 :
1675 : /* If user didn't provide CPU speed, we cannot show cycles/iter results. */
1676 19 : if (cpu_ghz > 0.0)
1677 : {
1678 0 : cycles_per_iteration = nsecs_per_iteration * cpu_ghz;
1679 0 : double_to_str (cpiter_buf, sizeof (cpiter_buf), cycles_per_iteration);
1680 : }
1681 :
1682 19 : if (csv_mode)
1683 : {
1684 0 : printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter\n",
1685 : current_section_name,
1686 0 : current_algo_name ? current_algo_name : "",
1687 0 : current_mode_name ? current_mode_name : "",
1688 : nsecpiter_buf,
1689 : cpiter_buf);
1690 : }
1691 : else
1692 : {
1693 19 : printf ("%14s %13s\n", nsecpiter_buf, cpiter_buf);
1694 : }
1695 : }
1696 :
1697 : void
1698 1 : kdf_bench (char **argv, int argc)
1699 : {
1700 : char algo_name[32];
1701 : int i, j;
1702 :
1703 1 : bench_print_section ("kdf", "KDF");
1704 :
1705 1 : if (!csv_mode)
1706 : {
1707 1 : printf (" %-*s | ", 24, "");
1708 1 : printf ("%14s %13s\n", "nanosecs/iter", "cycles/iter");
1709 : }
1710 :
1711 1 : if (argv && argc)
1712 : {
1713 0 : for (i = 0; i < argc; i++)
1714 : {
1715 0 : for (j = 1; j < 400; j++)
1716 : {
1717 0 : if (gcry_md_test_algo (j))
1718 0 : continue;
1719 :
1720 0 : snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
1721 : gcry_md_algo_name (j));
1722 :
1723 0 : if (!strcmp(argv[i], algo_name))
1724 0 : kdf_bench_one (GCRY_KDF_PBKDF2, j);
1725 : }
1726 : }
1727 : }
1728 : else
1729 : {
1730 400 : for (i = 1; i < 400; i++)
1731 399 : if (!gcry_md_test_algo (i))
1732 25 : kdf_bench_one (GCRY_KDF_PBKDF2, i);
1733 : }
1734 :
1735 1 : bench_print_footer (24);
1736 1 : }
1737 :
1738 :
1739 : /************************************************************** Main program. */
1740 :
1741 : void
1742 0 : print_help (void)
1743 : {
1744 : static const char *help_lines[] = {
1745 : "usage: bench-slope [options] [hash|mac|cipher|kdf [algonames]]",
1746 : "",
1747 : " options:",
1748 : " --cpu-mhz <mhz> Set CPU speed for calculating cycles",
1749 : " per bytes results.",
1750 : " --disable-hwf <features> Disable hardware acceleration feature(s)",
1751 : " for benchmarking.",
1752 : " --repetitions <n> Use N repetitions (default "
1753 : STR2(NUM_MEASUREMENT_REPETITIONS) ")",
1754 : " --unaligned Use unaligned input buffers.",
1755 : " --csv Use CSV output format",
1756 : NULL
1757 : };
1758 : const char **line;
1759 :
1760 0 : for (line = help_lines; *line; line++)
1761 0 : fprintf (stdout, "%s\n", *line);
1762 0 : }
1763 :
1764 :
1765 : /* Warm up CPU. */
1766 : static void
1767 1 : warm_up_cpu (void)
1768 : {
1769 : struct nsec_time start, end;
1770 :
1771 1 : get_nsec_time (&start);
1772 : do
1773 : {
1774 28949775 : get_nsec_time (&end);
1775 : }
1776 28949775 : while (get_time_nsec_diff (&start, &end) < 1000.0 * 1000.0 * 1000.0);
1777 1 : }
1778 :
1779 :
1780 : int
1781 1 : main (int argc, char **argv)
1782 : {
1783 1 : int last_argc = -1;
1784 1 : int debug = 0;
1785 :
1786 1 : if (argc)
1787 : {
1788 1 : argc--;
1789 1 : argv++;
1790 : }
1791 :
1792 : /* We skip this test if we are running under the test suite (no args
1793 : and srcdir defined) and GCRYPT_NO_BENCHMARKS is set. */
1794 1 : if (!argc && getenv ("srcdir") && getenv ("GCRYPT_NO_BENCHMARKS"))
1795 0 : exit (77);
1796 :
1797 1 : if (getenv ("GCRYPT_IN_REGRESSION_TEST"))
1798 : {
1799 1 : in_regression_test = 1;
1800 1 : num_measurement_repetitions = 2;
1801 : }
1802 : else
1803 0 : num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
1804 :
1805 2 : while (argc && last_argc != argc)
1806 : {
1807 0 : last_argc = argc;
1808 :
1809 0 : if (!strcmp (*argv, "--"))
1810 : {
1811 0 : argc--;
1812 0 : argv++;
1813 0 : break;
1814 : }
1815 0 : else if (!strcmp (*argv, "--help"))
1816 : {
1817 0 : print_help ();
1818 0 : exit (0);
1819 : }
1820 0 : else if (!strcmp (*argv, "--verbose"))
1821 : {
1822 0 : verbose++;
1823 0 : argc--;
1824 0 : argv++;
1825 : }
1826 0 : else if (!strcmp (*argv, "--debug"))
1827 : {
1828 0 : verbose += 2;
1829 0 : debug++;
1830 0 : argc--;
1831 0 : argv++;
1832 : }
1833 0 : else if (!strcmp (*argv, "--csv"))
1834 : {
1835 0 : csv_mode = 1;
1836 0 : argc--;
1837 0 : argv++;
1838 : }
1839 0 : else if (!strcmp (*argv, "--unaligned"))
1840 : {
1841 0 : unaligned_mode = 1;
1842 0 : argc--;
1843 0 : argv++;
1844 : }
1845 0 : else if (!strcmp (*argv, "--disable-hwf"))
1846 : {
1847 0 : argc--;
1848 0 : argv++;
1849 0 : if (argc)
1850 : {
1851 0 : if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
1852 0 : fprintf (stderr,
1853 : PGM
1854 : ": unknown hardware feature `%s' - option ignored\n",
1855 : *argv);
1856 0 : argc--;
1857 0 : argv++;
1858 : }
1859 : }
1860 0 : else if (!strcmp (*argv, "--cpu-mhz"))
1861 : {
1862 0 : argc--;
1863 0 : argv++;
1864 0 : if (argc)
1865 : {
1866 0 : cpu_ghz = atof (*argv);
1867 0 : cpu_ghz /= 1000; /* Mhz => Ghz */
1868 :
1869 0 : argc--;
1870 0 : argv++;
1871 : }
1872 : }
1873 0 : else if (!strcmp (*argv, "--repetitions"))
1874 : {
1875 0 : argc--;
1876 0 : argv++;
1877 0 : if (argc)
1878 : {
1879 0 : num_measurement_repetitions = atof (*argv);
1880 0 : if (num_measurement_repetitions < 2)
1881 : {
1882 0 : fprintf (stderr,
1883 : PGM
1884 : ": value for --repetitions too small - using %d\n",
1885 : NUM_MEASUREMENT_REPETITIONS);
1886 0 : num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
1887 : }
1888 0 : argc--;
1889 0 : argv++;
1890 : }
1891 : }
1892 : }
1893 :
1894 1 : gcry_control (GCRYCTL_SET_VERBOSITY, (int) verbose);
1895 :
1896 1 : if (!gcry_check_version (GCRYPT_VERSION))
1897 : {
1898 0 : fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n",
1899 : GCRYPT_VERSION, gcry_check_version (NULL));
1900 0 : exit (1);
1901 : }
1902 :
1903 1 : if (debug)
1904 0 : gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
1905 :
1906 1 : gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
1907 1 : gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
1908 1 : gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
1909 :
1910 1 : if (in_regression_test)
1911 1 : fputs ("Note: " PGM " running in quick regression test mode.\n", stdout);
1912 :
1913 1 : if (!argc)
1914 : {
1915 1 : warm_up_cpu ();
1916 1 : hash_bench (NULL, 0);
1917 1 : mac_bench (NULL, 0);
1918 1 : cipher_bench (NULL, 0);
1919 1 : kdf_bench (NULL, 0);
1920 : }
1921 0 : else if (!strcmp (*argv, "hash"))
1922 : {
1923 0 : argc--;
1924 0 : argv++;
1925 :
1926 0 : warm_up_cpu ();
1927 0 : hash_bench ((argc == 0) ? NULL : argv, argc);
1928 : }
1929 0 : else if (!strcmp (*argv, "mac"))
1930 : {
1931 0 : argc--;
1932 0 : argv++;
1933 :
1934 0 : warm_up_cpu ();
1935 0 : mac_bench ((argc == 0) ? NULL : argv, argc);
1936 : }
1937 0 : else if (!strcmp (*argv, "cipher"))
1938 : {
1939 0 : argc--;
1940 0 : argv++;
1941 :
1942 0 : warm_up_cpu ();
1943 0 : cipher_bench ((argc == 0) ? NULL : argv, argc);
1944 : }
1945 0 : else if (!strcmp (*argv, "kdf"))
1946 : {
1947 0 : argc--;
1948 0 : argv++;
1949 :
1950 0 : warm_up_cpu ();
1951 0 : kdf_bench ((argc == 0) ? NULL : argv, argc);
1952 : }
1953 : else
1954 : {
1955 0 : fprintf (stderr, PGM ": unknown argument: %s\n", *argv);
1956 0 : print_help ();
1957 : }
1958 :
1959 1 : return 0;
1960 : }
1961 :
1962 : #endif /* !NO_GET_NSEC_TIME */
|