tests/basic: add CTR mode carry overflow test vectors
[libgcrypt.git] / src / mpicalc.c
1 /* mpicalc.c - Simple RPN calculator using gcry_mpi functions
2  * Copyright (C) 1997, 1998, 1999, 2004, 2006, 2013  Werner Koch
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2.1 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19    This program is a simple RPN calculator which was originally used
20    to develop the mpi functions of GnuPG.  Values must be given in
21    hex.  Operation is like dc(1) except that the input/output radix is
22    always 16 and you can use a '-' to prefix a negative number.
23    Addition operators: ++ and --.  All operators must be delimited by
24    a blank.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33
34 #ifdef _GCRYPT_IN_LIBGCRYPT
35 # undef _GCRYPT_IN_LIBGCRYPT
36 # include "gcrypt.h"
37 #else
38 # include <gcrypt.h>
39 #endif
40
41
42 #define MPICALC_VERSION "2.0"
43 #define NEED_LIBGCRYPT_VERSION "1.6.0"
44
45 #define STACKSIZE  500
46 static gcry_mpi_t stack[STACKSIZE];
47 static int stackidx;
48
49
50 static int
51 scan_mpi (gcry_mpi_t retval, const char *string)
52 {
53   gpg_error_t err;
54   gcry_mpi_t val;
55
56   err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
57   if (err)
58     {
59       fprintf (stderr, "scanning input failed: %s\n", gpg_strerror (err));
60       return -1;
61     }
62   mpi_set (retval, val);
63   mpi_release (val);
64   return 0;
65 }
66
67
68 static void
69 print_mpi (gcry_mpi_t a)
70 {
71   gpg_error_t err;
72   char *buf;
73   void *bufaddr = &buf;
74
75   err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
76   if (err)
77     fprintf (stderr, "[error printing number: %s]\n", gpg_strerror (err));
78   else
79     {
80       fputs (buf, stdout);
81       gcry_free (buf);
82     }
83 }
84
85
86
87 static void
88 do_add (void)
89 {
90   if (stackidx < 2)
91     {
92       fputs ("stack underflow\n", stderr);
93       return;
94     }
95   mpi_add (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
96   stackidx--;
97 }
98
99 static void
100 do_sub (void)
101 {
102   if (stackidx < 2)
103     {
104       fputs ("stack underflow\n", stderr);
105       return;
106     }
107   mpi_sub (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
108   stackidx--;
109 }
110
111 static void
112 do_inc (void)
113 {
114   if (stackidx < 1)
115     {
116       fputs ("stack underflow\n", stderr);
117       return;
118     }
119   mpi_add_ui (stack[stackidx - 1], stack[stackidx - 1], 1);
120 }
121
122 static void
123 do_dec (void)
124 {
125   if (stackidx < 1)
126     {
127       fputs ("stack underflow\n", stderr);
128       return;
129     }
130   /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
131 }
132
133 static void
134 do_mul (void)
135 {
136   if (stackidx < 2)
137     {
138       fputs ("stack underflow\n", stderr);
139       return;
140     }
141   mpi_mul (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
142   stackidx--;
143 }
144
145 static void
146 do_mulm (void)
147 {
148   if (stackidx < 3)
149     {
150       fputs ("stack underflow\n", stderr);
151       return;
152     }
153   mpi_mulm (stack[stackidx - 3], stack[stackidx - 3],
154             stack[stackidx - 2], stack[stackidx - 1]);
155   stackidx -= 2;
156 }
157
158 static void
159 do_div (void)
160 {
161   if (stackidx < 2)
162     {
163       fputs ("stack underflow\n", stderr);
164       return;
165     }
166   mpi_fdiv (stack[stackidx - 2], NULL,
167             stack[stackidx - 2], stack[stackidx - 1]);
168   stackidx--;
169 }
170
171 static void
172 do_rem (void)
173 {
174   if (stackidx < 2)
175     {
176       fputs ("stack underflow\n", stderr);
177       return;
178     }
179   mpi_mod (stack[stackidx - 2],
180            stack[stackidx - 2], stack[stackidx - 1]);
181   stackidx--;
182 }
183
184 static void
185 do_powm (void)
186 {
187   gcry_mpi_t a;
188   if (stackidx < 3)
189     {
190       fputs ("stack underflow\n", stderr);
191       return;
192     }
193   a = mpi_new (0);
194   mpi_powm (a, stack[stackidx - 3], stack[stackidx - 2], stack[stackidx - 1]);
195   mpi_release (stack[stackidx - 3]);
196   stack[stackidx - 3] = a;
197   stackidx -= 2;
198 }
199
200 static void
201 do_inv (void)
202 {
203   gcry_mpi_t a;
204
205   if (stackidx < 2)
206     {
207       fputs ("stack underflow\n", stderr);
208       return;
209     }
210   a = mpi_new (0);
211   mpi_invm (a, stack[stackidx - 2], stack[stackidx - 1]);
212   mpi_set (stack[stackidx - 2], a);
213   mpi_release (a);
214   stackidx--;
215 }
216
217 static void
218 do_gcd (void)
219 {
220   gcry_mpi_t a;
221
222   if (stackidx < 2)
223     {
224       fputs ("stack underflow\n", stderr);
225       return;
226     }
227   a = mpi_new (0);
228   mpi_gcd (a, stack[stackidx - 2], stack[stackidx - 1]);
229   mpi_set (stack[stackidx - 2], a);
230   mpi_release (a);
231   stackidx--;
232 }
233
234 static void
235 do_lshift (void)
236 {
237   if (stackidx < 1)
238     {
239       fputs ("stack underflow\n", stderr);
240       return;
241     }
242   mpi_lshift (stack[stackidx - 1], stack[stackidx - 1], 1);
243 }
244
245 static void
246 do_rshift (void)
247 {
248   if (stackidx < 1)
249     {
250       fputs ("stack underflow\n", stderr);
251       return;
252     }
253   mpi_rshift (stack[stackidx - 1], stack[stackidx - 1], 1);
254 }
255
256 static void
257 do_nbits (void)
258 {
259   unsigned int n;
260
261   if (stackidx < 1)
262     {
263       fputs ("stack underflow\n", stderr);
264       return;
265     }
266   n = mpi_get_nbits (stack[stackidx - 1]);
267   mpi_set_ui (stack[stackidx - 1], n);
268 }
269
270
271 static void
272 do_primecheck (void)
273 {
274   gpg_error_t err;
275
276   if (stackidx < 1)
277     {
278       fputs ("stack underflow\n", stderr);
279       return;
280     }
281   err = gcry_prime_check (stack[stackidx - 1], 0);
282   mpi_set_ui (stack[stackidx - 1], !err);
283   if (err && gpg_err_code (err) != GPG_ERR_NO_PRIME)
284     fprintf (stderr, "checking prime failed: %s\n", gpg_strerror (err));
285 }
286
287
288 static int
289 my_getc (void)
290 {
291   static int shown;
292   int c;
293
294   for (;;)
295     {
296       if ((c = getc (stdin)) == EOF)
297         return EOF;
298       if (!(c & 0x80))
299         return c;
300
301       if (!shown)
302         {
303           shown = 1;
304           fputs ("note: Non ASCII characters are ignored\n", stderr);
305         }
306     }
307 }
308
309
310 static void
311 print_help (void)
312 {
313   fputs ("+   add           [0] := [1] + [0]          {-1}\n"
314          "-   subtract      [0] := [1] - [0]          {-1}\n"
315          "*   multiply      [0] := [1] * [0]          {-1}\n"
316          "/   divide        [0] := [1] - [0]          {-1}\n"
317          "%   modulo        [0] := [1] % [0]          {-1}\n"
318          "<   left shift    [0] := [0] << 1           {0}\n"
319          ">   right shift   [0] := [0] >> 1           {0}\n"
320          "++  increment     [0] := [0]++              {0}\n"
321          "--  decrement     [0] := [0]--              {0}\n"
322          "m   multiply mod  [0] := [2] * [1] mod [0]  {-2}\n"
323          "^   power mod     [0] := [2] ^ [1] mod [0]  {-2}\n"
324          "I   inverse mod   [0] := [1]^-1 mod [0]     {-1}\n"
325          "G   gcd           [0] := gcd([1],[0])       {-1}\n"
326          "i   remove item   [0] := [1]                {-1}\n"
327          "d   dup item      [-1] := [0]               {+1}\n"
328          "r   reverse       [0] := [1], [1] := [0]    {0}\n"
329          "b   # of bits     [0] := nbits([0])         {0}\n"
330          "P   prime check   [0] := is_prime([0])?1:0  {0}\n"
331          "c   clear stack\n"
332          "p   print top item\n"
333          "f   print the stack\n"
334          "#   ignore until end of line\n"
335          "?   print this help\n"
336          , stdout);
337 }
338
339
340
341 int
342 main (int argc, char **argv)
343 {
344   const char *pgm;
345   int last_argc = -1;
346   int print_config = 0;
347   int i, c;
348   int state = 0;
349   char strbuf[4096];
350   int stridx = 0;
351
352   if (argc)
353     {
354       pgm = strrchr (*argv, '/');
355       if (pgm)
356         pgm++;
357       else
358         pgm = *argv;
359       argc--; argv++;
360     }
361   else
362     pgm = "?";
363
364   while (argc && last_argc != argc )
365     {
366       last_argc = argc;
367       if (!strcmp (*argv, "--"))
368         {
369           argc--; argv++;
370           break;
371         }
372       else if (!strcmp (*argv, "--version")
373                || !strcmp (*argv, "--help"))
374         {
375           printf ("%s " MPICALC_VERSION "\n"
376                   "libgcrypt %s\n"
377                   "Copyright (C) 1997, 2013  Werner Koch\n"
378                   "License LGPLv2.1+: GNU LGPL version 2.1 or later "
379                   "<http://gnu.org/licenses/old-licenses/lgpl-2.1.html>\n"
380                   "This is free software: you are free to change and "
381                   "redistribute it.\n"
382                   "There is NO WARRANTY, to the extent permitted by law.\n"
383                   "\n"
384                   "Syntax: mpicalc [options]\n"
385                   "Simple interactive big integer RPN calculator\n"
386                   "\n"
387                   "Options:\n"
388                   "  --version           print version information\n"
389                   "  --print-config      print the Libgcrypt config\n"
390                   "  --disable-hwf NAME  disable feature NAME\n",
391                   pgm, gcry_check_version (NULL));
392           exit (0);
393         }
394       else if (!strcmp (*argv, "--print-config"))
395         {
396           argc--; argv++;
397           print_config = 1;
398         }
399       else if (!strcmp (*argv, "--disable-hwf"))
400         {
401           argc--; argv++;
402           if (argc)
403             {
404               if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
405                 fprintf (stderr, "%s: unknown hardware feature `%s'"
406                          " - option ignored\n", pgm, *argv);
407               argc--; argv++;
408             }
409         }
410     }
411
412   if (argc)
413     {
414       fprintf (stderr, "usage: %s [options]  (--help for help)\n", pgm);
415       exit (1);
416     }
417
418   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
419     {
420       fprintf (stderr, "%s: Libgcrypt is too old (need %s, have %s)\n",
421                pgm, NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
422       exit (1);
423     }
424   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
425   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
426   if (print_config)
427     {
428       gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
429       exit (0);
430     }
431
432   for (i = 0; i < STACKSIZE; i++)
433     stack[i] = NULL;
434   stackidx = 0;
435
436   while ((c = my_getc ()) != EOF)
437     {
438       if (!state) /* waiting */
439         {
440           if (isdigit (c))
441             {
442               state = 1;
443               ungetc (c, stdin);
444               strbuf[0] = '0';
445               strbuf[1] = 'x';
446               stridx = 2;
447             }
448           else if (isspace (c))
449             ;
450           else
451             {
452               switch (c)
453                 {
454                 case '#':
455                   state = 2;
456                   break;
457                 case '+':
458                   if ((c = my_getc ()) == '+')
459                     do_inc ();
460                   else
461                     {
462                       ungetc (c, stdin);
463                       do_add ();
464                     }
465                   break;
466                 case '-':
467                   if ((c = my_getc ()) == '-')
468                     do_dec ();
469                   else if (isdigit (c)
470                            || (c >= 'A' && c <= 'F')
471                            || (c >= 'a' && c <= 'f'))
472                     {
473                       state = 1;
474                       ungetc (c, stdin);
475                       strbuf[0] = '-';
476                       strbuf[1] = '0';
477                       strbuf[2] = 'x';
478                       stridx = 3;
479                     }
480                   else
481                     {
482                       ungetc (c, stdin);
483                       do_sub ();
484                     }
485                   break;
486                 case '*':
487                   do_mul ();
488                   break;
489                 case 'm':
490                   do_mulm ();
491                   break;
492                 case '/':
493                   do_div ();
494                   break;
495                 case '%':
496                   do_rem ();
497                   break;
498                 case '^':
499                   do_powm ();
500                   break;
501                 case '<':
502                   do_lshift ();
503                   break;
504                 case '>':
505                   do_rshift ();
506                   break;
507                 case 'I':
508                   do_inv ();
509                   break;
510                 case 'G':
511                   do_gcd ();
512                   break;
513                 case 'i':       /* dummy */
514                   if (!stackidx)
515                     fputs ("stack underflow\n", stderr);
516                   else
517                     {
518                       mpi_release (stack[stackidx - 1]);
519                       stackidx--;
520                     }
521                   break;
522                 case 'd':       /* duplicate the tos */
523                   if (!stackidx)
524                     fputs ("stack underflow\n", stderr);
525                   else if (stackidx < STACKSIZE)
526                     {
527                       mpi_release (stack[stackidx]);
528                       stack[stackidx] = mpi_copy (stack[stackidx - 1]);
529                       stackidx++;
530                     }
531                   else
532                     fputs ("stack overflow\n", stderr);
533                   break;
534                 case 'r':       /* swap top elements */
535                   if (stackidx < 2)
536                     fputs ("stack underflow\n", stderr);
537                   else if (stackidx < STACKSIZE)
538                     {
539                       gcry_mpi_t tmp = stack[stackidx-1];
540                       stack[stackidx-1] = stack[stackidx - 2];
541                       stack[stackidx-2] = tmp;
542                     }
543                   break;
544                 case 'b':
545                   do_nbits ();
546                   break;
547                 case 'P':
548                   do_primecheck ();
549                   break;
550                 case 'c':
551                   for (i = 0; i < stackidx; i++)
552                     {
553                       mpi_release (stack[i]); stack[i] = NULL;
554                     }
555                   stackidx = 0;
556                   break;
557                 case 'p':       /* print the tos */
558                   if (!stackidx)
559                     puts ("stack is empty");
560                   else
561                     {
562                       print_mpi (stack[stackidx - 1]);
563                       putchar ('\n');
564                     }
565                   break;
566                 case 'f':       /* print the stack */
567                   for (i = stackidx - 1; i >= 0; i--)
568                     {
569                       printf ("[%2d]: ", i);
570                       print_mpi (stack[i]);
571                       putchar ('\n');
572                     }
573                   break;
574                 case '?':
575                   print_help ();
576                   break;
577                 default:
578                   fputs ("invalid operator\n", stderr);
579                 }
580             }
581         }
582       else if (state == 1) /* In a number. */
583         {
584           if (!isxdigit (c))
585             {
586               /* Store the number */
587               state = 0;
588               ungetc (c, stdin);
589               if (stridx < sizeof strbuf)
590                 strbuf[stridx] = 0;
591
592               if (stackidx < STACKSIZE)
593                 {
594                   if (!stack[stackidx])
595                     stack[stackidx] = mpi_new (0);
596                   if (scan_mpi (stack[stackidx], strbuf))
597                     fputs ("invalid number\n", stderr);
598                   else
599                     stackidx++;
600                 }
601               else
602                 fputs ("stack overflow\n", stderr);
603             }
604           else
605             { /* Store a digit.  */
606               if (stridx < sizeof strbuf - 1)
607                 strbuf[stridx++] = c;
608               else if (stridx == sizeof strbuf - 1)
609                 {
610                   strbuf[stridx] = 0;
611                   fputs ("input too large - truncated\n", stderr);
612                   stridx++;
613                 }
614             }
615         }
616       else if (state == 2) /* In a comment. */
617         {
618           if (c == '\n')
619             state = 0;
620         }
621
622     }
623
624   for (i = 0; i < stackidx; i++)
625     mpi_release (stack[i]);
626   return 0;
627 }