nettle-benchmark.c 17.2 KB
Newer Older
1
2
3
4
5
6
7
8
/* nettle-benchmark.c
 *
 * Tries the performance of the various algorithms.
 *
 */
 
/* nettle, low-level cryptographics library
 *
Niels Möller's avatar
Niels Möller committed
9
 * Copyright (C) 2001, 2010, 2014 Niels Möller
10
11
12
13
14
15
16
17
18
19
20
21
22
 *  
 * The nettle library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * The nettle library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with the nettle library; see the file COPYING.LIB.  If not, write to
23
24
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02111-1301, USA.
25
26
 */

27
28
#if HAVE_CONFIG_H
# include "config.h"
29
30
31
32
#endif

#include <assert.h>
#include <errno.h>
33
#include <math.h>
Niels Möller's avatar
Niels Möller committed
34
#include <stdarg.h>
35
36
37
38
39
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <time.h>
40

41
42
#include "timing.h"

43
#include "aes.h"
Niels Möller's avatar
Niels Möller committed
44
45
46
#include "arcfour.h"
#include "blowfish.h"
#include "cast128.h"
Niels Möller's avatar
Niels Möller committed
47
#include "cbc.h"
Niels Möller's avatar
Niels Möller committed
48
#include "ctr.h"
Niels Möller's avatar
Niels Möller committed
49
#include "des.h"
Niels Möller's avatar
Niels Möller committed
50
#include "gcm.h"
51
#include "memxor.h"
52
#include "salsa20.h"
Niels Möller's avatar
Niels Möller committed
53
#include "serpent.h"
54
55
#include "sha1.h"
#include "sha2.h"
Niels Möller's avatar
Niels Möller committed
56
#include "sha3.h"
Niels Möller's avatar
Niels Möller committed
57
#include "twofish.h"
Niels Möller's avatar
Niels Möller committed
58
#include "umac.h"
59
#include "poly1305.h"
Niels Möller's avatar
Niels Möller committed
60

61
62
63
#include "nettle-meta.h"
#include "nettle-internal.h"

Niels Möller's avatar
Niels Möller committed
64
#include "getopt.h"
65

66
static double frequency = 0.0;
Niels Möller's avatar
Niels Möller committed
67

68
/* Process BENCH_BLOCK bytes at a time, for BENCH_INTERVAL seconds. */
69
#define BENCH_BLOCK 10240
70
#define BENCH_INTERVAL 0.1
Niels Möller's avatar
Niels Möller committed
71

72
73
/* FIXME: Proper configure test for rdtsc? */
#ifndef WITH_CYCLE_COUNTER
74
# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
75
76
77
78
79
80
81
#  define WITH_CYCLE_COUNTER 1
# else
#  define WITH_CYCLE_COUNTER 0
# endif
#endif

#if WITH_CYCLE_COUNTER
82
# if defined(__i386__)
83
84
85
86
87
88
89
90
91
#define GET_CYCLE_COUNTER(hi, lo)		\
  __asm__("xorl %%eax,%%eax\n"			\
	  "movl %%ebx, %%edi\n"			\
	  "cpuid\n"				\
	  "rdtsc\n"				\
	  "movl %%edi, %%ebx\n"			\
	  : "=a" (lo), "=d" (hi)		\
	  : /* No inputs. */			\
	  : "%edi", "%ecx", "cc")
92
93
94
95
96
97
98
99
100
101
102
# elif defined(__x86_64__)
#define GET_CYCLE_COUNTER(hi, lo)		\
  __asm__("xorl %%eax,%%eax\n"			\
	  "mov %%rbx, %%r10\n"			\
	  "cpuid\n"				\
	  "rdtsc\n"				\
	  "mov %%r10, %%rbx\n"			\
	  : "=a" (lo), "=d" (hi)		\
	  : /* No inputs. */			\
	  : "%r10", "%rcx", "cc")
# endif
103
104
105
#define BENCH_ITERATIONS 10
#endif

106
static void NORETURN PRINTF_STYLE(1,2)
Niels Möller's avatar
Niels Möller committed
107
108
109
110
111
112
113
114
115
116
die(const char *format, ...)
{
  va_list args;
  va_start(args, format);
  vfprintf(stderr, format, args);
  va_end(args);

  exit(EXIT_FAILURE);
}

117
118
static double overhead = 0.0; 

119
/* Returns second per function call */
120
121
122
static double
time_function(void (*f)(void *arg), void *arg)
{
123
  unsigned ncalls;
124
125
  double elapsed;

126
  for (ncalls = 10 ;;)
127
    {
128
      unsigned i;
129
130

      time_start();
131
132
      for (i = 0; i < ncalls; i++)
	f(arg);
133
      elapsed = time_end();
134
135
136
137
138
139
      if (elapsed > BENCH_INTERVAL)
	break;
      else if (elapsed < BENCH_INTERVAL / 10)
	ncalls *= 10;
      else
	ncalls *= 2;
140
    }
141
142
143
144
145
146
147
  return elapsed / ncalls - overhead;
}

static void
bench_nothing(void *arg UNUSED)
{
  return;
148
149
}

150
151
152
153
struct bench_memxor_info
{
  uint8_t *dst;
  const uint8_t *src;
154
  const uint8_t *other;  
155
156
157
158
159
160
161
162
163
};

static void
bench_memxor(void *arg)
{
  struct bench_memxor_info *info = arg;
  memxor (info->dst, info->src, BENCH_BLOCK);
}

164
165
166
167
168
169
170
static void
bench_memxor3(void *arg)
{
  struct bench_memxor_info *info = arg;
  memxor3 (info->dst, info->src, info->other, BENCH_BLOCK);
}

171
172
173
struct bench_hash_info
{
  void *ctx;
174
  nettle_hash_update_func *update;
175
176
177
178
179
180
181
182
183
184
  const uint8_t *data;
};

static void
bench_hash(void *arg)
{
  struct bench_hash_info *info = arg;
  info->update(info->ctx, BENCH_BLOCK, info->data);
}

185
186
187
struct bench_cipher_info
{
  void *ctx;
188
  nettle_crypt_func *crypt;
189
190
191
192
193
194
195
  uint8_t *data;
};

static void
bench_cipher(void *arg)
{
  struct bench_cipher_info *info = arg;
196
  info->crypt(info->ctx, BENCH_BLOCK, info->data, info->data);
197
198
199
200
201
}

struct bench_cbc_info
{
  void *ctx;
202
  nettle_crypt_func *crypt;
203
 
204
  uint8_t *data;
205
  
206
207
208
209
210
211
212
213
  unsigned block_size;
  uint8_t *iv;
};

static void
bench_cbc_encrypt(void *arg)
{
  struct bench_cbc_info *info = arg;
214
215
216
  cbc_encrypt(info->ctx, info->crypt,
	      info->block_size, info->iv,
	      BENCH_BLOCK, info->data, info->data);
217
218
219
220
221
222
}

static void
bench_cbc_decrypt(void *arg)
{
  struct bench_cbc_info *info = arg;
223
224
225
  cbc_decrypt(info->ctx, info->crypt,
	      info->block_size, info->iv,
	      BENCH_BLOCK, info->data, info->data);
226
227
}

Niels Möller's avatar
Niels Möller committed
228
229
230
231
232
233
234
235
236
static void
bench_ctr(void *arg)
{
  struct bench_cbc_info *info = arg;
  ctr_crypt(info->ctx, info->crypt,
	    info->block_size, info->iv,
	    BENCH_BLOCK, info->data, info->data);
}

237
238
239
240
241
/* Set data[i] = floor(sqrt(i)) */
static void
init_data(uint8_t *data)
{
  unsigned i,j;
Niels Möller's avatar
Niels Möller committed
242
  for (i = j = 0; i<BENCH_BLOCK;  i++)
243
244
245
246
247
248
249
250
    {
      if (j*j < i)
	j++;
      data[i] = j;
    }
}

static void
Niels Möller's avatar
Niels Möller committed
251
252
init_key(unsigned length,
         uint8_t *key)
253
{
Niels Möller's avatar
Niels Möller committed
254
255
256
  unsigned i;
  for (i = 0; i<length; i++)
    key[i] = i;
257
258
}

259
260
261
262
263
static void
header(void)
{
  printf("%18s %11s Mbyte/s%s\n",
	 "Algorithm", "mode", 
Niels Möller's avatar
Niels Möller committed
264
	 frequency > 0.0 ? " cycles/byte cycles/block" : "");  
265
266
}

Niels Möller's avatar
Niels Möller committed
267
static void
Niels Möller's avatar
Niels Möller committed
268
display(const char *name, const char *mode, unsigned block_size,
269
	double time)
Niels Möller's avatar
Niels Möller committed
270
{
271
  printf("%18s %11s %7.2f",
Niels Möller's avatar
Niels Möller committed
272
	 name, mode,
273
	 BENCH_BLOCK / (time * 1048576.0));
274
  if (frequency > 0.0)
Niels Möller's avatar
Niels Möller committed
275
    {
276
      printf(" %11.2f", time * frequency / BENCH_BLOCK);
Niels Möller's avatar
Niels Möller committed
277
      if (block_size > 0)
278
	printf(" %12.2f", time * frequency * block_size / BENCH_BLOCK);
Niels Möller's avatar
Niels Möller committed
279
    }
280
  printf("\n");
Niels Möller's avatar
Niels Möller committed
281
282
}

283
284
285
286
287
static void *
xalloc(size_t size)
{
  void *p = malloc(size);
  if (!p)
288
    die("Virtual memory exhausted.\n");
289
290
291
292

  return p;
}

293
294
295
296
297
298
299
300
301
302
303
304
static void
time_overhead(void)
{
  overhead = time_function(bench_nothing, NULL);
  printf("benchmark call overhead: %7f us", overhead * 1e6);
  if (frequency > 0.0)
    printf("%7.2f cycles\n", overhead * frequency);
  printf("\n");  
}



305
306
307
308
static void
time_memxor(void)
{
  struct bench_memxor_info info;
309
  uint8_t src[BENCH_BLOCK + sizeof(long)];
310
  uint8_t other[BENCH_BLOCK + sizeof(long)];
311
  uint8_t dst[BENCH_BLOCK];
312
313
314
315

  info.src = src;
  info.dst = dst;

316
317
  display ("memxor", "aligned", sizeof(unsigned long),
	   time_function(bench_memxor, &info));
318
  info.src = src + 1;
319
  display ("memxor", "unaligned", sizeof(unsigned long),
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
	   time_function(bench_memxor, &info));

  info.src = src;
  info.other = other;
  display ("memxor3", "aligned", sizeof(unsigned long),
	   time_function(bench_memxor3, &info));

  info.other = other + 1;
  display ("memxor3", "unaligned01", sizeof(unsigned long),
	   time_function(bench_memxor3, &info));
  info.src = src + 1;
  display ("memxor3", "unaligned11", sizeof(unsigned long),
	   time_function(bench_memxor3, &info));
  info.other = other + 2;
  display ("memxor3", "unaligned12", sizeof(unsigned long),
	   time_function(bench_memxor3, &info));  
336
337
}

338
339
340
341
342
static void
time_hash(const struct nettle_hash *hash)
{
  static uint8_t data[BENCH_BLOCK];
  struct bench_hash_info info;
343

344
  info.ctx = xalloc(hash->context_size); 
345
346
347
348
349
350
  info.update = hash->update;
  info.data = data;

  init_data(data);
  hash->init(info.ctx);

Niels Möller's avatar
Niels Möller committed
351
  display(hash->name, "update", hash->block_size,
352
	  time_function(bench_hash, &info));
353
354

  free(info.ctx);
355
356
}

Niels Möller's avatar
Niels Möller committed
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
static void
time_umac(void)
{
  static uint8_t data[BENCH_BLOCK];
  struct bench_hash_info info;
  struct umac32_ctx ctx32;
  struct umac64_ctx ctx64;
  struct umac96_ctx ctx96;
  struct umac128_ctx ctx128;
  
  uint8_t key[16];

  umac32_set_key (&ctx32, key);
  info.ctx = &ctx32;
  info.update = (nettle_hash_update_func *) umac32_update;
  info.data = data;

374
  display("umac32", "update", UMAC_DATA_SIZE,
Niels Möller's avatar
Niels Möller committed
375
376
377
378
379
380
381
	  time_function(bench_hash, &info));

  umac64_set_key (&ctx64, key);
  info.ctx = &ctx64;
  info.update = (nettle_hash_update_func *) umac64_update;
  info.data = data;

382
  display("umac64", "update", UMAC_DATA_SIZE,
Niels Möller's avatar
Niels Möller committed
383
384
385
386
387
388
389
	  time_function(bench_hash, &info));

  umac96_set_key (&ctx96, key);
  info.ctx = &ctx96;
  info.update = (nettle_hash_update_func *) umac96_update;
  info.data = data;

390
  display("umac96", "update", UMAC_DATA_SIZE,
Niels Möller's avatar
Niels Möller committed
391
392
393
394
395
396
397
	  time_function(bench_hash, &info));

  umac128_set_key (&ctx128, key);
  info.ctx = &ctx128;
  info.update = (nettle_hash_update_func *) umac128_update;
  info.data = data;

398
  display("umac128", "update", UMAC_DATA_SIZE,
Niels Möller's avatar
Niels Möller committed
399
400
401
	  time_function(bench_hash, &info));
}

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
static void
time_poly1305_aes(void)
{
  static uint8_t data[BENCH_BLOCK];
  struct bench_hash_info info;
  struct poly1305_aes_ctx ctx;
  uint8_t key[32];

  poly1305_aes_set_key (&ctx, key);
  info.ctx = &ctx;
  info.update = (nettle_hash_update_func *) poly1305_aes_update;
  info.data = data;

  display("poly1305-aes", "update", 1024,
	  time_function(bench_hash, &info));
}

Niels Möller's avatar
Niels Möller committed
419
static void
420
time_gcm(void)
Niels Möller's avatar
Niels Möller committed
421
422
{
  static uint8_t data[BENCH_BLOCK];
423
424
  struct bench_hash_info hinfo;
  struct bench_cipher_info cinfo;
Niels Möller's avatar
Niels Möller committed
425
  struct gcm_aes128_ctx ctx;
426

Niels Möller's avatar
Niels Möller committed
427
  uint8_t key[AES128_KEY_SIZE];
Niels Möller's avatar
Niels Möller committed
428
429
  uint8_t iv[GCM_IV_SIZE];

Niels Möller's avatar
Niels Möller committed
430
431
  gcm_aes128_set_key(&ctx, sizeof(key), key);
  gcm_aes128_set_iv(&ctx, sizeof(iv), iv);
Niels Möller's avatar
Niels Möller committed
432

433
  hinfo.ctx = &ctx;
Niels Möller's avatar
Niels Möller committed
434
  hinfo.update = (nettle_hash_update_func *) gcm_aes128_update;
435
436
  hinfo.data = data;
  
Niels Möller's avatar
Niels Möller committed
437
  display("gcm-aes128", "update", GCM_BLOCK_SIZE,
438
439
440
	  time_function(bench_hash, &hinfo));
  
  cinfo.ctx = &ctx;
Niels Möller's avatar
Niels Möller committed
441
  cinfo.crypt = (nettle_crypt_func *) gcm_aes128_encrypt;
442
  cinfo.data = data;
Niels Möller's avatar
Niels Möller committed
443

Niels Möller's avatar
Niels Möller committed
444
  display("gcm-aes128", "encrypt", GCM_BLOCK_SIZE,
445
446
	  time_function(bench_cipher, &cinfo));

Niels Möller's avatar
Niels Möller committed
447
  cinfo.crypt = (nettle_crypt_func *) gcm_aes128_decrypt;
448

Niels Möller's avatar
Niels Möller committed
449
  display("gcm-aes128", "decrypt", GCM_BLOCK_SIZE,
450
	  time_function(bench_cipher, &cinfo));
Niels Möller's avatar
Niels Möller committed
451
452
}

Niels Möller's avatar
Niels Möller committed
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
static void
time_eax(void)
{
  static uint8_t data[BENCH_BLOCK];
  struct bench_hash_info hinfo;
  struct bench_cipher_info cinfo;
  struct eax_aes128_ctx ctx;

  uint8_t key[AES128_KEY_SIZE];
  uint8_t iv[EAX_BLOCK_SIZE];

  eax_aes128_set_key (&ctx, sizeof(key), key);
  eax_aes128_set_nonce(&ctx, sizeof(iv), iv);

  hinfo.ctx = &ctx;
  hinfo.update = (nettle_hash_update_func *) eax_aes128_update;
  hinfo.data = data;

  display("eax-aes128", "update", GCM_BLOCK_SIZE,
         time_function(bench_hash, &hinfo));

  cinfo.ctx = &ctx;
  cinfo.crypt = (nettle_crypt_func *) eax_aes128_encrypt;
  cinfo.data = data;

  display("eax-aes128", "encrypt", GCM_BLOCK_SIZE,
	  time_function(bench_cipher, &cinfo));

  cinfo.crypt = (nettle_crypt_func *) eax_aes128_decrypt;

  display("eax-aes128", "decrypt", GCM_BLOCK_SIZE,
	  time_function(bench_cipher, &cinfo));
}

487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
static int
prefix_p(const char *prefix, const char *s)
{
  size_t i;
  for (i = 0; prefix[i]; i++)
    if (prefix[i] != s[i])
      return 0;
  return 1;
}

static int
block_cipher_p(const struct nettle_cipher *cipher)
{
  /* Don't use nettle cbc and ctr for openssl ciphers. */
  return cipher->block_size > 0 && !prefix_p("openssl", cipher->name);
}

Niels Möller's avatar
Niels Möller committed
504
static void
505
time_cipher(const struct nettle_cipher *cipher)
Niels Möller's avatar
Niels Möller committed
506
{
507
508
  void *ctx = xalloc(cipher->context_size);
  uint8_t *key = xalloc(cipher->key_size);
Niels Möller's avatar
Niels Möller committed
509

510
  static uint8_t data[BENCH_BLOCK];
Niels Möller's avatar
Niels Möller committed
511
512
513
514

  printf("\n");
  
  init_data(data);
515
516

  {
Niels Möller's avatar
Niels Möller committed
517
518
519
520
521
    /* Decent initializers are a GNU extension, so don't use it here. */
    struct bench_cipher_info info;
    info.ctx = ctx;
    info.crypt = cipher->encrypt;
    info.data = data;
522
    
Niels Möller's avatar
Niels Möller committed
523
    init_key(cipher->key_size, key);
524
    cipher->set_encrypt_key(ctx, cipher->key_size, key);
Niels Möller's avatar
Niels Möller committed
525

Niels Möller's avatar
Niels Möller committed
526
    display(cipher->name, "ECB encrypt", cipher->block_size,
Niels Möller's avatar
Niels Möller committed
527
	    time_function(bench_cipher, &info));
528
  }
Niels Möller's avatar
Niels Möller committed
529
  
530
  {
Niels Möller's avatar
Niels Möller committed
531
532
533
534
    struct bench_cipher_info info;
    info.ctx = ctx;
    info.crypt = cipher->decrypt;
    info.data = data;
535
    
Niels Möller's avatar
Niels Möller committed
536
    init_key(cipher->key_size, key);
537
    cipher->set_decrypt_key(ctx, cipher->key_size, key);
Niels Möller's avatar
Niels Möller committed
538

Niels Möller's avatar
Niels Möller committed
539
    display(cipher->name, "ECB decrypt", cipher->block_size,
Niels Möller's avatar
Niels Möller committed
540
	    time_function(bench_cipher, &info));
541
542
  }

543
  if (block_cipher_p(cipher))
Niels Möller's avatar
Niels Möller committed
544
    {
545
      uint8_t *iv = xalloc(cipher->block_size);
Niels Möller's avatar
Niels Möller committed
546
547
548
      
      /* Do CBC mode */
      {
Niels Möller's avatar
Niels Möller committed
549
550
551
552
553
554
        struct bench_cbc_info info;
	info.ctx = ctx;
	info.crypt = cipher->encrypt;
	info.data = data;
	info.block_size = cipher->block_size;
	info.iv = iv;
555
    
Niels Möller's avatar
Niels Möller committed
556
        memset(iv, 0, sizeof(iv));
557
    
558
        cipher->set_encrypt_key(ctx, cipher->key_size, key);
559

Niels Möller's avatar
Niels Möller committed
560
	display(cipher->name, "CBC encrypt", cipher->block_size,
Niels Möller's avatar
Niels Möller committed
561
		time_function(bench_cbc_encrypt, &info));
Niels Möller's avatar
Niels Möller committed
562
      }
563

Niels Möller's avatar
Niels Möller committed
564
      {
Niels Möller's avatar
Niels Möller committed
565
566
567
568
569
570
        struct bench_cbc_info info;
	info.ctx = ctx;
	info.crypt = cipher->decrypt;
	info.data = data;
	info.block_size = cipher->block_size;
	info.iv = iv;
571
    
Niels Möller's avatar
Niels Möller committed
572
        memset(iv, 0, sizeof(iv));
573

574
        cipher->set_decrypt_key(ctx, cipher->key_size, key);
575

Niels Möller's avatar
Niels Möller committed
576
	display(cipher->name, "CBC decrypt", cipher->block_size,
Niels Möller's avatar
Niels Möller committed
577
		time_function(bench_cbc_decrypt, &info));
Niels Möller's avatar
Niels Möller committed
578
      }
Niels Möller's avatar
Niels Möller committed
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596

      /* Do CTR mode */
      {
        struct bench_cbc_info info;
	info.ctx = ctx;
	info.crypt = cipher->encrypt;
	info.data = data;
	info.block_size = cipher->block_size;
	info.iv = iv;
    
        memset(iv, 0, sizeof(iv));
    
        cipher->set_encrypt_key(ctx, cipher->key_size, key);

	display(cipher->name, "CTR", cipher->block_size,
		time_function(bench_ctr, &info));	
      }
      
597
      free(iv);
Niels Möller's avatar
Niels Möller committed
598
    }
599
600
  free(ctx);
  free(key);
Niels Möller's avatar
Niels Möller committed
601
602
}

Niels Möller's avatar
Niels Möller committed
603
604
/* Try to get accurate cycle times for assembler functions. */
#if WITH_CYCLE_COUNTER
605
606
607
608
609
610
611
612
613
614
615
616
617
static int
compare_double(const void *ap, const void *bp)
{
  double a = *(const double *) ap;
  double b = *(const double *) bp;
  if (a < b)
    return -1;
  else if (a > b)
    return 1;
  else
    return 0;
}

Niels Möller's avatar
Niels Möller committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
#define TIME_CYCLES(t, code) do {				\
  double tc_count[5];						\
  uint32_t tc_start_lo, tc_start_hi, tc_end_lo, tc_end_hi;	\
  unsigned tc_i, tc_j;						\
  for (tc_j = 0; tc_j < 5; tc_j++)				\
    {								\
      tc_i = 0;							\
      GET_CYCLE_COUNTER(tc_start_hi, tc_start_lo);		\
      for (; tc_i < BENCH_ITERATIONS; tc_i++)			\
	{ code; }						\
								\
      GET_CYCLE_COUNTER(tc_end_hi, tc_end_lo);			\
								\
      tc_end_hi -= (tc_start_hi + (tc_start_lo > tc_end_lo));	\
      tc_end_lo -= tc_start_lo;					\
								\
      tc_count[tc_j] = ldexp(tc_end_hi, 32) + tc_end_lo;	\
    }								\
  qsort(tc_count, 5, sizeof(double), compare_double);		\
  (t) = tc_count[2] / BENCH_ITERATIONS;				\
} while (0)

640
641
642
643
static void
bench_sha1_compress(void)
{
  uint32_t state[_SHA1_DIGEST_LENGTH];
Niels Möller's avatar
Niels Möller committed
644
645
  uint8_t data[SHA1_DATA_SIZE];
  double t;
646

Niels Möller's avatar
Niels Möller committed
647
  TIME_CYCLES (t, _nettle_sha1_compress(state, data));
648

Niels Möller's avatar
Niels Möller committed
649
  printf("sha1_compress: %.2f cycles\n", t);  
650
651
}

652
653
654
655
static void
bench_salsa20_core(void)
{
  uint32_t state[_SALSA20_INPUT_LENGTH];
Niels Möller's avatar
Niels Möller committed
656
  double t;
657

Niels Möller's avatar
Niels Möller committed
658
659
660
  TIME_CYCLES (t, _nettle_salsa20_core(state, state, 20));
  printf("salsa20_core: %.2f cycles\n", t);  
}
661

Niels Möller's avatar
Niels Möller committed
662
663
664
665
666
static void
bench_sha3_permute(void)
{
  struct sha3_state state;
  double t;
667

Niels Möller's avatar
Niels Möller committed
668
669
  TIME_CYCLES (t, sha3_permute (&state));
  printf("sha3_permute: %.2f cycles (%.2f / round)\n", t, t / 24.0);
670
671
672
673
}
#else
#define bench_sha1_compress()
#define bench_salsa20_core()
Niels Möller's avatar
Niels Möller committed
674
#define bench_sha3_permute()
675
676
#endif

Niels Möller's avatar
Niels Möller committed
677
#if WITH_OPENSSL
678
679
680
681
# define OPENSSL(x) x,
#else
# define OPENSSL(x)
#endif
Niels Möller's avatar
Niels Möller committed
682
683

int
684
main(int argc, char **argv)
Niels Möller's avatar
Niels Möller committed
685
686
{
  unsigned i;
687
  int c;
688
  const char *alg;
689
690
691
692

  const struct nettle_hash *hashes[] =
    {
      &nettle_md2, &nettle_md4, &nettle_md5,
693
      OPENSSL(&nettle_openssl_md5)
694
      &nettle_sha1, OPENSSL(&nettle_openssl_sha1)
Niels Möller's avatar
Niels Möller committed
695
696
      &nettle_sha224, &nettle_sha256,
      &nettle_sha384, &nettle_sha512,
697
698
      &nettle_sha3_224, &nettle_sha3_256,
      &nettle_sha3_384, &nettle_sha3_512,
699
      &nettle_ripemd160, &nettle_gosthash94,
700
701
702
      NULL
    };

703
  const struct nettle_cipher *ciphers[] =
Niels Möller's avatar
Niels Möller committed
704
    {
705
      &nettle_aes128, &nettle_aes192, &nettle_aes256,
Niels Möller's avatar
Niels Möller committed
706
707
708
709
710
      OPENSSL(&nettle_openssl_aes128)
      OPENSSL(&nettle_openssl_aes192)
      OPENSSL(&nettle_openssl_aes256)
      &nettle_arcfour128, OPENSSL(&nettle_openssl_arcfour128)
      &nettle_blowfish128, OPENSSL(&nettle_openssl_blowfish128)
Niels Möller's avatar
Niels Möller committed
711
      &nettle_camellia128, &nettle_camellia192, &nettle_camellia256,
712
713
714
      &nettle_cast128, OPENSSL(&nettle_openssl_cast128)
      &nettle_des, OPENSSL(&nettle_openssl_des)
      &nettle_des3,
715
716
      &nettle_serpent256,
      &nettle_twofish128, &nettle_twofish192, &nettle_twofish256,
Niels Möller's avatar
Niels Möller committed
717
      &nettle_salsa20, &nettle_salsa20r12, &nettle_chacha,
718
      NULL
Niels Möller's avatar
Niels Möller committed
719
    };
720

721
722
723
724
725
726
727
728
729
730
  enum { OPT_HELP = 300 };
  static const struct option options[] =
    {
      /* Name, args, flag, val */
      { "help", no_argument, NULL, OPT_HELP },
      { "clock-frequency", required_argument, NULL, 'f' },
      { NULL, 0, NULL, 0 }
    };
  
  while ( (c = getopt_long(argc, argv, "f:", options, NULL)) != -1)
731
732
733
734
735
736
737
    switch (c)
      {
      case 'f':
	frequency = atof(optarg);
	if (frequency > 0.0)
	  break;

738
739
740
741
742
      case OPT_HELP:
	printf("Usage: nettle-benchmark [-f clock frequency] [alg]\n");
	return EXIT_SUCCESS;

      case '?':
743
744
745
746
747
748
	return EXIT_FAILURE;

      default:
	abort();
    }

749
  alg = argv[optind];
750

751
  time_init();
752
  bench_sha1_compress();
753
  bench_salsa20_core();
Niels Möller's avatar
Niels Möller committed
754
755
  bench_sha3_permute();
  printf("\n");
756
757
  time_overhead();

758
759
  header();

760
761
762
763
764
  if (!alg || strstr ("memxor", alg))
    {
      time_memxor();
      printf("\n");
    }
765
  
766
  for (i = 0; hashes[i]; i++)
767
768
    if (!alg || strstr(hashes[i]->name, alg))
      time_hash(hashes[i]);
Niels Möller's avatar
Niels Möller committed
769

Niels Möller's avatar
Niels Möller committed
770
771
772
  if (!alg || strstr ("umac", alg))
    time_umac();

773
774
775
  if (!alg || strstr ("poly1305-aes", alg))
    time_poly1305_aes();

776
  for (i = 0; ciphers[i]; i++)
777
778
779
    if (!alg || strstr(ciphers[i]->name, alg))
      time_cipher(ciphers[i]);

780
781
782
783
784
785
  if (!alg || strstr ("gcm", alg))
    {
      printf("\n");
      time_gcm();
    }

Niels Möller's avatar
Niels Möller committed
786
787
788
789
790
791
  if (!alg || strstr ("eax", alg))
    {
      printf("\n");
      time_eax();
    }

792
793
  return 0;
}