mpi: Support printing of negative numbers.
[libgcrypt.git] / tests / t-convert.c
1 /* t-convert.c  - Tests for mpi print and scna functions
2  * Copyright (C) 2013 g10 Code GmbH
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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <stdarg.h>
28
29 #include "../src/gcrypt-int.h"
30
31 #define PGM "t-convert"
32
33 #define DIM(v)               (sizeof(v)/sizeof((v)[0]))
34 #define DIMof(type,member)   DIM(((type *)0)->member)
35
36 static const char *wherestr;
37 static int verbose;
38 static int debug;
39 static int error_count;
40
41
42 #define xmalloc(a)    gcry_xmalloc ((a))
43 #define xcalloc(a,b)  gcry_xcalloc ((a),(b))
44 #define xfree(a)      gcry_free ((a))
45 #define pass() do { ; } while (0)
46
47 static void
48 show (const char *format, ...)
49 {
50   va_list arg_ptr;
51
52   if (!verbose)
53     return;
54   fprintf (stderr, "%s: ", PGM);
55   va_start (arg_ptr, format);
56   vfprintf (stderr, format, arg_ptr);
57   va_end (arg_ptr);
58 }
59
60 static void
61 showhex (const char *prefix, const void *buffer, size_t buflen)
62 {
63   const unsigned char *s;
64
65   if (!verbose)
66     return;
67   fprintf (stderr, "%s: %s ", PGM, prefix);
68   for (s= buffer; buflen; buflen--, s++)
69     fprintf (stderr, "%02x", *s);
70   putc ('\n', stderr);
71 }
72
73
74 /* Allocate a bit string consisting of '0' and '1' from the MPI A.  Do
75    not return any leading zero bits.  Caller needs to gcry_free the
76    result. */
77 static char *
78 mpi2bitstr_nlz (gcry_mpi_t a)
79 {
80   char *p, *buf;
81   size_t length = gcry_mpi_get_nbits (a);
82
83   if (!length)
84     {
85       buf = p = xmalloc (3);
86       *p++ = ' ';
87       *p++ = '0';
88     }
89   else
90     {
91       buf = p = xmalloc (length + 1 + 1);
92       *p++ = gcry_mpi_is_neg (a)? '-':' ';
93       while (length-- > 1)
94         *p++ = gcry_mpi_test_bit (a, length) ? '1':'0';
95       *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0';
96     }
97   *p = 0;
98   return buf;
99 }
100
101
102 static void
103 showmpi (const char *prefix, gcry_mpi_t a)
104 {
105   char *bitstr;
106
107   if (!verbose)
108     return;
109   bitstr = mpi2bitstr_nlz (a);
110   fprintf (stderr, "%s: %s%s\n", PGM, prefix, bitstr);
111   xfree (bitstr);
112 }
113
114
115 static void
116 fail (const char *format, ...)
117 {
118   va_list arg_ptr;
119
120   fflush (stdout);
121   fprintf (stderr, "%s: ", PGM);
122   if (wherestr)
123     fprintf (stderr, "%s: ", wherestr);
124   va_start (arg_ptr, format);
125   vfprintf (stderr, format, arg_ptr);
126   va_end (arg_ptr);
127   error_count++;
128 }
129
130 static void
131 die (const char *format, ...)
132 {
133   va_list arg_ptr;
134
135   fflush (stdout);
136   fprintf (stderr, "%s: ", PGM);
137   if (wherestr)
138     fprintf (stderr, "%s: ", wherestr);
139   va_start (arg_ptr, format);
140   vfprintf (stderr, format, arg_ptr);
141   va_end (arg_ptr);
142   exit (1);
143 }
144
145
146 /* Check that mpi_print does not return a negative zero.  */
147 static void
148 negative_zero (void)
149 {
150   gpg_error_t err;
151   gcry_mpi_t a;
152   char *buf;
153   void *bufaddr = &buf;
154   struct { const char *name; enum gcry_mpi_format format; } fmts[] =
155     {
156       /* { "STD", GCRYMPI_FMT_STD }, */
157       /* { "PGP", GCRYMPI_FMT_PGP }, */
158       /* { "SSH", GCRYMPI_FMT_SSH }, */
159       /* { "HEX", GCRYMPI_FMT_HEX }, */
160       { "USG", GCRYMPI_FMT_USG },
161       { NULL, 0 }
162     };
163   int i;
164
165   a = gcry_mpi_new (0);
166   for (i=0; fmts[i].name; i++)
167     {
168       err = gcry_mpi_aprint (fmts[i].format, bufaddr, NULL, a);
169       if (err)
170         fail ("error printing a zero as %s: %s\n",
171               fmts[i].name,gpg_strerror (err) );
172       else
173         gcry_free (buf);
174     }
175
176   /* With the current version of libgcrypt the next two statements
177      should set a to -0. */
178   gcry_mpi_sub_ui (a, a, 1);
179   gcry_mpi_add_ui (a, a, 1);
180
181   for (i=0; fmts[i].name; i++)
182     {
183       err = gcry_mpi_aprint (fmts[i].format, bufaddr, NULL, a);
184       if (err)
185         fail ("error printing a negative zero as %s: %s\n",
186               fmts[i].name,gpg_strerror (err) );
187       else
188         gcry_free (buf);
189     }
190
191   gcry_mpi_release (a);
192 }
193
194
195 static void
196 check_formats (void)
197 {
198   static struct {
199     int value;
200     struct {
201       const char *hex;
202       size_t stdlen;
203       const char *std;
204       size_t sshlen;
205       const char *ssh;
206       size_t usglen;
207       const char *usg;
208     } a;
209   } data[] = {
210     {    0, { "00",
211               0, "",
212               4, "\x00\x00\x00\x00",
213               0, "" }
214     },
215     {    1, { "01",
216               1, "\x01",
217               5, "\x00\x00\x00\x01\x01",
218               1, "\x01" }
219     },
220     {    2, { "02",
221               1, "\x02",
222               5, "\x00\x00\x00\x01\x02",
223               1, "\x02",  }
224     },
225     {  127, { "7F",
226               1, "\x7f",
227               5, "\x00\x00\x00\x01\x7f",
228               1, "\x7f"  }
229     },
230     {  128, { "0080",
231               2, "\x00\x80",
232               6, "\x00\x00\x00\x02\x00\x80",
233               1, "\x80" }
234     },
235     {  129, { "0081",
236               2, "\x00\x81",
237               6, "\x00\x00\x00\x02\x00\x81",
238               1, "\x81"  }
239     },
240     {  255, { "00FF",
241               2, "\x00\xff",
242               6, "\x00\x00\x00\x02\x00\xff",
243               1, "\xff" }
244     },
245     {  256, { "0100",
246               2, "\x01\x00",
247               6, "\x00\x00\x00\x02\x01\x00",
248               2, "\x01\x00" }
249     },
250     {  257, { "0101",
251               2, "\x01\x01",
252               6, "\x00\x00\x00\x02\x01\x01",
253               2, "\x01\x01" }
254     },
255     {   -1, { "-01",
256               1, "\xff",
257               5, "\x00\x00\x00\x01\xff",
258               1,"\x01" }
259     },
260     {   -2, { "-02",
261               1, "\xfe",
262               5, "\x00\x00\x00\x01\xfe",
263               1, "\x02" }
264     },
265     { -127, { "-7F",
266               1, "\x81",
267               5, "\x00\x00\x00\x01\x81",
268               1, "\x7f" }
269     },
270     { -128, { "-0080",
271               1, "\x80",
272               5, "\x00\x00\x00\x01\x80",
273               1, "\x80" }
274     },
275     { -129, { "-0081",
276               2, "\xff\x7f",
277               6, "\x00\x00\x00\x02\xff\x7f",
278               1, "\x81" }
279     },
280     { -255, { "-00FF",
281               2, "\xff\x01",
282               6, "\x00\x00\x00\x02\xff\x01",
283               1, "\xff" }
284     },
285     { -256, { "-0100",
286               2, "\xff\x00",
287               6, "\x00\x00\x00\x02\xff\x00",
288               2, "\x01\x00" }
289     },
290     { -257, { "-0101",
291               2, "\xfe\xff",
292               6, "\x00\x00\x00\x02\xfe\xff",
293               2, "\x01\x01" }
294     },
295     {  65535, { "00FFFF",
296                 3, "\x00\xff\xff",
297                 7, "\x00\x00\x00\x03\x00\xff\xff",
298                 2, "\xff\xff" }
299     },
300     {  65536, { "010000",
301                 3, "\x01\00\x00",
302                 7, "\x00\x00\x00\x03\x01\x00\x00",
303                 3, "\x01\x00\x00" }
304     },
305     {  65537, { "010001",
306                 3, "\x01\00\x01",
307                 7, "\x00\x00\x00\x03\x01\x00\x01",
308                 3, "\x01\x00\x01" }
309     },
310     { -65537, { "-010001",
311                 3, "\xfe\xff\xff",
312                 7, "\x00\x00\x00\x03\xfe\xff\xff",
313                 3, "\x01\x00\x01" }
314     },
315     { -65536, { "-010000",
316                 3, "\xff\x00\x00",
317                 7, "\x00\x00\x00\x03\xff\x00\x00",
318                 3, "\x01\x00\x00" }
319     },
320     { -65535, { "-00FFFF",
321                 3, "\xff\x00\x01",
322                 7, "\x00\x00\x00\x03\xff\x00\x01",
323                 2, "\xff\xff" }
324     }
325   };
326   gpg_error_t err;
327   gcry_mpi_t a, b;
328   char *buf;
329   void *bufaddr = &buf;
330   int idx;
331   size_t buflen;
332
333   a = gcry_mpi_new (0);
334   for (idx=0; idx < DIM(data); idx++)
335     {
336       if (debug)
337         show ("print test %d\n", data[idx].value);
338
339       if (data[idx].value < 0)
340         {
341           gcry_mpi_set_ui (a, -data[idx].value);
342           gcry_mpi_neg (a, a);
343         }
344       else
345         gcry_mpi_set_ui (a, data[idx].value);
346
347       err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
348       if (err)
349         fail ("error printing value %d as %s: %s\n",
350               data[idx].value, "HEX", gpg_strerror (err));
351       else
352         {
353           if (strcmp (buf, data[idx].a.hex))
354             {
355               fail ("error printing value %d as %s: %s\n",
356                     data[idx].value, "HEX", "wrong result");
357               show ("expected: '%s'\n", data[idx].a.hex);
358               show ("     got: '%s'\n", buf);
359             }
360           gcry_free (buf);
361         }
362
363       err = gcry_mpi_aprint (GCRYMPI_FMT_STD, bufaddr, &buflen, a);
364       if (err)
365         fail ("error printing value %d as %s: %s\n",
366               data[idx].value, "STD", gpg_strerror (err));
367       else
368         {
369           if (buflen != data[idx].a.stdlen
370               || memcmp (buf, data[idx].a.std, data[idx].a.stdlen))
371             {
372               fail ("error printing value %d as %s: %s\n",
373                     data[idx].value, "STD", "wrong result");
374               showhex ("expected:", data[idx].a.std, data[idx].a.stdlen);
375               showhex ("     got:", buf, buflen);
376             }
377           gcry_free (buf);
378         }
379
380       err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, bufaddr, &buflen, a);
381       if (err)
382         fail ("error printing value %d as %s: %s\n",
383               data[idx].value, "SSH", gpg_strerror (err));
384       else
385         {
386           if (buflen != data[idx].a.sshlen
387               || memcmp (buf, data[idx].a.ssh, data[idx].a.sshlen))
388             {
389               fail ("error printing value %d as %s: %s\n",
390                     data[idx].value, "SSH", "wrong result");
391               showhex ("expected:", data[idx].a.ssh, data[idx].a.sshlen);
392               showhex ("     got:", buf, buflen);
393             }
394           gcry_free (buf);
395         }
396
397       err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufaddr, &buflen, a);
398       if (err)
399         fail ("error printing value %d as %s: %s\n",
400               data[idx].value, "USG", gpg_strerror (err));
401       else
402         {
403           if (buflen != data[idx].a.usglen
404               || memcmp (buf, data[idx].a.usg, data[idx].a.usglen))
405             {
406               fail ("error printing value %d as %s: %s\n",
407                     data[idx].value, "USG", "wrong result");
408               showhex ("expected:", data[idx].a.usg, data[idx].a.usglen);
409               showhex ("     got:", buf, buflen);
410             }
411           gcry_free (buf);
412         }
413     }
414
415
416   /* Now for the other direction.  */
417   for (idx=0; idx < DIM(data); idx++)
418     {
419       if (debug)
420         show ("scan test %d\n", data[idx].value);
421
422       if (data[idx].value < 0)
423         {
424           gcry_mpi_set_ui (a, -data[idx].value);
425           gcry_mpi_neg (a, a);
426         }
427       else
428         gcry_mpi_set_ui (a, data[idx].value);
429
430       err = gcry_mpi_scan (&b, GCRYMPI_FMT_HEX, data[idx].a.hex, 0, &buflen);
431       if (err)
432         fail ("error scanning value %d from %s: %s\n",
433               data[idx].value, "HEX", gpg_strerror (err));
434       else
435         {
436           if (gcry_mpi_cmp (a, b))
437             {
438               fail ("error scanning value %d from %s: %s\n",
439                     data[idx].value, "HEX", "wrong result");
440               showmpi ("expected:", a);
441               showmpi ("     got:", b);
442             }
443           gcry_mpi_release (b);
444         }
445
446       err = gcry_mpi_scan (&b, GCRYMPI_FMT_STD,
447                            data[idx].a.std, data[idx].a.stdlen, &buflen);
448       if (err)
449         fail ("error scanning value %d as %s: %s\n",
450               data[idx].value, "STD", gpg_strerror (err));
451       else
452         {
453           if (gcry_mpi_cmp (a, b) || data[idx].a.stdlen != buflen)
454             {
455               fail ("error scanning value %d from %s: %s (%u)\n",
456                     data[idx].value, "STD", "wrong result", buflen);
457               showmpi ("expected:", a);
458               showmpi ("     got:", b);
459             }
460           gcry_mpi_release (b);
461         }
462
463       err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, bufaddr, &buflen, a);
464       if (err)
465         fail ("error printing value %d as %s: %s\n",
466               data[idx].value, "SSH", gpg_strerror (err));
467       else
468         {
469           if (buflen != data[idx].a.sshlen
470               || memcmp (buf, data[idx].a.ssh, data[idx].a.sshlen))
471             {
472               fail ("error printing value %d as %s: %s\n",
473                     data[idx].value, "SSH", "wrong result");
474               showhex ("expected:", data[idx].a.ssh, data[idx].a.sshlen);
475               showhex ("     got:", buf, buflen);
476             }
477           gcry_free (buf);
478         }
479
480       err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufaddr, &buflen, a);
481       if (err)
482         fail ("error printing value %d as %s: %s\n",
483               data[idx].value, "USG", gpg_strerror (err));
484       else
485         {
486           if (buflen != data[idx].a.usglen
487               || memcmp (buf, data[idx].a.usg, data[idx].a.usglen))
488             {
489               fail ("error printing value %d as %s: %s\n",
490                     data[idx].value, "USG", "wrong result");
491               showhex ("expected:", data[idx].a.usg, data[idx].a.usglen);
492               showhex ("     got:", buf, buflen);
493             }
494           gcry_free (buf);
495         }
496     }
497
498   gcry_mpi_release (a);
499 }
500
501
502 int
503 main (int argc, char **argv)
504 {
505   if (argc > 1 && !strcmp (argv[1], "--verbose"))
506     verbose = 1;
507   else if (argc > 1 && !strcmp (argv[1], "--debug"))
508     verbose = debug = 1;
509
510   if (!gcry_check_version (GCRYPT_VERSION))
511     die ("version mismatch\n");
512
513   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
514   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
515   if (debug)
516     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
517   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
518
519   negative_zero ();
520   check_formats ();
521
522   show ("All tests completed. Errors: %d\n", error_count);
523   return error_count ? 1 : 0;
524 }