2003-06-16 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / mpi / mpiutil.c
1 /* mpiutil.ac  -  Utility functions for MPI
2  * Copyright (C) 1998, 2000, 2001, 2002, 2003 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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "g10lib.h"
28 #include "mpi-internal.h"
29 #include "memory.h"
30
31 /****************
32  * Note:  It was a bad idea to use the number of limbs to allocate
33  *        because on a alpha the limbs are large but we normally need
34  *        integers of n bits - So we should chnage this to bits (or bytes).
35  *
36  *        But mpi_alloc is used in a lot of places :-)
37  */
38 gcry_mpi_t
39 _gcry_mpi_alloc( unsigned nlimbs )
40 {
41     gcry_mpi_t a;
42
43     a = gcry_xmalloc( sizeof *a );
44     a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 0 ) : NULL;
45     a->alloced = nlimbs;
46     a->nlimbs = 0;
47     a->sign = 0;
48     a->flags = 0;
49     return a;
50 }
51
52 void
53 _gcry_mpi_m_check( gcry_mpi_t a )
54 {
55     _gcry_check_heap(a);
56     _gcry_check_heap(a->d);
57 }
58
59 gcry_mpi_t
60 _gcry_mpi_alloc_secure( unsigned nlimbs )
61 {
62     gcry_mpi_t a;
63
64     a = gcry_xmalloc( sizeof *a );
65     a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 1 ) : NULL;
66     a->alloced = nlimbs;
67     a->flags = 1;
68     a->nlimbs = 0;
69     a->sign = 0;
70     return a;
71 }
72
73
74
75 mpi_ptr_t
76 _gcry_mpi_alloc_limb_space( unsigned nlimbs, int secure )
77 {
78     size_t len = nlimbs * sizeof(mpi_limb_t);
79     mpi_ptr_t p = NULL;
80
81     if (nlimbs)
82       p = secure? gcry_xmalloc_secure( len ) : gcry_xmalloc( len );
83
84     return p;
85 }
86
87 void
88 _gcry_mpi_free_limb_space( mpi_ptr_t a )
89 {
90     if( !a )
91         return;
92     gcry_free(a);
93 }
94
95
96 void
97 _gcry_mpi_assign_limb_space( gcry_mpi_t a, mpi_ptr_t ap, unsigned nlimbs )
98 {
99     mpi_free_limb_space(a->d);
100     a->d = ap;
101     a->alloced = nlimbs;
102 }
103
104
105
106 /****************
107  * Resize the array of A to NLIMBS. the additional space is cleared
108  * (set to 0) [done by gcry_realloc()]
109  */
110 void
111 _gcry_mpi_resize (gcry_mpi_t a, unsigned nlimbs)
112 {
113   if (nlimbs <= a->alloced)
114     return; /* no need to do it */
115
116   if (a->d)
117     a->d = gcry_xrealloc (a->d, nlimbs * sizeof (mpi_limb_t));
118   else
119     {
120       if (a->flags & 1)
121         /* Secure memory is wanted.  */
122         a->d = gcry_xcalloc_secure (nlimbs , sizeof (mpi_limb_t));
123       else
124         /* Standard memory.  */
125         a->d = gcry_xcalloc (nlimbs , sizeof (mpi_limb_t));
126     }
127   a->alloced = nlimbs;
128 }
129
130 void
131 _gcry_mpi_clear( gcry_mpi_t a )
132 {
133     a->nlimbs = 0;
134     a->flags = 0;
135 }
136
137
138 void
139 _gcry_mpi_free( gcry_mpi_t a )
140 {
141     if( !a )
142         return;
143     if( a->flags & 4 )
144         gcry_free( a->d );
145     else {
146         mpi_free_limb_space(a->d);
147     }
148     if( a->flags & ~7 )
149         log_bug("invalid flag value in mpi\n");
150     gcry_free(a);
151 }
152
153 static void
154 mpi_set_secure( gcry_mpi_t a )
155 {
156     mpi_ptr_t ap, bp;
157
158     if( (a->flags & 1) )
159         return;
160     a->flags |= 1;
161     ap = a->d;
162     if( !a->nlimbs ) {
163         assert(!ap);
164         return;
165     }
166     bp = mpi_alloc_limb_space( a->nlimbs, 1 );
167     MPN_COPY( bp, ap, a->nlimbs );
168     a->d = bp;
169     mpi_free_limb_space(ap);
170 }
171
172
173 gcry_mpi_t
174 gcry_mpi_set_opaque( gcry_mpi_t a, void *p, unsigned int nbits )
175 {
176     if( !a ) {
177         a = mpi_alloc(0);
178     }
179
180     if( a->flags & 4 )
181         gcry_free( a->d );
182     else {
183         mpi_free_limb_space(a->d);
184     }
185
186     a->d = p;
187     a->alloced = 0;
188     a->nlimbs = 0;
189     a->sign  = nbits;
190     a->flags = 4;
191     return a;
192 }
193
194
195 void *
196 gcry_mpi_get_opaque( gcry_mpi_t a, unsigned int *nbits )
197 {
198     if( !(a->flags & 4) )
199         log_bug("mpi_get_opaque on normal mpi\n");
200     if( nbits )
201         *nbits = a->sign;
202     return a->d;
203 }
204
205
206 /****************
207  * Note: This copy function should not interpret the MPI
208  *       but copy it transparently.
209  */
210 gcry_mpi_t
211 _gcry_mpi_copy( gcry_mpi_t a )
212 {
213     int i;
214     gcry_mpi_t b;
215
216     if( a && (a->flags & 4) ) {
217         void *p = gcry_is_secure(a->d)? gcry_xmalloc_secure( (a->sign+7)/8 )
218                                      : gcry_xmalloc( (a->sign+7)/8 );
219         memcpy( p, a->d, (a->sign+7)/8 );
220         b = gcry_mpi_set_opaque( NULL, p, a->sign );
221     }
222     else if( a ) {
223         b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs )
224                             : mpi_alloc( a->nlimbs );
225         b->nlimbs = a->nlimbs;
226         b->sign = a->sign;
227         b->flags  = a->flags;
228         for(i=0; i < b->nlimbs; i++ )
229             b->d[i] = a->d[i];
230     }
231     else
232         b = NULL;
233     return b;
234 }
235
236
237 /****************
238  * This function allocates an MPI which is optimized to hold
239  * a value as large as the one given in the argument and allocates it
240  * with the same flags as A.
241  */
242 gcry_mpi_t
243 _gcry_mpi_alloc_like( gcry_mpi_t a )
244 {
245     gcry_mpi_t b;
246
247     if( a && (a->flags & 4) ) {
248         int n = (a->sign+7)/8;
249         void *p = gcry_is_secure(a->d)? gcry_malloc_secure( n )
250                                      : gcry_malloc( n );
251         memcpy( p, a->d, n );
252         b = gcry_mpi_set_opaque( NULL, p, a->sign );
253     }
254     else if( a ) {
255         b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs )
256                             : mpi_alloc( a->nlimbs );
257         b->nlimbs = 0;
258         b->sign = 0;
259         b->flags = a->flags;
260     }
261     else
262         b = NULL;
263     return b;
264 }
265
266
267 void
268 _gcry_mpi_set( gcry_mpi_t w, gcry_mpi_t u)
269 {
270     mpi_ptr_t wp, up;
271     mpi_size_t usize = u->nlimbs;
272     int usign = u->sign;
273
274     RESIZE_IF_NEEDED(w, usize);
275     wp = w->d;
276     up = u->d;
277     MPN_COPY( wp, up, usize );
278     w->nlimbs = usize;
279     w->flags = u->flags;
280     w->sign = usign;
281 }
282
283
284 void
285 _gcry_mpi_set_ui( gcry_mpi_t w, unsigned long u)
286 {
287     RESIZE_IF_NEEDED(w, 1);
288     w->d[0] = u;
289     w->nlimbs = u? 1:0;
290     w->sign = 0;
291     w->flags = 0;
292 }
293
294
295 gcry_mpi_t
296 _gcry_mpi_alloc_set_ui( unsigned long u)
297 {
298     gcry_mpi_t w = mpi_alloc(1);
299     w->d[0] = u;
300     w->nlimbs = u? 1:0;
301     w->sign = 0;
302     return w;
303 }
304
305
306 void
307 _gcry_mpi_swap( gcry_mpi_t a, gcry_mpi_t b)
308 {
309     struct gcry_mpi tmp;
310
311     tmp = *a; *a = *b; *b = tmp;
312 }
313
314 void
315 gcry_mpi_swap( gcry_mpi_t a, gcry_mpi_t b)
316 {
317   _gcry_mpi_swap (a, b);
318 }
319
320
321 gcry_mpi_t
322 gcry_mpi_new( unsigned int nbits )
323 {
324     return _gcry_mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
325 }
326
327
328 gcry_mpi_t
329 gcry_mpi_snew( unsigned int nbits )
330 {
331     return _gcry_mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
332 }
333
334 void
335 gcry_mpi_release( gcry_mpi_t a )
336 {
337     _gcry_mpi_free( a );
338 }
339
340 gcry_mpi_t
341 gcry_mpi_copy( const gcry_mpi_t a )
342 {
343     return _gcry_mpi_copy( (gcry_mpi_t)a );
344 }
345
346 gcry_mpi_t
347 gcry_mpi_set( gcry_mpi_t w, const gcry_mpi_t u )
348 {
349     if( !w )
350         w = _gcry_mpi_alloc( mpi_get_nlimbs(u) );
351     _gcry_mpi_set( w, (gcry_mpi_t)u );
352     return w;
353 }
354
355 gcry_mpi_t
356 gcry_mpi_set_ui( gcry_mpi_t w, unsigned long u )
357 {
358     if( !w )
359         w = _gcry_mpi_alloc(1);
360     _gcry_mpi_set_ui( w, u );
361     return w;
362 }
363
364
365 void
366 gcry_mpi_randomize( gcry_mpi_t w,
367                     unsigned int nbits, enum gcry_random_level level )
368 {
369     char *p = mpi_is_secure(w) ? gcry_random_bytes( (nbits+7)/8, level )
370                                : gcry_random_bytes_secure( (nbits+7)/8, level );
371     _gcry_mpi_set_buffer( w, p, (nbits+7)/8, 0 );
372     gcry_free(p);
373 }
374
375
376 void
377 gcry_mpi_set_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
378 {
379     switch( flag ) {
380       case GCRYMPI_FLAG_SECURE:  mpi_set_secure(a); break;
381       case GCRYMPI_FLAG_OPAQUE:
382       default: log_bug("invalid flag value\n");
383     }
384 }
385
386 void
387 gcry_mpi_clear_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
388 {
389     switch( flag ) {
390       case GCRYMPI_FLAG_SECURE:
391       case GCRYMPI_FLAG_OPAQUE:
392       default: log_bug("invalid flag value\n");
393     }
394 }
395
396 int
397 gcry_mpi_get_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
398 {
399     switch( flag ) {
400       case GCRYMPI_FLAG_SECURE: return (a->flags & 1);
401       case GCRYMPI_FLAG_OPAQUE: return (a->flags & 4);
402       default: log_bug("invalid flag value\n");
403     }
404 }
405