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