Merge branch 'curve25519'
[gd/nettle] / gmp-glue.c
1 /* gmp-glue.c
2
3    Copyright (C) 2013 Niels Möller
4    Copyright (C) 2013 Red Hat
5
6    This file is part of GNU Nettle.
7
8    GNU Nettle is free software: you can redistribute it and/or
9    modify it under the terms of either:
10
11      * the GNU Lesser General Public License as published by the Free
12        Software Foundation; either version 3 of the License, or (at your
13        option) any later version.
14
15    or
16
17      * the GNU General Public License as published by the Free
18        Software Foundation; either version 2 of the License, or (at your
19        option) any later version.
20
21    or both in parallel, as here.
22
23    GNU Nettle is distributed in the hope that it will be useful,
24    but WITHOUT ANY WARRANTY; without even the implied warranty of
25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26    General Public License for more details.
27
28    You should have received copies of the GNU General Public License and
29    the GNU Lesser General Public License along with this program.  If
30    not, see http://www.gnu.org/licenses/.
31 */
32
33 #if HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <assert.h>
38 #include <stdlib.h>
39
40 #include "gmp-glue.h"
41
42 #if !GMP_HAVE_mpz_limbs_read
43
44 /* This implementation tries to make a minimal use of GMP internals.
45    We access and _mp_size and _mp_d, but not _mp_alloc. */
46
47 /* Use macros compatible with gmp-impl.h. */
48 #define ABS(x) ((x) >= 0 ? (x) : -(x))
49 #define PTR(x) ((x)->_mp_d)
50 #define SIZ(x) ((x)->_mp_size)
51 #define ABSIZ(x) ABS (SIZ (x))
52
53 #define MPN_NORMALIZE(xp, xn) do {              \
54     while ( (xn) > 0 && (xp)[xn-1] == 0)        \
55       (xn)--;                                   \
56   }  while (0)
57
58 /* NOTE: Makes an unnecessary realloc if allocation is already large
59    enough, but looking at _mp_alloc may break in future GMP
60    versions. */
61 #define MPZ_REALLOC(x, n) \
62   (ABSIZ(x) >= (n) ? PTR(x) : (_mpz_realloc ((x),(n)), PTR (x)))
63
64 #define MPZ_NEWALLOC MPZ_REALLOC
65
66 /* Read access to mpz numbers. */
67
68 /* Return limb pointer, for read-only operations. Use mpz_size to get
69    the number of limbs. */
70 const mp_limb_t *
71 mpz_limbs_read (mpz_srcptr x)
72 {
73   return PTR (x);
74 }
75
76 /* Write access to mpz numbers. */
77
78 /* Get a limb pointer for writing, previous contents may be
79    destroyed. */
80 mp_limb_t *
81 mpz_limbs_write (mpz_ptr x, mp_size_t n)
82 {
83   assert (n > 0);
84   return MPZ_NEWALLOC (x, n);
85 }
86
87 /* Get a limb pointer for writing, previous contents is intact. */
88 mp_limb_t *
89 mpz_limbs_modify (mpz_ptr x, mp_size_t n)
90 {
91   assert (n > 0);
92   return MPZ_REALLOC (x, n);
93 }
94
95 void
96 mpz_limbs_finish (mpz_ptr x, mp_size_t n)
97 {
98   assert (n >= 0);
99   MPN_NORMALIZE (PTR(x), n);
100
101   SIZ (x) = n;
102 }
103
104 /* Needs some ugly casts. */
105 mpz_srcptr
106 mpz_roinit_n (mpz_ptr x, const mp_limb_t *xp, mp_size_t xs)
107 {
108   mp_size_t xn = ABS (xs);
109   
110   MPN_NORMALIZE (xp, xn);
111
112   x->_mp_size = xs < 0 ? -xn : xn;
113   x->_mp_alloc = 0;
114   x->_mp_d = (mp_limb_t *) xp;
115   return x;
116 }
117 #endif /* !GMP_HAVE_mpz_limbs_read */
118
119 #if !GMP_HAVE_mpn_copyd
120 void
121 mpn_copyd (mp_ptr dst, mp_srcptr src, mp_size_t n)
122 {
123   mp_size_t i;
124   for (i = n - 1; i >= 0; i--)
125     dst[i] = src[i];
126 }
127
128 void
129 mpn_copyi (mp_ptr dst, mp_srcptr src, mp_size_t n)
130 {
131   mp_size_t i;
132   for (i = 0; i < n; i++)
133     dst[i] = src[i];
134 }
135
136 void
137 mpn_zero (mp_ptr ptr, mp_size_t n)
138 {
139   mp_size_t i;
140   for (i = 0; i < n; i++)
141     ptr[i] = 0;
142 }
143 #endif /* !GMP_HAVE_mpn_copyd */
144
145 /* Additional convenience functions. */
146
147 int
148 mpz_limbs_cmp (mpz_srcptr a, const mp_limb_t *bp, mp_size_t bn)
149 {
150   mp_size_t an = mpz_size (a);
151   assert (mpz_sgn (a) >= 0);
152   assert (bn >= 0);
153
154   if (an < bn)
155     return -1;
156   if (an > bn)
157     return 1;
158   if (an == 0)
159     return 0;
160
161   return mpn_cmp (mpz_limbs_read(a), bp, an);
162 }
163
164 /* Get a pointer to an n limb area, for read-only operation. n must be
165    greater or equal to the current size, and the mpz is zero-padded if
166    needed. */
167 const mp_limb_t *
168 mpz_limbs_read_n (mpz_ptr x, mp_size_t n)
169 {
170   mp_size_t xn = mpz_size (x);
171   mp_ptr xp;
172   
173   assert (xn <= n);
174
175   xp = mpz_limbs_modify (x, n);
176
177   if (xn < n)
178     mpn_zero (xp + xn, n - xn);
179
180   return xp;
181 }
182
183 void
184 mpz_limbs_copy (mp_limb_t *xp, mpz_srcptr x, mp_size_t n)
185 {
186   mp_size_t xn = mpz_size (x);
187
188   assert (xn <= n);
189   mpn_copyi (xp, mpz_limbs_read (x), xn);
190   if (xn < n)
191     mpn_zero (xp + xn, n - xn);
192 }
193
194 void
195 mpz_set_n (mpz_t r, const mp_limb_t *xp, mp_size_t xn)
196 {
197   mpn_copyi (mpz_limbs_write (r, xn), xp, xn);
198   mpz_limbs_finish (r, xn);
199 }
200
201 void
202 mpn_set_base256 (mp_limb_t *rp, mp_size_t rn,
203                  const uint8_t *xp, size_t xn)
204 {
205   size_t xi;
206   mp_limb_t out;
207   unsigned bits;
208   for (xi = xn, out = bits = 0; xi > 0 && rn > 0; )
209     {
210       mp_limb_t in = xp[--xi];
211       out |= (in << bits) & GMP_NUMB_MASK;
212       bits += 8;
213       if (bits >= GMP_NUMB_BITS)
214         {
215           *rp++ = out;
216           rn--;
217
218           bits -= GMP_NUMB_BITS;
219           out = in >> (8 - bits);
220         }
221     }
222   if (rn > 0)
223     {
224       *rp++ = out;
225       if (--rn > 0)
226         mpn_zero (rp, rn);
227     }
228 }
229
230 void
231 mpn_set_base256_le (mp_limb_t *rp, mp_size_t rn,
232                     const uint8_t *xp, size_t xn)
233 {
234   size_t xi;
235   mp_limb_t out;
236   unsigned bits;
237   for (xi = 0, out = bits = 0; xi < xn && rn > 0; )
238     {
239       mp_limb_t in = xp[xi++];
240       out |= (in << bits) & GMP_NUMB_MASK;
241       bits += 8;
242       if (bits >= GMP_NUMB_BITS)
243         {
244           *rp++ = out;
245           rn--;
246
247           bits -= GMP_NUMB_BITS;
248           out = in >> (8 - bits);
249         }
250     }
251   if (rn > 0)
252     {
253       *rp++ = out;
254       if (--rn > 0)
255         mpn_zero (rp, rn);
256     }
257 }
258
259 void
260 mpn_get_base256_le (uint8_t *rp, size_t rn,
261                     const mp_limb_t *xp, mp_size_t xn)
262 {
263   unsigned bits;
264   mp_limb_t in;
265   for (bits = in = 0; xn > 0 && rn > 0; )
266     {
267       if (bits >= 8)
268         {
269           *rp++ = in;
270           rn--;
271           in >>= 8;
272           bits -= 8;
273         }
274       else
275         {
276           uint8_t old = in;
277           in = *xp++;
278           xn--;
279           *rp++ = old | (in << bits);
280           in >>= (8 - bits);
281           bits += GMP_NUMB_BITS - 8;
282         }
283     }
284   while (rn > 0)
285     {
286       *rp++ = in;
287       rn--;
288       in >>= 8;
289     }
290 }
291
292 mp_limb_t *
293 gmp_alloc_limbs (mp_size_t n)
294 {
295
296   void *(*alloc_func)(size_t);
297
298   assert (n > 0);
299
300   mp_get_memory_functions (&alloc_func, NULL, NULL);
301   return (mp_limb_t *) alloc_func ( (size_t) n * sizeof(mp_limb_t));
302 }
303
304 void
305 gmp_free_limbs (mp_limb_t *p, mp_size_t n)
306 {
307   void (*free_func)(void *, size_t);
308   assert (n > 0);
309   assert (p != 0);
310   mp_get_memory_functions (NULL, NULL, &free_func);
311
312   free_func (p, (size_t) n * sizeof(mp_limb_t));
313 }
314
315 void *
316 gmp_alloc(size_t n)
317 {
318   void *(*alloc_func)(size_t);
319   assert (n > 0);
320
321   mp_get_memory_functions(&alloc_func, NULL, NULL);
322
323   return alloc_func (n);
324 }
325
326 void
327 gmp_free(void *p, size_t n)
328 {
329   void (*free_func)(void *, size_t);
330   assert (n > 0);
331   assert (p != 0);
332   mp_get_memory_functions (NULL, NULL, &free_func);
333
334   free_func (p, (size_t) n);
335 }