See ChangeLog: Fri Dec 31 14:06:56 CET 1999 Werner Koch
[gnupg.git] / mpi / mpiutil.c
1 /* mpiutil.ac  -  Utility functions for MPI
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * 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.h"
29 #include "mpi-internal.h"
30 #include "memory.h"
31
32 /****************
33  * Note:  It was a bad idea to use the number of limbs to allocate
34  *        because on a alpha the limbs are large but we normally need
35  *        integers of n bits - So we should chnage this to bits (or bytes).
36  *
37  *        But mpi_alloc is used in a lot of places :-)
38  */
39 MPI
40 mpi_alloc( unsigned nlimbs )
41 {
42     MPI a;
43
44     if( DBG_MEMORY )
45         log_debug("mpi_alloc(%u)\n", nlimbs*BITS_PER_MPI_LIMB );
46     a = g10_xmalloc( sizeof *a );
47     a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 0 ) : NULL;
48     a->alloced = nlimbs;
49     a->nlimbs = 0;
50     a->sign = 0;
51     a->flags = 0;
52     return a;
53 }
54
55 void
56 mpi_m_check( MPI a )
57 {
58     g10_check_heap(a);
59     g10_check_heap(a->d);
60 }
61
62 MPI
63 mpi_alloc_secure( unsigned nlimbs )
64 {
65     MPI a;
66
67     if( DBG_MEMORY )
68         log_debug("mpi_alloc_secure(%u)\n", nlimbs*BITS_PER_MPI_LIMB );
69     a = g10_xmalloc( sizeof *a );
70     a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 1 ) : NULL;
71     a->alloced = nlimbs;
72     a->flags = 1;
73     a->nlimbs = 0;
74     a->sign = 0;
75     return a;
76 }
77
78
79
80 mpi_ptr_t
81 mpi_alloc_limb_space( unsigned nlimbs, int secure )
82 {
83     size_t len = nlimbs * sizeof(mpi_limb_t);
84     mpi_ptr_t p;
85
86     if( DBG_MEMORY )
87         log_debug("mpi_alloc_limb_space(%u)\n", (unsigned)len*8 );
88
89     p = secure? g10_xmalloc_secure( len ) : g10_xmalloc( len );
90
91     return p;
92 }
93
94 void
95 mpi_free_limb_space( mpi_ptr_t a )
96 {
97     if( !a )
98         return;
99     if( DBG_MEMORY )
100         log_debug("mpi_free_limb_space\n" );
101
102     g10_free(a);
103 }
104
105
106 void
107 mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs )
108 {
109     mpi_free_limb_space(a->d);
110     a->d = ap;
111     a->alloced = nlimbs;
112 }
113
114
115
116 /****************
117  * Resize the array of A to NLIMBS. the additional space is cleared
118  * (set to 0) [done by g10_realloc()]
119  */
120 void
121 mpi_resize( MPI a, unsigned nlimbs )
122 {
123     if( nlimbs <= a->alloced )
124         return; /* no need to do it */
125     /* Note: a->secure is not used - instead the realloc functions
126      * take care of it. Maybe we should drop a->secure completely
127      * and rely on a mpi_is_secure function, which would be
128      * a wrapper around g10_is_secure
129      */
130     if( a->d )
131         a->d = g10_xrealloc(a->d, nlimbs * sizeof(mpi_limb_t) );
132     else  /* FIXME: It may not be allocted in secure memory */
133         a->d = g10_xcalloc( nlimbs , sizeof(mpi_limb_t) );
134     a->alloced = nlimbs;
135 }
136
137 void
138 mpi_clear( MPI a )
139 {
140     a->nlimbs = 0;
141     a->flags = 0;
142 }
143
144
145 void
146 mpi_free( MPI a )
147 {
148     if( !a )
149         return;
150     if( DBG_MEMORY )
151         log_debug("mpi_free\n" );
152     if( a->flags & 4 )
153         g10_free( a->d );
154     else {
155         mpi_free_limb_space(a->d);
156     }
157     if( a->flags & ~7 )
158         log_bug("invalid flag value in mpi\n");
159     g10_free(a);
160 }
161
162 static void
163 mpi_set_secure( MPI a )
164 {
165     mpi_ptr_t ap, bp;
166
167     if( (a->flags & 1) )
168         return;
169     a->flags |= 1;
170     ap = a->d;
171     if( !a->nlimbs ) {
172         assert(!ap);
173         return;
174     }
175     bp = mpi_alloc_limb_space( a->nlimbs, 1 );
176     MPN_COPY( bp, ap, a->nlimbs );
177     a->d = bp;
178     mpi_free_limb_space(ap);
179 }
180
181
182 MPI
183 gcry_mpi_set_opaque( MPI a, void *p, unsigned int nbits )
184 {
185     if( !a ) {
186         a = mpi_alloc(0);
187     }
188
189     if( a->flags & 4 )
190         g10_free( a->d );
191     else {
192         mpi_free_limb_space(a->d);
193     }
194
195     a->d = p;
196     a->alloced = 0;
197     a->nlimbs = 0;
198     a->sign  = nbits;
199     a->flags = 4;
200     return a;
201 }
202
203
204 void *
205 gcry_mpi_get_opaque( MPI a, unsigned int *nbits )
206 {
207     if( !(a->flags & 4) )
208         log_bug("mpi_get_opaque on normal mpi\n");
209     if( nbits )
210         *nbits = a->sign;
211     return a->d;
212 }
213
214
215 /****************
216  * Note: This copy function should not interpret the MPI
217  *       but copy it transparently.
218  */
219 MPI
220 mpi_copy( MPI a )
221 {
222     int i;
223     MPI b;
224
225     if( a && (a->flags & 4) ) {
226         void *p = g10_is_secure(a->d)? g10_xmalloc_secure( (a->sign+7)/8 )
227                                      : g10_xmalloc( (a->sign+7)/8 );
228         memcpy( p, a->d, (a->sign+7)/8 );
229         b = gcry_mpi_set_opaque( NULL, p, a->sign );
230     }
231     else if( a ) {
232         b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs )
233                             : mpi_alloc( a->nlimbs );
234         b->nlimbs = a->nlimbs;
235         b->sign = a->sign;
236         b->flags  = a->flags;
237         for(i=0; i < b->nlimbs; i++ )
238             b->d[i] = a->d[i];
239     }
240     else
241         b = NULL;
242     return b;
243 }
244
245
246 /****************
247  * This function allocates an MPI which is optimized to hold
248  * a value as large as the one given in the arhgument and allocates it
249  * with the same flags as A.
250  */
251 MPI
252 mpi_alloc_like( MPI a )
253 {
254     MPI b;
255
256     if( a && (a->flags & 4) ) {
257         int n = (a->sign+7)/8;
258         void *p = g10_is_secure(a->d)? g10_malloc_secure( n )
259                                      : g10_malloc( n );
260         memcpy( p, a->d, n );
261         b = gcry_mpi_set_opaque( NULL, p, a->sign );
262     }
263     else if( a ) {
264         b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs )
265                             : mpi_alloc( a->nlimbs );
266         b->nlimbs = 0;
267         b->sign = 0;
268         b->flags = a->flags;
269     }
270     else
271         b = NULL;
272     return b;
273 }
274
275
276 void
277 mpi_set( MPI w, MPI u)
278 {
279     mpi_ptr_t wp, up;
280     mpi_size_t usize = u->nlimbs;
281     int usign = u->sign;
282
283     RESIZE_IF_NEEDED(w, usize);
284     wp = w->d;
285     up = u->d;
286     MPN_COPY( wp, up, usize );
287     w->nlimbs = usize;
288     w->flags = u->flags;
289     w->sign = usign;
290 }
291
292
293 void
294 mpi_set_ui( MPI w, unsigned long u)
295 {
296     RESIZE_IF_NEEDED(w, 1);
297     w->d[0] = u;
298     w->nlimbs = u? 1:0;
299     w->sign = 0;
300     w->flags = 0;
301 }
302
303
304 MPI
305 mpi_alloc_set_ui( unsigned long u)
306 {
307     MPI w = mpi_alloc(1);
308     w->d[0] = u;
309     w->nlimbs = u? 1:0;
310     w->sign = 0;
311     return w;
312 }
313
314
315 void
316 mpi_swap( MPI a, MPI b)
317 {
318     struct gcry_mpi tmp;
319
320     tmp = *a; *a = *b; *b = tmp;
321 }
322
323
324 GCRY_MPI
325 gcry_mpi_new( unsigned int nbits )
326 {
327     return mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
328 }
329
330
331 GCRY_MPI
332 gcry_mpi_snew( unsigned int nbits )
333 {
334     return mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB );
335 }
336
337 void
338 gcry_mpi_release( GCRY_MPI a )
339 {
340     mpi_free( a );
341 }
342
343 GCRY_MPI
344 gcry_mpi_copy( const GCRY_MPI a )
345 {
346     return mpi_copy( (GCRY_MPI)a );
347 }
348
349 GCRY_MPI
350 gcry_mpi_set( GCRY_MPI w, const GCRY_MPI u )
351 {
352     if( !w )
353         w = mpi_alloc( mpi_get_nlimbs(u) );
354     mpi_set( w, (GCRY_MPI)u );
355     return w;
356 }
357
358 GCRY_MPI
359 gcry_mpi_set_ui( GCRY_MPI w, unsigned long u )
360 {
361     if( !w )
362         w = mpi_alloc(1);
363     mpi_set_ui( w, u );
364     return w;
365 }
366
367
368 int
369 gcry_mpi_cmp( const GCRY_MPI u, const GCRY_MPI v )
370 {
371     return mpi_cmp( (GCRY_MPI)u, (GCRY_MPI)v );
372 }
373
374 int
375 gcry_mpi_cmp_ui( const GCRY_MPI u, unsigned long v )
376 {
377     return mpi_cmp_ui( (GCRY_MPI)u, v );
378 }
379
380
381 void
382 gcry_mpi_randomize( GCRY_MPI w,
383                     unsigned int nbits, enum gcry_random_level level )
384 {
385     char *p = mpi_is_secure(w) ? gcry_random_bytes( (nbits+7)/8, level )
386                                : gcry_random_bytes_secure( (nbits+7)/8, level );
387     mpi_set_buffer( w, p, (nbits+7)/8, 0 );
388     m_free(p);
389 }
390
391
392 void
393 gcry_mpi_set_flag( GCRY_MPI a, enum gcry_mpi_flag flag )
394 {
395     switch( flag ) {
396       case GCRYMPI_FLAG_SECURE:  mpi_set_secure(a); break;
397       case GCRYMPI_FLAG_OPAQUE:
398       default: log_bug("invalid flag value\n");
399     }
400 }
401
402 void
403 gcry_mpi_clear_flag( GCRY_MPI a, enum gcry_mpi_flag flag )
404 {
405     switch( flag ) {
406       case GCRYMPI_FLAG_SECURE:
407       case GCRYMPI_FLAG_OPAQUE:
408       default: log_bug("invalid flag value\n");
409     }
410 }
411
412 int
413 gcry_mpi_get_flag( GCRY_MPI a, enum gcry_mpi_flag flag )
414 {
415     switch( flag ) {
416       case GCRYMPI_FLAG_SECURE: return (a->flags & 1);
417       case GCRYMPI_FLAG_OPAQUE: return (a->flags & 4);
418       default: log_bug("invalid flag value\n");
419     }
420 }
421
422