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