tests: Use common code for all tests.
[libgcrypt.git] / tests / t-mpi-bit.c
1 /* t-mpi-bit.c  - Tests for bit level functions
2  * Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <stdarg.h>
30
31 #define PGM "t-mpi-bit"
32 #include "t-common.h"
33
34
35 /* Allocate a bit string consisting of '0' and '1' from the MPI
36    A. Return the LENGTH least significant bits. Caller needs to xfree
37    the result. */
38 static char *
39 mpi2bitstr (gcry_mpi_t a, size_t length)
40 {
41   char *p, *buf;
42
43   buf = p = xmalloc (length+1);
44   while (length--)
45     *p++ = gcry_mpi_test_bit (a, length) ? '1':'0';
46   *p = 0;
47
48   return buf;
49 }
50
51 /* Allocate a bit string consisting of '0' and '1' from the MPI A.  Do
52    not return any leading zero bits. Caller needs to xfree the
53    result. */
54 static char *
55 mpi2bitstr_nlz (gcry_mpi_t a)
56 {
57   char *p, *buf;
58   size_t length = gcry_mpi_get_nbits (a);
59
60   if (!length)
61     {
62       buf = p = xmalloc (2);
63       *p++ = '0';
64     }
65   else
66     {
67       buf = p = xmalloc (length + 1);
68       while (length-- > 1)
69         *p++ = gcry_mpi_test_bit (a, length) ? '1':'0';
70       *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0';
71     }
72   *p = 0;
73   return buf;
74 }
75
76 /* Shift a bit string to the right. */
77 static void
78 rshiftbitstring (char *string, size_t n)
79 {
80   size_t len = strlen (string);
81
82   if (n > len)
83     n = len;
84
85   memmove (string+n, string, len-n);
86   memset (string, '0', n);
87 }
88
89 /* Shift a bit string to the left. Caller needs to free the result. */
90 static char *
91 lshiftbitstring (const char *string, size_t n)
92 {
93   size_t len = strlen (string);
94   char *result;
95
96   if (len+n+1 < len)
97     die ("internal overflow\n");
98   /* Allocate enough space. */
99   result = xmalloc (len+n+1);
100   for (; *string == '0' && string[1]; string++, len--)
101     ;
102   memcpy (result, string, len);
103   if (*string == '0' && !string[1])
104     n = 0; /* Avoid extra nulls for an only 0 string.  */
105   else
106     memset (result+len, '0', n);
107   result[len+n] = 0;
108   return result;
109 }
110
111
112 /* This is to check a bug reported by bpgcrypt at itaparica.org on
113    2006-07-31 against libgcrypt 1.2.2.  */
114 static void
115 one_bit_only (int highbit)
116 {
117   gcry_mpi_t a;
118   char *result;
119   int i;
120
121   wherestr = "one_bit_only";
122   info ("checking that set_%sbit does only set one bit\n", highbit?"high":"");
123
124   a = gcry_mpi_new (0);
125   gcry_mpi_randomize (a, 70, GCRY_WEAK_RANDOM);
126   gcry_mpi_set_ui (a, 0);
127
128   if (highbit)
129     gcry_mpi_set_highbit (a, 42);
130   else
131     gcry_mpi_set_bit (a, 42);
132   if (!gcry_mpi_test_bit (a, 42))
133     fail ("failed to set a bit\n");
134   gcry_mpi_clear_bit (a, 42);
135   if (gcry_mpi_test_bit (a, 42))
136     fail ("failed to clear a bit\n");
137   result = mpi2bitstr (a, 70);
138   assert (strlen (result) == 70);
139   for (i=0; result[i]; i++)
140     if ( result[i] != '0' )
141       break;
142   if (result[i])
143     fail ("spurious bits detected\n");
144   xfree (result);
145   gcry_mpi_release (a);
146 }
147
148 /* Check that right shifting actually works for an amount larger than
149    the number of bits per limb. */
150 static void
151 test_rshift (int pass)
152 {
153   gcry_mpi_t a, b;
154   char *result, *result2;
155   int i;
156
157   wherestr = "test_rshift";
158   info ("checking that rshift works as expected (pass %d)\n", pass);
159
160   a = gcry_mpi_new (0);
161   b = gcry_mpi_new (0);
162   gcry_mpi_randomize (a, 70, GCRY_WEAK_RANDOM);
163
164   for (i=0; i < 75; i++)
165     {
166       gcry_mpi_rshift (b, a, i);
167
168       result = mpi2bitstr (b, 72);
169       result2 = mpi2bitstr (a, 72);
170       rshiftbitstring (result2, i);
171       if (strcmp (result, result2))
172         {
173           info ("got =%s\n", result);
174           info ("want=%s\n", result2);
175           fail ("rshift by %d failed\n", i);
176         }
177       xfree (result);
178       xfree (result2);
179     }
180
181   /* Again. This time using in-place operation. */
182   gcry_mpi_randomize (a, 70, GCRY_WEAK_RANDOM);
183
184   for (i=0; i < 75; i++)
185     {
186       gcry_mpi_release (b);
187       b = gcry_mpi_copy (a);
188       gcry_mpi_rshift (b, b, i);
189
190       result = mpi2bitstr (b, 72);
191       result2 = mpi2bitstr (a, 72);
192       rshiftbitstring (result2, i);
193       if (strcmp (result, result2))
194         {
195           info ("got =%s\n", result);
196           info ("want=%s\n", result2);
197           fail ("in-place rshift by %d failed\n", i);
198         }
199       xfree (result2);
200       xfree (result);
201     }
202
203   gcry_mpi_release (b);
204   gcry_mpi_release (a);
205 }
206
207 /* Check that left shifting works correctly.  */
208 static void
209 test_lshift (int pass)
210 {
211   static int size_list[] = {1, 31, 32, 63, 64, 65, 70, 0};
212   int size_idx;
213   gcry_mpi_t a, b;
214   char *tmpstr, *result, *result2;
215   int i;
216
217   wherestr = "test_lshift";
218   info ("checking that lshift works as expected (pass %d)\n", pass);
219
220   for (size_idx=0; size_list[size_idx]; size_idx++)
221     {
222       a = gcry_mpi_new (0);
223       b = gcry_mpi_new (0);
224
225       /* gcry_mpi_randomize rounds up to full bytes, thus we need to
226          use gcry_mpi_clear_highbit to fix that.  */
227       gcry_mpi_randomize (a, size_list[size_idx], GCRY_WEAK_RANDOM);
228       gcry_mpi_clear_highbit (a, size_list[size_idx]);
229
230       for (i=0; i < 75; i++)
231         {
232           gcry_mpi_lshift (b, a, i);
233
234           result = mpi2bitstr_nlz (b);
235           tmpstr = mpi2bitstr_nlz (a);
236           result2 = lshiftbitstring (tmpstr, i);
237           xfree (tmpstr);
238           if (strcmp (result, result2))
239             {
240               info ("got =%s\n", result);
241               info ("want=%s\n", result2);
242               fail ("lshift by %d failed\n", i);
243             }
244           xfree (result);
245           xfree (result2);
246         }
247
248       /* Again. This time using in-place operation. */
249       gcry_mpi_randomize (a, size_list[size_idx], GCRY_WEAK_RANDOM);
250       gcry_mpi_clear_highbit (a, size_list[size_idx]);
251
252       for (i=0; i < 75; i++)
253         {
254           gcry_mpi_release (b);
255           b = gcry_mpi_copy (a);
256           gcry_mpi_lshift (b, b, i);
257
258           result = mpi2bitstr_nlz (b);
259           tmpstr = mpi2bitstr_nlz (a);
260           result2 = lshiftbitstring (tmpstr, i);
261           xfree (tmpstr);
262           if (strcmp (result, result2))
263             {
264               info ("got =%s\n", result);
265               info ("want=%s\n", result2);
266               fail ("in-place lshift by %d failed\n", i);
267             }
268           xfree (result2);
269           xfree (result);
270         }
271
272       gcry_mpi_release (b);
273       gcry_mpi_release (a);
274     }
275 }
276
277
278 /* Bug fixed on 2014-05-09:
279       a = gcry_mpi_new (1523);
280       gcry_mpi_set_bit (a, 1536);
281       didn't initialized all limbs in A.  */
282 static void
283 set_bit_with_resize (void)
284 {
285   gcry_mpi_t a;
286   int i;
287
288   wherestr = "set_bit_with_resize";
289   info ("checking that set_bit initializes all limbs\n");
290
291   a = gcry_mpi_new (1536);
292   gcry_mpi_set_bit (a, 1536);
293
294   if (!gcry_mpi_test_bit (a, 1536))
295     fail ("failed to set a bit\n");
296   for (i=0; i < 1536; i++)
297     {
298       if (gcry_mpi_test_bit (a, i))
299         {
300           fail ("spurious bit detected\n");
301           break;
302         }
303     }
304   if (gcry_mpi_test_bit (a, 1537))
305     fail ("more bits set than expected\n");
306   gcry_mpi_release (a);
307
308   wherestr = "set_highbit_with_resize";
309   info ("checking that set_highbit initializes all limbs\n");
310
311   a = gcry_mpi_new (1536);
312   gcry_mpi_set_highbit (a, 1536);
313
314   if (!gcry_mpi_test_bit (a, 1536))
315     fail ("failed to set a bit\n");
316   for (i=0; i < 1536; i++)
317     {
318       if (gcry_mpi_test_bit (a, i))
319         {
320           fail ("spurious bit detected\n");
321           break;
322         }
323     }
324   if (gcry_mpi_test_bit (a, 1537))
325     fail ("more bits set than expected\n");
326   gcry_mpi_release (a);
327 }
328
329
330 int
331 main (int argc, char **argv)
332 {
333   int i;
334
335   if (argc > 1 && !strcmp (argv[1], "--verbose"))
336     verbose = 1;
337   else if (argc > 1 && !strcmp (argv[1], "--debug"))
338     verbose = debug = 1;
339
340   if (!gcry_check_version (GCRYPT_VERSION))
341     die ("version mismatch\n");
342
343   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
344   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
345   if (debug)
346     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
347
348   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
349
350   one_bit_only (0);
351   one_bit_only (1);
352   for (i=0; i < 5; i++)
353     test_rshift (i); /* Run several times due to random initializations. */
354
355   for (i=0; i < 5; i++)
356     test_lshift (i); /* Run several times due to random initializations. */
357
358   set_bit_with_resize ();
359
360   info ("All tests completed. Errors: %d\n", error_count);
361   return error_count ? 1 : 0;
362 }