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