9516e82807f0227b4b6dc4d512a5244cb17486bb
[libgcrypt.git] / tests / benchmark.c
1 /* benchmark.c - for libgcrypt
2  *      Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <time.h>
27 #include <sys/times.h>
28 #include <gcrypt.h>
29
30 #define PGM "benchmark"
31 #define BUG() do {fprintf ( stderr, "Ooops at %s:%d\n", __FILE__ , __LINE__ );\
32                   exit(2);} while(0)
33
34
35 /* Helper for the start and stop timer. */
36 static clock_t started_at, stopped_at;
37
38
39 static void
40 start_timer (void)
41 {
42   struct tms tmp;
43
44   times (&tmp);
45   started_at = stopped_at = tmp.tms_utime;
46 }
47
48 static void
49 stop_timer (void)
50 {
51   struct tms tmp;
52
53   times (&tmp);
54   stopped_at = tmp.tms_utime;
55 }
56
57 static const char *
58 elapsed_time (void)
59 {
60   static char buf[50];
61
62   sprintf (buf, "%5.0fms",
63            (((double) (stopped_at - started_at))/CLOCKS_PER_SEC)*10000000);
64   return buf;
65 }
66
67
68 static void
69 random_bench (void)
70 {
71   char buf[128];
72   int i;
73
74   printf ("%-10s", "random");
75
76   start_timer ();
77   for (i=0; i < 100; i++)
78     gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
79   stop_timer ();
80   printf (" %s", elapsed_time ());
81
82   start_timer ();
83   for (i=0; i < 100; i++)
84     gcry_randomize (buf, 8, GCRY_STRONG_RANDOM);
85   stop_timer ();
86   printf (" %s", elapsed_time ());
87
88   putchar ('\n');
89 }
90
91
92
93 static void
94 md_bench ( const char *algoname )
95 {
96   int algo;
97   gcry_md_hd_t hd;
98   int i;
99   char buf[1000];
100   gcry_error_t err = GPG_ERR_NO_ERROR;
101
102   if (!algoname)
103     {
104       for (i=1; i < 400; i++)
105         if ( !gcry_md_test_algo (i) )
106           md_bench (gcry_md_algo_name (i));
107       return;
108     }
109
110   algo = gcry_md_map_name (algoname);
111   if (!algo)
112     {
113       fprintf (stderr, PGM ": invalid hash algorithm `%s'\n", algoname);
114       exit (1);
115     }
116
117   err = gcry_md_open (&hd, algo, 0);
118   if (err)
119     {
120       fprintf (stderr, PGM ": error opening hash algorithm `%s'\n", algoname);
121       exit (1);
122     }
123
124   for (i=0; i < sizeof buf; i++)
125     buf[i] = i;
126
127   printf ("%-12s", gcry_md_algo_name (algo));
128
129   start_timer ();
130   for (i=0; i < 1000; i++)
131     gcry_md_write (hd, buf, sizeof buf);
132   gcry_md_final (hd);
133   stop_timer ();
134   printf (" %s", elapsed_time ());
135
136   gcry_md_reset (hd);
137   start_timer ();
138   for (i=0; i < 10000; i++)
139     gcry_md_write (hd, buf, sizeof buf/10);
140   gcry_md_final (hd);
141   stop_timer ();
142   printf (" %s", elapsed_time ());
143
144   gcry_md_reset (hd);
145   start_timer ();
146   for (i=0; i < 1000000; i++)
147     gcry_md_write (hd, "", 1);
148   gcry_md_final (hd);
149   stop_timer ();
150   printf (" %s", elapsed_time ());
151
152   gcry_md_close (hd);
153   putchar ('\n');
154 }
155
156 static void
157 cipher_bench ( const char *algoname )
158 {
159   static int header_printed;
160   int algo;
161   gcry_cipher_hd_t hd;
162   int i;
163   int keylen, blklen;
164   char key[128];
165   char outbuf[1000], buf[1000];
166   size_t buflen;
167   static struct { int mode; const char *name; int blocked; } modes[] = {
168     { GCRY_CIPHER_MODE_ECB, "ECB", 1 },
169     { GCRY_CIPHER_MODE_CBC, "CBC", 1 },
170     { GCRY_CIPHER_MODE_CFB, "CFB", 0 },
171     { GCRY_CIPHER_MODE_CTR, "CTR", 0 },
172     { GCRY_CIPHER_MODE_STREAM, "STREAM", 0 },
173     {0}
174   };
175   int modeidx;
176   gcry_error_t err = GPG_ERR_NO_ERROR;
177
178
179   if (!algoname)
180     {
181       for (i=1; i < 400; i++)
182         if ( !gcry_cipher_test_algo (i) )
183           cipher_bench (gcry_cipher_algo_name (i));
184       return;
185     }
186
187
188   if (!header_printed)
189     {
190       printf ("%-10s", "");
191       for (modeidx=0; modes[modeidx].mode; modeidx++)
192         printf (" %-15s", modes[modeidx].name );
193       putchar ('\n');
194       printf ("%-10s", "");
195       for (modeidx=0; modes[modeidx].mode; modeidx++)
196         printf (" ---------------" );
197       putchar ('\n');
198       header_printed = 1;
199     }
200
201   algo = gcry_cipher_map_name (algoname);
202   if (!algo)
203     {
204       fprintf (stderr, PGM ": invalid cipher algorithm `%s'\n", algoname);
205       exit (1);
206     }
207
208   keylen = gcry_cipher_get_algo_keylen (algo);
209   if (!keylen)
210     {
211       fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
212                algoname);
213       exit (1);
214     }
215   if ( keylen > sizeof key )
216     {
217         fprintf (stderr, PGM ": algo %d, keylength problem (%d)\n",
218                  algo, keylen );
219         exit (1);
220     }
221   for (i=0; i < keylen; i++)
222     key[i] = i + (clock () & 0xff);
223
224   blklen = gcry_cipher_get_algo_blklen (algo);
225   if (!blklen)
226     {
227       fprintf (stderr, PGM ": failed to get block length for algorithm `%s'\n",
228                algoname);
229       exit (1);
230     }
231
232   printf ("%-10s", gcry_cipher_algo_name (algo));
233   fflush (stdout);
234
235   for (modeidx=0; modes[modeidx].mode; modeidx++)
236     {
237       if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM)
238           | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
239         {
240           printf ("                " );
241           continue;
242         }
243
244       for (i=0; i < sizeof buf; i++)
245         buf[i] = i;
246
247       err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0);
248       if (err)
249         {
250           fprintf (stderr, PGM ": error opening cipher `%s'\n", algoname);
251           exit (1);
252         }
253       
254       err = gcry_cipher_setkey (hd, key, keylen);
255       if (err)
256       { 
257           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
258                    gpg_strerror (err));
259           gcry_cipher_close (hd);
260           exit (1);
261         }
262
263       buflen = sizeof buf;
264       if (modes[modeidx].blocked)
265         buflen = (buflen / blklen) * blklen;
266
267       start_timer ();
268       for (i=err=0; !err && i < 1000; i++)
269         err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen);
270       stop_timer ();
271       printf (" %s", elapsed_time ());
272       fflush (stdout);
273       gcry_cipher_close (hd);
274       if (err)
275         { 
276           fprintf (stderr, "gcry_cipher_encrypt failed: %s\n",
277                    gpg_strerror (err) );
278           exit (1);
279         }
280
281       err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0);
282       if (err)
283         {
284           fprintf (stderr, PGM ": error opening cipher `%s'/n", algoname);
285           exit (1);
286         }
287       
288       err = gcry_cipher_setkey (hd, key, keylen);
289       if (err)
290         { 
291           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
292                    gpg_strerror (err));
293           gcry_cipher_close (hd);
294           exit (1);
295         }
296
297       start_timer ();
298       for (i=err=0; !err && i < 1000; i++)
299         err = gcry_cipher_decrypt ( hd, outbuf, buflen,  buf, buflen);
300       stop_timer ();
301       printf (" %s", elapsed_time ());
302       fflush (stdout);
303       gcry_cipher_close (hd);
304       if (err)
305         { 
306           fprintf (stderr, "gcry_cipher_decrypt failed: %s\n",
307                    gpg_strerror (err) );
308           exit (1);
309         }
310     }
311
312   putchar ('\n');
313 }
314
315
316 static void
317 do_powm ( const char *n_str, const char *e_str, const char *m_str)
318 {
319   gcry_mpi_t e, n, msg, cip;
320   gcry_error_t err;
321   int i;
322
323   err = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, n_str, 0, 0);
324   if (err) BUG ();
325   err = gcry_mpi_scan (&e, GCRYMPI_FMT_HEX, e_str, 0, 0);
326   if (err) BUG ();
327   err = gcry_mpi_scan (&msg, GCRYMPI_FMT_HEX, m_str, 0, 0);
328   if (err) BUG ();
329
330   cip = gcry_mpi_new (0);
331
332   start_timer ();
333   for (i=0; i < 1000; i++)
334     gcry_mpi_powm (cip, msg, e, n);
335   stop_timer ();
336   printf (" %s", elapsed_time ()); fflush (stdout);
337 /*    { */
338 /*      char *buf; */
339
340 /*      if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf, NULL, cip)) */
341 /*        BUG (); */
342 /*      printf ("result: %s\n", buf); */
343 /*      gcry_free (buf); */
344 /*    } */
345   gcry_mpi_release (cip);
346   gcry_mpi_release (msg);
347   gcry_mpi_release (n);
348   gcry_mpi_release (e);
349 }
350
351
352 static void
353 mpi_bench (void)
354 {
355   printf ("%-10s", "powm"); fflush (stdout);
356
357   do_powm (
358 "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E4",
359            "29", 
360 "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8"
361            );
362   do_powm (
363            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
364            "29", 
365            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
366            );
367   do_powm (
368            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA4071620A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
369            "29", 
370            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
371            );
372
373   putchar ('\n');
374
375
376 }
377
378
379 int
380 main( int argc, char **argv )
381 {
382   if (argc)
383     { argc--; argv++; }
384
385   if ( !argc )
386     {
387       md_bench (NULL);
388       putchar ('\n');
389       cipher_bench (NULL);
390       putchar ('\n');
391       mpi_bench ();
392       putchar ('\n');
393       random_bench ();
394     }
395   else if ( !strcmp (*argv, "--help"))
396      fputs ("usage: benchmark [md|cipher|random|mpi [algonames]]\n", stdout);
397   else if ( !strcmp (*argv, "random"))
398     {
399       random_bench ();
400     }
401   else if ( !strcmp (*argv, "md"))
402     {
403       if (argc == 1)
404         md_bench (NULL);
405       else
406         for (argc--, argv++; argc; argc--, argv++)
407           md_bench ( *argv );
408     }
409   else if ( !strcmp (*argv, "cipher"))
410     {
411       if (argc == 1)
412         cipher_bench (NULL);
413       else
414         for (argc--, argv++; argc; argc--, argv++)
415           cipher_bench ( *argv );
416     }
417   else if ( !strcmp (*argv, "mpi"))
418     {
419         mpi_bench ();
420     }
421   else
422     {
423       fprintf (stderr, PGM ": bad arguments\n");
424       return 1;
425     }
426   
427   return 0;
428 }
429
430