Add EAX mode
[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 int
746 bench_xts_encrypt_init (struct bench_obj *obj)
747 {
748   struct bench_cipher_mode *mode = obj->priv;
749   gcry_cipher_hd_t hd;
750   int err, keylen;
751
752   /* For XTS, benchmark with typical data-unit size (512 byte sectors). */
753   obj->min_bufsize = 512;
754   obj->max_bufsize = 16 * obj->min_bufsize;
755   obj->step_size = obj->min_bufsize;
756   obj->num_measure_repetitions = num_measurement_repetitions;
757
758   err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0);
759   if (err)
760     {
761       fprintf (stderr, PGM ": error opening cipher `%s'\n",
762                gcry_cipher_algo_name (mode->algo));
763       exit (1);
764     }
765
766   /* Double key-length for XTS. */
767   keylen = gcry_cipher_get_algo_keylen (mode->algo) * 2;
768   if (keylen)
769     {
770       char key[keylen];
771       int i;
772
773       for (i = 0; i < keylen; i++)
774         key[i] = 0x33 ^ (11 - i);
775
776       err = gcry_cipher_setkey (hd, key, keylen);
777       if (err)
778         {
779           fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n",
780                    gpg_strerror (err));
781           gcry_cipher_close (hd);
782           exit (1);
783         }
784     }
785   else
786     {
787       fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
788                gcry_cipher_algo_name (mode->algo));
789       gcry_cipher_close (hd);
790       exit (1);
791     }
792
793   obj->priv = hd;
794
795   return 0;
796 }
797
798 static void
799 bench_xts_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
800 {
801   gcry_cipher_hd_t hd = obj->priv;
802   unsigned int pos;
803   static const char tweak[16] = { 0xff, 0xff, 0xfe, };
804   size_t sectorlen = obj->step_size;
805   char *cbuf = buf;
806   int err;
807
808   gcry_cipher_setiv (hd, tweak, sizeof (tweak));
809
810   /* Process each sector separately. */
811
812   for (pos = 0; pos < buflen; pos += sectorlen, cbuf += sectorlen)
813     {
814       err = gcry_cipher_encrypt (hd, cbuf, sectorlen, cbuf, sectorlen);
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 }
824
825 static void
826 bench_xts_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
827 {
828   gcry_cipher_hd_t hd = obj->priv;
829   unsigned int pos;
830   static const char tweak[16] = { 0xff, 0xff, 0xfe, };
831   size_t sectorlen = obj->step_size;
832   char *cbuf = buf;
833   int err;
834
835   gcry_cipher_setiv (hd, tweak, sizeof (tweak));
836
837   /* Process each sector separately. */
838
839   for (pos = 0; pos < buflen; pos += sectorlen, cbuf += sectorlen)
840     {
841       err = gcry_cipher_decrypt (hd, cbuf, sectorlen, cbuf, sectorlen);
842       if (err)
843         {
844           fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
845                   gpg_strerror (err));
846           gcry_cipher_close (hd);
847           exit (1);
848         }
849     }
850 }
851
852 static struct bench_ops xts_encrypt_ops = {
853   &bench_xts_encrypt_init,
854   &bench_encrypt_free,
855   &bench_xts_encrypt_do_bench
856 };
857
858 static struct bench_ops xts_decrypt_ops = {
859   &bench_xts_encrypt_init,
860   &bench_encrypt_free,
861   &bench_xts_decrypt_do_bench
862 };
863
864
865 static void
866 bench_ccm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
867 {
868   gcry_cipher_hd_t hd = obj->priv;
869   int err;
870   char tag[8];
871   char nonce[11] = { 0x80, 0x01, };
872   u64 params[3];
873
874   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
875
876   /* Set CCM lengths */
877   params[0] = buflen;
878   params[1] = 0;                /*aadlen */
879   params[2] = sizeof (tag);
880   err =
881     gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
882   if (err)
883     {
884       fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
885                gpg_strerror (err));
886       gcry_cipher_close (hd);
887       exit (1);
888     }
889
890   err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
891   if (err)
892     {
893       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
894                gpg_strerror (err));
895       gcry_cipher_close (hd);
896       exit (1);
897     }
898
899   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
900   if (err)
901     {
902       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
903                gpg_strerror (err));
904       gcry_cipher_close (hd);
905       exit (1);
906     }
907 }
908
909 static void
910 bench_ccm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
911 {
912   gcry_cipher_hd_t hd = obj->priv;
913   int err;
914   char tag[8] = { 0, };
915   char nonce[11] = { 0x80, 0x01, };
916   u64 params[3];
917
918   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
919
920   /* Set CCM lengths */
921   params[0] = buflen;
922   params[1] = 0;                /*aadlen */
923   params[2] = sizeof (tag);
924   err =
925     gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
926   if (err)
927     {
928       fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
929                gpg_strerror (err));
930       gcry_cipher_close (hd);
931       exit (1);
932     }
933
934   err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
935   if (err)
936     {
937       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
938                gpg_strerror (err));
939       gcry_cipher_close (hd);
940       exit (1);
941     }
942
943   err = gcry_cipher_checktag (hd, tag, sizeof (tag));
944   if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
945     err = gpg_error (GPG_ERR_NO_ERROR);
946   if (err)
947     {
948       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
949                gpg_strerror (err));
950       gcry_cipher_close (hd);
951       exit (1);
952     }
953 }
954
955 static void
956 bench_ccm_authenticate_do_bench (struct bench_obj *obj, void *buf,
957                                  size_t buflen)
958 {
959   gcry_cipher_hd_t hd = obj->priv;
960   int err;
961   char tag[8] = { 0, };
962   char nonce[11] = { 0x80, 0x01, };
963   u64 params[3];
964   char data = 0xff;
965
966   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
967
968   /* Set CCM lengths */
969   params[0] = sizeof (data);    /*datalen */
970   params[1] = buflen;           /*aadlen */
971   params[2] = sizeof (tag);
972   err =
973     gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
974   if (err)
975     {
976       fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
977                gpg_strerror (err));
978       gcry_cipher_close (hd);
979       exit (1);
980     }
981
982   err = gcry_cipher_authenticate (hd, buf, buflen);
983   if (err)
984     {
985       fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
986                gpg_strerror (err));
987       gcry_cipher_close (hd);
988       exit (1);
989     }
990
991   err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
992   if (err)
993     {
994       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
995                gpg_strerror (err));
996       gcry_cipher_close (hd);
997       exit (1);
998     }
999
1000   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1001   if (err)
1002     {
1003       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1004                gpg_strerror (err));
1005       gcry_cipher_close (hd);
1006       exit (1);
1007     }
1008 }
1009
1010 static struct bench_ops ccm_encrypt_ops = {
1011   &bench_encrypt_init,
1012   &bench_encrypt_free,
1013   &bench_ccm_encrypt_do_bench
1014 };
1015
1016 static struct bench_ops ccm_decrypt_ops = {
1017   &bench_encrypt_init,
1018   &bench_encrypt_free,
1019   &bench_ccm_decrypt_do_bench
1020 };
1021
1022 static struct bench_ops ccm_authenticate_ops = {
1023   &bench_encrypt_init,
1024   &bench_encrypt_free,
1025   &bench_ccm_authenticate_do_bench
1026 };
1027
1028
1029 static void
1030 bench_aead_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
1031                              const char *nonce, size_t noncelen)
1032 {
1033   gcry_cipher_hd_t hd = obj->priv;
1034   int err;
1035   char tag[16];
1036
1037   gcry_cipher_setiv (hd, nonce, noncelen);
1038
1039   gcry_cipher_final (hd);
1040   err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
1041   if (err)
1042     {
1043       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1044            gpg_strerror (err));
1045       gcry_cipher_close (hd);
1046       exit (1);
1047     }
1048
1049   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1050   if (err)
1051     {
1052       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1053            gpg_strerror (err));
1054       gcry_cipher_close (hd);
1055       exit (1);
1056     }
1057 }
1058
1059 static void
1060 bench_aead_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
1061                              const char *nonce, size_t noncelen)
1062 {
1063   gcry_cipher_hd_t hd = obj->priv;
1064   int err;
1065   char tag[16] = { 0, };
1066
1067   gcry_cipher_setiv (hd, nonce, noncelen);
1068
1069   gcry_cipher_final (hd);
1070   err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
1071   if (err)
1072     {
1073       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1074            gpg_strerror (err));
1075       gcry_cipher_close (hd);
1076       exit (1);
1077     }
1078
1079   err = gcry_cipher_checktag (hd, tag, sizeof (tag));
1080   if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
1081     err = gpg_error (GPG_ERR_NO_ERROR);
1082   if (err)
1083     {
1084       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1085            gpg_strerror (err));
1086       gcry_cipher_close (hd);
1087       exit (1);
1088     }
1089 }
1090
1091 static void
1092 bench_aead_authenticate_do_bench (struct bench_obj *obj, void *buf,
1093                                   size_t buflen, const char *nonce,
1094                                   size_t noncelen)
1095 {
1096   gcry_cipher_hd_t hd = obj->priv;
1097   int err;
1098   char tag[16] = { 0, };
1099   char data = 0xff;
1100
1101   err = gcry_cipher_setiv (hd, nonce, noncelen);
1102   if (err)
1103     {
1104       fprintf (stderr, PGM ": gcry_cipher_setiv failed: %s\n",
1105            gpg_strerror (err));
1106       gcry_cipher_close (hd);
1107       exit (1);
1108     }
1109
1110   err = gcry_cipher_authenticate (hd, buf, buflen);
1111   if (err)
1112     {
1113       fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
1114            gpg_strerror (err));
1115       gcry_cipher_close (hd);
1116       exit (1);
1117     }
1118
1119   gcry_cipher_final (hd);
1120   err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
1121   if (err)
1122     {
1123       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1124            gpg_strerror (err));
1125       gcry_cipher_close (hd);
1126       exit (1);
1127     }
1128
1129   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1130   if (err)
1131     {
1132       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1133            gpg_strerror (err));
1134       gcry_cipher_close (hd);
1135       exit (1);
1136     }
1137 }
1138
1139
1140 static void
1141 bench_gcm_encrypt_do_bench (struct bench_obj *obj, void *buf,
1142                             size_t buflen)
1143 {
1144   char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1145                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1146   bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1147 }
1148
1149 static void
1150 bench_gcm_decrypt_do_bench (struct bench_obj *obj, void *buf,
1151                             size_t buflen)
1152 {
1153   char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1154                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1155   bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1156 }
1157
1158 static void
1159 bench_gcm_authenticate_do_bench (struct bench_obj *obj, void *buf,
1160                                  size_t buflen)
1161 {
1162   char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1163                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1164   bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1165 }
1166
1167 static struct bench_ops gcm_encrypt_ops = {
1168   &bench_encrypt_init,
1169   &bench_encrypt_free,
1170   &bench_gcm_encrypt_do_bench
1171 };
1172
1173 static struct bench_ops gcm_decrypt_ops = {
1174   &bench_encrypt_init,
1175   &bench_encrypt_free,
1176   &bench_gcm_decrypt_do_bench
1177 };
1178
1179 static struct bench_ops gcm_authenticate_ops = {
1180   &bench_encrypt_init,
1181   &bench_encrypt_free,
1182   &bench_gcm_authenticate_do_bench
1183 };
1184
1185
1186 static void
1187 bench_ocb_encrypt_do_bench (struct bench_obj *obj, void *buf,
1188                             size_t buflen)
1189 {
1190   char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1191                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1192                      0x00, 0x00, 0x01 };
1193   bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1194 }
1195
1196 static void
1197 bench_ocb_decrypt_do_bench (struct bench_obj *obj, void *buf,
1198                             size_t buflen)
1199 {
1200   char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1201                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1202                      0x00, 0x00, 0x01 };
1203   bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1204 }
1205
1206 static void
1207 bench_ocb_authenticate_do_bench (struct bench_obj *obj, void *buf,
1208                                  size_t buflen)
1209 {
1210   char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1211                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1212                      0x00, 0x00, 0x01 };
1213   bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1214 }
1215
1216 static struct bench_ops ocb_encrypt_ops = {
1217   &bench_encrypt_init,
1218   &bench_encrypt_free,
1219   &bench_ocb_encrypt_do_bench
1220 };
1221
1222 static struct bench_ops ocb_decrypt_ops = {
1223   &bench_encrypt_init,
1224   &bench_encrypt_free,
1225   &bench_ocb_decrypt_do_bench
1226 };
1227
1228 static struct bench_ops ocb_authenticate_ops = {
1229   &bench_encrypt_init,
1230   &bench_encrypt_free,
1231   &bench_ocb_authenticate_do_bench
1232 };
1233
1234 static void
1235 bench_eax_encrypt_do_bench (struct bench_obj *obj, void *buf,
1236                             size_t buflen)
1237 {
1238   char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1239                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1240                      0x00, 0x00, 0x01, 0x00 };
1241   bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1242 }
1243
1244 static void
1245 bench_eax_decrypt_do_bench (struct bench_obj *obj, void *buf,
1246                             size_t buflen)
1247 {
1248   char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1249                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1250                      0x00, 0x00, 0x01, 0x00 };
1251   bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1252 }
1253
1254 static void
1255 bench_eax_authenticate_do_bench (struct bench_obj *obj, void *buf,
1256                                  size_t buflen)
1257 {
1258   char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1259                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1260                      0x00, 0x00, 0x01, 0x00 };
1261   bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1262 }
1263
1264 static struct bench_ops eax_encrypt_ops = {
1265   &bench_encrypt_init,
1266   &bench_encrypt_free,
1267   &bench_eax_encrypt_do_bench
1268 };
1269
1270 static struct bench_ops eax_decrypt_ops = {
1271   &bench_encrypt_init,
1272   &bench_encrypt_free,
1273   &bench_eax_decrypt_do_bench
1274 };
1275
1276 static struct bench_ops eax_authenticate_ops = {
1277   &bench_encrypt_init,
1278   &bench_encrypt_free,
1279   &bench_eax_authenticate_do_bench
1280 };
1281
1282 static void
1283 bench_poly1305_encrypt_do_bench (struct bench_obj *obj, void *buf,
1284                                  size_t buflen)
1285 {
1286   char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1287   bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1288 }
1289
1290 static void
1291 bench_poly1305_decrypt_do_bench (struct bench_obj *obj, void *buf,
1292                                  size_t buflen)
1293 {
1294   char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1295   bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1296 }
1297
1298 static void
1299 bench_poly1305_authenticate_do_bench (struct bench_obj *obj, void *buf,
1300                                       size_t buflen)
1301 {
1302   char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1303   bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1304 }
1305
1306 static struct bench_ops poly1305_encrypt_ops = {
1307   &bench_encrypt_init,
1308   &bench_encrypt_free,
1309   &bench_poly1305_encrypt_do_bench
1310 };
1311
1312 static struct bench_ops poly1305_decrypt_ops = {
1313   &bench_encrypt_init,
1314   &bench_encrypt_free,
1315   &bench_poly1305_decrypt_do_bench
1316 };
1317
1318 static struct bench_ops poly1305_authenticate_ops = {
1319   &bench_encrypt_init,
1320   &bench_encrypt_free,
1321   &bench_poly1305_authenticate_do_bench
1322 };
1323
1324
1325 static struct bench_cipher_mode cipher_modes[] = {
1326   {GCRY_CIPHER_MODE_ECB, "ECB enc", &encrypt_ops},
1327   {GCRY_CIPHER_MODE_ECB, "ECB dec", &decrypt_ops},
1328   {GCRY_CIPHER_MODE_CBC, "CBC enc", &encrypt_ops},
1329   {GCRY_CIPHER_MODE_CBC, "CBC dec", &decrypt_ops},
1330   {GCRY_CIPHER_MODE_CFB, "CFB enc", &encrypt_ops},
1331   {GCRY_CIPHER_MODE_CFB, "CFB dec", &decrypt_ops},
1332   {GCRY_CIPHER_MODE_OFB, "OFB enc", &encrypt_ops},
1333   {GCRY_CIPHER_MODE_OFB, "OFB dec", &decrypt_ops},
1334   {GCRY_CIPHER_MODE_CTR, "CTR enc", &encrypt_ops},
1335   {GCRY_CIPHER_MODE_CTR, "CTR dec", &decrypt_ops},
1336   {GCRY_CIPHER_MODE_XTS, "XTS enc", &xts_encrypt_ops},
1337   {GCRY_CIPHER_MODE_XTS, "XTS dec", &xts_decrypt_ops},
1338   {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops},
1339   {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops},
1340   {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops},
1341   {GCRY_CIPHER_MODE_EAX, "EAX enc",  &eax_encrypt_ops},
1342   {GCRY_CIPHER_MODE_EAX, "EAX dec",  &eax_decrypt_ops},
1343   {GCRY_CIPHER_MODE_EAX, "EAX auth", &eax_authenticate_ops},
1344   {GCRY_CIPHER_MODE_GCM, "GCM enc", &gcm_encrypt_ops},
1345   {GCRY_CIPHER_MODE_GCM, "GCM dec", &gcm_decrypt_ops},
1346   {GCRY_CIPHER_MODE_GCM, "GCM auth", &gcm_authenticate_ops},
1347   {GCRY_CIPHER_MODE_OCB, "OCB enc",  &ocb_encrypt_ops},
1348   {GCRY_CIPHER_MODE_OCB, "OCB dec",  &ocb_decrypt_ops},
1349   {GCRY_CIPHER_MODE_OCB, "OCB auth", &ocb_authenticate_ops},
1350   {GCRY_CIPHER_MODE_POLY1305, "POLY1305 enc", &poly1305_encrypt_ops},
1351   {GCRY_CIPHER_MODE_POLY1305, "POLY1305 dec", &poly1305_decrypt_ops},
1352   {GCRY_CIPHER_MODE_POLY1305, "POLY1305 auth", &poly1305_authenticate_ops},
1353   {0},
1354 };
1355
1356
1357 static void
1358 cipher_bench_one (int algo, struct bench_cipher_mode *pmode)
1359 {
1360   struct bench_cipher_mode mode = *pmode;
1361   struct bench_obj obj = { 0 };
1362   double result;
1363   unsigned int blklen;
1364
1365   mode.algo = algo;
1366
1367   /* Check if this mode is ok */
1368   blklen = gcry_cipher_get_algo_blklen (algo);
1369   if (!blklen)
1370     return;
1371
1372   /* Stream cipher? Only test with "ECB" and POLY1305. */
1373   if (blklen == 1 && (mode.mode != GCRY_CIPHER_MODE_ECB &&
1374                       mode.mode != GCRY_CIPHER_MODE_POLY1305))
1375     return;
1376   if (blklen == 1 && mode.mode == GCRY_CIPHER_MODE_ECB)
1377     {
1378       mode.mode = GCRY_CIPHER_MODE_STREAM;
1379       mode.name = mode.ops == &encrypt_ops ? "STREAM enc" : "STREAM dec";
1380     }
1381
1382   /* Poly1305 has restriction for cipher algorithm */
1383   if (mode.mode == GCRY_CIPHER_MODE_POLY1305 && algo != GCRY_CIPHER_CHACHA20)
1384     return;
1385
1386   /* CCM has restrictions for block-size */
1387   if (mode.mode == GCRY_CIPHER_MODE_CCM && blklen != GCRY_CCM_BLOCK_LEN)
1388     return;
1389
1390   /* GCM has restrictions for block-size */
1391   if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN)
1392     return;
1393
1394   /* XTS has restrictions for block-size */
1395   if (mode.mode == GCRY_CIPHER_MODE_XTS && blklen != GCRY_XTS_BLOCK_LEN)
1396     return;
1397
1398   /* Our OCB implementation has restrictions for block-size.  */
1399   if (mode.mode == GCRY_CIPHER_MODE_OCB && blklen != GCRY_OCB_BLOCK_LEN)
1400     return;
1401
1402   bench_print_mode (14, mode.name);
1403
1404   obj.ops = mode.ops;
1405   obj.priv = &mode;
1406
1407   result = do_slope_benchmark (&obj);
1408
1409   bench_print_result (result);
1410 }
1411
1412
1413 static void
1414 _cipher_bench (int algo)
1415 {
1416   const char *algoname;
1417   int i;
1418
1419   algoname = gcry_cipher_algo_name (algo);
1420
1421   bench_print_header (14, algoname);
1422
1423   for (i = 0; cipher_modes[i].mode; i++)
1424     cipher_bench_one (algo, &cipher_modes[i]);
1425
1426   bench_print_footer (14);
1427 }
1428
1429
1430 void
1431 cipher_bench (char **argv, int argc)
1432 {
1433   int i, algo;
1434
1435   bench_print_section ("cipher", "Cipher");
1436
1437   if (argv && argc)
1438     {
1439       for (i = 0; i < argc; i++)
1440         {
1441           algo = gcry_cipher_map_name (argv[i]);
1442           if (algo)
1443             _cipher_bench (algo);
1444         }
1445     }
1446   else
1447     {
1448       for (i = 1; i < 400; i++)
1449         if (!gcry_cipher_test_algo (i))
1450           _cipher_bench (i);
1451     }
1452 }
1453
1454
1455 /*********************************************************** Hash benchmarks. */
1456
1457 struct bench_hash_mode
1458 {
1459   const char *name;
1460   struct bench_ops *ops;
1461
1462   int algo;
1463 };
1464
1465
1466 static int
1467 bench_hash_init (struct bench_obj *obj)
1468 {
1469   struct bench_hash_mode *mode = obj->priv;
1470   gcry_md_hd_t hd;
1471   int err;
1472
1473   obj->min_bufsize = BUF_START_SIZE;
1474   obj->max_bufsize = BUF_END_SIZE;
1475   obj->step_size = BUF_STEP_SIZE;
1476   obj->num_measure_repetitions = num_measurement_repetitions;
1477
1478   err = gcry_md_open (&hd, mode->algo, 0);
1479   if (err)
1480     {
1481       fprintf (stderr, PGM ": error opening hash `%s'\n",
1482                gcry_md_algo_name (mode->algo));
1483       exit (1);
1484     }
1485
1486   obj->priv = hd;
1487
1488   return 0;
1489 }
1490
1491 static void
1492 bench_hash_free (struct bench_obj *obj)
1493 {
1494   gcry_md_hd_t hd = obj->priv;
1495
1496   gcry_md_close (hd);
1497 }
1498
1499 static void
1500 bench_hash_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1501 {
1502   gcry_md_hd_t hd = obj->priv;
1503
1504   gcry_md_reset (hd);
1505   gcry_md_write (hd, buf, buflen);
1506   gcry_md_final (hd);
1507 }
1508
1509 static struct bench_ops hash_ops = {
1510   &bench_hash_init,
1511   &bench_hash_free,
1512   &bench_hash_do_bench
1513 };
1514
1515
1516 static struct bench_hash_mode hash_modes[] = {
1517   {"", &hash_ops},
1518   {0},
1519 };
1520
1521
1522 static void
1523 hash_bench_one (int algo, struct bench_hash_mode *pmode)
1524 {
1525   struct bench_hash_mode mode = *pmode;
1526   struct bench_obj obj = { 0 };
1527   double result;
1528
1529   mode.algo = algo;
1530
1531   if (mode.name[0] == '\0')
1532     bench_print_algo (-14, gcry_md_algo_name (algo));
1533   else
1534     bench_print_algo (14, mode.name);
1535
1536   obj.ops = mode.ops;
1537   obj.priv = &mode;
1538
1539   result = do_slope_benchmark (&obj);
1540
1541   bench_print_result (result);
1542 }
1543
1544 static void
1545 _hash_bench (int algo)
1546 {
1547   int i;
1548
1549   for (i = 0; hash_modes[i].name; i++)
1550     hash_bench_one (algo, &hash_modes[i]);
1551 }
1552
1553 void
1554 hash_bench (char **argv, int argc)
1555 {
1556   int i, algo;
1557
1558   bench_print_section ("hash", "Hash");
1559   bench_print_header (14, "");
1560
1561   if (argv && argc)
1562     {
1563       for (i = 0; i < argc; i++)
1564         {
1565           algo = gcry_md_map_name (argv[i]);
1566           if (algo)
1567             _hash_bench (algo);
1568         }
1569     }
1570   else
1571     {
1572       for (i = 1; i < 400; i++)
1573         if (!gcry_md_test_algo (i))
1574           _hash_bench (i);
1575     }
1576
1577   bench_print_footer (14);
1578 }
1579
1580
1581 /************************************************************ MAC benchmarks. */
1582
1583 struct bench_mac_mode
1584 {
1585   const char *name;
1586   struct bench_ops *ops;
1587
1588   int algo;
1589 };
1590
1591
1592 static int
1593 bench_mac_init (struct bench_obj *obj)
1594 {
1595   struct bench_mac_mode *mode = obj->priv;
1596   gcry_mac_hd_t hd;
1597   int err;
1598   unsigned int keylen;
1599   void *key;
1600
1601   obj->min_bufsize = BUF_START_SIZE;
1602   obj->max_bufsize = BUF_END_SIZE;
1603   obj->step_size = BUF_STEP_SIZE;
1604   obj->num_measure_repetitions = num_measurement_repetitions;
1605
1606   keylen = gcry_mac_get_algo_keylen (mode->algo);
1607   if (keylen == 0)
1608     keylen = 32;
1609   key = malloc (keylen);
1610   if (!key)
1611     {
1612       fprintf (stderr, PGM ": couldn't allocate %d bytes\n", keylen);
1613       exit (1);
1614     }
1615   memset(key, 42, keylen);
1616
1617   err = gcry_mac_open (&hd, mode->algo, 0, NULL);
1618   if (err)
1619     {
1620       fprintf (stderr, PGM ": error opening mac `%s'\n",
1621                gcry_mac_algo_name (mode->algo));
1622       free (key);
1623       exit (1);
1624     }
1625
1626   err = gcry_mac_setkey (hd, key, keylen);
1627   if (err)
1628     {
1629       fprintf (stderr, PGM ": error setting key for mac `%s'\n",
1630                gcry_mac_algo_name (mode->algo));
1631       free (key);
1632       exit (1);
1633     }
1634
1635   switch (mode->algo)
1636     {
1637     default:
1638       break;
1639     case GCRY_MAC_POLY1305_AES:
1640     case GCRY_MAC_POLY1305_CAMELLIA:
1641     case GCRY_MAC_POLY1305_TWOFISH:
1642     case GCRY_MAC_POLY1305_SERPENT:
1643     case GCRY_MAC_POLY1305_SEED:
1644       gcry_mac_setiv (hd, key, 16);
1645       break;
1646     }
1647
1648   obj->priv = hd;
1649
1650   free (key);
1651   return 0;
1652 }
1653
1654 static void
1655 bench_mac_free (struct bench_obj *obj)
1656 {
1657   gcry_mac_hd_t hd = obj->priv;
1658
1659   gcry_mac_close (hd);
1660 }
1661
1662 static void
1663 bench_mac_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1664 {
1665   gcry_mac_hd_t hd = obj->priv;
1666   size_t bs;
1667   char b;
1668
1669   gcry_mac_reset (hd);
1670   gcry_mac_write (hd, buf, buflen);
1671   bs = sizeof(b);
1672   gcry_mac_read (hd, &b, &bs);
1673 }
1674
1675 static struct bench_ops mac_ops = {
1676   &bench_mac_init,
1677   &bench_mac_free,
1678   &bench_mac_do_bench
1679 };
1680
1681
1682 static struct bench_mac_mode mac_modes[] = {
1683   {"", &mac_ops},
1684   {0},
1685 };
1686
1687
1688 static void
1689 mac_bench_one (int algo, struct bench_mac_mode *pmode)
1690 {
1691   struct bench_mac_mode mode = *pmode;
1692   struct bench_obj obj = { 0 };
1693   double result;
1694
1695   mode.algo = algo;
1696
1697   if (mode.name[0] == '\0')
1698     bench_print_algo (-18, gcry_mac_algo_name (algo));
1699   else
1700     bench_print_algo (18, mode.name);
1701
1702   obj.ops = mode.ops;
1703   obj.priv = &mode;
1704
1705   result = do_slope_benchmark (&obj);
1706
1707   bench_print_result (result);
1708 }
1709
1710 static void
1711 _mac_bench (int algo)
1712 {
1713   int i;
1714
1715   for (i = 0; mac_modes[i].name; i++)
1716     mac_bench_one (algo, &mac_modes[i]);
1717 }
1718
1719 void
1720 mac_bench (char **argv, int argc)
1721 {
1722   int i, algo;
1723
1724   bench_print_section ("mac", "MAC");
1725   bench_print_header (18, "");
1726
1727   if (argv && argc)
1728     {
1729       for (i = 0; i < argc; i++)
1730         {
1731           algo = gcry_mac_map_name (argv[i]);
1732           if (algo)
1733             _mac_bench (algo);
1734         }
1735     }
1736   else
1737     {
1738       for (i = 1; i < 600; i++)
1739         if (!gcry_mac_test_algo (i))
1740           _mac_bench (i);
1741     }
1742
1743   bench_print_footer (18);
1744 }
1745
1746
1747 /************************************************************ KDF benchmarks. */
1748
1749 struct bench_kdf_mode
1750 {
1751   struct bench_ops *ops;
1752
1753   int algo;
1754   int subalgo;
1755 };
1756
1757
1758 static int
1759 bench_kdf_init (struct bench_obj *obj)
1760 {
1761   struct bench_kdf_mode *mode = obj->priv;
1762
1763   if (mode->algo == GCRY_KDF_PBKDF2)
1764     {
1765       obj->min_bufsize = 2;
1766       obj->max_bufsize = 2 * 32;
1767       obj->step_size = 2;
1768     }
1769
1770   obj->num_measure_repetitions = num_measurement_repetitions;
1771
1772   return 0;
1773 }
1774
1775 static void
1776 bench_kdf_free (struct bench_obj *obj)
1777 {
1778   (void)obj;
1779 }
1780
1781 static void
1782 bench_kdf_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1783 {
1784   struct bench_kdf_mode *mode = obj->priv;
1785   char keybuf[16];
1786
1787   (void)buf;
1788
1789   if (mode->algo == GCRY_KDF_PBKDF2)
1790     {
1791       gcry_kdf_derive("qwerty", 6, mode->algo, mode->subalgo, "01234567", 8,
1792                       buflen, sizeof(keybuf), keybuf);
1793     }
1794 }
1795
1796 static struct bench_ops kdf_ops = {
1797   &bench_kdf_init,
1798   &bench_kdf_free,
1799   &bench_kdf_do_bench
1800 };
1801
1802
1803 static void
1804 kdf_bench_one (int algo, int subalgo)
1805 {
1806   struct bench_kdf_mode mode = { &kdf_ops };
1807   struct bench_obj obj = { 0 };
1808   double nsecs_per_iteration;
1809   double cycles_per_iteration;
1810   char algo_name[32];
1811   char nsecpiter_buf[16];
1812   char cpiter_buf[16];
1813
1814   mode.algo = algo;
1815   mode.subalgo = subalgo;
1816
1817   switch (subalgo)
1818     {
1819     case GCRY_MD_CRC32:
1820     case GCRY_MD_CRC32_RFC1510:
1821     case GCRY_MD_CRC24_RFC2440:
1822     case GCRY_MD_MD4:
1823       /* Skip CRC32s. */
1824       return;
1825     }
1826
1827   if (gcry_md_get_algo_dlen (subalgo) == 0)
1828     {
1829       /* Skip XOFs */
1830       return;
1831     }
1832
1833   *algo_name = 0;
1834
1835   if (algo == GCRY_KDF_PBKDF2)
1836     {
1837       snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
1838                 gcry_md_algo_name (subalgo));
1839     }
1840
1841   bench_print_algo (-24, algo_name);
1842
1843   obj.ops = mode.ops;
1844   obj.priv = &mode;
1845
1846   nsecs_per_iteration = do_slope_benchmark (&obj);
1847
1848   strcpy(cpiter_buf, csv_mode ? "" : "-");
1849
1850   double_to_str (nsecpiter_buf, sizeof (nsecpiter_buf), nsecs_per_iteration);
1851
1852   /* If user didn't provide CPU speed, we cannot show cycles/iter results.  */
1853   if (cpu_ghz > 0.0)
1854     {
1855       cycles_per_iteration = nsecs_per_iteration * cpu_ghz;
1856       double_to_str (cpiter_buf, sizeof (cpiter_buf), cycles_per_iteration);
1857     }
1858
1859   if (csv_mode)
1860     {
1861       printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter\n",
1862               current_section_name,
1863               current_algo_name ? current_algo_name : "",
1864               current_mode_name ? current_mode_name : "",
1865               nsecpiter_buf,
1866               cpiter_buf);
1867     }
1868   else
1869     {
1870       printf ("%14s %13s\n", nsecpiter_buf, cpiter_buf);
1871     }
1872 }
1873
1874 void
1875 kdf_bench (char **argv, int argc)
1876 {
1877   char algo_name[32];
1878   int i, j;
1879
1880   bench_print_section ("kdf", "KDF");
1881
1882   if (!csv_mode)
1883     {
1884       printf (" %-*s | ", 24, "");
1885       printf ("%14s %13s\n", "nanosecs/iter", "cycles/iter");
1886     }
1887
1888   if (argv && argc)
1889     {
1890       for (i = 0; i < argc; i++)
1891         {
1892           for (j = 1; j < 400; j++)
1893             {
1894               if (gcry_md_test_algo (j))
1895                 continue;
1896
1897               snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
1898                         gcry_md_algo_name (j));
1899
1900               if (!strcmp(argv[i], algo_name))
1901                 kdf_bench_one (GCRY_KDF_PBKDF2, j);
1902             }
1903         }
1904     }
1905   else
1906     {
1907       for (i = 1; i < 400; i++)
1908         if (!gcry_md_test_algo (i))
1909           kdf_bench_one (GCRY_KDF_PBKDF2, i);
1910     }
1911
1912   bench_print_footer (24);
1913 }
1914
1915
1916 /************************************************************** Main program. */
1917
1918 void
1919 print_help (void)
1920 {
1921   static const char *help_lines[] = {
1922     "usage: bench-slope [options] [hash|mac|cipher|kdf [algonames]]",
1923     "",
1924     " options:",
1925     "   --cpu-mhz <mhz>           Set CPU speed for calculating cycles",
1926     "                             per bytes results.",
1927     "   --disable-hwf <features>  Disable hardware acceleration feature(s)",
1928     "                             for benchmarking.",
1929     "   --repetitions <n>         Use N repetitions (default "
1930                                      STR2(NUM_MEASUREMENT_REPETITIONS) ")",
1931     "   --unaligned               Use unaligned input buffers.",
1932     "   --csv                     Use CSV output format",
1933     NULL
1934   };
1935   const char **line;
1936
1937   for (line = help_lines; *line; line++)
1938     fprintf (stdout, "%s\n", *line);
1939 }
1940
1941
1942 /* Warm up CPU.  */
1943 static void
1944 warm_up_cpu (void)
1945 {
1946   struct nsec_time start, end;
1947
1948   get_nsec_time (&start);
1949   do
1950     {
1951       get_nsec_time (&end);
1952     }
1953   while (get_time_nsec_diff (&start, &end) < 1000.0 * 1000.0 * 1000.0);
1954 }
1955
1956
1957 int
1958 main (int argc, char **argv)
1959 {
1960   int last_argc = -1;
1961
1962   if (argc)
1963     {
1964       argc--;
1965       argv++;
1966     }
1967
1968   /* We skip this test if we are running under the test suite (no args
1969      and srcdir defined) and GCRYPT_NO_BENCHMARKS is set.  */
1970   if (!argc && getenv ("srcdir") && getenv ("GCRYPT_NO_BENCHMARKS"))
1971     exit (77);
1972
1973   if (getenv ("GCRYPT_IN_REGRESSION_TEST"))
1974     {
1975       in_regression_test = 1;
1976       num_measurement_repetitions = 2;
1977     }
1978   else
1979     num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
1980
1981   while (argc && last_argc != argc)
1982     {
1983       last_argc = argc;
1984
1985       if (!strcmp (*argv, "--"))
1986         {
1987           argc--;
1988           argv++;
1989           break;
1990         }
1991       else if (!strcmp (*argv, "--help"))
1992         {
1993           print_help ();
1994           exit (0);
1995         }
1996       else if (!strcmp (*argv, "--verbose"))
1997         {
1998           verbose++;
1999           argc--;
2000           argv++;
2001         }
2002       else if (!strcmp (*argv, "--debug"))
2003         {
2004           verbose += 2;
2005           debug++;
2006           argc--;
2007           argv++;
2008         }
2009       else if (!strcmp (*argv, "--csv"))
2010         {
2011           csv_mode = 1;
2012           argc--;
2013           argv++;
2014         }
2015       else if (!strcmp (*argv, "--unaligned"))
2016         {
2017           unaligned_mode = 1;
2018           argc--;
2019           argv++;
2020         }
2021       else if (!strcmp (*argv, "--disable-hwf"))
2022         {
2023           argc--;
2024           argv++;
2025           if (argc)
2026             {
2027               if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
2028                 fprintf (stderr,
2029                          PGM
2030                          ": unknown hardware feature `%s' - option ignored\n",
2031                          *argv);
2032               argc--;
2033               argv++;
2034             }
2035         }
2036       else if (!strcmp (*argv, "--cpu-mhz"))
2037         {
2038           argc--;
2039           argv++;
2040           if (argc)
2041             {
2042               cpu_ghz = atof (*argv);
2043               cpu_ghz /= 1000;  /* Mhz => Ghz */
2044
2045               argc--;
2046               argv++;
2047             }
2048         }
2049       else if (!strcmp (*argv, "--repetitions"))
2050         {
2051           argc--;
2052           argv++;
2053           if (argc)
2054             {
2055               num_measurement_repetitions = atof (*argv);
2056               if (num_measurement_repetitions < 2)
2057                 {
2058                   fprintf (stderr,
2059                            PGM
2060                            ": value for --repetitions too small - using %d\n",
2061                            NUM_MEASUREMENT_REPETITIONS);
2062                   num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
2063                 }
2064               argc--;
2065               argv++;
2066             }
2067         }
2068     }
2069
2070   xgcry_control (GCRYCTL_SET_VERBOSITY, (int) verbose);
2071
2072   if (!gcry_check_version (GCRYPT_VERSION))
2073     {
2074       fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n",
2075                GCRYPT_VERSION, gcry_check_version (NULL));
2076       exit (1);
2077     }
2078
2079   if (debug)
2080     xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
2081
2082   xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
2083   xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
2084   xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2085
2086   if (in_regression_test)
2087     fputs ("Note: " PGM " running in quick regression test mode.\n", stdout);
2088
2089   if (!argc)
2090     {
2091       warm_up_cpu ();
2092       hash_bench (NULL, 0);
2093       mac_bench (NULL, 0);
2094       cipher_bench (NULL, 0);
2095       kdf_bench (NULL, 0);
2096     }
2097   else if (!strcmp (*argv, "hash"))
2098     {
2099       argc--;
2100       argv++;
2101
2102       warm_up_cpu ();
2103       hash_bench ((argc == 0) ? NULL : argv, argc);
2104     }
2105   else if (!strcmp (*argv, "mac"))
2106     {
2107       argc--;
2108       argv++;
2109
2110       warm_up_cpu ();
2111       mac_bench ((argc == 0) ? NULL : argv, argc);
2112     }
2113   else if (!strcmp (*argv, "cipher"))
2114     {
2115       argc--;
2116       argv++;
2117
2118       warm_up_cpu ();
2119       cipher_bench ((argc == 0) ? NULL : argv, argc);
2120     }
2121   else if (!strcmp (*argv, "kdf"))
2122     {
2123       argc--;
2124       argv++;
2125
2126       warm_up_cpu ();
2127       kdf_bench ((argc == 0) ? NULL : argv, argc);
2128     }
2129   else
2130     {
2131       fprintf (stderr, PGM ": unknown argument: %s\n", *argv);
2132       print_help ();
2133     }
2134
2135   return 0;
2136 }
2137
2138 #endif /* !NO_GET_NSEC_TIME */