initially checkin
[gnupg.git] / mpi / mpiutil.c
1 /* mpiutil.c  -  Utility functions for MPI
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 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  * G10 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 <assert.h>
25
26 #include "mpi.h"
27 #include "mpi-internal.h"
28 #include "memory.h"
29 #include "util.h"
30
31
32 #ifdef M_DEBUG
33   #undef mpi_alloc
34   #undef mpi_alloc_secure
35   #undef mpi_free
36 #endif
37
38 typedef struct unused_obj {
39     struct unused_obj *next;
40     unsigned length;
41     union {
42         MPI mpi;
43         mpi_limb_t *limb;
44     } u;
45 } *unused_obj_t;
46
47 static unused_obj_t unused_objs;
48 static unused_obj_t unused_mpis;
49 static unused_obj_t unused_limbs;
50
51
52 MPI
53 #ifdef M_DEBUG
54 mpi_debug_alloc( unsigned nlimbs, const char *info )
55 #else
56 mpi_alloc( unsigned nlimbs )
57 #endif
58 {
59     MPI a;
60
61     if( unused_mpis ) {
62         unused_obj_t u;
63
64         if( DBG_MEMORY )
65             log_debug("mpi_alloc(%lu) reusing\n", nlimbs*BITS_PER_MPI_LIMB );
66         a = unused_mpis->u.mpi;
67         u = unused_mpis;
68         unused_mpis = unused_mpis->next;
69         u->next = unused_objs;
70         unused_objs = u;
71     }
72     else {
73         if( DBG_MEMORY )
74             log_debug("mpi_alloc(%lu) new\n", nlimbs*BITS_PER_MPI_LIMB );
75       #ifdef M_DEBUG
76         a = m_debug_alloc( sizeof *a, info );
77       #else
78         a = m_alloc( sizeof *a );
79       #endif
80     }
81   #ifdef M_DEBUG
82     a->d = mpi_debug_alloc_limb_space( nlimbs, info );
83   #else
84     a->d = mpi_alloc_limb_space( nlimbs );
85   #endif
86     a->alloced = nlimbs;
87     a->nlimbs = 0;
88     a->sign = 0;
89     return a;
90 }
91
92 void
93 mpi_m_check( MPI a )
94 {
95     m_check(a);
96     m_check(a->d);
97 }
98
99 MPI
100 #ifdef M_DEBUG
101 mpi_debug_alloc_secure( unsigned nlimbs, const char *info )
102 #else
103 mpi_alloc_secure( unsigned nlimbs )
104 #endif
105 {
106     MPI a;
107
108     a = m_alloc( sizeof *a );
109   #ifdef M_DEBUG
110     a->d = m_debug_alloc_secure( nlimbs * sizeof(mpi_limb_t), info );
111   #else
112     a->d = m_alloc_secure( nlimbs * sizeof(mpi_limb_t) );
113   #endif
114     a->alloced = nlimbs;
115     a->nlimbs = 0;
116     a->sign = 0;
117     return a;
118 }
119
120
121 mpi_ptr_t
122 #ifdef M_DEBUG
123 mpi_debug_alloc_limb_space( unsigned nlimbs, const char *info )
124 #else
125 mpi_alloc_limb_space( unsigned nlimbs )
126 #endif
127 {
128     unused_obj_t u;
129     size_t len = nlimbs * sizeof(mpi_limb_t);
130
131     for(u=unused_limbs; u; u = u->next )
132         if( u->length >= len ) {
133             u->length = 0;
134             if( DBG_MEMORY )
135                 log_debug("mpi_alloc_limb_space(%lu) reusing\n", len*8 );
136             return u->u.limb;
137         }
138     if( DBG_MEMORY )
139         log_debug("mpi_alloc_limb_space(%u) new\n", len*8 );
140   #ifdef M_DEBUG
141     return m_debug_alloc( len, info );
142   #else
143     return m_alloc( len );
144   #endif
145 }
146
147 void
148 #ifdef M_DEBUG
149 mpi_debug_free_limb_space( mpi_ptr_t a, const char *info )
150 #else
151 mpi_free_limb_space( mpi_ptr_t a )
152 #endif
153 {
154     unused_obj_t u;
155
156     if( !a )
157         return;
158     if( DBG_MEMORY )
159         log_debug("mpi_free_limb_space of size %lu\n", (ulong)m_size(a)*8 );
160     for(u=unused_limbs; u; u = u->next )
161         if( !u->length ) {
162             u->length = m_size(a);
163             u->u.limb = a;
164             return;
165         }
166
167     if( (u=unused_objs) )
168         unused_objs = unused_objs->next;
169     else
170         u = m_alloc( sizeof *u );
171     u->length = m_size(a);
172     u->u.limb = a;
173     u->next = unused_limbs;
174     unused_limbs = u;
175 }
176
177
178 void
179 mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs )
180 {
181     mpi_free_limb_space(a->d);
182     a->d = ap;
183     a->alloced = nlimbs;
184 }
185
186
187
188 /****************
189  * Resize the array of A to NLIMBS. the additional space is cleared
190  * (set to 0) [done by m_realloc()]
191  */
192 void
193 #ifdef M_DEBUG
194 mpi_debug_resize( MPI a, unsigned nlimbs, const char *info )
195 #else
196 mpi_resize( MPI a, unsigned nlimbs )
197 #endif
198 {
199     if( nlimbs <= a->alloced )
200         return; /* no need to do it */
201   #ifdef M_DEBUG
202     if( a->d )
203         a->d = m_debug_realloc(a->d, nlimbs * sizeof(mpi_limb_t), info );
204     else
205         a->d = m_debug_alloc_clear( nlimbs * sizeof(mpi_limb_t), info );
206   #else
207     if( a->d )
208         a->d = m_realloc(a->d, nlimbs * sizeof(mpi_limb_t) );
209     else
210         a->d = m_alloc_clear( nlimbs * sizeof(mpi_limb_t) );
211   #endif
212     a->alloced = nlimbs;
213 }
214
215 void
216 mpi_clear( MPI a )
217 {
218     a->nlimbs = 0;
219 }
220
221
222 void
223 #ifdef M_DEBUG
224 mpi_debug_free( MPI a, const char *info )
225 #else
226 mpi_free( MPI a )
227 #endif
228 {
229     unused_obj_t u;
230
231     if( !a )
232         return;
233     if( DBG_MEMORY )
234         log_debug("mpi_free\n" );
235   #ifdef M_DEBUG
236     mpi_debug_free_limb_space(a->d, info);
237   #else
238     mpi_free_limb_space(a->d);
239   #endif
240
241     if( (u=unused_objs) )
242         unused_objs = unused_objs->next;
243     else
244         u = m_alloc( sizeof *u );
245     u->u.mpi = a;
246     u->next = unused_mpis;
247     unused_mpis = u;
248 }
249
250
251 MPI
252 #ifdef M_DEBUG
253 mpi_debug_copy( MPI a, const char *info )
254 #else
255 mpi_copy( MPI a )
256 #endif
257 {
258     int i;
259     MPI b;
260
261     if( a ) {
262       #ifdef M_DEBUG
263         b = mpi_debug_alloc( a->nlimbs, info );
264       #else
265         b = mpi_alloc( a->nlimbs );
266       #endif
267         b->nlimbs = a->nlimbs;
268         for(i=0; i < b->nlimbs; i++ )
269             b->d[i] = a->d[i];
270     }
271     else
272         b = NULL;
273     return b;
274 }
275
276
277 void
278 mpi_set( MPI w, MPI u)
279 {
280     mpi_ptr_t wp, up;
281     mpi_size_t usize = u->nlimbs;
282     int usign = u->sign;
283
284     RESIZE_IF_NEEDED(w, usize);
285     wp = w->d;
286     up = u->d;
287     MPN_COPY( wp, up, usize );
288     w->nlimbs = usize;
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 }
301
302
303 MPI
304 mpi_alloc_set_ui( unsigned long u)
305 {
306   #ifdef M_DEBUG
307     MPI w = mpi_debug_alloc(1,"alloc_set_ui");
308   #else
309     MPI w = mpi_alloc(1);
310   #endif
311     w->d[0] = u;
312     w->nlimbs = u? 1:0;
313     w->sign = 0;
314     return w;
315 }
316
317
318 void
319 mpi_swap( MPI a, MPI b)
320 {
321     MPI x;
322
323     x = a; a = b; b = x;
324 }
325
326