* basic.c (check_digests): Add CRC.
[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_STREAM, "STREAM", 0 },
162     {0}
163   };
164   int modeidx;
165
166   if (!header_printed)
167     {
168       printf ("%-10s", "Algo");
169       for (modeidx=0; modes[modeidx].mode; modeidx++)
170         printf (" %-15s", modes[modeidx].name );
171       putchar ('\n');
172       printf ( "----------");
173       for (modeidx=0; modes[modeidx].mode; modeidx++)
174         printf (" ---------------" );
175       putchar ('\n');
176       header_printed = 1;
177     }
178
179   if (!algo)
180     {
181       fprintf (stderr, PGM ": invalid cipher algorithm `%s'\n", algoname);
182       exit (1);
183     }
184
185   keylen = gcry_cipher_get_algo_keylen (algo);
186   if ( keylen > sizeof key )
187     {
188         fprintf (stderr, PGM ": algo %d, keylength problem (%d)\n",
189                  algo, keylen );
190         exit (1);
191     }
192   for (i=0; i < keylen; i++)
193     key[i] = i + (clock () & 0xff);
194
195   blklen = gcry_cipher_get_algo_blklen (algo);
196
197   printf ("%-10s", gcry_cipher_algo_name (algo));
198   fflush (stdout);
199
200   for (modeidx=0; modes[modeidx].mode; modeidx++)
201     {
202       if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM)
203           | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
204         {
205           printf ("                " );
206           continue;
207         }
208
209       for (i=0; i < sizeof buf; i++)
210         buf[i] = i;
211
212       hd = gcry_cipher_open (algo, modes[modeidx].mode, 0);
213       if (!hd)
214         {
215           fprintf (stderr, PGM ": error opening cipher `%s'\n", algoname);
216           exit (1);
217         }
218       
219       if (gcry_cipher_setkey (hd, key, keylen))
220         { 
221           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
222                    gcry_strerror (-1) );
223           gcry_cipher_close (hd);
224           exit (1);
225         }
226
227       buflen = sizeof buf;
228       if (modes[modeidx].blocked)
229         buflen = (buflen / blklen) * blklen;
230
231       start_timer ();
232       for (i=err=0; !err && i < 1000; i++)
233         err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen);
234       stop_timer ();
235       printf (" %s", elapsed_time ());
236       fflush (stdout);
237       gcry_cipher_close (hd);
238       if (err)
239         { 
240           fprintf (stderr, "gcry_cipher_encrypt failed: %s\n",
241                    gcry_strerror (err) );
242           exit (1);
243         }
244
245       hd = gcry_cipher_open (algo, modes[modeidx].mode, 0);
246       if (!hd)
247         {
248           fprintf (stderr, PGM ": error opening cipher `%s'/n", algoname);
249           exit (1);
250         }
251       
252       if (gcry_cipher_setkey (hd, key, keylen))
253         { 
254           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
255                    gcry_strerror (-1) );
256           gcry_cipher_close (hd);
257           exit (1);
258         }
259
260       start_timer ();
261       for (i=err=0; !err && i < 1000; i++)
262         err = gcry_cipher_decrypt ( hd, outbuf, buflen,  buf, buflen);
263       stop_timer ();
264       printf (" %s", elapsed_time ());
265       fflush (stdout);
266       gcry_cipher_close (hd);
267       if (err)
268         { 
269           fprintf (stderr, "gcry_cipher_decrypt failed: %s\n",
270                    gcry_strerror (err) );
271           exit (1);
272         }
273     }
274
275   putchar ('\n');
276 }
277
278
279 static void
280 do_powm ( const char *n_str, const char *e_str, const char *m_str)
281 {
282   GcryMPI e, n, msg, cip;
283   int i, err;
284
285   err = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, n_str, 0 );
286   if (err) BUG ();
287   err = gcry_mpi_scan (&e, GCRYMPI_FMT_HEX, e_str, 0);
288   if (err) BUG ();
289   err = gcry_mpi_scan (&msg, GCRYMPI_FMT_HEX, m_str, 0);
290   if (err) BUG ();
291
292   cip = gcry_mpi_new (0);
293
294   start_timer ();
295   for (i=0; i < 1000; i++)
296     gcry_mpi_powm (cip, msg, e, n);
297   stop_timer ();
298   printf (" %s", elapsed_time ()); fflush (stdout);
299 /*    { */
300 /*      char *buf; */
301
302 /*      if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf, NULL, cip)) */
303 /*        BUG (); */
304 /*      printf ("result: %s\n", buf); */
305 /*      gcry_free (buf); */
306 /*    } */
307   gcry_mpi_release (cip);
308   gcry_mpi_release (msg);
309   gcry_mpi_release (n);
310   gcry_mpi_release (e);
311 }
312
313
314 static void
315 mpi_bench (void)
316 {
317   printf ("%-10s", "powm"); fflush (stdout);
318
319   do_powm (
320 "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E4",
321            "29", 
322 "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8"
323            );
324   do_powm (
325            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
326            "29", 
327            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
328            );
329   do_powm (
330            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA4071620A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
331            "29", 
332            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
333            );
334
335   putchar ('\n');
336
337
338 }
339
340
341
342
343
344
345 int
346 main( int argc, char **argv )
347 {
348   if (argc < 2 )
349     {
350       fprintf (stderr, "usage: benchmark md|cipher|random|mpi [algonames]\n");
351       return 1;
352     }
353   argc--; argv++;
354   
355   if ( !strcmp (*argv, "random"))
356     {
357       random_bench ();
358     }
359   else if ( !strcmp (*argv, "md"))
360     {
361       for (argc--, argv++; argc; argc--, argv++)
362         md_bench ( *argv );
363     }
364   else if ( !strcmp (*argv, "cipher"))
365     {
366       for (argc--, argv++; argc; argc--, argv++)
367         cipher_bench ( *argv );
368     }
369   else if ( !strcmp (*argv, "mpi"))
370     {
371         mpi_bench ();
372     }
373   else
374     {
375       fprintf (stderr, PGM ": bad arguments\n");
376       return 1;
377     }
378   
379   return 0;
380 }
381
382