A whole bunch of changes to eventually support
[libgcrypt.git] / tests / benchmark.c
index 04cfedc..f428a15 100644 (file)
@@ -1,5 +1,5 @@
 /* benchmark.c - for libgcrypt
- *     Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2004, 2005, 2006, 2008 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -14,8 +14,7 @@
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
+#include <stdarg.h>
+#ifdef _WIN32
+#include <windows.h>
+#else
 #include <sys/times.h>
+#endif
 #include <gcrypt.h>
 
 #define PGM "benchmark"
 
+static int verbose;
+
+/* Do encryption tests with large buffers.  */
+static int large_buffers;
+
+/* Number of cipher repetitions.  */
+static int cipher_repetitions;
+
+
 static const char sample_private_dsa_key_1024[] =
 "(private-key\n"
 "  (dsa\n"
@@ -223,59 +236,127 @@ static const char sample_public_dsa_key_3072[] =
 
 
 /* Helper for the start and stop timer. */
+#ifdef _WIN32
+struct {
+  FILETIME creation_time, exit_time, kernel_time, user_time;
+} started_at, stopped_at;
+#else
 static clock_t started_at, stopped_at;
+#endif
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr ;
+
+  va_start( arg_ptr, format ) ;
+  putchar ('\n');
+  fputs ( PGM ": ", stderr);
+  vfprintf (stderr, format, arg_ptr );
+  va_end(arg_ptr);
+  exit (1);
+}
+
+static void
+show_sexp (const char *prefix, gcry_sexp_t a)
+{
+  char *buf;
+  size_t size;
+
+  fputs (prefix, stderr);
+  size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+  buf = malloc (size);
+  if (!buf)
+    die ("out of core\n");
+
+  gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+  fprintf (stderr, "%.*s", (int)size, buf);
+}
 
 
 static void
 start_timer (void)
 {
+#ifdef _WIN32
+  GetProcessTimes (GetCurrentProcess (),
+                   &started_at.creation_time, &started_at.exit_time,
+                   &started_at.kernel_time, &started_at.user_time);
+  stopped_at = started_at;
+#else
   struct tms tmp;
 
   times (&tmp);
   started_at = stopped_at = tmp.tms_utime;
+#endif
 }
 
 static void
 stop_timer (void)
 {
+#ifdef _WIN32
+  GetProcessTimes (GetCurrentProcess (),
+                   &stopped_at.creation_time, &stopped_at.exit_time,
+                   &stopped_at.kernel_time, &stopped_at.user_time);
+#else
   struct tms tmp;
 
   times (&tmp);
   stopped_at = tmp.tms_utime;
+#endif
 }
 
 static const char *
 elapsed_time (void)
 {
   static char buf[50];
-
-  sprintf (buf, "%5.0fms",
-           (((double) (stopped_at - started_at))/CLOCKS_PER_SEC)*10000000);
+#if _WIN32
+  unsigned long long t1, t2, t;
+
+  t1 = (((unsigned long long)started_at.kernel_time.dwHighDateTime << 32)
+        + started_at.kernel_time.dwLowDateTime);
+  t1 += (((unsigned long long)started_at.user_time.dwHighDateTime << 32)
+        + started_at.user_time.dwLowDateTime);
+  t2 = (((unsigned long long)stopped_at.kernel_time.dwHighDateTime << 32)
+        + stopped_at.kernel_time.dwLowDateTime);
+  t2 += (((unsigned long long)stopped_at.user_time.dwHighDateTime << 32)
+        + stopped_at.user_time.dwLowDateTime);
+  t = (t2 - t1)/10000;
+  snprintf (buf, sizeof buf, "%5lums", (unsigned long)t );
+#else
+  snprintf (buf, sizeof buf, "%5.0fms",
+            (((double) (stopped_at - started_at))/CLOCKS_PER_SEC)*10000000);
+#endif
   return buf;
 }
 
 
 static void
-random_bench (void)
+random_bench (int very_strong)
 {
   char buf[128];
   int i;
 
   printf ("%-10s", "random");
 
-  start_timer ();
-  for (i=0; i < 100; i++)
-    gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
-  stop_timer ();
-  printf (" %s", elapsed_time ());
+  if (!very_strong)
+    {
+      start_timer ();
+      for (i=0; i < 100; i++)
+        gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
+      stop_timer ();
+      printf (" %s", elapsed_time ());
+    }
 
   start_timer ();
   for (i=0; i < 100; i++)
-    gcry_randomize (buf, 8, GCRY_STRONG_RANDOM);
+    gcry_randomize (buf, 8,
+                    very_strong? GCRY_VERY_STRONG_RANDOM:GCRY_STRONG_RANDOM);
   stop_timer ();
   printf (" %s", elapsed_time ());
 
   putchar ('\n');
+  if (verbose)
+    gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
 }
 
 
@@ -352,12 +433,14 @@ cipher_bench ( const char *algoname )
   int i;
   int keylen, blklen;
   char key[128];
-  char outbuf[1000], buf[1000];
-  size_t buflen;
+  char *outbuf, *buf;
+  size_t allocated_buflen, buflen;
+  int repetitions;
   static struct { int mode; const char *name; int blocked; } modes[] = {
     { GCRY_CIPHER_MODE_ECB, "ECB", 1 },
     { GCRY_CIPHER_MODE_CBC, "CBC", 1 },
     { GCRY_CIPHER_MODE_CFB, "CFB", 0 },
+    { GCRY_CIPHER_MODE_OFB, "OFB", 0 },
     { GCRY_CIPHER_MODE_CTR, "CTR", 0 },
     { GCRY_CIPHER_MODE_STREAM, "STREAM", 0 },
     {0}
@@ -374,14 +457,30 @@ cipher_bench ( const char *algoname )
       return;
     }
 
+  if (large_buffers)
+    {
+      allocated_buflen = 1024 * 100;
+      repetitions = 10;
+    }
+  else
+    {
+      allocated_buflen = 1024;
+      repetitions = 1000;
+    }
+  repetitions *= cipher_repetitions;
+
+  buf = gcry_xmalloc (allocated_buflen);
+  outbuf = gcry_xmalloc (allocated_buflen);
 
   if (!header_printed)
     {
-      printf ("%-10s", "");
+      if (cipher_repetitions != 1)
+        printf ("Running each test %d times.\n", cipher_repetitions);
+      printf ("%-12s", "");
       for (modeidx=0; modes[modeidx].mode; modeidx++)
         printf (" %-15s", modes[modeidx].name );
       putchar ('\n');
-      printf ("%-10s", "");
+      printf ("%-12s", "");
       for (modeidx=0; modes[modeidx].mode; modeidx++)
         printf (" ---------------" );
       putchar ('\n');
@@ -419,7 +518,7 @@ cipher_bench ( const char *algoname )
       exit (1);
     }
 
-  printf ("%-10s", gcry_cipher_algo_name (algo));
+  printf ("%-12s", gcry_cipher_algo_name (algo));
   fflush (stdout);
 
   for (modeidx=0; modes[modeidx].mode; modeidx++)
@@ -450,14 +549,15 @@ cipher_bench ( const char *algoname )
           exit (1);
         }
 
-      buflen = sizeof buf;
+      buflen = allocated_buflen;
       if (modes[modeidx].blocked)
         buflen = (buflen / blklen) * blklen;
-
+      
       start_timer ();
-      for (i=err=0; !err && i < 1000; i++)
+      for (i=err=0; !err && i < repetitions; i++)
         err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen);
       stop_timer ();
+
       printf (" %s", elapsed_time ());
       fflush (stdout);
       gcry_cipher_close (hd);
@@ -485,7 +585,7 @@ cipher_bench ( const char *algoname )
         }
 
       start_timer ();
-      for (i=err=0; !err && i < 1000; i++)
+      for (i=err=0; !err && i < repetitions; i++)
         err = gcry_cipher_decrypt ( hd, outbuf, buflen,  buf, buflen);
       stop_timer ();
       printf (" %s", elapsed_time ());
@@ -500,12 +600,132 @@ cipher_bench ( const char *algoname )
     }
 
   putchar ('\n');
+  gcry_free (buf);
+  gcry_free (outbuf);
 }
 
 
 
 static void
-dsa_bench (void)
+rsa_bench (int iterations, int print_header, int no_blinding)
+{
+  gpg_error_t err;
+  int p_sizes[] = { 1024, 2048, 3072, 4096 };
+  int testno;
+
+  if (print_header)
+    printf ("Algorithm         generate %4d*sign %4d*verify\n"
+            "------------------------------------------------\n",
+            iterations, iterations );
+  for (testno=0; testno < DIM (p_sizes); testno++)
+    {
+      gcry_sexp_t key_spec, key_pair, pub_key, sec_key;
+      gcry_mpi_t x;
+      gcry_sexp_t data;
+      gcry_sexp_t sig = NULL;
+      int count;
+
+      printf ("RSA %3d bit    ", p_sizes[testno]);
+      fflush (stdout);
+
+      err = gcry_sexp_build (&key_spec, NULL,
+                             "(genkey (RSA (nbits %d)))", p_sizes[testno]);
+      if (err)
+        die ("creating S-expression failed: %s\n", gcry_strerror (err));
+
+      start_timer ();
+      err = gcry_pk_genkey (&key_pair, key_spec);
+      if (err)
+        die ("creating %d bit RSA key failed: %s\n",
+             p_sizes[testno], gcry_strerror (err));
+
+      pub_key = gcry_sexp_find_token (key_pair, "public-key", 0);
+      if (! pub_key)
+        die ("public part missing in key\n");
+      sec_key = gcry_sexp_find_token (key_pair, "private-key", 0);
+      if (! sec_key)
+        die ("private part missing in key\n");
+      gcry_sexp_release (key_pair);
+      gcry_sexp_release (key_spec);
+
+      stop_timer ();
+      printf ("   %s", elapsed_time ());
+      fflush (stdout);
+
+      x = gcry_mpi_new (p_sizes[testno]);
+      gcry_mpi_randomize (x, p_sizes[testno]-8, GCRY_WEAK_RANDOM);
+      err = gcry_sexp_build (&data, NULL,
+                             "(data (flags raw) (value %m))", x);
+      gcry_mpi_release (x);
+      if (err)
+        die ("converting data failed: %s\n", gcry_strerror (err));
+
+      start_timer ();
+      for (count=0; count < iterations; count++)
+        {
+          gcry_sexp_release (sig);
+          err = gcry_pk_sign (&sig, data, sec_key);
+          if (err)
+            die ("signing failed (%d): %s\n", count, gpg_strerror (err));
+        }
+      stop_timer ();
+      printf ("   %s", elapsed_time ());
+      fflush (stdout);
+
+      start_timer ();
+      for (count=0; count < iterations; count++)
+        {
+          err = gcry_pk_verify (sig, data, pub_key);
+          if (err)
+            {
+              putchar ('\n');
+              show_sexp ("seckey:\n", sec_key);
+              show_sexp ("data:\n", data);
+              show_sexp ("sig:\n", sig);
+              die ("verify failed (%d): %s\n", count, gpg_strerror (err));
+            }
+        }
+      stop_timer ();
+      printf ("     %s", elapsed_time ());
+
+      if (no_blinding)
+        {
+          fflush (stdout);
+          x = gcry_mpi_new (p_sizes[testno]);
+          gcry_mpi_randomize (x, p_sizes[testno]-8, GCRY_WEAK_RANDOM);
+          err = gcry_sexp_build (&data, NULL,
+                                 "(data (flags no-blinding) (value %m))", x);
+          gcry_mpi_release (x);
+          if (err)
+            die ("converting data failed: %s\n", gcry_strerror (err));
+
+          start_timer ();
+          for (count=0; count < iterations; count++)
+            {
+              gcry_sexp_release (sig);
+              err = gcry_pk_sign (&sig, data, sec_key);
+              if (err)
+                die ("signing failed (%d): %s\n", count, gpg_strerror (err));
+            }
+          stop_timer ();
+          printf ("   %s", elapsed_time ());
+          fflush (stdout);
+        }
+
+      putchar ('\n');
+      fflush (stdout);
+
+      gcry_sexp_release (sig);
+      gcry_sexp_release (data);
+      gcry_sexp_release (sec_key);
+      gcry_sexp_release (pub_key);
+    }
+}
+
+
+
+static void
+dsa_bench (int iterations, int print_header)
 {
   gpg_error_t err;
   gcry_sexp_t pub_key[3], sec_key[3];
@@ -539,9 +759,10 @@ dsa_bench (void)
       exit (1);
     }
 
-
-  fputs ("DSA 100 times    sign  verify\n"
-         "-----------------------------\n", stdout);
+  if (print_header)
+    printf ("Algorithm         generate %4d*sign %4d*verify\n"
+            "------------------------------------------------\n",
+            iterations, iterations );
   for (i=0; i < DIM (q_sizes); i++)
     {
       gcry_mpi_t x;
@@ -557,9 +778,11 @@ dsa_bench (void)
           exit (1);
         }
 
-      printf ("DSA %d/%d ", p_sizes[i], q_sizes[i]);
+      printf ("DSA %d/%d             -", p_sizes[i], q_sizes[i]);
+      fflush (stdout);
+
       start_timer ();
-      for (j=0; j < 100; j++)
+      for (j=0; j < iterations; j++)
         {
           err = gcry_pk_sign (&sig, data, sec_key[i]);
           if (err)
@@ -571,10 +794,11 @@ dsa_bench (void)
             }
         }
       stop_timer ();
-      printf (" %s", elapsed_time ());
+      printf ("   %s", elapsed_time ());
+      fflush (stdout);
 
       start_timer ();
-      for (j=0; j < 100; j++)
+      for (j=0; j < iterations; j++)
         {
           err = gcry_pk_verify (sig, data, pub_key[i]);
           if (err)
@@ -586,7 +810,8 @@ dsa_bench (void)
             }
         }
       stop_timer ();
-      printf (" %s\n", elapsed_time ());
+      printf ("     %s\n", elapsed_time ());
+      fflush (stdout);
 
       gcry_sexp_release (sig);
       gcry_sexp_release (data);
@@ -601,6 +826,98 @@ dsa_bench (void)
 }
 
 
+static void
+ecc_bench (int iterations, int print_header)
+{
+#if USE_ECC
+  gpg_error_t err;
+  int p_sizes[] = { 192, 224, 256, 384, 521 };
+  int testno;
+
+  if (print_header)
+    printf ("Algorithm         generate %4d*sign %4d*verify\n"
+            "------------------------------------------------\n",
+            iterations, iterations );
+  for (testno=0; testno < DIM (p_sizes); testno++)
+    {
+      gcry_sexp_t key_spec, key_pair, pub_key, sec_key;
+      gcry_mpi_t x;
+      gcry_sexp_t data;
+      gcry_sexp_t sig = NULL;
+      int count;
+
+      printf ("ECDSA %3d bit ", p_sizes[testno]);
+      fflush (stdout);
+
+      err = gcry_sexp_build (&key_spec, NULL,
+                             "(genkey (ECDSA (nbits %d)))", p_sizes[testno]);
+      if (err)
+        die ("creating S-expression failed: %s\n", gcry_strerror (err));
+
+      start_timer ();
+      err = gcry_pk_genkey (&key_pair, key_spec);
+      if (err)
+        die ("creating %d bit ECC key failed: %s\n",
+             p_sizes[testno], gcry_strerror (err));
+
+      pub_key = gcry_sexp_find_token (key_pair, "public-key", 0);
+      if (! pub_key)
+        die ("public part missing in key\n");
+      sec_key = gcry_sexp_find_token (key_pair, "private-key", 0);
+      if (! sec_key)
+        die ("private part missing in key\n");
+      gcry_sexp_release (key_pair);
+      gcry_sexp_release (key_spec);
+
+      stop_timer ();
+      printf ("     %s", elapsed_time ());
+      fflush (stdout);
+
+      x = gcry_mpi_new (p_sizes[testno]);
+      gcry_mpi_randomize (x, p_sizes[testno], GCRY_WEAK_RANDOM);
+      err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x);
+      gcry_mpi_release (x);
+      if (err)
+        die ("converting data failed: %s\n", gcry_strerror (err));
+
+      start_timer ();
+      for (count=0; count < iterations; count++)
+        {
+          gcry_sexp_release (sig);
+          err = gcry_pk_sign (&sig, data, sec_key);
+          if (err)
+            die ("signing failed: %s\n", gpg_strerror (err));
+        }
+      stop_timer ();
+      printf ("   %s", elapsed_time ());
+      fflush (stdout);
+
+      start_timer ();
+      for (count=0; count < iterations; count++)
+        {
+          err = gcry_pk_verify (sig, data, pub_key);
+          if (err)
+            {
+              putchar ('\n');
+              show_sexp ("seckey:\n", sec_key);
+              show_sexp ("data:\n", data);
+              show_sexp ("sig:\n", sig);
+              die ("verify failed: %s\n", gpg_strerror (err));
+            }
+        }
+      stop_timer ();
+      printf ("     %s\n", elapsed_time ());
+      fflush (stdout);
+
+      gcry_sexp_release (sig);
+      gcry_sexp_release (data);
+      gcry_sexp_release (sec_key);
+      gcry_sexp_release (pub_key);
+    }
+#endif /*USE_ECC*/
+}
+
+
 
 static void
 do_powm ( const char *n_str, const char *e_str, const char *m_str)
@@ -668,33 +985,108 @@ mpi_bench (void)
 int
 main( int argc, char **argv )
 {
+  int last_argc = -1;
+  int no_blinding = 0;
+
+
   if (argc)
     { argc--; argv++; }
 
-  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   if (!gcry_check_version (GCRYPT_VERSION))
     {
       fprintf (stderr, PGM ": version mismatch\n");
       exit (1);
     }
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
+  if (argc && !strcmp (*argv, "--use-random-daemon"))
+    {
+      gcry_control (GCRYCTL_USE_RANDOM_DAEMON, 1);
+      argc--; argv++;
+    }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: benchmark "
+                 "[md|cipher|random|mpi|rsa|dsa|ecc [algonames]]\n",
+                 stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--use-random-daemon"))
+        {
+          gcry_control (GCRYCTL_USE_RANDOM_DAEMON, 1);
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--no-blinding"))
+        {
+          no_blinding = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--large-buffers"))
+        {
+          large_buffers = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--cipher-repetition"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              cipher_repetitions = atoi(*argv);
+              argc--; argv++;
+            }
+        }
+      else if (!strcmp (*argv, "--fips"))
+        {
+          argc--; argv++;
+          gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+        }
+    }          
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 
+  if (cipher_repetitions < 1)
+    cipher_repetitions = 1;
+  
   if ( !argc )
     {
+      gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
       md_bench (NULL);
       putchar ('\n');
       cipher_bench (NULL);
       putchar ('\n');
+      rsa_bench (100, 1, no_blinding);
+      dsa_bench (100, 0);
+      ecc_bench (100, 0);
+      putchar ('\n');
       mpi_bench ();
       putchar ('\n');
-      random_bench ();
+      random_bench (0);
     }
-  else if ( !strcmp (*argv, "--help"))
-     fputs ("usage: benchmark [md|cipher|random|mpi|dsa [algonames]]\n",
-            stdout);
-  else if ( !strcmp (*argv, "random"))
+  else if ( !strcmp (*argv, "random") || !strcmp (*argv, "strongrandom"))
     {
-      random_bench ();
+      if (argc == 1)
+        random_bench ((**argv == 's'));
+      else if (argc == 2)
+        {
+          gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, argv[1]);
+          random_bench ((**argv == 's'));
+          gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
+        }
+      else
+        fputs ("usage: benchmark [strong]random [seedfile]\n", stdout);
     }
   else if ( !strcmp (*argv, "md"))
     {
@@ -716,9 +1108,20 @@ main( int argc, char **argv )
     {
         mpi_bench ();
     }
+  else if ( !strcmp (*argv, "rsa"))
+    {
+        gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+        rsa_bench (100, 1, no_blinding);
+    }
   else if ( !strcmp (*argv, "dsa"))
     {
-        dsa_bench ();
+        gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+        dsa_bench (100, 1);
+    }
+  else if ( !strcmp (*argv, "ecc"))
+    {
+        gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+        ecc_bench (100, 1);
     }
   else
     {
@@ -729,4 +1132,3 @@ main( int argc, char **argv )
   return 0;
 }
 
-