2003-05-21 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / src / benchmark.c
1 /* benchmark.c - for libgcrypt
2  *      Copyright (C) 2002 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 = gcry_md_map_name (algoname);
97   GcryMDHd hd;
98   int i;
99   char buf[1000];
100
101   if (!algo)
102     {
103       fprintf (stderr, PGM ": invalid hash algorithm `%s'\n", algoname);
104       exit (1);
105     }
106   
107   hd = gcry_md_open (algo, 0);
108   if (!hd)
109     {
110       fprintf (stderr, PGM ": error opeing hash algorithm `%s'/n", algoname);
111       exit (1);
112     }
113
114   for (i=0; i < sizeof buf; i++)
115     buf[i] = i;
116
117   printf ("%-10s", gcry_md_algo_name (algo));
118
119   start_timer ();
120   for (i=0; i < 1000; i++)
121     gcry_md_write (hd, buf, sizeof buf);
122   gcry_md_final (hd);
123   stop_timer ();
124   printf (" %s", elapsed_time ());
125
126   gcry_md_reset (hd);
127   start_timer ();
128   for (i=0; i < 10000; i++)
129     gcry_md_write (hd, buf, sizeof buf/10);
130   gcry_md_final (hd);
131   stop_timer ();
132   printf (" %s", elapsed_time ());
133
134   gcry_md_reset (hd);
135   start_timer ();
136   for (i=0; i < 1000000; i++)
137     gcry_md_write (hd, "", 1);
138   gcry_md_final (hd);
139   stop_timer ();
140   printf (" %s", elapsed_time ());
141
142   gcry_md_close (hd);
143   putchar ('\n');
144 }
145
146 static void
147 cipher_bench ( const char *algoname )
148 {
149   static int header_printed;
150   int algo = gcry_cipher_map_name (algoname);
151   GcryCipherHd hd;
152   int err, i;
153   int keylen, blklen;
154   char key[128];
155   char outbuf[1000], buf[1000];
156   size_t buflen;
157   static struct { int mode; const char *name; int blocked; } modes[] = {
158     { GCRY_CIPHER_MODE_ECB, "ECB", 1 },
159     { GCRY_CIPHER_MODE_CBC, "CBC", 1 },
160     { GCRY_CIPHER_MODE_CFB, "CFB", 0 },
161     { GCRY_CIPHER_MODE_CTR, "CTR", 0 },
162     { GCRY_CIPHER_MODE_STREAM, "STREAM", 0 },
163     {0}
164   };
165   int modeidx;
166
167   if (!header_printed)
168     {
169       printf ("%-10s", "Algo");
170       for (modeidx=0; modes[modeidx].mode; modeidx++)
171         printf (" %-15s", modes[modeidx].name );
172       putchar ('\n');
173       printf ( "----------");
174       for (modeidx=0; modes[modeidx].mode; modeidx++)
175         printf (" ---------------" );
176       putchar ('\n');
177       header_printed = 1;
178     }
179
180   if (!algo)
181     {
182       fprintf (stderr, PGM ": invalid cipher algorithm `%s'\n", algoname);
183       exit (1);
184     }
185
186   keylen = gcry_cipher_get_algo_keylen (algo);
187   if ( keylen > sizeof key )
188     {
189         fprintf (stderr, PGM ": algo %d, keylength problem (%d)\n",
190                  algo, keylen );
191         exit (1);
192     }
193   for (i=0; i < keylen; i++)
194     key[i] = i + (clock () & 0xff);
195
196   blklen = gcry_cipher_get_algo_blklen (algo);
197
198   printf ("%-10s", gcry_cipher_algo_name (algo));
199   fflush (stdout);
200
201   for (modeidx=0; modes[modeidx].mode; modeidx++)
202     {
203       if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM)
204           | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
205         {
206           printf ("                " );
207           continue;
208         }
209
210       for (i=0; i < sizeof buf; i++)
211         buf[i] = i;
212
213       hd = gcry_cipher_open (algo, modes[modeidx].mode, 0);
214       if (!hd)
215         {
216           fprintf (stderr, PGM ": error opening cipher `%s'\n", algoname);
217           exit (1);
218         }
219       
220       if (gcry_cipher_setkey (hd, key, keylen))
221         { 
222           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
223                    gcry_strerror (-1) );
224           gcry_cipher_close (hd);
225           exit (1);
226         }
227
228       buflen = sizeof buf;
229       if (modes[modeidx].blocked)
230         buflen = (buflen / blklen) * blklen;
231
232       start_timer ();
233       for (i=err=0; !err && i < 1000; i++)
234         err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen);
235       stop_timer ();
236       printf (" %s", elapsed_time ());
237       fflush (stdout);
238       gcry_cipher_close (hd);
239       if (err)
240         { 
241           fprintf (stderr, "gcry_cipher_encrypt failed: %s\n",
242                    gcry_strerror (err) );
243           exit (1);
244         }
245
246       hd = gcry_cipher_open (algo, modes[modeidx].mode, 0);
247       if (!hd)
248         {
249           fprintf (stderr, PGM ": error opening cipher `%s'/n", algoname);
250           exit (1);
251         }
252       
253       if (gcry_cipher_setkey (hd, key, keylen))
254         { 
255           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
256                    gcry_strerror (-1) );
257           gcry_cipher_close (hd);
258           exit (1);
259         }
260
261       start_timer ();
262       for (i=err=0; !err && i < 1000; i++)
263         err = gcry_cipher_decrypt ( hd, outbuf, buflen,  buf, buflen);
264       stop_timer ();
265       printf (" %s", elapsed_time ());
266       fflush (stdout);
267       gcry_cipher_close (hd);
268       if (err)
269         { 
270           fprintf (stderr, "gcry_cipher_decrypt failed: %s\n",
271                    gcry_strerror (err) );
272           exit (1);
273         }
274     }
275
276   putchar ('\n');
277 }
278
279
280 static void
281 do_powm ( const char *n_str, const char *e_str, const char *m_str)
282 {
283   GcryMPI e, n, msg, cip;
284   int i, err;
285
286   err = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, n_str, 0 );
287   if (err) BUG ();
288   err = gcry_mpi_scan (&e, GCRYMPI_FMT_HEX, e_str, 0);
289   if (err) BUG ();
290   err = gcry_mpi_scan (&msg, GCRYMPI_FMT_HEX, m_str, 0);
291   if (err) BUG ();
292
293   cip = gcry_mpi_new (0);
294
295   start_timer ();
296   for (i=0; i < 1000; i++)
297     gcry_mpi_powm (cip, msg, e, n);
298   stop_timer ();
299   printf (" %s", elapsed_time ()); fflush (stdout);
300 /*    { */
301 /*      char *buf; */
302
303 /*      if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf, NULL, cip)) */
304 /*        BUG (); */
305 /*      printf ("result: %s\n", buf); */
306 /*      gcry_free (buf); */
307 /*    } */
308   gcry_mpi_release (cip);
309   gcry_mpi_release (msg);
310   gcry_mpi_release (n);
311   gcry_mpi_release (e);
312 }
313
314
315 static void
316 mpi_bench (void)
317 {
318   printf ("%-10s", "powm"); fflush (stdout);
319
320   do_powm (
321 "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E4",
322            "29", 
323 "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8"
324            );
325   do_powm (
326            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
327            "29", 
328            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
329            );
330   do_powm (
331            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA4071620A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
332            "29", 
333            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
334            );
335
336   putchar ('\n');
337
338
339 }
340
341
342
343
344
345
346 int
347 main( int argc, char **argv )
348 {
349   if (argc < 2 )
350     {
351       fprintf (stderr, "usage: benchmark md|cipher|random|mpi [algonames]\n");
352       return 1;
353     }
354   argc--; argv++;
355   
356   if ( !strcmp (*argv, "random"))
357     {
358       random_bench ();
359     }
360   else if ( !strcmp (*argv, "md"))
361     {
362       for (argc--, argv++; argc; argc--, argv++)
363         md_bench ( *argv );
364     }
365   else if ( !strcmp (*argv, "cipher"))
366     {
367       for (argc--, argv++; argc; argc--, argv++)
368         cipher_bench ( *argv );
369     }
370   else if ( !strcmp (*argv, "mpi"))
371     {
372         mpi_bench ();
373     }
374   else
375     {
376       fprintf (stderr, PGM ": bad arguments\n");
377       return 1;
378     }
379   
380   return 0;
381 }
382
383