1 /* nettle-benchmark.c
2 
3    Tests the performance of the various algorithms.
4 
5    Copyright (C) 2001, 2010, 2014 Niels Möller
6 
7    This file is part of GNU Nettle.
8 
9    GNU Nettle is free software: you can redistribute it and/or
10    modify it under the terms of either:
11 
12      * the GNU Lesser General Public License as published by the Free
13        Software Foundation; either version 3 of the License, or (at your
14        option) any later version.
15 
16    or
17 
18      * the GNU General Public License as published by the Free
19        Software Foundation; either version 2 of the License, or (at your
20        option) any later version.
21 
22    or both in parallel, as here.
23 
24    GNU Nettle is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27    General Public License for more details.
28 
29    You should have received copies of the GNU General Public License and
30    the GNU Lesser General Public License along with this program.  If
31    not, see http://www.gnu.org/licenses/.
32 */
33 
34 #if HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37 
38 #include <assert.h>
39 #include <errno.h>
40 #include <math.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #include <time.h>
47 
48 #include "timing.h"
49 
50 #include "aes.h"
51 #include "arcfour.h"
52 #include "blowfish.h"
53 #include "cast128.h"
54 #include "cbc.h"
55 #include "ctr.h"
56 #include "des.h"
57 #include "eax.h"
58 #include "gcm.h"
59 #include "memxor.h"
60 #include "salsa20.h"
61 #include "salsa20-internal.h"
62 #include "serpent.h"
63 #include "sha1.h"
64 #include "sha2.h"
65 #include "sha3.h"
66 #include "twofish.h"
67 #include "umac.h"
68 #include "cmac.h"
69 #include "poly1305.h"
70 #include "hmac.h"
71 
72 #include "nettle-meta.h"
73 #include "nettle-internal.h"
74 
75 #include "getopt.h"
76 
77 static double frequency = 0.0;
78 
79 /* Process BENCH_BLOCK bytes at a time, for BENCH_INTERVAL seconds. */
80 #define BENCH_BLOCK 10240
81 #define BENCH_INTERVAL 0.1
82 
83 /* FIXME: Proper configure test for rdtsc? */
84 #ifndef WITH_CYCLE_COUNTER
85 # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
86 #  define WITH_CYCLE_COUNTER 1
87 # else
88 #  define WITH_CYCLE_COUNTER 0
89 # endif
90 #endif
91 
92 #if WITH_CYCLE_COUNTER
93 # if defined(__i386__)
94 #define GET_CYCLE_COUNTER(hi, lo)		\
95   __asm__ volatile ("xorl %%eax,%%eax\n"	\
96 		    "movl %%ebx, %%edi\n"	\
97 		    "cpuid\n"			\
98 		    "rdtsc\n"			\
99 		    "movl %%edi, %%ebx\n"	\
100 		    : "=a" (lo), "=d" (hi)	\
101 		    : /* No inputs. */		\
102 		    : "%edi", "%ecx", "cc")
103 # elif defined(__x86_64__)
104 #define GET_CYCLE_COUNTER(hi, lo)		\
105   __asm__ volatile ("xorl %%eax,%%eax\n"	\
106 		    "mov %%rbx, %%r10\n"	\
107 		    "cpuid\n"			\
108 		    "rdtsc\n"			\
109 		    "mov %%r10, %%rbx\n"	\
110 		    : "=a" (lo), "=d" (hi)	\
111 		    : /* No inputs. */		\
112 		    : "%r10", "%rcx", "cc")
113 # endif
114 #define BENCH_ITERATIONS 10
115 #endif
116 
117 static void NORETURN PRINTF_STYLE(1,2)
die(const char * format,...)118 die(const char *format, ...)
119 {
120   va_list args;
121   va_start(args, format);
122   vfprintf(stderr, format, args);
123   va_end(args);
124 
125   exit(EXIT_FAILURE);
126 }
127 
128 static double overhead = 0.0;
129 
130 /* Returns second per function call */
131 static double
time_function(void (* f)(void * arg),void * arg)132 time_function(void (*f)(void *arg), void *arg)
133 {
134   unsigned ncalls;
135   double elapsed;
136 
137   for (ncalls = 10 ;;)
138     {
139       unsigned i;
140 
141       time_start();
142       for (i = 0; i < ncalls; i++)
143 	f(arg);
144       elapsed = time_end();
145       if (elapsed > BENCH_INTERVAL)
146 	break;
147       else if (elapsed < BENCH_INTERVAL / 10)
148 	ncalls *= 10;
149       else
150 	ncalls *= 2;
151     }
152   return elapsed / ncalls - overhead;
153 }
154 
155 static void
bench_nothing(void * arg UNUSED)156 bench_nothing(void *arg UNUSED)
157 {
158   return;
159 }
160 
161 struct bench_memxor_info
162 {
163   void *dst;
164   const void *src;
165   const void *other;
166 };
167 
168 static void
bench_memxor(void * arg)169 bench_memxor(void *arg)
170 {
171   struct bench_memxor_info *info = arg;
172   memxor (info->dst, info->src, BENCH_BLOCK);
173 }
174 
175 static void
bench_memxor3(void * arg)176 bench_memxor3(void *arg)
177 {
178   struct bench_memxor_info *info = arg;
179   memxor3 (info->dst, info->src, info->other, BENCH_BLOCK);
180 }
181 
182 struct bench_hash_info
183 {
184   void *ctx;
185   nettle_hash_update_func *update;
186   const uint8_t *data;
187 };
188 
189 static void
bench_hash(void * arg)190 bench_hash(void *arg)
191 {
192   struct bench_hash_info *info = arg;
193   info->update(info->ctx, BENCH_BLOCK, info->data);
194 }
195 
196 struct bench_cipher_info
197 {
198   void *ctx;
199   nettle_cipher_func *crypt;
200   uint8_t *data;
201 };
202 
203 static void
bench_cipher(void * arg)204 bench_cipher(void *arg)
205 {
206   struct bench_cipher_info *info = arg;
207   info->crypt(info->ctx, BENCH_BLOCK, info->data, info->data);
208 }
209 
210 struct bench_cbc_info
211 {
212   void *ctx;
213   nettle_cipher_func *crypt;
214 
215   const uint8_t *src;
216   uint8_t *dst;
217 
218   unsigned block_size;
219   uint8_t *iv;
220 };
221 
222 static void
bench_cbc_encrypt(void * arg)223 bench_cbc_encrypt(void *arg)
224 {
225   struct bench_cbc_info *info = arg;
226   cbc_encrypt(info->ctx, info->crypt,
227 	      info->block_size, info->iv,
228 	      BENCH_BLOCK, info->dst, info->src);
229 }
230 
231 static void
bench_cbc_decrypt(void * arg)232 bench_cbc_decrypt(void *arg)
233 {
234   struct bench_cbc_info *info = arg;
235   cbc_decrypt(info->ctx, info->crypt,
236 	      info->block_size, info->iv,
237 	      BENCH_BLOCK, info->dst, info->src);
238 }
239 
240 static void
bench_ctr(void * arg)241 bench_ctr(void *arg)
242 {
243   struct bench_cbc_info *info = arg;
244   ctr_crypt(info->ctx, info->crypt,
245 	    info->block_size, info->iv,
246 	    BENCH_BLOCK, info->dst, info->src);
247 }
248 
249 struct bench_aead_info
250 {
251   void *ctx;
252   nettle_crypt_func *crypt;
253   nettle_hash_update_func *update;
254   uint8_t *data;
255 };
256 
257 static void
bench_aead_crypt(void * arg)258 bench_aead_crypt(void *arg)
259 {
260   const struct bench_aead_info *info = arg;
261   info->crypt (info->ctx, BENCH_BLOCK, info->data, info->data);
262 }
263 
264 static void
bench_aead_update(void * arg)265 bench_aead_update(void *arg)
266 {
267   const struct bench_aead_info *info = arg;
268   info->update (info->ctx, BENCH_BLOCK, info->data);
269 }
270 
271 /* Set data[i] = floor(sqrt(i)) */
272 static void
init_data(uint8_t * data)273 init_data(uint8_t *data)
274 {
275   unsigned i,j;
276   for (i = j = 0; i<BENCH_BLOCK;  i++)
277     {
278       if (j*j < i)
279 	j++;
280       data[i] = j;
281     }
282 }
283 
284 static void
init_key(unsigned length,uint8_t * key)285 init_key(unsigned length,
286          uint8_t *key)
287 {
288   unsigned i;
289   for (i = 0; i<length; i++)
290     key[i] = i;
291 }
292 
293 static void
init_nonce(unsigned length,uint8_t * nonce)294 init_nonce(unsigned length,
295 	   uint8_t *nonce)
296 {
297   unsigned i;
298   for (i = 0; i<length; i++)
299     nonce[i] = 3*i;
300 }
301 
302 static void
header(void)303 header(void)
304 {
305   printf("%18s %12s Mbyte/s%s\n",
306 	 "Algorithm", "mode",
307 	 frequency > 0.0 ? " cycles/byte cycles/block" : "");
308 }
309 
310 static void
display(const char * name,const char * mode,unsigned block_size,double time)311 display(const char *name, const char *mode, unsigned block_size,
312 	double time)
313 {
314   printf("%18s %12s %7.2f",
315 	 name, mode,
316 	 BENCH_BLOCK / (time * 1048576.0));
317   if (frequency > 0.0)
318     {
319       printf(" %11.2f", time * frequency / BENCH_BLOCK);
320       if (block_size > 0)
321 	printf(" %12.2f", time * frequency * block_size / BENCH_BLOCK);
322     }
323   printf("\n");
324 }
325 
326 static void *
xalloc(size_t size)327 xalloc(size_t size)
328 {
329   void *p = malloc(size);
330   if (!p)
331     die("Virtual memory exhausted.\n");
332 
333   return p;
334 }
335 
336 static void
time_overhead(void)337 time_overhead(void)
338 {
339   overhead = time_function(bench_nothing, NULL);
340   printf("benchmark call overhead: %7f us", overhead * 1e6);
341   if (frequency > 0.0)
342     printf("%7.2f cycles\n", overhead * frequency);
343   printf("\n");
344 }
345 
346 
347 
348 static void
time_memxor(void)349 time_memxor(void)
350 {
351   struct bench_memxor_info info;
352   unsigned long src[BENCH_BLOCK / sizeof(long) + 2];
353   unsigned long other[BENCH_BLOCK / sizeof(long) + 2];
354   unsigned long dst[BENCH_BLOCK / sizeof(long) + 1];
355 
356   info.src = src;
357   info.dst = dst;
358 
359   display ("memxor", "aligned", sizeof(unsigned long),
360 	   time_function(bench_memxor, &info));
361   info.src = (const char *) src + 1;
362   display ("memxor", "unaligned", sizeof(unsigned long),
363 	   time_function(bench_memxor, &info));
364 
365   info.src = src;
366   info.other = other;
367   display ("memxor3", "aligned", sizeof(unsigned long),
368 	   time_function(bench_memxor3, &info));
369 
370   info.other = (const char *) other + 1;
371   display ("memxor3", "unaligned01", sizeof(unsigned long),
372 	   time_function(bench_memxor3, &info));
373   info.src = (const char *) src + 1;
374   display ("memxor3", "unaligned11", sizeof(unsigned long),
375 	   time_function(bench_memxor3, &info));
376   info.other = (const char *) other + 2;
377   display ("memxor3", "unaligned12", sizeof(unsigned long),
378 	   time_function(bench_memxor3, &info));
379 }
380 
381 static void
time_hash(const struct nettle_hash * hash)382 time_hash(const struct nettle_hash *hash)
383 {
384   static uint8_t data[BENCH_BLOCK];
385   struct bench_hash_info info;
386 
387   info.ctx = xalloc(hash->context_size);
388   info.update = hash->update;
389   info.data = data;
390 
391   init_data(data);
392   hash->init(info.ctx);
393 
394   display(hash->name, "update", hash->block_size,
395 	  time_function(bench_hash, &info));
396 
397   free(info.ctx);
398 }
399 
400 static void
time_umac(void)401 time_umac(void)
402 {
403   static uint8_t data[BENCH_BLOCK];
404   struct bench_hash_info info;
405   struct umac32_ctx ctx32;
406   struct umac64_ctx ctx64;
407   struct umac96_ctx ctx96;
408   struct umac128_ctx ctx128;
409 
410   uint8_t key[16];
411 
412   umac32_set_key (&ctx32, key);
413   info.ctx = &ctx32;
414   info.update = (nettle_hash_update_func *) umac32_update;
415   info.data = data;
416 
417   display("umac32", "update", UMAC_BLOCK_SIZE,
418 	  time_function(bench_hash, &info));
419 
420   umac64_set_key (&ctx64, key);
421   info.ctx = &ctx64;
422   info.update = (nettle_hash_update_func *) umac64_update;
423   info.data = data;
424 
425   display("umac64", "update", UMAC_BLOCK_SIZE,
426 	  time_function(bench_hash, &info));
427 
428   umac96_set_key (&ctx96, key);
429   info.ctx = &ctx96;
430   info.update = (nettle_hash_update_func *) umac96_update;
431   info.data = data;
432 
433   display("umac96", "update", UMAC_BLOCK_SIZE,
434 	  time_function(bench_hash, &info));
435 
436   umac128_set_key (&ctx128, key);
437   info.ctx = &ctx128;
438   info.update = (nettle_hash_update_func *) umac128_update;
439   info.data = data;
440 
441   display("umac128", "update", UMAC_BLOCK_SIZE,
442 	  time_function(bench_hash, &info));
443 }
444 
445 static void
time_cmac(void)446 time_cmac(void)
447 {
448   static uint8_t data[BENCH_BLOCK];
449   struct bench_hash_info info;
450   struct cmac_aes128_ctx ctx;
451 
452   uint8_t key[16];
453 
454   cmac_aes128_set_key (&ctx, key);
455   info.ctx = &ctx;
456   info.update = (nettle_hash_update_func *) cmac_aes128_update;
457   info.data = data;
458 
459   display("cmac-aes128", "update", AES_BLOCK_SIZE,
460 	  time_function(bench_hash, &info));
461 }
462 
463 static void
time_poly1305_aes(void)464 time_poly1305_aes(void)
465 {
466   static uint8_t data[BENCH_BLOCK];
467   struct bench_hash_info info;
468   struct poly1305_aes_ctx ctx;
469   uint8_t key[32];
470 
471   poly1305_aes_set_key (&ctx, key);
472   info.ctx = &ctx;
473   info.update = (nettle_hash_update_func *) poly1305_aes_update;
474   info.data = data;
475 
476   display("poly1305-aes", "update", 1024,
477 	  time_function(bench_hash, &info));
478 }
479 
480 struct bench_hmac_info
481 {
482   void *ctx;
483   nettle_hash_update_func *update;
484   nettle_hash_digest_func *digest;
485   size_t length;
486   size_t digest_length;
487   const uint8_t *data;
488 };
489 
490 static void
bench_hmac(void * arg)491 bench_hmac(void *arg)
492 {
493   struct bench_hmac_info *info = arg;
494   uint8_t digest[NETTLE_MAX_HASH_DIGEST_SIZE];
495   size_t pos, length;
496 
497   length = info->length;
498   for (pos = 0; pos < BENCH_BLOCK; pos += length)
499     {
500       size_t single = pos + length < BENCH_BLOCK ?
501 			length :
502 			BENCH_BLOCK - pos;
503       info->update(info->ctx, single, info->data + pos);
504       info->digest(info->ctx, info->digest_length, digest);
505     }
506 }
507 
508 static const struct
509 {
510   size_t length;
511   const char *msg;
512 } hmac_tests[] = {
513   { 64, "64 bytes" },
514   { 256, "256 bytes" },
515   { 1024, "1024 bytes" },
516   { 4096, "4096 bytes" },
517   { BENCH_BLOCK, "single msg" },
518   { 0, NULL },
519 };
520 
521 static void
time_hmac_md5(void)522 time_hmac_md5(void)
523 {
524   static uint8_t data[BENCH_BLOCK];
525   struct bench_hmac_info info;
526   struct hmac_md5_ctx md5_ctx;
527   unsigned int pos;
528 
529   init_data(data);
530   info.data = data;
531 
532   hmac_md5_set_key(&md5_ctx, MD5_BLOCK_SIZE, data);
533   info.ctx = &md5_ctx;
534   info.update = (nettle_hash_update_func *) hmac_md5_update;
535   info.digest = (nettle_hash_digest_func *) hmac_md5_digest;
536   info.digest_length = MD5_DIGEST_SIZE;
537 
538   for (pos = 0; hmac_tests[pos].length != 0; pos++)
539     {
540       info.length = hmac_tests[pos].length;
541       display("hmac-md5", hmac_tests[pos].msg, MD5_BLOCK_SIZE,
542 	      time_function(bench_hmac, &info));
543     }
544 }
545 
546 static void
time_hmac_sha1(void)547 time_hmac_sha1(void)
548 {
549   static uint8_t data[BENCH_BLOCK];
550   struct bench_hmac_info info;
551   struct hmac_sha1_ctx sha1_ctx;
552   unsigned int pos;
553 
554   init_data(data);
555   info.data = data;
556 
557   hmac_sha1_set_key(&sha1_ctx, SHA1_BLOCK_SIZE, data);
558   info.ctx = &sha1_ctx;
559   info.update = (nettle_hash_update_func *) hmac_sha1_update;
560   info.digest = (nettle_hash_digest_func *) hmac_sha1_digest;
561   info.digest_length = SHA1_DIGEST_SIZE;
562 
563   for (pos = 0; hmac_tests[pos].length != 0; pos++)
564     {
565       info.length = hmac_tests[pos].length;
566       display("hmac-sha1", hmac_tests[pos].msg, SHA1_BLOCK_SIZE,
567 	      time_function(bench_hmac, &info));
568     }
569 }
570 
571 static void
time_hmac_sha256(void)572 time_hmac_sha256(void)
573 {
574   static uint8_t data[BENCH_BLOCK];
575   struct bench_hmac_info info;
576   struct hmac_sha256_ctx sha256_ctx;
577   unsigned int pos;
578 
579   init_data(data);
580   info.data = data;
581 
582   hmac_sha256_set_key(&sha256_ctx, SHA256_BLOCK_SIZE, data);
583   info.ctx = &sha256_ctx;
584   info.update = (nettle_hash_update_func *) hmac_sha256_update;
585   info.digest = (nettle_hash_digest_func *) hmac_sha256_digest;
586   info.digest_length = SHA256_DIGEST_SIZE;
587 
588   for (pos = 0; hmac_tests[pos].length != 0; pos++)
589     {
590       info.length = hmac_tests[pos].length;
591       display("hmac-sha256", hmac_tests[pos].msg, SHA256_BLOCK_SIZE,
592 	      time_function(bench_hmac, &info));
593     }
594 }
595 
596 static void
time_hmac_sha512(void)597 time_hmac_sha512(void)
598 {
599   static uint8_t data[BENCH_BLOCK];
600   struct bench_hmac_info info;
601   struct hmac_sha512_ctx sha512_ctx;
602   unsigned int pos;
603 
604   init_data(data);
605   info.data = data;
606 
607   hmac_sha512_set_key(&sha512_ctx, SHA512_BLOCK_SIZE, data);
608   info.ctx = &sha512_ctx;
609   info.update = (nettle_hash_update_func *) hmac_sha512_update;
610   info.digest = (nettle_hash_digest_func *) hmac_sha512_digest;
611   info.digest_length = SHA512_DIGEST_SIZE;
612 
613   for (pos = 0; hmac_tests[pos].length != 0; pos++)
614     {
615       info.length = hmac_tests[pos].length;
616       display("hmac-sha512", hmac_tests[pos].msg, SHA512_BLOCK_SIZE,
617 	      time_function(bench_hmac, &info));
618     }
619 }
620 
621 static int
prefix_p(const char * prefix,const char * s)622 prefix_p(const char *prefix, const char *s)
623 {
624   size_t i;
625   for (i = 0; prefix[i]; i++)
626     if (prefix[i] != s[i])
627       return 0;
628   return 1;
629 }
630 
631 static int
block_cipher_p(const struct nettle_cipher * cipher)632 block_cipher_p(const struct nettle_cipher *cipher)
633 {
634   /* Don't use nettle cbc and ctr for openssl ciphers. */
635   return cipher->block_size > 0 && !prefix_p("openssl", cipher->name);
636 }
637 
638 static void
time_cipher(const struct nettle_cipher * cipher)639 time_cipher(const struct nettle_cipher *cipher)
640 {
641   void *ctx = xalloc(cipher->context_size);
642   uint8_t *key = xalloc(cipher->key_size);
643 
644   static uint8_t src_data[BENCH_BLOCK];
645   static uint8_t data[BENCH_BLOCK];
646 
647   printf("\n");
648 
649   init_data(data);
650   init_data(src_data);
651 
652   {
653     /* Decent initializers are a GNU extension, so don't use it here. */
654     struct bench_cipher_info info;
655     info.ctx = ctx;
656     info.crypt = cipher->encrypt;
657     info.data = data;
658 
659     init_key(cipher->key_size, key);
660     cipher->set_encrypt_key(ctx, key);
661 
662     display(cipher->name, "ECB encrypt", cipher->block_size,
663 	    time_function(bench_cipher, &info));
664   }
665 
666   {
667     struct bench_cipher_info info;
668     info.ctx = ctx;
669     info.crypt = cipher->decrypt;
670     info.data = data;
671 
672     init_key(cipher->key_size, key);
673     cipher->set_decrypt_key(ctx, key);
674 
675     display(cipher->name, "ECB decrypt", cipher->block_size,
676 	    time_function(bench_cipher, &info));
677   }
678 
679   if (block_cipher_p(cipher))
680     {
681       uint8_t *iv = xalloc(cipher->block_size);
682 
683       /* Do CBC mode */
684       {
685         struct bench_cbc_info info;
686 	info.ctx = ctx;
687 	info.crypt = cipher->encrypt;
688 	info.src = src_data;
689 	info.dst = data;
690 	info.block_size = cipher->block_size;
691 	info.iv = iv;
692 
693         memset(iv, 0, cipher->block_size);
694 
695         cipher->set_encrypt_key(ctx, key);
696 
697 	display(cipher->name, "CBC encrypt", cipher->block_size,
698 		time_function(bench_cbc_encrypt, &info));
699       }
700 
701       {
702         struct bench_cbc_info info;
703 	info.ctx = ctx;
704 	info.crypt = cipher->decrypt;
705 	info.src = src_data;
706 	info.dst = data;
707 	info.block_size = cipher->block_size;
708 	info.iv = iv;
709 
710         memset(iv, 0, cipher->block_size);
711 
712         cipher->set_decrypt_key(ctx, key);
713 
714 	display(cipher->name, "CBC decrypt", cipher->block_size,
715 		time_function(bench_cbc_decrypt, &info));
716 
717 	memset(iv, 0, cipher->block_size);
718 	info.src = data;
719 
720 	display(cipher->name, "  (in-place)", cipher->block_size,
721 		time_function(bench_cbc_decrypt, &info));
722       }
723 
724       /* Do CTR mode */
725       {
726         struct bench_cbc_info info;
727 	info.ctx = ctx;
728 	info.crypt = cipher->encrypt;
729 	info.src = src_data;
730 	info.dst = data;
731 	info.block_size = cipher->block_size;
732 	info.iv = iv;
733 
734         memset(iv, 0, cipher->block_size);
735 
736         cipher->set_encrypt_key(ctx, key);
737 
738 	display(cipher->name, "CTR", cipher->block_size,
739 		time_function(bench_ctr, &info));
740 
741 	memset(iv, 0, cipher->block_size);
742 	info.src = data;
743 
744 	display(cipher->name, "  (in-place)", cipher->block_size,
745 		time_function(bench_ctr, &info));
746       }
747 
748       free(iv);
749     }
750   free(ctx);
751   free(key);
752 }
753 
754 static void
time_aead(const struct nettle_aead * aead)755 time_aead(const struct nettle_aead *aead)
756 {
757   void *ctx = xalloc(aead->context_size);
758   uint8_t *key = xalloc(aead->key_size);
759   uint8_t *nonce = xalloc(aead->nonce_size);
760   static uint8_t data[BENCH_BLOCK];
761 
762   printf("\n");
763 
764   init_data(data);
765   if (aead->set_nonce)
766     init_nonce (aead->nonce_size, nonce);
767 
768   {
769     /* Decent initializers are a GNU extension, so don't use it here. */
770     struct bench_aead_info info;
771     info.ctx = ctx;
772     info.crypt = aead->encrypt;
773     info.data = data;
774 
775     init_key(aead->key_size, key);
776     aead->set_encrypt_key(ctx, key);
777     if (aead->set_nonce)
778       aead->set_nonce (ctx, nonce);
779 
780     display(aead->name, "encrypt", aead->block_size,
781 	    time_function(bench_aead_crypt, &info));
782   }
783 
784   {
785     struct bench_aead_info info;
786     info.ctx = ctx;
787     info.crypt = aead->decrypt;
788     info.data = data;
789 
790     init_key(aead->key_size, key);
791     aead->set_decrypt_key(ctx, key);
792     if (aead->set_nonce)
793       aead->set_nonce (ctx, nonce);
794 
795     display(aead->name, "decrypt", aead->block_size,
796 	    time_function(bench_aead_crypt, &info));
797   }
798 
799   if (aead->update)
800     {
801       struct bench_aead_info info;
802       info.ctx = ctx;
803       info.update = aead->update;
804       info.data = data;
805 
806       aead->set_encrypt_key(ctx, key);
807 
808       if (aead->set_nonce)
809 	aead->set_nonce (ctx, nonce);
810 
811       display(aead->name, "update", aead->block_size,
812 	      time_function(bench_aead_update, &info));
813     }
814   free(ctx);
815   free(key);
816   free(nonce);
817 }
818 
819 /* Try to get accurate cycle times for assembler functions. */
820 #if WITH_CYCLE_COUNTER
821 static int
compare_double(const void * ap,const void * bp)822 compare_double(const void *ap, const void *bp)
823 {
824   double a = *(const double *) ap;
825   double b = *(const double *) bp;
826   if (a < b)
827     return -1;
828   else if (a > b)
829     return 1;
830   else
831     return 0;
832 }
833 
834 #define TIME_CYCLES(t, code) do {				\
835   double tc_count[5];						\
836   uint32_t tc_start_lo, tc_start_hi, tc_end_lo, tc_end_hi;	\
837   unsigned tc_i, tc_j;						\
838   for (tc_j = 0; tc_j < 5; tc_j++)				\
839     {								\
840       tc_i = 0;							\
841       GET_CYCLE_COUNTER(tc_start_hi, tc_start_lo);		\
842       for (; tc_i < BENCH_ITERATIONS; tc_i++)			\
843 	{ code; }						\
844 								\
845       GET_CYCLE_COUNTER(tc_end_hi, tc_end_lo);			\
846 								\
847       tc_end_hi -= (tc_start_hi + (tc_start_lo > tc_end_lo));	\
848       tc_end_lo -= tc_start_lo;					\
849 								\
850       tc_count[tc_j] = ldexp(tc_end_hi, 32) + tc_end_lo;	\
851     }								\
852   qsort(tc_count, 5, sizeof(double), compare_double);		\
853   (t) = tc_count[2] / BENCH_ITERATIONS;				\
854 } while (0)
855 
856 static void
bench_sha1_compress(void)857 bench_sha1_compress(void)
858 {
859   uint32_t state[_SHA1_DIGEST_LENGTH];
860   uint8_t data[SHA1_BLOCK_SIZE];
861   double t;
862 
863   TIME_CYCLES (t, nettle_sha1_compress(state, data));
864 
865   printf("sha1_compress: %.2f cycles\n", t);
866 }
867 
868 static void
bench_salsa20_core(void)869 bench_salsa20_core(void)
870 {
871   uint32_t state[_SALSA20_INPUT_LENGTH];
872   double t;
873 
874   TIME_CYCLES (t, _nettle_salsa20_core(state, state, 20));
875   printf("salsa20_core: %.2f cycles\n", t);
876 }
877 
878 static void
bench_sha3_permute(void)879 bench_sha3_permute(void)
880 {
881   struct sha3_state state;
882   double t;
883 
884   TIME_CYCLES (t, sha3_permute (&state));
885   printf("sha3_permute: %.2f cycles (%.2f / round)\n", t, t / 24.0);
886 }
887 #else
888 #define bench_sha1_compress()
889 #define bench_salsa20_core()
890 #define bench_sha3_permute()
891 #endif
892 
893 #if WITH_OPENSSL
894 # define OPENSSL(x) x,
895 #else
896 # define OPENSSL(x)
897 #endif
898 
899 int
main(int argc,char ** argv)900 main(int argc, char **argv)
901 {
902   unsigned i;
903   int c;
904   const char *alg;
905 
906 #if WITH_OPENSSL
907   nettle_openssl_init();
908 #endif
909 
910   const struct nettle_hash *hashes[] =
911     {
912       &nettle_md2, &nettle_md4, &nettle_md5,
913       OPENSSL(&nettle_openssl_md5)
914       &nettle_sha1, OPENSSL(&nettle_openssl_sha1)
915       &nettle_sha224, &nettle_sha256,
916       &nettle_sha384, &nettle_sha512,
917       &nettle_sha512_224, &nettle_sha512_256,
918       &nettle_sha3_224, &nettle_sha3_256,
919       &nettle_sha3_384, &nettle_sha3_512,
920       &nettle_ripemd160, &nettle_gosthash94,
921       NULL
922     };
923 
924   const struct nettle_cipher *ciphers[] =
925     {
926       &nettle_aes128, &nettle_aes192, &nettle_aes256,
927       OPENSSL(&nettle_openssl_aes128)
928       OPENSSL(&nettle_openssl_aes192)
929       OPENSSL(&nettle_openssl_aes256)
930       &nettle_blowfish128, OPENSSL(&nettle_openssl_blowfish128)
931       &nettle_camellia128, &nettle_camellia192, &nettle_camellia256,
932       &nettle_cast128, OPENSSL(&nettle_openssl_cast128)
933       &nettle_des, OPENSSL(&nettle_openssl_des)
934       &nettle_des3,
935       &nettle_serpent256,
936       &nettle_twofish128, &nettle_twofish192, &nettle_twofish256,
937       NULL
938     };
939 
940   const struct nettle_aead *aeads[] =
941     {
942       /* Stream ciphers */
943       &nettle_arcfour128, OPENSSL(&nettle_openssl_arcfour128)
944       &nettle_salsa20, &nettle_salsa20r12, &nettle_chacha,
945       /* Proper AEAD algorithme. */
946       &nettle_gcm_aes128,
947       &nettle_gcm_aes192,
948       &nettle_gcm_aes256,
949       OPENSSL(&nettle_openssl_gcm_aes128)
950       OPENSSL(&nettle_openssl_gcm_aes192)
951       OPENSSL(&nettle_openssl_gcm_aes256)
952       &nettle_gcm_camellia128,
953       &nettle_gcm_camellia256,
954       &nettle_eax_aes128,
955       &nettle_chacha_poly1305,
956       NULL
957     };
958 
959   enum { OPT_HELP = 300 };
960   static const struct option options[] =
961     {
962       /* Name, args, flag, val */
963       { "help", no_argument, NULL, OPT_HELP },
964       { "clock-frequency", required_argument, NULL, 'f' },
965       { NULL, 0, NULL, 0 }
966     };
967 
968   while ( (c = getopt_long(argc, argv, "f:", options, NULL)) != -1)
969     switch (c)
970       {
971       case 'f':
972 	frequency = atof(optarg);
973 	if (frequency > 0.0)
974 	  break;
975 	/* Fall through */
976 
977       case OPT_HELP:
978 	printf("Usage: nettle-benchmark [-f clock frequency] [alg...]\n");
979 	return EXIT_SUCCESS;
980 
981       case '?':
982 	return EXIT_FAILURE;
983 
984       default:
985 	abort();
986     }
987 
988   time_init();
989   bench_sha1_compress();
990   bench_salsa20_core();
991   bench_sha3_permute();
992   printf("\n");
993   time_overhead();
994 
995   header();
996 
997   do
998     {
999       alg = argv[optind];
1000 
1001       if (!alg || strstr ("memxor", alg))
1002 	{
1003 	  time_memxor();
1004 	  printf("\n");
1005 	}
1006 
1007       for (i = 0; hashes[i]; i++)
1008 	if (!alg || strstr(hashes[i]->name, alg))
1009 	  time_hash(hashes[i]);
1010 
1011       if (!alg || strstr ("umac", alg))
1012 	time_umac();
1013 
1014       if (!alg || strstr ("cmac", alg))
1015 	time_cmac();
1016 
1017       if (!alg || strstr ("poly1305-aes", alg))
1018 	time_poly1305_aes();
1019 
1020       for (i = 0; ciphers[i]; i++)
1021 	if (!alg || strstr(ciphers[i]->name, alg))
1022 	  time_cipher(ciphers[i]);
1023 
1024       for (i = 0; aeads[i]; i++)
1025 	if (!alg || strstr(aeads[i]->name, alg))
1026 	  time_aead(aeads[i]);
1027 
1028       if (!alg || strstr ("hmac-md5", alg))
1029 	time_hmac_md5();
1030 
1031       if (!alg || strstr ("hmac-sha1", alg))
1032 	time_hmac_sha1();
1033 
1034       if (!alg || strstr ("hmac-sha256", alg))
1035 	time_hmac_sha256();
1036 
1037       if (!alg || strstr ("hmac-sha512", alg))
1038 	time_hmac_sha512();
1039 
1040       optind++;
1041     } while (alg && argv[optind]);
1042 
1043   return 0;
1044 }
1045