1f2ba9e96SDina K Nimeh /* BEGIN CSTYLED */
2f9fbec18Smcpowers /*
3f9fbec18Smcpowers * mpi.c
4f9fbec18Smcpowers *
5f9fbec18Smcpowers * Arbitrary precision integer arithmetic library
6f9fbec18Smcpowers *
7f9fbec18Smcpowers * ***** BEGIN LICENSE BLOCK *****
8f9fbec18Smcpowers * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9f9fbec18Smcpowers *
10f9fbec18Smcpowers * The contents of this file are subject to the Mozilla Public License Version
11f9fbec18Smcpowers * 1.1 (the "License"); you may not use this file except in compliance with
12f9fbec18Smcpowers * the License. You may obtain a copy of the License at
13f9fbec18Smcpowers * http://www.mozilla.org/MPL/
14f9fbec18Smcpowers *
15f9fbec18Smcpowers * Software distributed under the License is distributed on an "AS IS" basis,
16f9fbec18Smcpowers * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17f9fbec18Smcpowers * for the specific language governing rights and limitations under the
18f9fbec18Smcpowers * License.
19f9fbec18Smcpowers *
20f9fbec18Smcpowers * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
21f9fbec18Smcpowers *
22f9fbec18Smcpowers * The Initial Developer of the Original Code is
23f9fbec18Smcpowers * Michael J. Fromberger.
24f9fbec18Smcpowers * Portions created by the Initial Developer are Copyright (C) 1998
25f9fbec18Smcpowers * the Initial Developer. All Rights Reserved.
26f9fbec18Smcpowers *
27f9fbec18Smcpowers * Contributor(s):
28f9fbec18Smcpowers * Netscape Communications Corporation
29f9fbec18Smcpowers * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
30f9fbec18Smcpowers *
31f9fbec18Smcpowers * Alternatively, the contents of this file may be used under the terms of
32f9fbec18Smcpowers * either the GNU General Public License Version 2 or later (the "GPL"), or
33f9fbec18Smcpowers * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34f9fbec18Smcpowers * in which case the provisions of the GPL or the LGPL are applicable instead
35f9fbec18Smcpowers * of those above. If you wish to allow use of your version of this file only
36f9fbec18Smcpowers * under the terms of either the GPL or the LGPL, and not to allow others to
37f9fbec18Smcpowers * use your version of this file under the terms of the MPL, indicate your
38f9fbec18Smcpowers * decision by deleting the provisions above and replace them with the notice
39f9fbec18Smcpowers * and other provisions required by the GPL or the LGPL. If you do not delete
40f9fbec18Smcpowers * the provisions above, a recipient may use your version of this file under
41f9fbec18Smcpowers * the terms of any one of the MPL, the GPL or the LGPL.
42f9fbec18Smcpowers *
43f9fbec18Smcpowers * ***** END LICENSE BLOCK ***** */
44f9fbec18Smcpowers /*
45f2ba9e96SDina K Nimeh * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
46f9fbec18Smcpowers *
47f9fbec18Smcpowers * Sun elects to use this software under the MPL license.
48f9fbec18Smcpowers */
49f9fbec18Smcpowers
50f9fbec18Smcpowers /* $Id: mpi.c,v 1.45 2006/09/29 20:12:21 alexei.volkov.bugs%sun.com Exp $ */
51f9fbec18Smcpowers
52f9fbec18Smcpowers #include "mpi-priv.h"
53f9fbec18Smcpowers #if defined(OSF1)
54f9fbec18Smcpowers #include <c_asm.h>
55f9fbec18Smcpowers #endif
56f9fbec18Smcpowers
57f9fbec18Smcpowers #if MP_LOGTAB
58f9fbec18Smcpowers /*
59f9fbec18Smcpowers A table of the logs of 2 for various bases (the 0 and 1 entries of
60*55fea89dSDan Cross this table are meaningless and should not be referenced).
61f9fbec18Smcpowers
62f9fbec18Smcpowers This table is used to compute output lengths for the mp_toradix()
63f9fbec18Smcpowers function. Since a number n in radix r takes up about log_r(n)
64f9fbec18Smcpowers digits, we estimate the output size by taking the least integer
65f9fbec18Smcpowers greater than log_r(n), where:
66f9fbec18Smcpowers
67f9fbec18Smcpowers log_r(n) = log_2(n) * log_r(2)
68f9fbec18Smcpowers
69f9fbec18Smcpowers This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
70*55fea89dSDan Cross which are the output bases supported.
71f9fbec18Smcpowers */
72f9fbec18Smcpowers #include "logtab.h"
73f9fbec18Smcpowers #endif
74f9fbec18Smcpowers
75f9fbec18Smcpowers /* {{{ Constant strings */
76f9fbec18Smcpowers
77f9fbec18Smcpowers /* Constant strings returned by mp_strerror() */
78f9fbec18Smcpowers static const char *mp_err_string[] = {
79f9fbec18Smcpowers "unknown result code", /* say what? */
80f9fbec18Smcpowers "boolean true", /* MP_OKAY, MP_YES */
81f9fbec18Smcpowers "boolean false", /* MP_NO */
82f9fbec18Smcpowers "out of memory", /* MP_MEM */
83f9fbec18Smcpowers "argument out of range", /* MP_RANGE */
84f9fbec18Smcpowers "invalid input parameter", /* MP_BADARG */
85f9fbec18Smcpowers "result is undefined" /* MP_UNDEF */
86f9fbec18Smcpowers };
87f9fbec18Smcpowers
88f9fbec18Smcpowers /* Value to digit maps for radix conversion */
89f9fbec18Smcpowers
90f9fbec18Smcpowers /* s_dmap_1 - standard digits and letters */
91*55fea89dSDan Cross static const char *s_dmap_1 =
92f9fbec18Smcpowers "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
93f9fbec18Smcpowers
94f9fbec18Smcpowers /* }}} */
95f9fbec18Smcpowers
96f9fbec18Smcpowers unsigned long mp_allocs;
97f9fbec18Smcpowers unsigned long mp_frees;
98f9fbec18Smcpowers unsigned long mp_copies;
99f9fbec18Smcpowers
100f9fbec18Smcpowers /* {{{ Default precision manipulation */
101f9fbec18Smcpowers
102f9fbec18Smcpowers /* Default precision for newly created mp_int's */
103f9fbec18Smcpowers static mp_size s_mp_defprec = MP_DEFPREC;
104f9fbec18Smcpowers
mp_get_prec(void)105f9fbec18Smcpowers mp_size mp_get_prec(void)
106f9fbec18Smcpowers {
107f9fbec18Smcpowers return s_mp_defprec;
108f9fbec18Smcpowers
109f9fbec18Smcpowers } /* end mp_get_prec() */
110f9fbec18Smcpowers
mp_set_prec(mp_size prec)111f9fbec18Smcpowers void mp_set_prec(mp_size prec)
112f9fbec18Smcpowers {
113f9fbec18Smcpowers if(prec == 0)
114f9fbec18Smcpowers s_mp_defprec = MP_DEFPREC;
115f9fbec18Smcpowers else
116f9fbec18Smcpowers s_mp_defprec = prec;
117f9fbec18Smcpowers
118f9fbec18Smcpowers } /* end mp_set_prec() */
119f9fbec18Smcpowers
120f9fbec18Smcpowers /* }}} */
121f9fbec18Smcpowers
122f9fbec18Smcpowers /*------------------------------------------------------------------------*/
123f9fbec18Smcpowers /* {{{ mp_init(mp, kmflag) */
124f9fbec18Smcpowers
125f9fbec18Smcpowers /*
126f9fbec18Smcpowers mp_init(mp, kmflag)
127f9fbec18Smcpowers
128f9fbec18Smcpowers Initialize a new zero-valued mp_int. Returns MP_OKAY if successful,
129f9fbec18Smcpowers MP_MEM if memory could not be allocated for the structure.
130f9fbec18Smcpowers */
131f9fbec18Smcpowers
mp_init(mp_int * mp,int kmflag)132f9fbec18Smcpowers mp_err mp_init(mp_int *mp, int kmflag)
133f9fbec18Smcpowers {
134f9fbec18Smcpowers return mp_init_size(mp, s_mp_defprec, kmflag);
135f9fbec18Smcpowers
136f9fbec18Smcpowers } /* end mp_init() */
137f9fbec18Smcpowers
138f9fbec18Smcpowers /* }}} */
139f9fbec18Smcpowers
140f9fbec18Smcpowers /* {{{ mp_init_size(mp, prec, kmflag) */
141f9fbec18Smcpowers
142f9fbec18Smcpowers /*
143f9fbec18Smcpowers mp_init_size(mp, prec, kmflag)
144f9fbec18Smcpowers
145f9fbec18Smcpowers Initialize a new zero-valued mp_int with at least the given
146f9fbec18Smcpowers precision; returns MP_OKAY if successful, or MP_MEM if memory could
147f9fbec18Smcpowers not be allocated for the structure.
148f9fbec18Smcpowers */
149f9fbec18Smcpowers
mp_init_size(mp_int * mp,mp_size prec,int kmflag)150f9fbec18Smcpowers mp_err mp_init_size(mp_int *mp, mp_size prec, int kmflag)
151f9fbec18Smcpowers {
152f9fbec18Smcpowers ARGCHK(mp != NULL && prec > 0, MP_BADARG);
153f9fbec18Smcpowers
154f9fbec18Smcpowers prec = MP_ROUNDUP(prec, s_mp_defprec);
155f9fbec18Smcpowers if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit), kmflag)) == NULL)
156f9fbec18Smcpowers return MP_MEM;
157f9fbec18Smcpowers
158f9fbec18Smcpowers SIGN(mp) = ZPOS;
159f9fbec18Smcpowers USED(mp) = 1;
160f9fbec18Smcpowers ALLOC(mp) = prec;
161f2ba9e96SDina K Nimeh FLAG(mp) = kmflag;
162f9fbec18Smcpowers
163f9fbec18Smcpowers return MP_OKAY;
164f9fbec18Smcpowers
165f9fbec18Smcpowers } /* end mp_init_size() */
166f9fbec18Smcpowers
167f9fbec18Smcpowers /* }}} */
168f9fbec18Smcpowers
169f9fbec18Smcpowers /* {{{ mp_init_copy(mp, from) */
170f9fbec18Smcpowers
171f9fbec18Smcpowers /*
172f9fbec18Smcpowers mp_init_copy(mp, from)
173f9fbec18Smcpowers
174f9fbec18Smcpowers Initialize mp as an exact copy of from. Returns MP_OKAY if
175f9fbec18Smcpowers successful, MP_MEM if memory could not be allocated for the new
176f9fbec18Smcpowers structure.
177f9fbec18Smcpowers */
178f9fbec18Smcpowers
mp_init_copy(mp_int * mp,const mp_int * from)179f9fbec18Smcpowers mp_err mp_init_copy(mp_int *mp, const mp_int *from)
180f9fbec18Smcpowers {
181f9fbec18Smcpowers ARGCHK(mp != NULL && from != NULL, MP_BADARG);
182f9fbec18Smcpowers
183f9fbec18Smcpowers if(mp == from)
184f9fbec18Smcpowers return MP_OKAY;
185f9fbec18Smcpowers
186f9fbec18Smcpowers if((DIGITS(mp) = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL)
187f9fbec18Smcpowers return MP_MEM;
188f9fbec18Smcpowers
189f9fbec18Smcpowers s_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
190f9fbec18Smcpowers USED(mp) = USED(from);
191f9fbec18Smcpowers ALLOC(mp) = ALLOC(from);
192f9fbec18Smcpowers SIGN(mp) = SIGN(from);
193f9fbec18Smcpowers FLAG(mp) = FLAG(from);
194f9fbec18Smcpowers
195f9fbec18Smcpowers return MP_OKAY;
196f9fbec18Smcpowers
197f9fbec18Smcpowers } /* end mp_init_copy() */
198f9fbec18Smcpowers
199f9fbec18Smcpowers /* }}} */
200f9fbec18Smcpowers
201f9fbec18Smcpowers /* {{{ mp_copy(from, to) */
202f9fbec18Smcpowers
203f9fbec18Smcpowers /*
204f9fbec18Smcpowers mp_copy(from, to)
205f9fbec18Smcpowers
206f9fbec18Smcpowers Copies the mp_int 'from' to the mp_int 'to'. It is presumed that
207f9fbec18Smcpowers 'to' has already been initialized (if not, use mp_init_copy()
208f9fbec18Smcpowers instead). If 'from' and 'to' are identical, nothing happens.
209f9fbec18Smcpowers */
210f9fbec18Smcpowers
mp_copy(const mp_int * from,mp_int * to)211f9fbec18Smcpowers mp_err mp_copy(const mp_int *from, mp_int *to)
212f9fbec18Smcpowers {
213f9fbec18Smcpowers ARGCHK(from != NULL && to != NULL, MP_BADARG);
214f9fbec18Smcpowers
215f9fbec18Smcpowers if(from == to)
216f9fbec18Smcpowers return MP_OKAY;
217f9fbec18Smcpowers
218f9fbec18Smcpowers ++mp_copies;
219f9fbec18Smcpowers { /* copy */
220f9fbec18Smcpowers mp_digit *tmp;
221f9fbec18Smcpowers
222f9fbec18Smcpowers /*
223f9fbec18Smcpowers If the allocated buffer in 'to' already has enough space to hold
224f9fbec18Smcpowers all the used digits of 'from', we'll re-use it to avoid hitting
225f9fbec18Smcpowers the memory allocater more than necessary; otherwise, we'd have
226f9fbec18Smcpowers to grow anyway, so we just allocate a hunk and make the copy as
227f9fbec18Smcpowers usual
228f9fbec18Smcpowers */
229f9fbec18Smcpowers if(ALLOC(to) >= USED(from)) {
230f9fbec18Smcpowers s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
231f9fbec18Smcpowers s_mp_copy(DIGITS(from), DIGITS(to), USED(from));
232*55fea89dSDan Cross
233f9fbec18Smcpowers } else {
234f9fbec18Smcpowers if((tmp = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL)
235f9fbec18Smcpowers return MP_MEM;
236f9fbec18Smcpowers
237f9fbec18Smcpowers s_mp_copy(DIGITS(from), tmp, USED(from));
238f9fbec18Smcpowers
239f9fbec18Smcpowers if(DIGITS(to) != NULL) {
240f9fbec18Smcpowers #if MP_CRYPTO
241f9fbec18Smcpowers s_mp_setz(DIGITS(to), ALLOC(to));
242f9fbec18Smcpowers #endif
243f9fbec18Smcpowers s_mp_free(DIGITS(to), ALLOC(to));
244f9fbec18Smcpowers }
245f9fbec18Smcpowers
246f9fbec18Smcpowers DIGITS(to) = tmp;
247f9fbec18Smcpowers ALLOC(to) = ALLOC(from);
248f9fbec18Smcpowers }
249f9fbec18Smcpowers
250f9fbec18Smcpowers /* Copy the precision and sign from the original */
251f9fbec18Smcpowers USED(to) = USED(from);
252f9fbec18Smcpowers SIGN(to) = SIGN(from);
253f2ba9e96SDina K Nimeh FLAG(to) = FLAG(from);
254f9fbec18Smcpowers } /* end copy */
255f9fbec18Smcpowers
256f9fbec18Smcpowers return MP_OKAY;
257f9fbec18Smcpowers
258f9fbec18Smcpowers } /* end mp_copy() */
259f9fbec18Smcpowers
260f9fbec18Smcpowers /* }}} */
261f9fbec18Smcpowers
262f9fbec18Smcpowers /* {{{ mp_exch(mp1, mp2) */
263f9fbec18Smcpowers
264f9fbec18Smcpowers /*
265f9fbec18Smcpowers mp_exch(mp1, mp2)
266f9fbec18Smcpowers
267f9fbec18Smcpowers Exchange mp1 and mp2 without allocating any intermediate memory
268f9fbec18Smcpowers (well, unless you count the stack space needed for this call and the
269f9fbec18Smcpowers locals it creates...). This cannot fail.
270f9fbec18Smcpowers */
271f9fbec18Smcpowers
mp_exch(mp_int * mp1,mp_int * mp2)272f9fbec18Smcpowers void mp_exch(mp_int *mp1, mp_int *mp2)
273f9fbec18Smcpowers {
274f9fbec18Smcpowers #if MP_ARGCHK == 2
275f9fbec18Smcpowers assert(mp1 != NULL && mp2 != NULL);
276f9fbec18Smcpowers #else
277f9fbec18Smcpowers if(mp1 == NULL || mp2 == NULL)
278f9fbec18Smcpowers return;
279f9fbec18Smcpowers #endif
280f9fbec18Smcpowers
281f9fbec18Smcpowers s_mp_exch(mp1, mp2);
282f9fbec18Smcpowers
283f9fbec18Smcpowers } /* end mp_exch() */
284f9fbec18Smcpowers
285f9fbec18Smcpowers /* }}} */
286f9fbec18Smcpowers
287f9fbec18Smcpowers /* {{{ mp_clear(mp) */
288f9fbec18Smcpowers
289f9fbec18Smcpowers /*
290f9fbec18Smcpowers mp_clear(mp)
291f9fbec18Smcpowers
292f9fbec18Smcpowers Release the storage used by an mp_int, and void its fields so that
293f9fbec18Smcpowers if someone calls mp_clear() again for the same int later, we won't
294f9fbec18Smcpowers get tollchocked.
295f9fbec18Smcpowers */
296f9fbec18Smcpowers
mp_clear(mp_int * mp)297f9fbec18Smcpowers void mp_clear(mp_int *mp)
298f9fbec18Smcpowers {
299f9fbec18Smcpowers if(mp == NULL)
300f9fbec18Smcpowers return;
301f9fbec18Smcpowers
302f9fbec18Smcpowers if(DIGITS(mp) != NULL) {
303f9fbec18Smcpowers #if MP_CRYPTO
304f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
305f9fbec18Smcpowers #endif
306f9fbec18Smcpowers s_mp_free(DIGITS(mp), ALLOC(mp));
307f9fbec18Smcpowers DIGITS(mp) = NULL;
308f9fbec18Smcpowers }
309f9fbec18Smcpowers
310f9fbec18Smcpowers USED(mp) = 0;
311f9fbec18Smcpowers ALLOC(mp) = 0;
312f9fbec18Smcpowers
313f9fbec18Smcpowers } /* end mp_clear() */
314f9fbec18Smcpowers
315f9fbec18Smcpowers /* }}} */
316f9fbec18Smcpowers
317f9fbec18Smcpowers /* {{{ mp_zero(mp) */
318f9fbec18Smcpowers
319f9fbec18Smcpowers /*
320*55fea89dSDan Cross mp_zero(mp)
321f9fbec18Smcpowers
322f9fbec18Smcpowers Set mp to zero. Does not change the allocated size of the structure,
323f9fbec18Smcpowers and therefore cannot fail (except on a bad argument, which we ignore)
324f9fbec18Smcpowers */
mp_zero(mp_int * mp)325f9fbec18Smcpowers void mp_zero(mp_int *mp)
326f9fbec18Smcpowers {
327f9fbec18Smcpowers if(mp == NULL)
328f9fbec18Smcpowers return;
329f9fbec18Smcpowers
330f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
331f9fbec18Smcpowers USED(mp) = 1;
332f9fbec18Smcpowers SIGN(mp) = ZPOS;
333f9fbec18Smcpowers
334f9fbec18Smcpowers } /* end mp_zero() */
335f9fbec18Smcpowers
336f9fbec18Smcpowers /* }}} */
337f9fbec18Smcpowers
338f9fbec18Smcpowers /* {{{ mp_set(mp, d) */
339f9fbec18Smcpowers
mp_set(mp_int * mp,mp_digit d)340f9fbec18Smcpowers void mp_set(mp_int *mp, mp_digit d)
341f9fbec18Smcpowers {
342f9fbec18Smcpowers if(mp == NULL)
343f9fbec18Smcpowers return;
344f9fbec18Smcpowers
345f9fbec18Smcpowers mp_zero(mp);
346f9fbec18Smcpowers DIGIT(mp, 0) = d;
347f9fbec18Smcpowers
348f9fbec18Smcpowers } /* end mp_set() */
349f9fbec18Smcpowers
350f9fbec18Smcpowers /* }}} */
351f9fbec18Smcpowers
352f9fbec18Smcpowers /* {{{ mp_set_int(mp, z) */
353f9fbec18Smcpowers
mp_set_int(mp_int * mp,long z)354f9fbec18Smcpowers mp_err mp_set_int(mp_int *mp, long z)
355f9fbec18Smcpowers {
356f9fbec18Smcpowers int ix;
357f9fbec18Smcpowers unsigned long v = labs(z);
358f9fbec18Smcpowers mp_err res;
359f9fbec18Smcpowers
360f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG);
361f9fbec18Smcpowers
362f9fbec18Smcpowers mp_zero(mp);
363f9fbec18Smcpowers if(z == 0)
364f9fbec18Smcpowers return MP_OKAY; /* shortcut for zero */
365f9fbec18Smcpowers
366f9fbec18Smcpowers if (sizeof v <= sizeof(mp_digit)) {
367f9fbec18Smcpowers DIGIT(mp,0) = v;
368f9fbec18Smcpowers } else {
369f9fbec18Smcpowers for (ix = sizeof(long) - 1; ix >= 0; ix--) {
370f9fbec18Smcpowers if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
371f9fbec18Smcpowers return res;
372f9fbec18Smcpowers
373f9fbec18Smcpowers res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
374f9fbec18Smcpowers if (res != MP_OKAY)
375f9fbec18Smcpowers return res;
376f9fbec18Smcpowers }
377f9fbec18Smcpowers }
378f9fbec18Smcpowers if(z < 0)
379f9fbec18Smcpowers SIGN(mp) = NEG;
380f9fbec18Smcpowers
381f9fbec18Smcpowers return MP_OKAY;
382f9fbec18Smcpowers
383f9fbec18Smcpowers } /* end mp_set_int() */
384f9fbec18Smcpowers
385f9fbec18Smcpowers /* }}} */
386f9fbec18Smcpowers
387f9fbec18Smcpowers /* {{{ mp_set_ulong(mp, z) */
388f9fbec18Smcpowers
mp_set_ulong(mp_int * mp,unsigned long z)389f9fbec18Smcpowers mp_err mp_set_ulong(mp_int *mp, unsigned long z)
390f9fbec18Smcpowers {
391f9fbec18Smcpowers int ix;
392f9fbec18Smcpowers mp_err res;
393f9fbec18Smcpowers
394f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG);
395f9fbec18Smcpowers
396f9fbec18Smcpowers mp_zero(mp);
397f9fbec18Smcpowers if(z == 0)
398f9fbec18Smcpowers return MP_OKAY; /* shortcut for zero */
399f9fbec18Smcpowers
400f9fbec18Smcpowers if (sizeof z <= sizeof(mp_digit)) {
401f9fbec18Smcpowers DIGIT(mp,0) = z;
402f9fbec18Smcpowers } else {
403f9fbec18Smcpowers for (ix = sizeof(long) - 1; ix >= 0; ix--) {
404f9fbec18Smcpowers if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
405f9fbec18Smcpowers return res;
406f9fbec18Smcpowers
407f9fbec18Smcpowers res = s_mp_add_d(mp, (mp_digit)((z >> (ix * CHAR_BIT)) & UCHAR_MAX));
408f9fbec18Smcpowers if (res != MP_OKAY)
409f9fbec18Smcpowers return res;
410f9fbec18Smcpowers }
411f9fbec18Smcpowers }
412f9fbec18Smcpowers return MP_OKAY;
413f9fbec18Smcpowers } /* end mp_set_ulong() */
414f9fbec18Smcpowers
415f9fbec18Smcpowers /* }}} */
416f9fbec18Smcpowers
417f9fbec18Smcpowers /*------------------------------------------------------------------------*/
418f9fbec18Smcpowers /* {{{ Digit arithmetic */
419f9fbec18Smcpowers
420f9fbec18Smcpowers /* {{{ mp_add_d(a, d, b) */
421f9fbec18Smcpowers
422f9fbec18Smcpowers /*
423f9fbec18Smcpowers mp_add_d(a, d, b)
424f9fbec18Smcpowers
425f9fbec18Smcpowers Compute the sum b = a + d, for a single digit d. Respects the sign of
426f9fbec18Smcpowers its primary addend (single digits are unsigned anyway).
427f9fbec18Smcpowers */
428f9fbec18Smcpowers
mp_add_d(const mp_int * a,mp_digit d,mp_int * b)429f9fbec18Smcpowers mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b)
430f9fbec18Smcpowers {
431f9fbec18Smcpowers mp_int tmp;
432f9fbec18Smcpowers mp_err res;
433f9fbec18Smcpowers
434f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
435f9fbec18Smcpowers
436f9fbec18Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
437f9fbec18Smcpowers return res;
438f9fbec18Smcpowers
439f9fbec18Smcpowers if(SIGN(&tmp) == ZPOS) {
440f9fbec18Smcpowers if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
441f9fbec18Smcpowers goto CLEANUP;
442f9fbec18Smcpowers } else if(s_mp_cmp_d(&tmp, d) >= 0) {
443f9fbec18Smcpowers if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
444f9fbec18Smcpowers goto CLEANUP;
445f9fbec18Smcpowers } else {
446f9fbec18Smcpowers mp_neg(&tmp, &tmp);
447f9fbec18Smcpowers
448f9fbec18Smcpowers DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
449f9fbec18Smcpowers }
450f9fbec18Smcpowers
451f9fbec18Smcpowers if(s_mp_cmp_d(&tmp, 0) == 0)
452f9fbec18Smcpowers SIGN(&tmp) = ZPOS;
453f9fbec18Smcpowers
454f9fbec18Smcpowers s_mp_exch(&tmp, b);
455f9fbec18Smcpowers
456f9fbec18Smcpowers CLEANUP:
457f9fbec18Smcpowers mp_clear(&tmp);
458f9fbec18Smcpowers return res;
459f9fbec18Smcpowers
460f9fbec18Smcpowers } /* end mp_add_d() */
461f9fbec18Smcpowers
462f9fbec18Smcpowers /* }}} */
463f9fbec18Smcpowers
464f9fbec18Smcpowers /* {{{ mp_sub_d(a, d, b) */
465f9fbec18Smcpowers
466f9fbec18Smcpowers /*
467f9fbec18Smcpowers mp_sub_d(a, d, b)
468f9fbec18Smcpowers
469f9fbec18Smcpowers Compute the difference b = a - d, for a single digit d. Respects the
470f9fbec18Smcpowers sign of its subtrahend (single digits are unsigned anyway).
471f9fbec18Smcpowers */
472f9fbec18Smcpowers
mp_sub_d(const mp_int * a,mp_digit d,mp_int * b)473f9fbec18Smcpowers mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b)
474f9fbec18Smcpowers {
475f9fbec18Smcpowers mp_int tmp;
476f9fbec18Smcpowers mp_err res;
477f9fbec18Smcpowers
478f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
479f9fbec18Smcpowers
480f9fbec18Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
481f9fbec18Smcpowers return res;
482f9fbec18Smcpowers
483f9fbec18Smcpowers if(SIGN(&tmp) == NEG) {
484f9fbec18Smcpowers if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
485f9fbec18Smcpowers goto CLEANUP;
486f9fbec18Smcpowers } else if(s_mp_cmp_d(&tmp, d) >= 0) {
487f9fbec18Smcpowers if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
488f9fbec18Smcpowers goto CLEANUP;
489f9fbec18Smcpowers } else {
490f9fbec18Smcpowers mp_neg(&tmp, &tmp);
491f9fbec18Smcpowers
492f9fbec18Smcpowers DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
493f9fbec18Smcpowers SIGN(&tmp) = NEG;
494f9fbec18Smcpowers }
495f9fbec18Smcpowers
496f9fbec18Smcpowers if(s_mp_cmp_d(&tmp, 0) == 0)
497f9fbec18Smcpowers SIGN(&tmp) = ZPOS;
498f9fbec18Smcpowers
499f9fbec18Smcpowers s_mp_exch(&tmp, b);
500f9fbec18Smcpowers
501f9fbec18Smcpowers CLEANUP:
502f9fbec18Smcpowers mp_clear(&tmp);
503f9fbec18Smcpowers return res;
504f9fbec18Smcpowers
505f9fbec18Smcpowers } /* end mp_sub_d() */
506f9fbec18Smcpowers
507f9fbec18Smcpowers /* }}} */
508f9fbec18Smcpowers
509f9fbec18Smcpowers /* {{{ mp_mul_d(a, d, b) */
510f9fbec18Smcpowers
511f9fbec18Smcpowers /*
512f9fbec18Smcpowers mp_mul_d(a, d, b)
513f9fbec18Smcpowers
514f9fbec18Smcpowers Compute the product b = a * d, for a single digit d. Respects the sign
515f9fbec18Smcpowers of its multiplicand (single digits are unsigned anyway)
516f9fbec18Smcpowers */
517f9fbec18Smcpowers
mp_mul_d(const mp_int * a,mp_digit d,mp_int * b)518f9fbec18Smcpowers mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b)
519f9fbec18Smcpowers {
520f9fbec18Smcpowers mp_err res;
521f9fbec18Smcpowers
522f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
523f9fbec18Smcpowers
524f9fbec18Smcpowers if(d == 0) {
525f9fbec18Smcpowers mp_zero(b);
526f9fbec18Smcpowers return MP_OKAY;
527f9fbec18Smcpowers }
528f9fbec18Smcpowers
529f9fbec18Smcpowers if((res = mp_copy(a, b)) != MP_OKAY)
530f9fbec18Smcpowers return res;
531f9fbec18Smcpowers
532f9fbec18Smcpowers res = s_mp_mul_d(b, d);
533f9fbec18Smcpowers
534f9fbec18Smcpowers return res;
535f9fbec18Smcpowers
536f9fbec18Smcpowers } /* end mp_mul_d() */
537f9fbec18Smcpowers
538f9fbec18Smcpowers /* }}} */
539f9fbec18Smcpowers
540f9fbec18Smcpowers /* {{{ mp_mul_2(a, c) */
541f9fbec18Smcpowers
mp_mul_2(const mp_int * a,mp_int * c)542f9fbec18Smcpowers mp_err mp_mul_2(const mp_int *a, mp_int *c)
543f9fbec18Smcpowers {
544f9fbec18Smcpowers mp_err res;
545f9fbec18Smcpowers
546f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
547f9fbec18Smcpowers
548f9fbec18Smcpowers if((res = mp_copy(a, c)) != MP_OKAY)
549f9fbec18Smcpowers return res;
550f9fbec18Smcpowers
551f9fbec18Smcpowers return s_mp_mul_2(c);
552f9fbec18Smcpowers
553f9fbec18Smcpowers } /* end mp_mul_2() */
554f9fbec18Smcpowers
555f9fbec18Smcpowers /* }}} */
556f9fbec18Smcpowers
557f9fbec18Smcpowers /* {{{ mp_div_d(a, d, q, r) */
558f9fbec18Smcpowers
559f9fbec18Smcpowers /*
560f9fbec18Smcpowers mp_div_d(a, d, q, r)
561f9fbec18Smcpowers
562f9fbec18Smcpowers Compute the quotient q = a / d and remainder r = a mod d, for a
563f9fbec18Smcpowers single digit d. Respects the sign of its divisor (single digits are
564f9fbec18Smcpowers unsigned anyway).
565f9fbec18Smcpowers */
566f9fbec18Smcpowers
mp_div_d(const mp_int * a,mp_digit d,mp_int * q,mp_digit * r)567f9fbec18Smcpowers mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r)
568f9fbec18Smcpowers {
569f9fbec18Smcpowers mp_err res;
570f9fbec18Smcpowers mp_int qp;
571f9fbec18Smcpowers mp_digit rem;
572f9fbec18Smcpowers int pow;
573f9fbec18Smcpowers
574f9fbec18Smcpowers ARGCHK(a != NULL, MP_BADARG);
575f9fbec18Smcpowers
576f9fbec18Smcpowers if(d == 0)
577f9fbec18Smcpowers return MP_RANGE;
578f9fbec18Smcpowers
579f9fbec18Smcpowers /* Shortcut for powers of two ... */
580f9fbec18Smcpowers if((pow = s_mp_ispow2d(d)) >= 0) {
581f9fbec18Smcpowers mp_digit mask;
582f9fbec18Smcpowers
583f9fbec18Smcpowers mask = ((mp_digit)1 << pow) - 1;
584f9fbec18Smcpowers rem = DIGIT(a, 0) & mask;
585f9fbec18Smcpowers
586f9fbec18Smcpowers if(q) {
587f9fbec18Smcpowers mp_copy(a, q);
588f9fbec18Smcpowers s_mp_div_2d(q, pow);
589f9fbec18Smcpowers }
590f9fbec18Smcpowers
591f9fbec18Smcpowers if(r)
592f9fbec18Smcpowers *r = rem;
593f9fbec18Smcpowers
594f9fbec18Smcpowers return MP_OKAY;
595f9fbec18Smcpowers }
596f9fbec18Smcpowers
597f9fbec18Smcpowers if((res = mp_init_copy(&qp, a)) != MP_OKAY)
598f9fbec18Smcpowers return res;
599f9fbec18Smcpowers
600f9fbec18Smcpowers res = s_mp_div_d(&qp, d, &rem);
601f9fbec18Smcpowers
602f9fbec18Smcpowers if(s_mp_cmp_d(&qp, 0) == 0)
603f9fbec18Smcpowers SIGN(q) = ZPOS;
604f9fbec18Smcpowers
605f9fbec18Smcpowers if(r)
606f9fbec18Smcpowers *r = rem;
607f9fbec18Smcpowers
608f9fbec18Smcpowers if(q)
609f9fbec18Smcpowers s_mp_exch(&qp, q);
610f9fbec18Smcpowers
611f9fbec18Smcpowers mp_clear(&qp);
612f9fbec18Smcpowers return res;
613f9fbec18Smcpowers
614f9fbec18Smcpowers } /* end mp_div_d() */
615f9fbec18Smcpowers
616f9fbec18Smcpowers /* }}} */
617f9fbec18Smcpowers
618f9fbec18Smcpowers /* {{{ mp_div_2(a, c) */
619f9fbec18Smcpowers
620f9fbec18Smcpowers /*
621f9fbec18Smcpowers mp_div_2(a, c)
622f9fbec18Smcpowers
623f9fbec18Smcpowers Compute c = a / 2, disregarding the remainder.
624f9fbec18Smcpowers */
625f9fbec18Smcpowers
mp_div_2(const mp_int * a,mp_int * c)626f9fbec18Smcpowers mp_err mp_div_2(const mp_int *a, mp_int *c)
627f9fbec18Smcpowers {
628f9fbec18Smcpowers mp_err res;
629f9fbec18Smcpowers
630f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
631f9fbec18Smcpowers
632f9fbec18Smcpowers if((res = mp_copy(a, c)) != MP_OKAY)
633f9fbec18Smcpowers return res;
634f9fbec18Smcpowers
635f9fbec18Smcpowers s_mp_div_2(c);
636f9fbec18Smcpowers
637f9fbec18Smcpowers return MP_OKAY;
638f9fbec18Smcpowers
639f9fbec18Smcpowers } /* end mp_div_2() */
640f9fbec18Smcpowers
641f9fbec18Smcpowers /* }}} */
642f9fbec18Smcpowers
643f9fbec18Smcpowers /* {{{ mp_expt_d(a, d, b) */
644f9fbec18Smcpowers
mp_expt_d(const mp_int * a,mp_digit d,mp_int * c)645f9fbec18Smcpowers mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c)
646f9fbec18Smcpowers {
647f9fbec18Smcpowers mp_int s, x;
648f9fbec18Smcpowers mp_err res;
649f9fbec18Smcpowers
650f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
651f9fbec18Smcpowers
652f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
653f9fbec18Smcpowers return res;
654f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
655f9fbec18Smcpowers goto X;
656f9fbec18Smcpowers
657f9fbec18Smcpowers DIGIT(&s, 0) = 1;
658f9fbec18Smcpowers
659f9fbec18Smcpowers while(d != 0) {
660f9fbec18Smcpowers if(d & 1) {
661f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
662f9fbec18Smcpowers goto CLEANUP;
663f9fbec18Smcpowers }
664f9fbec18Smcpowers
665f9fbec18Smcpowers d /= 2;
666f9fbec18Smcpowers
667f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
668f9fbec18Smcpowers goto CLEANUP;
669f9fbec18Smcpowers }
670f9fbec18Smcpowers
671f9fbec18Smcpowers s_mp_exch(&s, c);
672f9fbec18Smcpowers
673f9fbec18Smcpowers CLEANUP:
674f9fbec18Smcpowers mp_clear(&x);
675f9fbec18Smcpowers X:
676f9fbec18Smcpowers mp_clear(&s);
677f9fbec18Smcpowers
678f9fbec18Smcpowers return res;
679f9fbec18Smcpowers
680f9fbec18Smcpowers } /* end mp_expt_d() */
681f9fbec18Smcpowers
682f9fbec18Smcpowers /* }}} */
683f9fbec18Smcpowers
684f9fbec18Smcpowers /* }}} */
685f9fbec18Smcpowers
686f9fbec18Smcpowers /*------------------------------------------------------------------------*/
687f9fbec18Smcpowers /* {{{ Full arithmetic */
688f9fbec18Smcpowers
689f9fbec18Smcpowers /* {{{ mp_abs(a, b) */
690f9fbec18Smcpowers
691f9fbec18Smcpowers /*
692f9fbec18Smcpowers mp_abs(a, b)
693f9fbec18Smcpowers
694f9fbec18Smcpowers Compute b = |a|. 'a' and 'b' may be identical.
695f9fbec18Smcpowers */
696f9fbec18Smcpowers
mp_abs(const mp_int * a,mp_int * b)697f9fbec18Smcpowers mp_err mp_abs(const mp_int *a, mp_int *b)
698f9fbec18Smcpowers {
699f9fbec18Smcpowers mp_err res;
700f9fbec18Smcpowers
701f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
702f9fbec18Smcpowers
703f9fbec18Smcpowers if((res = mp_copy(a, b)) != MP_OKAY)
704f9fbec18Smcpowers return res;
705f9fbec18Smcpowers
706f9fbec18Smcpowers SIGN(b) = ZPOS;
707f9fbec18Smcpowers
708f9fbec18Smcpowers return MP_OKAY;
709f9fbec18Smcpowers
710f9fbec18Smcpowers } /* end mp_abs() */
711f9fbec18Smcpowers
712f9fbec18Smcpowers /* }}} */
713f9fbec18Smcpowers
714f9fbec18Smcpowers /* {{{ mp_neg(a, b) */
715f9fbec18Smcpowers
716f9fbec18Smcpowers /*
717f9fbec18Smcpowers mp_neg(a, b)
718f9fbec18Smcpowers
719f9fbec18Smcpowers Compute b = -a. 'a' and 'b' may be identical.
720f9fbec18Smcpowers */
721f9fbec18Smcpowers
mp_neg(const mp_int * a,mp_int * b)722f9fbec18Smcpowers mp_err mp_neg(const mp_int *a, mp_int *b)
723f9fbec18Smcpowers {
724f9fbec18Smcpowers mp_err res;
725f9fbec18Smcpowers
726f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
727f9fbec18Smcpowers
728f9fbec18Smcpowers if((res = mp_copy(a, b)) != MP_OKAY)
729f9fbec18Smcpowers return res;
730f9fbec18Smcpowers
731*55fea89dSDan Cross if(s_mp_cmp_d(b, 0) == MP_EQ)
732f9fbec18Smcpowers SIGN(b) = ZPOS;
733*55fea89dSDan Cross else
734f9fbec18Smcpowers SIGN(b) = (SIGN(b) == NEG) ? ZPOS : NEG;
735f9fbec18Smcpowers
736f9fbec18Smcpowers return MP_OKAY;
737f9fbec18Smcpowers
738f9fbec18Smcpowers } /* end mp_neg() */
739f9fbec18Smcpowers
740f9fbec18Smcpowers /* }}} */
741f9fbec18Smcpowers
742f9fbec18Smcpowers /* {{{ mp_add(a, b, c) */
743f9fbec18Smcpowers
744f9fbec18Smcpowers /*
745f9fbec18Smcpowers mp_add(a, b, c)
746f9fbec18Smcpowers
747f9fbec18Smcpowers Compute c = a + b. All parameters may be identical.
748f9fbec18Smcpowers */
749f9fbec18Smcpowers
mp_add(const mp_int * a,const mp_int * b,mp_int * c)750f9fbec18Smcpowers mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
751f9fbec18Smcpowers {
752f9fbec18Smcpowers mp_err res;
753f9fbec18Smcpowers
754f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
755f9fbec18Smcpowers
756f9fbec18Smcpowers if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */
757f9fbec18Smcpowers MP_CHECKOK( s_mp_add_3arg(a, b, c) );
758f9fbec18Smcpowers } else if(s_mp_cmp(a, b) >= 0) { /* different sign: |a| >= |b| */
759f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
760f9fbec18Smcpowers } else { /* different sign: |a| < |b| */
761f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
762f9fbec18Smcpowers }
763f9fbec18Smcpowers
764f9fbec18Smcpowers if (s_mp_cmp_d(c, 0) == MP_EQ)
765f9fbec18Smcpowers SIGN(c) = ZPOS;
766f9fbec18Smcpowers
767f9fbec18Smcpowers CLEANUP:
768f9fbec18Smcpowers return res;
769f9fbec18Smcpowers
770f9fbec18Smcpowers } /* end mp_add() */
771f9fbec18Smcpowers
772f9fbec18Smcpowers /* }}} */
773f9fbec18Smcpowers
774f9fbec18Smcpowers /* {{{ mp_sub(a, b, c) */
775f9fbec18Smcpowers
776f9fbec18Smcpowers /*
777f9fbec18Smcpowers mp_sub(a, b, c)
778f9fbec18Smcpowers
779f9fbec18Smcpowers Compute c = a - b. All parameters may be identical.
780f9fbec18Smcpowers */
781f9fbec18Smcpowers
mp_sub(const mp_int * a,const mp_int * b,mp_int * c)782f9fbec18Smcpowers mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
783f9fbec18Smcpowers {
784f9fbec18Smcpowers mp_err res;
785f9fbec18Smcpowers int magDiff;
786f9fbec18Smcpowers
787f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
788f9fbec18Smcpowers
789f9fbec18Smcpowers if (a == b) {
790f9fbec18Smcpowers mp_zero(c);
791f9fbec18Smcpowers return MP_OKAY;
792f9fbec18Smcpowers }
793f9fbec18Smcpowers
794f9fbec18Smcpowers if (MP_SIGN(a) != MP_SIGN(b)) {
795f9fbec18Smcpowers MP_CHECKOK( s_mp_add_3arg(a, b, c) );
796f9fbec18Smcpowers } else if (!(magDiff = s_mp_cmp(a, b))) {
797f9fbec18Smcpowers mp_zero(c);
798f9fbec18Smcpowers res = MP_OKAY;
799f9fbec18Smcpowers } else if (magDiff > 0) {
800f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
801f9fbec18Smcpowers } else {
802f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
803f9fbec18Smcpowers MP_SIGN(c) = !MP_SIGN(a);
804f9fbec18Smcpowers }
805f9fbec18Smcpowers
806f9fbec18Smcpowers if (s_mp_cmp_d(c, 0) == MP_EQ)
807f9fbec18Smcpowers MP_SIGN(c) = MP_ZPOS;
808f9fbec18Smcpowers
809f9fbec18Smcpowers CLEANUP:
810f9fbec18Smcpowers return res;
811f9fbec18Smcpowers
812f9fbec18Smcpowers } /* end mp_sub() */
813f9fbec18Smcpowers
814f9fbec18Smcpowers /* }}} */
815f9fbec18Smcpowers
816f9fbec18Smcpowers /* {{{ mp_mul(a, b, c) */
817f9fbec18Smcpowers
818f9fbec18Smcpowers /*
819f9fbec18Smcpowers mp_mul(a, b, c)
820f9fbec18Smcpowers
821f9fbec18Smcpowers Compute c = a * b. All parameters may be identical.
822f9fbec18Smcpowers */
mp_mul(const mp_int * a,const mp_int * b,mp_int * c)823f9fbec18Smcpowers mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int * c)
824f9fbec18Smcpowers {
825f9fbec18Smcpowers mp_digit *pb;
826f9fbec18Smcpowers mp_int tmp;
827f9fbec18Smcpowers mp_err res;
828f9fbec18Smcpowers mp_size ib;
829f9fbec18Smcpowers mp_size useda, usedb;
830f9fbec18Smcpowers
831f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
832f9fbec18Smcpowers
833f9fbec18Smcpowers if (a == c) {
834f9fbec18Smcpowers if ((res = mp_init_copy(&tmp, a)) != MP_OKAY)
835f9fbec18Smcpowers return res;
836*55fea89dSDan Cross if (a == b)
837f9fbec18Smcpowers b = &tmp;
838f9fbec18Smcpowers a = &tmp;
839f9fbec18Smcpowers } else if (b == c) {
840f9fbec18Smcpowers if ((res = mp_init_copy(&tmp, b)) != MP_OKAY)
841f9fbec18Smcpowers return res;
842f9fbec18Smcpowers b = &tmp;
843f9fbec18Smcpowers } else {
844f9fbec18Smcpowers MP_DIGITS(&tmp) = 0;
845f9fbec18Smcpowers }
846f9fbec18Smcpowers
847f9fbec18Smcpowers if (MP_USED(a) < MP_USED(b)) {
848f9fbec18Smcpowers const mp_int *xch = b; /* switch a and b, to do fewer outer loops */
849f9fbec18Smcpowers b = a;
850f9fbec18Smcpowers a = xch;
851f9fbec18Smcpowers }
852f9fbec18Smcpowers
853f9fbec18Smcpowers MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
854f9fbec18Smcpowers if((res = s_mp_pad(c, USED(a) + USED(b))) != MP_OKAY)
855f9fbec18Smcpowers goto CLEANUP;
856f9fbec18Smcpowers
857f9fbec18Smcpowers #ifdef NSS_USE_COMBA
858f9fbec18Smcpowers if ((MP_USED(a) == MP_USED(b)) && IS_POWER_OF_2(MP_USED(b))) {
859f9fbec18Smcpowers if (MP_USED(a) == 4) {
860f9fbec18Smcpowers s_mp_mul_comba_4(a, b, c);
861f9fbec18Smcpowers goto CLEANUP;
862f9fbec18Smcpowers }
863f9fbec18Smcpowers if (MP_USED(a) == 8) {
864f9fbec18Smcpowers s_mp_mul_comba_8(a, b, c);
865f9fbec18Smcpowers goto CLEANUP;
866f9fbec18Smcpowers }
867f9fbec18Smcpowers if (MP_USED(a) == 16) {
868f9fbec18Smcpowers s_mp_mul_comba_16(a, b, c);
869f9fbec18Smcpowers goto CLEANUP;
870f9fbec18Smcpowers }
871f9fbec18Smcpowers if (MP_USED(a) == 32) {
872f9fbec18Smcpowers s_mp_mul_comba_32(a, b, c);
873f9fbec18Smcpowers goto CLEANUP;
874*55fea89dSDan Cross }
875f9fbec18Smcpowers }
876f9fbec18Smcpowers #endif
877f9fbec18Smcpowers
878f9fbec18Smcpowers pb = MP_DIGITS(b);
879f9fbec18Smcpowers s_mpv_mul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c));
880f9fbec18Smcpowers
881f9fbec18Smcpowers /* Outer loop: Digits of b */
882f9fbec18Smcpowers useda = MP_USED(a);
883f9fbec18Smcpowers usedb = MP_USED(b);
884f9fbec18Smcpowers for (ib = 1; ib < usedb; ib++) {
885f9fbec18Smcpowers mp_digit b_i = *pb++;
886f9fbec18Smcpowers
887f9fbec18Smcpowers /* Inner product: Digits of a */
888f9fbec18Smcpowers if (b_i)
889f9fbec18Smcpowers s_mpv_mul_d_add(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
890f9fbec18Smcpowers else
891f9fbec18Smcpowers MP_DIGIT(c, ib + useda) = b_i;
892f9fbec18Smcpowers }
893f9fbec18Smcpowers
894f9fbec18Smcpowers s_mp_clamp(c);
895f9fbec18Smcpowers
896f9fbec18Smcpowers if(SIGN(a) == SIGN(b) || s_mp_cmp_d(c, 0) == MP_EQ)
897f9fbec18Smcpowers SIGN(c) = ZPOS;
898f9fbec18Smcpowers else
899f9fbec18Smcpowers SIGN(c) = NEG;
900f9fbec18Smcpowers
901f9fbec18Smcpowers CLEANUP:
902f9fbec18Smcpowers mp_clear(&tmp);
903f9fbec18Smcpowers return res;
904f9fbec18Smcpowers } /* end mp_mul() */
905f9fbec18Smcpowers
906f9fbec18Smcpowers /* }}} */
907f9fbec18Smcpowers
908f9fbec18Smcpowers /* {{{ mp_sqr(a, sqr) */
909f9fbec18Smcpowers
910f9fbec18Smcpowers #if MP_SQUARE
911f9fbec18Smcpowers /*
912f9fbec18Smcpowers Computes the square of a. This can be done more
913f9fbec18Smcpowers efficiently than a general multiplication, because many of the
914f9fbec18Smcpowers computation steps are redundant when squaring. The inner product
915f9fbec18Smcpowers step is a bit more complicated, but we save a fair number of
916f9fbec18Smcpowers iterations of the multiplication loop.
917f9fbec18Smcpowers */
918f9fbec18Smcpowers
919f9fbec18Smcpowers /* sqr = a^2; Caller provides both a and tmp; */
mp_sqr(const mp_int * a,mp_int * sqr)920f9fbec18Smcpowers mp_err mp_sqr(const mp_int *a, mp_int *sqr)
921f9fbec18Smcpowers {
922f9fbec18Smcpowers mp_digit *pa;
923f9fbec18Smcpowers mp_digit d;
924f9fbec18Smcpowers mp_err res;
925f9fbec18Smcpowers mp_size ix;
926f9fbec18Smcpowers mp_int tmp;
927f9fbec18Smcpowers int count;
928f9fbec18Smcpowers
929f9fbec18Smcpowers ARGCHK(a != NULL && sqr != NULL, MP_BADARG);
930f9fbec18Smcpowers
931f9fbec18Smcpowers if (a == sqr) {
932f9fbec18Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
933f9fbec18Smcpowers return res;
934f9fbec18Smcpowers a = &tmp;
935f9fbec18Smcpowers } else {
936f9fbec18Smcpowers DIGITS(&tmp) = 0;
937f9fbec18Smcpowers res = MP_OKAY;
938f9fbec18Smcpowers }
939f9fbec18Smcpowers
940f9fbec18Smcpowers ix = 2 * MP_USED(a);
941f9fbec18Smcpowers if (ix > MP_ALLOC(sqr)) {
942*55fea89dSDan Cross MP_USED(sqr) = 1;
943f9fbec18Smcpowers MP_CHECKOK( s_mp_grow(sqr, ix) );
944*55fea89dSDan Cross }
945f9fbec18Smcpowers MP_USED(sqr) = ix;
946f9fbec18Smcpowers MP_DIGIT(sqr, 0) = 0;
947f9fbec18Smcpowers
948f9fbec18Smcpowers #ifdef NSS_USE_COMBA
949f9fbec18Smcpowers if (IS_POWER_OF_2(MP_USED(a))) {
950f9fbec18Smcpowers if (MP_USED(a) == 4) {
951f9fbec18Smcpowers s_mp_sqr_comba_4(a, sqr);
952f9fbec18Smcpowers goto CLEANUP;
953f9fbec18Smcpowers }
954f9fbec18Smcpowers if (MP_USED(a) == 8) {
955f9fbec18Smcpowers s_mp_sqr_comba_8(a, sqr);
956f9fbec18Smcpowers goto CLEANUP;
957f9fbec18Smcpowers }
958f9fbec18Smcpowers if (MP_USED(a) == 16) {
959f9fbec18Smcpowers s_mp_sqr_comba_16(a, sqr);
960f9fbec18Smcpowers goto CLEANUP;
961f9fbec18Smcpowers }
962f9fbec18Smcpowers if (MP_USED(a) == 32) {
963f9fbec18Smcpowers s_mp_sqr_comba_32(a, sqr);
964f9fbec18Smcpowers goto CLEANUP;
965*55fea89dSDan Cross }
966f9fbec18Smcpowers }
967f9fbec18Smcpowers #endif
968f9fbec18Smcpowers
969f9fbec18Smcpowers pa = MP_DIGITS(a);
970f9fbec18Smcpowers count = MP_USED(a) - 1;
971f9fbec18Smcpowers if (count > 0) {
972f9fbec18Smcpowers d = *pa++;
973f9fbec18Smcpowers s_mpv_mul_d(pa, count, d, MP_DIGITS(sqr) + 1);
974f9fbec18Smcpowers for (ix = 3; --count > 0; ix += 2) {
975f9fbec18Smcpowers d = *pa++;
976f9fbec18Smcpowers s_mpv_mul_d_add(pa, count, d, MP_DIGITS(sqr) + ix);
977f9fbec18Smcpowers } /* for(ix ...) */
978f9fbec18Smcpowers MP_DIGIT(sqr, MP_USED(sqr)-1) = 0; /* above loop stopped short of this. */
979f9fbec18Smcpowers
980f9fbec18Smcpowers /* now sqr *= 2 */
981f9fbec18Smcpowers s_mp_mul_2(sqr);
982f9fbec18Smcpowers } else {
983f9fbec18Smcpowers MP_DIGIT(sqr, 1) = 0;
984f9fbec18Smcpowers }
985f9fbec18Smcpowers
986f9fbec18Smcpowers /* now add the squares of the digits of a to sqr. */
987f9fbec18Smcpowers s_mpv_sqr_add_prop(MP_DIGITS(a), MP_USED(a), MP_DIGITS(sqr));
988f9fbec18Smcpowers
989f9fbec18Smcpowers SIGN(sqr) = ZPOS;
990f9fbec18Smcpowers s_mp_clamp(sqr);
991f9fbec18Smcpowers
992f9fbec18Smcpowers CLEANUP:
993f9fbec18Smcpowers mp_clear(&tmp);
994f9fbec18Smcpowers return res;
995f9fbec18Smcpowers
996f9fbec18Smcpowers } /* end mp_sqr() */
997f9fbec18Smcpowers #endif
998f9fbec18Smcpowers
999f9fbec18Smcpowers /* }}} */
1000f9fbec18Smcpowers
1001f9fbec18Smcpowers /* {{{ mp_div(a, b, q, r) */
1002f9fbec18Smcpowers
1003f9fbec18Smcpowers /*
1004f9fbec18Smcpowers mp_div(a, b, q, r)
1005f9fbec18Smcpowers
1006f9fbec18Smcpowers Compute q = a / b and r = a mod b. Input parameters may be re-used
1007f9fbec18Smcpowers as output parameters. If q or r is NULL, that portion of the
1008f9fbec18Smcpowers computation will be discarded (although it will still be computed)
1009f9fbec18Smcpowers */
mp_div(const mp_int * a,const mp_int * b,mp_int * q,mp_int * r)1010f9fbec18Smcpowers mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r)
1011f9fbec18Smcpowers {
1012f9fbec18Smcpowers mp_err res;
1013f9fbec18Smcpowers mp_int *pQ, *pR;
1014f9fbec18Smcpowers mp_int qtmp, rtmp, btmp;
1015f9fbec18Smcpowers int cmp;
1016f9fbec18Smcpowers mp_sign signA;
1017f9fbec18Smcpowers mp_sign signB;
1018f9fbec18Smcpowers
1019f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
1020*55fea89dSDan Cross
1021f9fbec18Smcpowers signA = MP_SIGN(a);
1022f9fbec18Smcpowers signB = MP_SIGN(b);
1023f9fbec18Smcpowers
1024f9fbec18Smcpowers if(mp_cmp_z(b) == MP_EQ)
1025f9fbec18Smcpowers return MP_RANGE;
1026f9fbec18Smcpowers
1027f9fbec18Smcpowers DIGITS(&qtmp) = 0;
1028f9fbec18Smcpowers DIGITS(&rtmp) = 0;
1029f9fbec18Smcpowers DIGITS(&btmp) = 0;
1030f9fbec18Smcpowers
1031f9fbec18Smcpowers /* Set up some temporaries... */
1032f9fbec18Smcpowers if (!r || r == a || r == b) {
1033f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&rtmp, a) );
1034f9fbec18Smcpowers pR = &rtmp;
1035f9fbec18Smcpowers } else {
1036f9fbec18Smcpowers MP_CHECKOK( mp_copy(a, r) );
1037f9fbec18Smcpowers pR = r;
1038f9fbec18Smcpowers }
1039f9fbec18Smcpowers
1040f9fbec18Smcpowers if (!q || q == a || q == b) {
1041f9fbec18Smcpowers MP_CHECKOK( mp_init_size(&qtmp, MP_USED(a), FLAG(a)) );
1042f9fbec18Smcpowers pQ = &qtmp;
1043f9fbec18Smcpowers } else {
1044f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(q, MP_USED(a)) );
1045f9fbec18Smcpowers pQ = q;
1046f9fbec18Smcpowers mp_zero(pQ);
1047f9fbec18Smcpowers }
1048f9fbec18Smcpowers
1049f9fbec18Smcpowers /*
1050f9fbec18Smcpowers If |a| <= |b|, we can compute the solution without division;
1051f9fbec18Smcpowers otherwise, we actually do the work required.
1052f9fbec18Smcpowers */
1053f9fbec18Smcpowers if ((cmp = s_mp_cmp(a, b)) <= 0) {
1054f9fbec18Smcpowers if (cmp) {
1055f9fbec18Smcpowers /* r was set to a above. */
1056f9fbec18Smcpowers mp_zero(pQ);
1057f9fbec18Smcpowers } else {
1058f9fbec18Smcpowers mp_set(pQ, 1);
1059f9fbec18Smcpowers mp_zero(pR);
1060f9fbec18Smcpowers }
1061f9fbec18Smcpowers } else {
1062f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&btmp, b) );
1063f9fbec18Smcpowers MP_CHECKOK( s_mp_div(pR, &btmp, pQ) );
1064f9fbec18Smcpowers }
1065f9fbec18Smcpowers
1066f9fbec18Smcpowers /* Compute the signs for the output */
1067f9fbec18Smcpowers MP_SIGN(pR) = signA; /* Sr = Sa */
1068f9fbec18Smcpowers /* Sq = ZPOS if Sa == Sb */ /* Sq = NEG if Sa != Sb */
1069f9fbec18Smcpowers MP_SIGN(pQ) = (signA == signB) ? ZPOS : NEG;
1070f9fbec18Smcpowers
1071f9fbec18Smcpowers if(s_mp_cmp_d(pQ, 0) == MP_EQ)
1072f9fbec18Smcpowers SIGN(pQ) = ZPOS;
1073f9fbec18Smcpowers if(s_mp_cmp_d(pR, 0) == MP_EQ)
1074f9fbec18Smcpowers SIGN(pR) = ZPOS;
1075f9fbec18Smcpowers
1076f9fbec18Smcpowers /* Copy output, if it is needed */
1077*55fea89dSDan Cross if(q && q != pQ)
1078f9fbec18Smcpowers s_mp_exch(pQ, q);
1079f9fbec18Smcpowers
1080*55fea89dSDan Cross if(r && r != pR)
1081f9fbec18Smcpowers s_mp_exch(pR, r);
1082f9fbec18Smcpowers
1083f9fbec18Smcpowers CLEANUP:
1084f9fbec18Smcpowers mp_clear(&btmp);
1085f9fbec18Smcpowers mp_clear(&rtmp);
1086f9fbec18Smcpowers mp_clear(&qtmp);
1087f9fbec18Smcpowers
1088f9fbec18Smcpowers return res;
1089f9fbec18Smcpowers
1090f9fbec18Smcpowers } /* end mp_div() */
1091f9fbec18Smcpowers
1092f9fbec18Smcpowers /* }}} */
1093f9fbec18Smcpowers
1094f9fbec18Smcpowers /* {{{ mp_div_2d(a, d, q, r) */
1095f9fbec18Smcpowers
mp_div_2d(const mp_int * a,mp_digit d,mp_int * q,mp_int * r)1096f9fbec18Smcpowers mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r)
1097f9fbec18Smcpowers {
1098f9fbec18Smcpowers mp_err res;
1099f9fbec18Smcpowers
1100f9fbec18Smcpowers ARGCHK(a != NULL, MP_BADARG);
1101f9fbec18Smcpowers
1102f9fbec18Smcpowers if(q) {
1103f9fbec18Smcpowers if((res = mp_copy(a, q)) != MP_OKAY)
1104f9fbec18Smcpowers return res;
1105f9fbec18Smcpowers }
1106f9fbec18Smcpowers if(r) {
1107f9fbec18Smcpowers if((res = mp_copy(a, r)) != MP_OKAY)
1108f9fbec18Smcpowers return res;
1109f9fbec18Smcpowers }
1110f9fbec18Smcpowers if(q) {
1111f9fbec18Smcpowers s_mp_div_2d(q, d);
1112f9fbec18Smcpowers }
1113f9fbec18Smcpowers if(r) {
1114f9fbec18Smcpowers s_mp_mod_2d(r, d);
1115f9fbec18Smcpowers }
1116f9fbec18Smcpowers
1117f9fbec18Smcpowers return MP_OKAY;
1118f9fbec18Smcpowers
1119f9fbec18Smcpowers } /* end mp_div_2d() */
1120f9fbec18Smcpowers
1121f9fbec18Smcpowers /* }}} */
1122f9fbec18Smcpowers
1123f9fbec18Smcpowers /* {{{ mp_expt(a, b, c) */
1124f9fbec18Smcpowers
1125f9fbec18Smcpowers /*
1126f9fbec18Smcpowers mp_expt(a, b, c)
1127f9fbec18Smcpowers
1128f9fbec18Smcpowers Compute c = a ** b, that is, raise a to the b power. Uses a
1129f9fbec18Smcpowers standard iterative square-and-multiply technique.
1130f9fbec18Smcpowers */
1131f9fbec18Smcpowers
mp_expt(mp_int * a,mp_int * b,mp_int * c)1132f9fbec18Smcpowers mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c)
1133f9fbec18Smcpowers {
1134f9fbec18Smcpowers mp_int s, x;
1135f9fbec18Smcpowers mp_err res;
1136f9fbec18Smcpowers mp_digit d;
1137f9fbec18Smcpowers int dig, bit;
1138f9fbec18Smcpowers
1139f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1140f9fbec18Smcpowers
1141f9fbec18Smcpowers if(mp_cmp_z(b) < 0)
1142f9fbec18Smcpowers return MP_RANGE;
1143f9fbec18Smcpowers
1144f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
1145f9fbec18Smcpowers return res;
1146f9fbec18Smcpowers
1147f9fbec18Smcpowers mp_set(&s, 1);
1148f9fbec18Smcpowers
1149f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
1150f9fbec18Smcpowers goto X;
1151f9fbec18Smcpowers
1152f9fbec18Smcpowers /* Loop over low-order digits in ascending order */
1153f9fbec18Smcpowers for(dig = 0; dig < (USED(b) - 1); dig++) {
1154f9fbec18Smcpowers d = DIGIT(b, dig);
1155f9fbec18Smcpowers
1156f9fbec18Smcpowers /* Loop over bits of each non-maximal digit */
1157f9fbec18Smcpowers for(bit = 0; bit < DIGIT_BIT; bit++) {
1158f9fbec18Smcpowers if(d & 1) {
1159*55fea89dSDan Cross if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1160f9fbec18Smcpowers goto CLEANUP;
1161f9fbec18Smcpowers }
1162f9fbec18Smcpowers
1163f9fbec18Smcpowers d >>= 1;
1164*55fea89dSDan Cross
1165f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
1166f9fbec18Smcpowers goto CLEANUP;
1167f9fbec18Smcpowers }
1168f9fbec18Smcpowers }
1169f9fbec18Smcpowers
1170f9fbec18Smcpowers /* Consider now the last digit... */
1171f9fbec18Smcpowers d = DIGIT(b, dig);
1172f9fbec18Smcpowers
1173f9fbec18Smcpowers while(d) {
1174f9fbec18Smcpowers if(d & 1) {
1175f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1176f9fbec18Smcpowers goto CLEANUP;
1177f9fbec18Smcpowers }
1178f9fbec18Smcpowers
1179f9fbec18Smcpowers d >>= 1;
1180f9fbec18Smcpowers
1181f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
1182f9fbec18Smcpowers goto CLEANUP;
1183f9fbec18Smcpowers }
1184*55fea89dSDan Cross
1185f9fbec18Smcpowers if(mp_iseven(b))
1186f9fbec18Smcpowers SIGN(&s) = SIGN(a);
1187f9fbec18Smcpowers
1188f9fbec18Smcpowers res = mp_copy(&s, c);
1189f9fbec18Smcpowers
1190f9fbec18Smcpowers CLEANUP:
1191f9fbec18Smcpowers mp_clear(&x);
1192f9fbec18Smcpowers X:
1193f9fbec18Smcpowers mp_clear(&s);
1194f9fbec18Smcpowers
1195f9fbec18Smcpowers return res;
1196f9fbec18Smcpowers
1197f9fbec18Smcpowers } /* end mp_expt() */
1198f9fbec18Smcpowers
1199f9fbec18Smcpowers /* }}} */
1200f9fbec18Smcpowers
1201f9fbec18Smcpowers /* {{{ mp_2expt(a, k) */
1202f9fbec18Smcpowers
1203f9fbec18Smcpowers /* Compute a = 2^k */
1204f9fbec18Smcpowers
mp_2expt(mp_int * a,mp_digit k)1205f9fbec18Smcpowers mp_err mp_2expt(mp_int *a, mp_digit k)
1206f9fbec18Smcpowers {
1207f9fbec18Smcpowers ARGCHK(a != NULL, MP_BADARG);
1208f9fbec18Smcpowers
1209f9fbec18Smcpowers return s_mp_2expt(a, k);
1210f9fbec18Smcpowers
1211f9fbec18Smcpowers } /* end mp_2expt() */
1212f9fbec18Smcpowers
1213f9fbec18Smcpowers /* }}} */
1214f9fbec18Smcpowers
1215f9fbec18Smcpowers /* {{{ mp_mod(a, m, c) */
1216f9fbec18Smcpowers
1217f9fbec18Smcpowers /*
1218f9fbec18Smcpowers mp_mod(a, m, c)
1219f9fbec18Smcpowers
1220f9fbec18Smcpowers Compute c = a (mod m). Result will always be 0 <= c < m.
1221f9fbec18Smcpowers */
1222f9fbec18Smcpowers
mp_mod(const mp_int * a,const mp_int * m,mp_int * c)1223f9fbec18Smcpowers mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c)
1224f9fbec18Smcpowers {
1225f9fbec18Smcpowers mp_err res;
1226f9fbec18Smcpowers int mag;
1227f9fbec18Smcpowers
1228f9fbec18Smcpowers ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
1229f9fbec18Smcpowers
1230f9fbec18Smcpowers if(SIGN(m) == NEG)
1231f9fbec18Smcpowers return MP_RANGE;
1232f9fbec18Smcpowers
1233f9fbec18Smcpowers /*
1234f9fbec18Smcpowers If |a| > m, we need to divide to get the remainder and take the
1235*55fea89dSDan Cross absolute value.
1236f9fbec18Smcpowers
1237f9fbec18Smcpowers If |a| < m, we don't need to do any division, just copy and adjust
1238f9fbec18Smcpowers the sign (if a is negative).
1239f9fbec18Smcpowers
1240f9fbec18Smcpowers If |a| == m, we can simply set the result to zero.
1241f9fbec18Smcpowers
1242f9fbec18Smcpowers This order is intended to minimize the average path length of the
1243f9fbec18Smcpowers comparison chain on common workloads -- the most frequent cases are
1244f9fbec18Smcpowers that |a| != m, so we do those first.
1245f9fbec18Smcpowers */
1246f9fbec18Smcpowers if((mag = s_mp_cmp(a, m)) > 0) {
1247f9fbec18Smcpowers if((res = mp_div(a, m, NULL, c)) != MP_OKAY)
1248f9fbec18Smcpowers return res;
1249*55fea89dSDan Cross
1250f9fbec18Smcpowers if(SIGN(c) == NEG) {
1251f9fbec18Smcpowers if((res = mp_add(c, m, c)) != MP_OKAY)
1252f9fbec18Smcpowers return res;
1253f9fbec18Smcpowers }
1254f9fbec18Smcpowers
1255f9fbec18Smcpowers } else if(mag < 0) {
1256f9fbec18Smcpowers if((res = mp_copy(a, c)) != MP_OKAY)
1257f9fbec18Smcpowers return res;
1258f9fbec18Smcpowers
1259f9fbec18Smcpowers if(mp_cmp_z(a) < 0) {
1260f9fbec18Smcpowers if((res = mp_add(c, m, c)) != MP_OKAY)
1261f9fbec18Smcpowers return res;
1262f9fbec18Smcpowers
1263f9fbec18Smcpowers }
1264*55fea89dSDan Cross
1265f9fbec18Smcpowers } else {
1266f9fbec18Smcpowers mp_zero(c);
1267f9fbec18Smcpowers
1268f9fbec18Smcpowers }
1269f9fbec18Smcpowers
1270f9fbec18Smcpowers return MP_OKAY;
1271f9fbec18Smcpowers
1272f9fbec18Smcpowers } /* end mp_mod() */
1273f9fbec18Smcpowers
1274f9fbec18Smcpowers /* }}} */
1275f9fbec18Smcpowers
1276f9fbec18Smcpowers /* {{{ mp_mod_d(a, d, c) */
1277f9fbec18Smcpowers
1278f9fbec18Smcpowers /*
1279f9fbec18Smcpowers mp_mod_d(a, d, c)
1280f9fbec18Smcpowers
1281f9fbec18Smcpowers Compute c = a (mod d). Result will always be 0 <= c < d
1282f9fbec18Smcpowers */
mp_mod_d(const mp_int * a,mp_digit d,mp_digit * c)1283f9fbec18Smcpowers mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c)
1284f9fbec18Smcpowers {
1285f9fbec18Smcpowers mp_err res;
1286f9fbec18Smcpowers mp_digit rem;
1287f9fbec18Smcpowers
1288f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
1289f9fbec18Smcpowers
1290f9fbec18Smcpowers if(s_mp_cmp_d(a, d) > 0) {
1291f9fbec18Smcpowers if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
1292f9fbec18Smcpowers return res;
1293f9fbec18Smcpowers
1294f9fbec18Smcpowers } else {
1295f9fbec18Smcpowers if(SIGN(a) == NEG)
1296f9fbec18Smcpowers rem = d - DIGIT(a, 0);
1297f9fbec18Smcpowers else
1298f9fbec18Smcpowers rem = DIGIT(a, 0);
1299f9fbec18Smcpowers }
1300f9fbec18Smcpowers
1301f9fbec18Smcpowers if(c)
1302f9fbec18Smcpowers *c = rem;
1303f9fbec18Smcpowers
1304f9fbec18Smcpowers return MP_OKAY;
1305f9fbec18Smcpowers
1306f9fbec18Smcpowers } /* end mp_mod_d() */
1307f9fbec18Smcpowers
1308f9fbec18Smcpowers /* }}} */
1309f9fbec18Smcpowers
1310f9fbec18Smcpowers /* {{{ mp_sqrt(a, b) */
1311f9fbec18Smcpowers
1312f9fbec18Smcpowers /*
1313f9fbec18Smcpowers mp_sqrt(a, b)
1314f9fbec18Smcpowers
1315f9fbec18Smcpowers Compute the integer square root of a, and store the result in b.
1316f9fbec18Smcpowers Uses an integer-arithmetic version of Newton's iterative linear
1317f9fbec18Smcpowers approximation technique to determine this value; the result has the
1318f9fbec18Smcpowers following two properties:
1319f9fbec18Smcpowers
1320f9fbec18Smcpowers b^2 <= a
1321f9fbec18Smcpowers (b+1)^2 >= a
1322f9fbec18Smcpowers
1323f9fbec18Smcpowers It is a range error to pass a negative value.
1324f9fbec18Smcpowers */
mp_sqrt(const mp_int * a,mp_int * b)1325f9fbec18Smcpowers mp_err mp_sqrt(const mp_int *a, mp_int *b)
1326f9fbec18Smcpowers {
1327f9fbec18Smcpowers mp_int x, t;
1328f9fbec18Smcpowers mp_err res;
1329f9fbec18Smcpowers mp_size used;
1330f9fbec18Smcpowers
1331f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
1332f9fbec18Smcpowers
1333f9fbec18Smcpowers /* Cannot take square root of a negative value */
1334f9fbec18Smcpowers if(SIGN(a) == NEG)
1335f9fbec18Smcpowers return MP_RANGE;
1336f9fbec18Smcpowers
1337f9fbec18Smcpowers /* Special cases for zero and one, trivial */
1338f9fbec18Smcpowers if(mp_cmp_d(a, 1) <= 0)
1339f9fbec18Smcpowers return mp_copy(a, b);
1340*55fea89dSDan Cross
1341f9fbec18Smcpowers /* Initialize the temporaries we'll use below */
1342f9fbec18Smcpowers if((res = mp_init_size(&t, USED(a), FLAG(a))) != MP_OKAY)
1343f9fbec18Smcpowers return res;
1344f9fbec18Smcpowers
1345f9fbec18Smcpowers /* Compute an initial guess for the iteration as a itself */
1346f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
1347f9fbec18Smcpowers goto X;
1348f9fbec18Smcpowers
1349f9fbec18Smcpowers used = MP_USED(&x);
1350f9fbec18Smcpowers if (used > 1) {
1351f9fbec18Smcpowers s_mp_rshd(&x, used / 2);
1352f9fbec18Smcpowers }
1353f9fbec18Smcpowers
1354f9fbec18Smcpowers for(;;) {
1355f9fbec18Smcpowers /* t = (x * x) - a */
1356f9fbec18Smcpowers mp_copy(&x, &t); /* can't fail, t is big enough for original x */
1357f9fbec18Smcpowers if((res = mp_sqr(&t, &t)) != MP_OKAY ||
1358f9fbec18Smcpowers (res = mp_sub(&t, a, &t)) != MP_OKAY)
1359f9fbec18Smcpowers goto CLEANUP;
1360f9fbec18Smcpowers
1361f9fbec18Smcpowers /* t = t / 2x */
1362f9fbec18Smcpowers s_mp_mul_2(&x);
1363f9fbec18Smcpowers if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY)
1364f9fbec18Smcpowers goto CLEANUP;
1365f9fbec18Smcpowers s_mp_div_2(&x);
1366f9fbec18Smcpowers
1367f9fbec18Smcpowers /* Terminate the loop, if the quotient is zero */
1368f9fbec18Smcpowers if(mp_cmp_z(&t) == MP_EQ)
1369f9fbec18Smcpowers break;
1370f9fbec18Smcpowers
1371f9fbec18Smcpowers /* x = x - t */
1372f9fbec18Smcpowers if((res = mp_sub(&x, &t, &x)) != MP_OKAY)
1373f9fbec18Smcpowers goto CLEANUP;
1374f9fbec18Smcpowers
1375f9fbec18Smcpowers }
1376f9fbec18Smcpowers
1377f9fbec18Smcpowers /* Copy result to output parameter */
1378f9fbec18Smcpowers mp_sub_d(&x, 1, &x);
1379f9fbec18Smcpowers s_mp_exch(&x, b);
1380f9fbec18Smcpowers
1381f9fbec18Smcpowers CLEANUP:
1382f9fbec18Smcpowers mp_clear(&x);
1383f9fbec18Smcpowers X:
1384*55fea89dSDan Cross mp_clear(&t);
1385f9fbec18Smcpowers
1386f9fbec18Smcpowers return res;
1387f9fbec18Smcpowers
1388f9fbec18Smcpowers } /* end mp_sqrt() */
1389f9fbec18Smcpowers
1390f9fbec18Smcpowers /* }}} */
1391f9fbec18Smcpowers
1392f9fbec18Smcpowers /* }}} */
1393f9fbec18Smcpowers
1394f9fbec18Smcpowers /*------------------------------------------------------------------------*/
1395f9fbec18Smcpowers /* {{{ Modular arithmetic */
1396f9fbec18Smcpowers
1397f9fbec18Smcpowers #if MP_MODARITH
1398f9fbec18Smcpowers /* {{{ mp_addmod(a, b, m, c) */
1399f9fbec18Smcpowers
1400f9fbec18Smcpowers /*
1401f9fbec18Smcpowers mp_addmod(a, b, m, c)
1402f9fbec18Smcpowers
1403f9fbec18Smcpowers Compute c = (a + b) mod m
1404f9fbec18Smcpowers */
1405f9fbec18Smcpowers
mp_addmod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)1406f9fbec18Smcpowers mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
1407f9fbec18Smcpowers {
1408f9fbec18Smcpowers mp_err res;
1409f9fbec18Smcpowers
1410f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
1411f9fbec18Smcpowers
1412f9fbec18Smcpowers if((res = mp_add(a, b, c)) != MP_OKAY)
1413f9fbec18Smcpowers return res;
1414f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
1415f9fbec18Smcpowers return res;
1416f9fbec18Smcpowers
1417f9fbec18Smcpowers return MP_OKAY;
1418f9fbec18Smcpowers
1419f9fbec18Smcpowers }
1420f9fbec18Smcpowers
1421f9fbec18Smcpowers /* }}} */
1422f9fbec18Smcpowers
1423f9fbec18Smcpowers /* {{{ mp_submod(a, b, m, c) */
1424f9fbec18Smcpowers
1425f9fbec18Smcpowers /*
1426f9fbec18Smcpowers mp_submod(a, b, m, c)
1427f9fbec18Smcpowers
1428f9fbec18Smcpowers Compute c = (a - b) mod m
1429f9fbec18Smcpowers */
1430f9fbec18Smcpowers
mp_submod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)1431f9fbec18Smcpowers mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
1432f9fbec18Smcpowers {
1433f9fbec18Smcpowers mp_err res;
1434f9fbec18Smcpowers
1435f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
1436f9fbec18Smcpowers
1437f9fbec18Smcpowers if((res = mp_sub(a, b, c)) != MP_OKAY)
1438f9fbec18Smcpowers return res;
1439f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
1440f9fbec18Smcpowers return res;
1441f9fbec18Smcpowers
1442f9fbec18Smcpowers return MP_OKAY;
1443f9fbec18Smcpowers
1444f9fbec18Smcpowers }
1445f9fbec18Smcpowers
1446f9fbec18Smcpowers /* }}} */
1447f9fbec18Smcpowers
1448f9fbec18Smcpowers /* {{{ mp_mulmod(a, b, m, c) */
1449f9fbec18Smcpowers
1450f9fbec18Smcpowers /*
1451f9fbec18Smcpowers mp_mulmod(a, b, m, c)
1452f9fbec18Smcpowers
1453f9fbec18Smcpowers Compute c = (a * b) mod m
1454f9fbec18Smcpowers */
1455f9fbec18Smcpowers
mp_mulmod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)1456f9fbec18Smcpowers mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
1457f9fbec18Smcpowers {
1458f9fbec18Smcpowers mp_err res;
1459f9fbec18Smcpowers
1460f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
1461f9fbec18Smcpowers
1462f9fbec18Smcpowers if((res = mp_mul(a, b, c)) != MP_OKAY)
1463f9fbec18Smcpowers return res;
1464f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
1465f9fbec18Smcpowers return res;
1466f9fbec18Smcpowers
1467f9fbec18Smcpowers return MP_OKAY;
1468f9fbec18Smcpowers
1469f9fbec18Smcpowers }
1470f9fbec18Smcpowers
1471f9fbec18Smcpowers /* }}} */
1472f9fbec18Smcpowers
1473f9fbec18Smcpowers /* {{{ mp_sqrmod(a, m, c) */
1474f9fbec18Smcpowers
1475f9fbec18Smcpowers #if MP_SQUARE
mp_sqrmod(const mp_int * a,const mp_int * m,mp_int * c)1476f9fbec18Smcpowers mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c)
1477f9fbec18Smcpowers {
1478f9fbec18Smcpowers mp_err res;
1479f9fbec18Smcpowers
1480f9fbec18Smcpowers ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
1481f9fbec18Smcpowers
1482f9fbec18Smcpowers if((res = mp_sqr(a, c)) != MP_OKAY)
1483f9fbec18Smcpowers return res;
1484f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
1485f9fbec18Smcpowers return res;
1486f9fbec18Smcpowers
1487f9fbec18Smcpowers return MP_OKAY;
1488f9fbec18Smcpowers
1489f9fbec18Smcpowers } /* end mp_sqrmod() */
1490f9fbec18Smcpowers #endif
1491f9fbec18Smcpowers
1492f9fbec18Smcpowers /* }}} */
1493f9fbec18Smcpowers
1494f9fbec18Smcpowers /* {{{ s_mp_exptmod(a, b, m, c) */
1495f9fbec18Smcpowers
1496f9fbec18Smcpowers /*
1497f9fbec18Smcpowers s_mp_exptmod(a, b, m, c)
1498f9fbec18Smcpowers
1499f9fbec18Smcpowers Compute c = (a ** b) mod m. Uses a standard square-and-multiply
1500f9fbec18Smcpowers method with modular reductions at each step. (This is basically the
1501f9fbec18Smcpowers same code as mp_expt(), except for the addition of the reductions)
1502*55fea89dSDan Cross
1503f9fbec18Smcpowers The modular reductions are done using Barrett's algorithm (see
1504f9fbec18Smcpowers s_mp_reduce() below for details)
1505f9fbec18Smcpowers */
1506f9fbec18Smcpowers
s_mp_exptmod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)1507f9fbec18Smcpowers mp_err s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
1508f9fbec18Smcpowers {
1509f9fbec18Smcpowers mp_int s, x, mu;
1510f9fbec18Smcpowers mp_err res;
1511f9fbec18Smcpowers mp_digit d;
1512f9fbec18Smcpowers int dig, bit;
1513f9fbec18Smcpowers
1514f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1515f9fbec18Smcpowers
1516f9fbec18Smcpowers if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0)
1517f9fbec18Smcpowers return MP_RANGE;
1518f9fbec18Smcpowers
1519f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
1520f9fbec18Smcpowers return res;
1521f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY ||
1522f9fbec18Smcpowers (res = mp_mod(&x, m, &x)) != MP_OKAY)
1523f9fbec18Smcpowers goto X;
1524f9fbec18Smcpowers if((res = mp_init(&mu, FLAG(a))) != MP_OKAY)
1525f9fbec18Smcpowers goto MU;
1526f9fbec18Smcpowers
1527f9fbec18Smcpowers mp_set(&s, 1);
1528f9fbec18Smcpowers
1529f9fbec18Smcpowers /* mu = b^2k / m */
1530*55fea89dSDan Cross s_mp_add_d(&mu, 1);
1531f9fbec18Smcpowers s_mp_lshd(&mu, 2 * USED(m));
1532f9fbec18Smcpowers if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
1533f9fbec18Smcpowers goto CLEANUP;
1534f9fbec18Smcpowers
1535f9fbec18Smcpowers /* Loop over digits of b in ascending order, except highest order */
1536f9fbec18Smcpowers for(dig = 0; dig < (USED(b) - 1); dig++) {
1537f9fbec18Smcpowers d = DIGIT(b, dig);
1538f9fbec18Smcpowers
1539f9fbec18Smcpowers /* Loop over the bits of the lower-order digits */
1540f9fbec18Smcpowers for(bit = 0; bit < DIGIT_BIT; bit++) {
1541f9fbec18Smcpowers if(d & 1) {
1542f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1543f9fbec18Smcpowers goto CLEANUP;
1544f9fbec18Smcpowers if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
1545f9fbec18Smcpowers goto CLEANUP;
1546f9fbec18Smcpowers }
1547f9fbec18Smcpowers
1548f9fbec18Smcpowers d >>= 1;
1549f9fbec18Smcpowers
1550f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
1551f9fbec18Smcpowers goto CLEANUP;
1552f9fbec18Smcpowers if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
1553f9fbec18Smcpowers goto CLEANUP;
1554f9fbec18Smcpowers }
1555f9fbec18Smcpowers }
1556f9fbec18Smcpowers
1557f9fbec18Smcpowers /* Now do the last digit... */
1558f9fbec18Smcpowers d = DIGIT(b, dig);
1559f9fbec18Smcpowers
1560f9fbec18Smcpowers while(d) {
1561f9fbec18Smcpowers if(d & 1) {
1562f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1563f9fbec18Smcpowers goto CLEANUP;
1564f9fbec18Smcpowers if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
1565f9fbec18Smcpowers goto CLEANUP;
1566f9fbec18Smcpowers }
1567f9fbec18Smcpowers
1568f9fbec18Smcpowers d >>= 1;
1569f9fbec18Smcpowers
1570f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
1571f9fbec18Smcpowers goto CLEANUP;
1572f9fbec18Smcpowers if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
1573f9fbec18Smcpowers goto CLEANUP;
1574f9fbec18Smcpowers }
1575f9fbec18Smcpowers
1576f9fbec18Smcpowers s_mp_exch(&s, c);
1577f9fbec18Smcpowers
1578f9fbec18Smcpowers CLEANUP:
1579f9fbec18Smcpowers mp_clear(&mu);
1580f9fbec18Smcpowers MU:
1581f9fbec18Smcpowers mp_clear(&x);
1582f9fbec18Smcpowers X:
1583f9fbec18Smcpowers mp_clear(&s);
1584f9fbec18Smcpowers
1585f9fbec18Smcpowers return res;
1586f9fbec18Smcpowers
1587f9fbec18Smcpowers } /* end s_mp_exptmod() */
1588f9fbec18Smcpowers
1589f9fbec18Smcpowers /* }}} */
1590f9fbec18Smcpowers
1591f9fbec18Smcpowers /* {{{ mp_exptmod_d(a, d, m, c) */
1592f9fbec18Smcpowers
mp_exptmod_d(const mp_int * a,mp_digit d,const mp_int * m,mp_int * c)1593f9fbec18Smcpowers mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c)
1594f9fbec18Smcpowers {
1595f9fbec18Smcpowers mp_int s, x;
1596f9fbec18Smcpowers mp_err res;
1597f9fbec18Smcpowers
1598f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
1599f9fbec18Smcpowers
1600f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
1601f9fbec18Smcpowers return res;
1602f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
1603f9fbec18Smcpowers goto X;
1604f9fbec18Smcpowers
1605f9fbec18Smcpowers mp_set(&s, 1);
1606f9fbec18Smcpowers
1607f9fbec18Smcpowers while(d != 0) {
1608f9fbec18Smcpowers if(d & 1) {
1609f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY ||
1610f9fbec18Smcpowers (res = mp_mod(&s, m, &s)) != MP_OKAY)
1611f9fbec18Smcpowers goto CLEANUP;
1612f9fbec18Smcpowers }
1613f9fbec18Smcpowers
1614f9fbec18Smcpowers d /= 2;
1615f9fbec18Smcpowers
1616f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY ||
1617f9fbec18Smcpowers (res = mp_mod(&x, m, &x)) != MP_OKAY)
1618f9fbec18Smcpowers goto CLEANUP;
1619f9fbec18Smcpowers }
1620f9fbec18Smcpowers
1621f9fbec18Smcpowers s_mp_exch(&s, c);
1622f9fbec18Smcpowers
1623f9fbec18Smcpowers CLEANUP:
1624f9fbec18Smcpowers mp_clear(&x);
1625f9fbec18Smcpowers X:
1626f9fbec18Smcpowers mp_clear(&s);
1627f9fbec18Smcpowers
1628f9fbec18Smcpowers return res;
1629f9fbec18Smcpowers
1630f9fbec18Smcpowers } /* end mp_exptmod_d() */
1631f9fbec18Smcpowers
1632f9fbec18Smcpowers /* }}} */
1633f9fbec18Smcpowers #endif /* if MP_MODARITH */
1634f9fbec18Smcpowers
1635f9fbec18Smcpowers /* }}} */
1636f9fbec18Smcpowers
1637f9fbec18Smcpowers /*------------------------------------------------------------------------*/
1638f9fbec18Smcpowers /* {{{ Comparison functions */
1639f9fbec18Smcpowers
1640f9fbec18Smcpowers /* {{{ mp_cmp_z(a) */
1641f9fbec18Smcpowers
1642f9fbec18Smcpowers /*
1643f9fbec18Smcpowers mp_cmp_z(a)
1644f9fbec18Smcpowers
1645f9fbec18Smcpowers Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0.
1646f9fbec18Smcpowers */
1647f9fbec18Smcpowers
mp_cmp_z(const mp_int * a)1648f9fbec18Smcpowers int mp_cmp_z(const mp_int *a)
1649f9fbec18Smcpowers {
1650f9fbec18Smcpowers if(SIGN(a) == NEG)
1651f9fbec18Smcpowers return MP_LT;
1652f9fbec18Smcpowers else if(USED(a) == 1 && DIGIT(a, 0) == 0)
1653f9fbec18Smcpowers return MP_EQ;
1654f9fbec18Smcpowers else
1655f9fbec18Smcpowers return MP_GT;
1656f9fbec18Smcpowers
1657f9fbec18Smcpowers } /* end mp_cmp_z() */
1658f9fbec18Smcpowers
1659f9fbec18Smcpowers /* }}} */
1660f9fbec18Smcpowers
1661f9fbec18Smcpowers /* {{{ mp_cmp_d(a, d) */
1662f9fbec18Smcpowers
1663f9fbec18Smcpowers /*
1664f9fbec18Smcpowers mp_cmp_d(a, d)
1665f9fbec18Smcpowers
1666f9fbec18Smcpowers Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d
1667f9fbec18Smcpowers */
1668f9fbec18Smcpowers
mp_cmp_d(const mp_int * a,mp_digit d)1669f9fbec18Smcpowers int mp_cmp_d(const mp_int *a, mp_digit d)
1670f9fbec18Smcpowers {
1671f9fbec18Smcpowers ARGCHK(a != NULL, MP_EQ);
1672f9fbec18Smcpowers
1673f9fbec18Smcpowers if(SIGN(a) == NEG)
1674f9fbec18Smcpowers return MP_LT;
1675f9fbec18Smcpowers
1676f9fbec18Smcpowers return s_mp_cmp_d(a, d);
1677f9fbec18Smcpowers
1678f9fbec18Smcpowers } /* end mp_cmp_d() */
1679f9fbec18Smcpowers
1680f9fbec18Smcpowers /* }}} */
1681f9fbec18Smcpowers
1682f9fbec18Smcpowers /* {{{ mp_cmp(a, b) */
1683f9fbec18Smcpowers
mp_cmp(const mp_int * a,const mp_int * b)1684f9fbec18Smcpowers int mp_cmp(const mp_int *a, const mp_int *b)
1685f9fbec18Smcpowers {
1686f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_EQ);
1687f9fbec18Smcpowers
1688f9fbec18Smcpowers if(SIGN(a) == SIGN(b)) {
1689f9fbec18Smcpowers int mag;
1690f9fbec18Smcpowers
1691f9fbec18Smcpowers if((mag = s_mp_cmp(a, b)) == MP_EQ)
1692f9fbec18Smcpowers return MP_EQ;
1693f9fbec18Smcpowers
1694f9fbec18Smcpowers if(SIGN(a) == ZPOS)
1695f9fbec18Smcpowers return mag;
1696f9fbec18Smcpowers else
1697f9fbec18Smcpowers return -mag;
1698f9fbec18Smcpowers
1699f9fbec18Smcpowers } else if(SIGN(a) == ZPOS) {
1700f9fbec18Smcpowers return MP_GT;
1701f9fbec18Smcpowers } else {
1702f9fbec18Smcpowers return MP_LT;
1703f9fbec18Smcpowers }
1704f9fbec18Smcpowers
1705f9fbec18Smcpowers } /* end mp_cmp() */
1706f9fbec18Smcpowers
1707f9fbec18Smcpowers /* }}} */
1708f9fbec18Smcpowers
1709f9fbec18Smcpowers /* {{{ mp_cmp_mag(a, b) */
1710f9fbec18Smcpowers
1711f9fbec18Smcpowers /*
1712f9fbec18Smcpowers mp_cmp_mag(a, b)
1713f9fbec18Smcpowers
1714f9fbec18Smcpowers Compares |a| <=> |b|, and returns an appropriate comparison result
1715f9fbec18Smcpowers */
1716f9fbec18Smcpowers
mp_cmp_mag(mp_int * a,mp_int * b)1717f9fbec18Smcpowers int mp_cmp_mag(mp_int *a, mp_int *b)
1718f9fbec18Smcpowers {
1719f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_EQ);
1720f9fbec18Smcpowers
1721f9fbec18Smcpowers return s_mp_cmp(a, b);
1722f9fbec18Smcpowers
1723f9fbec18Smcpowers } /* end mp_cmp_mag() */
1724f9fbec18Smcpowers
1725f9fbec18Smcpowers /* }}} */
1726f9fbec18Smcpowers
1727f9fbec18Smcpowers /* {{{ mp_cmp_int(a, z, kmflag) */
1728f9fbec18Smcpowers
1729f9fbec18Smcpowers /*
1730f9fbec18Smcpowers This just converts z to an mp_int, and uses the existing comparison
1731f9fbec18Smcpowers routines. This is sort of inefficient, but it's not clear to me how
1732f9fbec18Smcpowers frequently this wil get used anyway. For small positive constants,
1733f9fbec18Smcpowers you can always use mp_cmp_d(), and for zero, there is mp_cmp_z().
1734f9fbec18Smcpowers */
mp_cmp_int(const mp_int * a,long z,int kmflag)1735f9fbec18Smcpowers int mp_cmp_int(const mp_int *a, long z, int kmflag)
1736f9fbec18Smcpowers {
1737f9fbec18Smcpowers mp_int tmp;
1738f9fbec18Smcpowers int out;
1739f9fbec18Smcpowers
1740f9fbec18Smcpowers ARGCHK(a != NULL, MP_EQ);
1741*55fea89dSDan Cross
1742f9fbec18Smcpowers mp_init(&tmp, kmflag); mp_set_int(&tmp, z);
1743f9fbec18Smcpowers out = mp_cmp(a, &tmp);
1744f9fbec18Smcpowers mp_clear(&tmp);
1745f9fbec18Smcpowers
1746f9fbec18Smcpowers return out;
1747f9fbec18Smcpowers
1748f9fbec18Smcpowers } /* end mp_cmp_int() */
1749f9fbec18Smcpowers
1750f9fbec18Smcpowers /* }}} */
1751f9fbec18Smcpowers
1752f9fbec18Smcpowers /* {{{ mp_isodd(a) */
1753f9fbec18Smcpowers
1754f9fbec18Smcpowers /*
1755f9fbec18Smcpowers mp_isodd(a)
1756f9fbec18Smcpowers
1757f9fbec18Smcpowers Returns a true (non-zero) value if a is odd, false (zero) otherwise.
1758f9fbec18Smcpowers */
mp_isodd(const mp_int * a)1759f9fbec18Smcpowers int mp_isodd(const mp_int *a)
1760f9fbec18Smcpowers {
1761f9fbec18Smcpowers ARGCHK(a != NULL, 0);
1762f9fbec18Smcpowers
1763f9fbec18Smcpowers return (int)(DIGIT(a, 0) & 1);
1764f9fbec18Smcpowers
1765f9fbec18Smcpowers } /* end mp_isodd() */
1766f9fbec18Smcpowers
1767f9fbec18Smcpowers /* }}} */
1768f9fbec18Smcpowers
1769f9fbec18Smcpowers /* {{{ mp_iseven(a) */
1770f9fbec18Smcpowers
mp_iseven(const mp_int * a)1771f9fbec18Smcpowers int mp_iseven(const mp_int *a)
1772f9fbec18Smcpowers {
1773f9fbec18Smcpowers return !mp_isodd(a);
1774f9fbec18Smcpowers
1775f9fbec18Smcpowers } /* end mp_iseven() */
1776f9fbec18Smcpowers
1777f9fbec18Smcpowers /* }}} */
1778f9fbec18Smcpowers
1779f9fbec18Smcpowers /* }}} */
1780f9fbec18Smcpowers
1781f9fbec18Smcpowers /*------------------------------------------------------------------------*/
1782f9fbec18Smcpowers /* {{{ Number theoretic functions */
1783f9fbec18Smcpowers
1784f9fbec18Smcpowers #if MP_NUMTH
1785f9fbec18Smcpowers /* {{{ mp_gcd(a, b, c) */
1786f9fbec18Smcpowers
1787f9fbec18Smcpowers /*
1788f9fbec18Smcpowers Like the old mp_gcd() function, except computes the GCD using the
1789f9fbec18Smcpowers binary algorithm due to Josef Stein in 1961 (via Knuth).
1790f9fbec18Smcpowers */
mp_gcd(mp_int * a,mp_int * b,mp_int * c)1791f9fbec18Smcpowers mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c)
1792f9fbec18Smcpowers {
1793f9fbec18Smcpowers mp_err res;
1794f9fbec18Smcpowers mp_int u, v, t;
1795f9fbec18Smcpowers mp_size k = 0;
1796f9fbec18Smcpowers
1797f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1798f9fbec18Smcpowers
1799f9fbec18Smcpowers if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ)
1800f9fbec18Smcpowers return MP_RANGE;
1801f9fbec18Smcpowers if(mp_cmp_z(a) == MP_EQ) {
1802f9fbec18Smcpowers return mp_copy(b, c);
1803f9fbec18Smcpowers } else if(mp_cmp_z(b) == MP_EQ) {
1804f9fbec18Smcpowers return mp_copy(a, c);
1805f9fbec18Smcpowers }
1806f9fbec18Smcpowers
1807f9fbec18Smcpowers if((res = mp_init(&t, FLAG(a))) != MP_OKAY)
1808f9fbec18Smcpowers return res;
1809f9fbec18Smcpowers if((res = mp_init_copy(&u, a)) != MP_OKAY)
1810f9fbec18Smcpowers goto U;
1811f9fbec18Smcpowers if((res = mp_init_copy(&v, b)) != MP_OKAY)
1812f9fbec18Smcpowers goto V;
1813f9fbec18Smcpowers
1814f9fbec18Smcpowers SIGN(&u) = ZPOS;
1815f9fbec18Smcpowers SIGN(&v) = ZPOS;
1816f9fbec18Smcpowers
1817f9fbec18Smcpowers /* Divide out common factors of 2 until at least 1 of a, b is even */
1818f9fbec18Smcpowers while(mp_iseven(&u) && mp_iseven(&v)) {
1819f9fbec18Smcpowers s_mp_div_2(&u);
1820f9fbec18Smcpowers s_mp_div_2(&v);
1821f9fbec18Smcpowers ++k;
1822f9fbec18Smcpowers }
1823f9fbec18Smcpowers
1824f9fbec18Smcpowers /* Initialize t */
1825f9fbec18Smcpowers if(mp_isodd(&u)) {
1826f9fbec18Smcpowers if((res = mp_copy(&v, &t)) != MP_OKAY)
1827f9fbec18Smcpowers goto CLEANUP;
1828*55fea89dSDan Cross
1829f9fbec18Smcpowers /* t = -v */
1830f9fbec18Smcpowers if(SIGN(&v) == ZPOS)
1831f9fbec18Smcpowers SIGN(&t) = NEG;
1832f9fbec18Smcpowers else
1833f9fbec18Smcpowers SIGN(&t) = ZPOS;
1834*55fea89dSDan Cross
1835f9fbec18Smcpowers } else {
1836f9fbec18Smcpowers if((res = mp_copy(&u, &t)) != MP_OKAY)
1837f9fbec18Smcpowers goto CLEANUP;
1838f9fbec18Smcpowers
1839f9fbec18Smcpowers }
1840f9fbec18Smcpowers
1841f9fbec18Smcpowers for(;;) {
1842f9fbec18Smcpowers while(mp_iseven(&t)) {
1843f9fbec18Smcpowers s_mp_div_2(&t);
1844f9fbec18Smcpowers }
1845f9fbec18Smcpowers
1846f9fbec18Smcpowers if(mp_cmp_z(&t) == MP_GT) {
1847f9fbec18Smcpowers if((res = mp_copy(&t, &u)) != MP_OKAY)
1848f9fbec18Smcpowers goto CLEANUP;
1849f9fbec18Smcpowers
1850f9fbec18Smcpowers } else {
1851f9fbec18Smcpowers if((res = mp_copy(&t, &v)) != MP_OKAY)
1852f9fbec18Smcpowers goto CLEANUP;
1853f9fbec18Smcpowers
1854f9fbec18Smcpowers /* v = -t */
1855f9fbec18Smcpowers if(SIGN(&t) == ZPOS)
1856f9fbec18Smcpowers SIGN(&v) = NEG;
1857f9fbec18Smcpowers else
1858f9fbec18Smcpowers SIGN(&v) = ZPOS;
1859f9fbec18Smcpowers }
1860f9fbec18Smcpowers
1861f9fbec18Smcpowers if((res = mp_sub(&u, &v, &t)) != MP_OKAY)
1862f9fbec18Smcpowers goto CLEANUP;
1863f9fbec18Smcpowers
1864f9fbec18Smcpowers if(s_mp_cmp_d(&t, 0) == MP_EQ)
1865f9fbec18Smcpowers break;
1866f9fbec18Smcpowers }
1867f9fbec18Smcpowers
1868f9fbec18Smcpowers s_mp_2expt(&v, k); /* v = 2^k */
1869f9fbec18Smcpowers res = mp_mul(&u, &v, c); /* c = u * v */
1870f9fbec18Smcpowers
1871f9fbec18Smcpowers CLEANUP:
1872f9fbec18Smcpowers mp_clear(&v);
1873f9fbec18Smcpowers V:
1874f9fbec18Smcpowers mp_clear(&u);
1875f9fbec18Smcpowers U:
1876f9fbec18Smcpowers mp_clear(&t);
1877f9fbec18Smcpowers
1878f9fbec18Smcpowers return res;
1879f9fbec18Smcpowers
1880f9fbec18Smcpowers } /* end mp_gcd() */
1881f9fbec18Smcpowers
1882f9fbec18Smcpowers /* }}} */
1883f9fbec18Smcpowers
1884f9fbec18Smcpowers /* {{{ mp_lcm(a, b, c) */
1885f9fbec18Smcpowers
1886f9fbec18Smcpowers /* We compute the least common multiple using the rule:
1887f9fbec18Smcpowers
1888f9fbec18Smcpowers ab = [a, b](a, b)
1889f9fbec18Smcpowers
1890f9fbec18Smcpowers ... by computing the product, and dividing out the gcd.
1891f9fbec18Smcpowers */
1892f9fbec18Smcpowers
mp_lcm(mp_int * a,mp_int * b,mp_int * c)1893f9fbec18Smcpowers mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c)
1894f9fbec18Smcpowers {
1895f9fbec18Smcpowers mp_int gcd, prod;
1896f9fbec18Smcpowers mp_err res;
1897f9fbec18Smcpowers
1898f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1899f9fbec18Smcpowers
1900f9fbec18Smcpowers /* Set up temporaries */
1901f9fbec18Smcpowers if((res = mp_init(&gcd, FLAG(a))) != MP_OKAY)
1902f9fbec18Smcpowers return res;
1903f9fbec18Smcpowers if((res = mp_init(&prod, FLAG(a))) != MP_OKAY)
1904f9fbec18Smcpowers goto GCD;
1905f9fbec18Smcpowers
1906f9fbec18Smcpowers if((res = mp_mul(a, b, &prod)) != MP_OKAY)
1907f9fbec18Smcpowers goto CLEANUP;
1908f9fbec18Smcpowers if((res = mp_gcd(a, b, &gcd)) != MP_OKAY)
1909f9fbec18Smcpowers goto CLEANUP;
1910f9fbec18Smcpowers
1911f9fbec18Smcpowers res = mp_div(&prod, &gcd, c, NULL);
1912f9fbec18Smcpowers
1913f9fbec18Smcpowers CLEANUP:
1914f9fbec18Smcpowers mp_clear(&prod);
1915f9fbec18Smcpowers GCD:
1916f9fbec18Smcpowers mp_clear(&gcd);
1917f9fbec18Smcpowers
1918f9fbec18Smcpowers return res;
1919f9fbec18Smcpowers
1920f9fbec18Smcpowers } /* end mp_lcm() */
1921f9fbec18Smcpowers
1922f9fbec18Smcpowers /* }}} */
1923f9fbec18Smcpowers
1924f9fbec18Smcpowers /* {{{ mp_xgcd(a, b, g, x, y) */
1925f9fbec18Smcpowers
1926f9fbec18Smcpowers /*
1927f9fbec18Smcpowers mp_xgcd(a, b, g, x, y)
1928f9fbec18Smcpowers
1929f9fbec18Smcpowers Compute g = (a, b) and values x and y satisfying Bezout's identity
1930f9fbec18Smcpowers (that is, ax + by = g). This uses the binary extended GCD algorithm
1931f9fbec18Smcpowers based on the Stein algorithm used for mp_gcd()
1932f9fbec18Smcpowers See algorithm 14.61 in Handbook of Applied Cryptogrpahy.
1933f9fbec18Smcpowers */
1934f9fbec18Smcpowers
mp_xgcd(const mp_int * a,const mp_int * b,mp_int * g,mp_int * x,mp_int * y)1935f9fbec18Smcpowers mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y)
1936f9fbec18Smcpowers {
1937f9fbec18Smcpowers mp_int gx, xc, yc, u, v, A, B, C, D;
1938f9fbec18Smcpowers mp_int *clean[9];
1939f9fbec18Smcpowers mp_err res;
1940f9fbec18Smcpowers int last = -1;
1941f9fbec18Smcpowers
1942f9fbec18Smcpowers if(mp_cmp_z(b) == 0)
1943f9fbec18Smcpowers return MP_RANGE;
1944f9fbec18Smcpowers
1945f9fbec18Smcpowers /* Initialize all these variables we need */
1946f9fbec18Smcpowers MP_CHECKOK( mp_init(&u, FLAG(a)) );
1947f9fbec18Smcpowers clean[++last] = &u;
1948f9fbec18Smcpowers MP_CHECKOK( mp_init(&v, FLAG(a)) );
1949f9fbec18Smcpowers clean[++last] = &v;
1950f9fbec18Smcpowers MP_CHECKOK( mp_init(&gx, FLAG(a)) );
1951f9fbec18Smcpowers clean[++last] = &gx;
1952f9fbec18Smcpowers MP_CHECKOK( mp_init(&A, FLAG(a)) );
1953f9fbec18Smcpowers clean[++last] = &A;
1954f9fbec18Smcpowers MP_CHECKOK( mp_init(&B, FLAG(a)) );
1955f9fbec18Smcpowers clean[++last] = &B;
1956f9fbec18Smcpowers MP_CHECKOK( mp_init(&C, FLAG(a)) );
1957f9fbec18Smcpowers clean[++last] = &C;
1958f9fbec18Smcpowers MP_CHECKOK( mp_init(&D, FLAG(a)) );
1959f9fbec18Smcpowers clean[++last] = &D;
1960f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&xc, a) );
1961f9fbec18Smcpowers clean[++last] = &xc;
1962f9fbec18Smcpowers mp_abs(&xc, &xc);
1963f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&yc, b) );
1964f9fbec18Smcpowers clean[++last] = &yc;
1965f9fbec18Smcpowers mp_abs(&yc, &yc);
1966f9fbec18Smcpowers
1967f9fbec18Smcpowers mp_set(&gx, 1);
1968f9fbec18Smcpowers
1969f9fbec18Smcpowers /* Divide by two until at least one of them is odd */
1970f9fbec18Smcpowers while(mp_iseven(&xc) && mp_iseven(&yc)) {
1971f9fbec18Smcpowers mp_size nx = mp_trailing_zeros(&xc);
1972f9fbec18Smcpowers mp_size ny = mp_trailing_zeros(&yc);
1973f9fbec18Smcpowers mp_size n = MP_MIN(nx, ny);
1974f9fbec18Smcpowers s_mp_div_2d(&xc,n);
1975f9fbec18Smcpowers s_mp_div_2d(&yc,n);
1976f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(&gx,n) );
1977f9fbec18Smcpowers }
1978f9fbec18Smcpowers
1979f9fbec18Smcpowers mp_copy(&xc, &u);
1980f9fbec18Smcpowers mp_copy(&yc, &v);
1981f9fbec18Smcpowers mp_set(&A, 1); mp_set(&D, 1);
1982f9fbec18Smcpowers
1983f9fbec18Smcpowers /* Loop through binary GCD algorithm */
1984f9fbec18Smcpowers do {
1985f9fbec18Smcpowers while(mp_iseven(&u)) {
1986f9fbec18Smcpowers s_mp_div_2(&u);
1987f9fbec18Smcpowers
1988f9fbec18Smcpowers if(mp_iseven(&A) && mp_iseven(&B)) {
1989f9fbec18Smcpowers s_mp_div_2(&A); s_mp_div_2(&B);
1990f9fbec18Smcpowers } else {
1991f9fbec18Smcpowers MP_CHECKOK( mp_add(&A, &yc, &A) );
1992f9fbec18Smcpowers s_mp_div_2(&A);
1993f9fbec18Smcpowers MP_CHECKOK( mp_sub(&B, &xc, &B) );
1994f9fbec18Smcpowers s_mp_div_2(&B);
1995f9fbec18Smcpowers }
1996f9fbec18Smcpowers }
1997f9fbec18Smcpowers
1998f9fbec18Smcpowers while(mp_iseven(&v)) {
1999f9fbec18Smcpowers s_mp_div_2(&v);
2000f9fbec18Smcpowers
2001f9fbec18Smcpowers if(mp_iseven(&C) && mp_iseven(&D)) {
2002f9fbec18Smcpowers s_mp_div_2(&C); s_mp_div_2(&D);
2003f9fbec18Smcpowers } else {
2004f9fbec18Smcpowers MP_CHECKOK( mp_add(&C, &yc, &C) );
2005f9fbec18Smcpowers s_mp_div_2(&C);
2006f9fbec18Smcpowers MP_CHECKOK( mp_sub(&D, &xc, &D) );
2007f9fbec18Smcpowers s_mp_div_2(&D);
2008f9fbec18Smcpowers }
2009f9fbec18Smcpowers }
2010f9fbec18Smcpowers
2011f9fbec18Smcpowers if(mp_cmp(&u, &v) >= 0) {
2012f9fbec18Smcpowers MP_CHECKOK( mp_sub(&u, &v, &u) );
2013f9fbec18Smcpowers MP_CHECKOK( mp_sub(&A, &C, &A) );
2014f9fbec18Smcpowers MP_CHECKOK( mp_sub(&B, &D, &B) );
2015f9fbec18Smcpowers } else {
2016f9fbec18Smcpowers MP_CHECKOK( mp_sub(&v, &u, &v) );
2017f9fbec18Smcpowers MP_CHECKOK( mp_sub(&C, &A, &C) );
2018f9fbec18Smcpowers MP_CHECKOK( mp_sub(&D, &B, &D) );
2019f9fbec18Smcpowers }
2020f9fbec18Smcpowers } while (mp_cmp_z(&u) != 0);
2021f9fbec18Smcpowers
2022f9fbec18Smcpowers /* copy results to output */
2023f9fbec18Smcpowers if(x)
2024f9fbec18Smcpowers MP_CHECKOK( mp_copy(&C, x) );
2025f9fbec18Smcpowers
2026f9fbec18Smcpowers if(y)
2027f9fbec18Smcpowers MP_CHECKOK( mp_copy(&D, y) );
2028*55fea89dSDan Cross
2029f9fbec18Smcpowers if(g)
2030f9fbec18Smcpowers MP_CHECKOK( mp_mul(&gx, &v, g) );
2031f9fbec18Smcpowers
2032f9fbec18Smcpowers CLEANUP:
2033f9fbec18Smcpowers while(last >= 0)
2034f9fbec18Smcpowers mp_clear(clean[last--]);
2035f9fbec18Smcpowers
2036f9fbec18Smcpowers return res;
2037f9fbec18Smcpowers
2038f9fbec18Smcpowers } /* end mp_xgcd() */
2039f9fbec18Smcpowers
2040f9fbec18Smcpowers /* }}} */
2041f9fbec18Smcpowers
mp_trailing_zeros(const mp_int * mp)2042f9fbec18Smcpowers mp_size mp_trailing_zeros(const mp_int *mp)
2043f9fbec18Smcpowers {
2044f9fbec18Smcpowers mp_digit d;
2045f9fbec18Smcpowers mp_size n = 0;
2046f9fbec18Smcpowers int ix;
2047f9fbec18Smcpowers
2048f9fbec18Smcpowers if (!mp || !MP_DIGITS(mp) || !mp_cmp_z(mp))
2049f9fbec18Smcpowers return n;
2050f9fbec18Smcpowers
2051f9fbec18Smcpowers for (ix = 0; !(d = MP_DIGIT(mp,ix)) && (ix < MP_USED(mp)); ++ix)
2052f9fbec18Smcpowers n += MP_DIGIT_BIT;
2053f9fbec18Smcpowers if (!d)
2054f9fbec18Smcpowers return 0; /* shouldn't happen, but ... */
2055f9fbec18Smcpowers #if !defined(MP_USE_UINT_DIGIT)
2056f9fbec18Smcpowers if (!(d & 0xffffffffU)) {
2057f9fbec18Smcpowers d >>= 32;
2058f9fbec18Smcpowers n += 32;
2059f9fbec18Smcpowers }
2060f9fbec18Smcpowers #endif
2061f9fbec18Smcpowers if (!(d & 0xffffU)) {
2062f9fbec18Smcpowers d >>= 16;
2063f9fbec18Smcpowers n += 16;
2064f9fbec18Smcpowers }
2065f9fbec18Smcpowers if (!(d & 0xffU)) {
2066f9fbec18Smcpowers d >>= 8;
2067f9fbec18Smcpowers n += 8;
2068f9fbec18Smcpowers }
2069f9fbec18Smcpowers if (!(d & 0xfU)) {
2070f9fbec18Smcpowers d >>= 4;
2071f9fbec18Smcpowers n += 4;
2072f9fbec18Smcpowers }
2073f9fbec18Smcpowers if (!(d & 0x3U)) {
2074f9fbec18Smcpowers d >>= 2;
2075f9fbec18Smcpowers n += 2;
2076f9fbec18Smcpowers }
2077f9fbec18Smcpowers if (!(d & 0x1U)) {
2078f9fbec18Smcpowers d >>= 1;
2079f9fbec18Smcpowers n += 1;
2080f9fbec18Smcpowers }
2081f9fbec18Smcpowers #if MP_ARGCHK == 2
2082f9fbec18Smcpowers assert(0 != (d & 1));
2083f9fbec18Smcpowers #endif
2084f9fbec18Smcpowers return n;
2085f9fbec18Smcpowers }
2086f9fbec18Smcpowers
2087f9fbec18Smcpowers /* Given a and prime p, computes c and k such that a*c == 2**k (mod p).
2088f9fbec18Smcpowers ** Returns k (positive) or error (negative).
2089f9fbec18Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
2090f9fbec18Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo).
2091f9fbec18Smcpowers */
s_mp_almost_inverse(const mp_int * a,const mp_int * p,mp_int * c)2092f9fbec18Smcpowers mp_err s_mp_almost_inverse(const mp_int *a, const mp_int *p, mp_int *c)
2093f9fbec18Smcpowers {
2094f9fbec18Smcpowers mp_err res;
2095f9fbec18Smcpowers mp_err k = 0;
2096f9fbec18Smcpowers mp_int d, f, g;
2097f9fbec18Smcpowers
2098f9fbec18Smcpowers ARGCHK(a && p && c, MP_BADARG);
2099f9fbec18Smcpowers
2100f9fbec18Smcpowers MP_DIGITS(&d) = 0;
2101f9fbec18Smcpowers MP_DIGITS(&f) = 0;
2102f9fbec18Smcpowers MP_DIGITS(&g) = 0;
2103f9fbec18Smcpowers MP_CHECKOK( mp_init(&d, FLAG(a)) );
2104f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&f, a) ); /* f = a */
2105f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&g, p) ); /* g = p */
2106f9fbec18Smcpowers
2107f9fbec18Smcpowers mp_set(c, 1);
2108f9fbec18Smcpowers mp_zero(&d);
2109f9fbec18Smcpowers
2110f9fbec18Smcpowers if (mp_cmp_z(&f) == 0) {
2111f9fbec18Smcpowers res = MP_UNDEF;
2112*55fea89dSDan Cross } else
2113f9fbec18Smcpowers for (;;) {
2114f9fbec18Smcpowers int diff_sign;
2115f9fbec18Smcpowers while (mp_iseven(&f)) {
2116f9fbec18Smcpowers mp_size n = mp_trailing_zeros(&f);
2117f9fbec18Smcpowers if (!n) {
2118f9fbec18Smcpowers res = MP_UNDEF;
2119f9fbec18Smcpowers goto CLEANUP;
2120f9fbec18Smcpowers }
2121f9fbec18Smcpowers s_mp_div_2d(&f, n);
2122f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(&d, n) );
2123f9fbec18Smcpowers k += n;
2124f9fbec18Smcpowers }
2125f9fbec18Smcpowers if (mp_cmp_d(&f, 1) == MP_EQ) { /* f == 1 */
2126f9fbec18Smcpowers res = k;
2127f9fbec18Smcpowers break;
2128f9fbec18Smcpowers }
2129f9fbec18Smcpowers diff_sign = mp_cmp(&f, &g);
2130f9fbec18Smcpowers if (diff_sign < 0) { /* f < g */
2131f9fbec18Smcpowers s_mp_exch(&f, &g);
2132f9fbec18Smcpowers s_mp_exch(c, &d);
2133f9fbec18Smcpowers } else if (diff_sign == 0) { /* f == g */
2134f9fbec18Smcpowers res = MP_UNDEF; /* a and p are not relatively prime */
2135f9fbec18Smcpowers break;
2136f9fbec18Smcpowers }
2137f9fbec18Smcpowers if ((MP_DIGIT(&f,0) % 4) == (MP_DIGIT(&g,0) % 4)) {
2138f9fbec18Smcpowers MP_CHECKOK( mp_sub(&f, &g, &f) ); /* f = f - g */
2139f9fbec18Smcpowers MP_CHECKOK( mp_sub(c, &d, c) ); /* c = c - d */
2140f9fbec18Smcpowers } else {
2141f9fbec18Smcpowers MP_CHECKOK( mp_add(&f, &g, &f) ); /* f = f + g */
2142f9fbec18Smcpowers MP_CHECKOK( mp_add(c, &d, c) ); /* c = c + d */
2143f9fbec18Smcpowers }
2144f9fbec18Smcpowers }
2145f9fbec18Smcpowers if (res >= 0) {
2146f9fbec18Smcpowers while (MP_SIGN(c) != MP_ZPOS) {
2147f9fbec18Smcpowers MP_CHECKOK( mp_add(c, p, c) );
2148f9fbec18Smcpowers }
2149f9fbec18Smcpowers res = k;
2150f9fbec18Smcpowers }
2151f9fbec18Smcpowers
2152f9fbec18Smcpowers CLEANUP:
2153f9fbec18Smcpowers mp_clear(&d);
2154f9fbec18Smcpowers mp_clear(&f);
2155f9fbec18Smcpowers mp_clear(&g);
2156f9fbec18Smcpowers return res;
2157f9fbec18Smcpowers }
2158f9fbec18Smcpowers
2159f9fbec18Smcpowers /* Compute T = (P ** -1) mod MP_RADIX. Also works for 16-bit mp_digits.
2160f9fbec18Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
2161f9fbec18Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo).
2162f9fbec18Smcpowers */
s_mp_invmod_radix(mp_digit P)2163f9fbec18Smcpowers mp_digit s_mp_invmod_radix(mp_digit P)
2164f9fbec18Smcpowers {
2165f9fbec18Smcpowers mp_digit T = P;
2166f9fbec18Smcpowers T *= 2 - (P * T);
2167f9fbec18Smcpowers T *= 2 - (P * T);
2168f9fbec18Smcpowers T *= 2 - (P * T);
2169f9fbec18Smcpowers T *= 2 - (P * T);
2170f9fbec18Smcpowers #if !defined(MP_USE_UINT_DIGIT)
2171f9fbec18Smcpowers T *= 2 - (P * T);
2172f9fbec18Smcpowers T *= 2 - (P * T);
2173f9fbec18Smcpowers #endif
2174f9fbec18Smcpowers return T;
2175f9fbec18Smcpowers }
2176f9fbec18Smcpowers
2177*55fea89dSDan Cross /* Given c, k, and prime p, where a*c == 2**k (mod p),
2178f9fbec18Smcpowers ** Compute x = (a ** -1) mod p. This is similar to Montgomery reduction.
2179f9fbec18Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
2180f9fbec18Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo).
2181f9fbec18Smcpowers */
s_mp_fixup_reciprocal(const mp_int * c,const mp_int * p,int k,mp_int * x)2182f9fbec18Smcpowers mp_err s_mp_fixup_reciprocal(const mp_int *c, const mp_int *p, int k, mp_int *x)
2183f9fbec18Smcpowers {
2184f9fbec18Smcpowers int k_orig = k;
2185f9fbec18Smcpowers mp_digit r;
2186f9fbec18Smcpowers mp_size ix;
2187f9fbec18Smcpowers mp_err res;
2188f9fbec18Smcpowers
2189f9fbec18Smcpowers if (mp_cmp_z(c) < 0) { /* c < 0 */
2190f9fbec18Smcpowers MP_CHECKOK( mp_add(c, p, x) ); /* x = c + p */
2191f9fbec18Smcpowers } else {
2192f9fbec18Smcpowers MP_CHECKOK( mp_copy(c, x) ); /* x = c */
2193f9fbec18Smcpowers }
2194f9fbec18Smcpowers
2195f9fbec18Smcpowers /* make sure x is large enough */
2196f9fbec18Smcpowers ix = MP_HOWMANY(k, MP_DIGIT_BIT) + MP_USED(p) + 1;
2197f9fbec18Smcpowers ix = MP_MAX(ix, MP_USED(x));
2198f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(x, ix) );
2199f9fbec18Smcpowers
2200f9fbec18Smcpowers r = 0 - s_mp_invmod_radix(MP_DIGIT(p,0));
2201f9fbec18Smcpowers
2202f9fbec18Smcpowers for (ix = 0; k > 0; ix++) {
2203f9fbec18Smcpowers int j = MP_MIN(k, MP_DIGIT_BIT);
2204f9fbec18Smcpowers mp_digit v = r * MP_DIGIT(x, ix);
2205f9fbec18Smcpowers if (j < MP_DIGIT_BIT) {
2206f9fbec18Smcpowers v &= ((mp_digit)1 << j) - 1; /* v = v mod (2 ** j) */
2207f9fbec18Smcpowers }
2208f9fbec18Smcpowers s_mp_mul_d_add_offset(p, v, x, ix); /* x += p * v * (RADIX ** ix) */
2209f9fbec18Smcpowers k -= j;
2210f9fbec18Smcpowers }
2211f9fbec18Smcpowers s_mp_clamp(x);
2212f9fbec18Smcpowers s_mp_div_2d(x, k_orig);
2213f9fbec18Smcpowers res = MP_OKAY;
2214f9fbec18Smcpowers
2215f9fbec18Smcpowers CLEANUP:
2216f9fbec18Smcpowers return res;
2217f9fbec18Smcpowers }
2218f9fbec18Smcpowers
2219f9fbec18Smcpowers /* compute mod inverse using Schroeppel's method, only if m is odd */
s_mp_invmod_odd_m(const mp_int * a,const mp_int * m,mp_int * c)2220f9fbec18Smcpowers mp_err s_mp_invmod_odd_m(const mp_int *a, const mp_int *m, mp_int *c)
2221f9fbec18Smcpowers {
2222f9fbec18Smcpowers int k;
2223f9fbec18Smcpowers mp_err res;
2224f9fbec18Smcpowers mp_int x;
2225f9fbec18Smcpowers
2226f9fbec18Smcpowers ARGCHK(a && m && c, MP_BADARG);
2227f9fbec18Smcpowers
2228f9fbec18Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
2229f9fbec18Smcpowers return MP_RANGE;
2230f9fbec18Smcpowers if (mp_iseven(m))
2231f9fbec18Smcpowers return MP_UNDEF;
2232f9fbec18Smcpowers
2233f9fbec18Smcpowers MP_DIGITS(&x) = 0;
2234f9fbec18Smcpowers
2235f9fbec18Smcpowers if (a == c) {
2236f9fbec18Smcpowers if ((res = mp_init_copy(&x, a)) != MP_OKAY)
2237f9fbec18Smcpowers return res;
2238*55fea89dSDan Cross if (a == m)
2239f9fbec18Smcpowers m = &x;
2240f9fbec18Smcpowers a = &x;
2241f9fbec18Smcpowers } else if (m == c) {
2242f9fbec18Smcpowers if ((res = mp_init_copy(&x, m)) != MP_OKAY)
2243f9fbec18Smcpowers return res;
2244f9fbec18Smcpowers m = &x;
2245f9fbec18Smcpowers } else {
2246f9fbec18Smcpowers MP_DIGITS(&x) = 0;
2247f9fbec18Smcpowers }
2248f9fbec18Smcpowers
2249f9fbec18Smcpowers MP_CHECKOK( s_mp_almost_inverse(a, m, c) );
2250f9fbec18Smcpowers k = res;
2251f9fbec18Smcpowers MP_CHECKOK( s_mp_fixup_reciprocal(c, m, k, c) );
2252f9fbec18Smcpowers CLEANUP:
2253f9fbec18Smcpowers mp_clear(&x);
2254f9fbec18Smcpowers return res;
2255f9fbec18Smcpowers }
2256f9fbec18Smcpowers
2257f9fbec18Smcpowers /* Known good algorithm for computing modular inverse. But slow. */
mp_invmod_xgcd(const mp_int * a,const mp_int * m,mp_int * c)2258f9fbec18Smcpowers mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c)
2259f9fbec18Smcpowers {
2260f9fbec18Smcpowers mp_int g, x;
2261f9fbec18Smcpowers mp_err res;
2262f9fbec18Smcpowers
2263f9fbec18Smcpowers ARGCHK(a && m && c, MP_BADARG);
2264f9fbec18Smcpowers
2265f9fbec18Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
2266f9fbec18Smcpowers return MP_RANGE;
2267f9fbec18Smcpowers
2268f9fbec18Smcpowers MP_DIGITS(&g) = 0;
2269f9fbec18Smcpowers MP_DIGITS(&x) = 0;
2270f9fbec18Smcpowers MP_CHECKOK( mp_init(&x, FLAG(a)) );
2271f9fbec18Smcpowers MP_CHECKOK( mp_init(&g, FLAG(a)) );
2272f9fbec18Smcpowers
2273f9fbec18Smcpowers MP_CHECKOK( mp_xgcd(a, m, &g, &x, NULL) );
2274f9fbec18Smcpowers
2275f9fbec18Smcpowers if (mp_cmp_d(&g, 1) != MP_EQ) {
2276f9fbec18Smcpowers res = MP_UNDEF;
2277f9fbec18Smcpowers goto CLEANUP;
2278f9fbec18Smcpowers }
2279f9fbec18Smcpowers
2280f9fbec18Smcpowers res = mp_mod(&x, m, c);
2281f9fbec18Smcpowers SIGN(c) = SIGN(a);
2282f9fbec18Smcpowers
2283f9fbec18Smcpowers CLEANUP:
2284f9fbec18Smcpowers mp_clear(&x);
2285f9fbec18Smcpowers mp_clear(&g);
2286f9fbec18Smcpowers
2287f9fbec18Smcpowers return res;
2288f9fbec18Smcpowers }
2289f9fbec18Smcpowers
2290f9fbec18Smcpowers /* modular inverse where modulus is 2**k. */
2291f9fbec18Smcpowers /* c = a**-1 mod 2**k */
s_mp_invmod_2d(const mp_int * a,mp_size k,mp_int * c)2292f9fbec18Smcpowers mp_err s_mp_invmod_2d(const mp_int *a, mp_size k, mp_int *c)
2293f9fbec18Smcpowers {
2294f9fbec18Smcpowers mp_err res;
2295f9fbec18Smcpowers mp_size ix = k + 4;
2296f9fbec18Smcpowers mp_int t0, t1, val, tmp, two2k;
2297f9fbec18Smcpowers
2298f9fbec18Smcpowers static const mp_digit d2 = 2;
2299f9fbec18Smcpowers static const mp_int two = { 0, MP_ZPOS, 1, 1, (mp_digit *)&d2 };
2300f9fbec18Smcpowers
2301f9fbec18Smcpowers if (mp_iseven(a))
2302f9fbec18Smcpowers return MP_UNDEF;
2303f9fbec18Smcpowers if (k <= MP_DIGIT_BIT) {
2304f9fbec18Smcpowers mp_digit i = s_mp_invmod_radix(MP_DIGIT(a,0));
2305f9fbec18Smcpowers if (k < MP_DIGIT_BIT)
2306f9fbec18Smcpowers i &= ((mp_digit)1 << k) - (mp_digit)1;
2307f9fbec18Smcpowers mp_set(c, i);
2308f9fbec18Smcpowers return MP_OKAY;
2309f9fbec18Smcpowers }
2310f9fbec18Smcpowers MP_DIGITS(&t0) = 0;
2311f9fbec18Smcpowers MP_DIGITS(&t1) = 0;
2312f9fbec18Smcpowers MP_DIGITS(&val) = 0;
2313f9fbec18Smcpowers MP_DIGITS(&tmp) = 0;
2314f9fbec18Smcpowers MP_DIGITS(&two2k) = 0;
2315f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&val, a) );
2316f9fbec18Smcpowers s_mp_mod_2d(&val, k);
2317f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&t0, &val) );
2318f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&t1, &t0) );
2319f9fbec18Smcpowers MP_CHECKOK( mp_init(&tmp, FLAG(a)) );
2320f9fbec18Smcpowers MP_CHECKOK( mp_init(&two2k, FLAG(a)) );
2321f9fbec18Smcpowers MP_CHECKOK( s_mp_2expt(&two2k, k) );
2322f9fbec18Smcpowers do {
2323f9fbec18Smcpowers MP_CHECKOK( mp_mul(&val, &t1, &tmp) );
2324f9fbec18Smcpowers MP_CHECKOK( mp_sub(&two, &tmp, &tmp) );
2325f9fbec18Smcpowers MP_CHECKOK( mp_mul(&t1, &tmp, &t1) );
2326f9fbec18Smcpowers s_mp_mod_2d(&t1, k);
2327f9fbec18Smcpowers while (MP_SIGN(&t1) != MP_ZPOS) {
2328f9fbec18Smcpowers MP_CHECKOK( mp_add(&t1, &two2k, &t1) );
2329f9fbec18Smcpowers }
2330*55fea89dSDan Cross if (mp_cmp(&t1, &t0) == MP_EQ)
2331f9fbec18Smcpowers break;
2332f9fbec18Smcpowers MP_CHECKOK( mp_copy(&t1, &t0) );
2333f9fbec18Smcpowers } while (--ix > 0);
2334f9fbec18Smcpowers if (!ix) {
2335f9fbec18Smcpowers res = MP_UNDEF;
2336f9fbec18Smcpowers } else {
2337f9fbec18Smcpowers mp_exch(c, &t1);
2338f9fbec18Smcpowers }
2339f9fbec18Smcpowers
2340f9fbec18Smcpowers CLEANUP:
2341f9fbec18Smcpowers mp_clear(&t0);
2342f9fbec18Smcpowers mp_clear(&t1);
2343f9fbec18Smcpowers mp_clear(&val);
2344f9fbec18Smcpowers mp_clear(&tmp);
2345f9fbec18Smcpowers mp_clear(&two2k);
2346f9fbec18Smcpowers return res;
2347f9fbec18Smcpowers }
2348f9fbec18Smcpowers
s_mp_invmod_even_m(const mp_int * a,const mp_int * m,mp_int * c)2349f9fbec18Smcpowers mp_err s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c)
2350f9fbec18Smcpowers {
2351f9fbec18Smcpowers mp_err res;
2352f9fbec18Smcpowers mp_size k;
2353f9fbec18Smcpowers mp_int oddFactor, evenFactor; /* factors of the modulus */
2354f9fbec18Smcpowers mp_int oddPart, evenPart; /* parts to combine via CRT. */
2355f9fbec18Smcpowers mp_int C2, tmp1, tmp2;
2356f9fbec18Smcpowers
2357f9fbec18Smcpowers /*static const mp_digit d1 = 1; */
2358f9fbec18Smcpowers /*static const mp_int one = { MP_ZPOS, 1, 1, (mp_digit *)&d1 }; */
2359f9fbec18Smcpowers
2360f9fbec18Smcpowers if ((res = s_mp_ispow2(m)) >= 0) {
2361f9fbec18Smcpowers k = res;
2362f9fbec18Smcpowers return s_mp_invmod_2d(a, k, c);
2363f9fbec18Smcpowers }
2364f9fbec18Smcpowers MP_DIGITS(&oddFactor) = 0;
2365f9fbec18Smcpowers MP_DIGITS(&evenFactor) = 0;
2366f9fbec18Smcpowers MP_DIGITS(&oddPart) = 0;
2367f9fbec18Smcpowers MP_DIGITS(&evenPart) = 0;
2368f9fbec18Smcpowers MP_DIGITS(&C2) = 0;
2369f9fbec18Smcpowers MP_DIGITS(&tmp1) = 0;
2370f9fbec18Smcpowers MP_DIGITS(&tmp2) = 0;
2371f9fbec18Smcpowers
2372f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&oddFactor, m) ); /* oddFactor = m */
2373f9fbec18Smcpowers MP_CHECKOK( mp_init(&evenFactor, FLAG(m)) );
2374f9fbec18Smcpowers MP_CHECKOK( mp_init(&oddPart, FLAG(m)) );
2375f9fbec18Smcpowers MP_CHECKOK( mp_init(&evenPart, FLAG(m)) );
2376f9fbec18Smcpowers MP_CHECKOK( mp_init(&C2, FLAG(m)) );
2377f9fbec18Smcpowers MP_CHECKOK( mp_init(&tmp1, FLAG(m)) );
2378f9fbec18Smcpowers MP_CHECKOK( mp_init(&tmp2, FLAG(m)) );
2379f9fbec18Smcpowers
2380f9fbec18Smcpowers k = mp_trailing_zeros(m);
2381f9fbec18Smcpowers s_mp_div_2d(&oddFactor, k);
2382f9fbec18Smcpowers MP_CHECKOK( s_mp_2expt(&evenFactor, k) );
2383f9fbec18Smcpowers
2384f9fbec18Smcpowers /* compute a**-1 mod oddFactor. */
2385f9fbec18Smcpowers MP_CHECKOK( s_mp_invmod_odd_m(a, &oddFactor, &oddPart) );
2386f9fbec18Smcpowers /* compute a**-1 mod evenFactor, where evenFactor == 2**k. */
2387f9fbec18Smcpowers MP_CHECKOK( s_mp_invmod_2d( a, k, &evenPart) );
2388f9fbec18Smcpowers
2389f9fbec18Smcpowers /* Use Chinese Remainer theorem to compute a**-1 mod m. */
2390*55fea89dSDan Cross /* let m1 = oddFactor, v1 = oddPart,
2391f9fbec18Smcpowers * let m2 = evenFactor, v2 = evenPart.
2392f9fbec18Smcpowers */
2393f9fbec18Smcpowers
2394f9fbec18Smcpowers /* Compute C2 = m1**-1 mod m2. */
2395f9fbec18Smcpowers MP_CHECKOK( s_mp_invmod_2d(&oddFactor, k, &C2) );
2396f9fbec18Smcpowers
2397f9fbec18Smcpowers /* compute u = (v2 - v1)*C2 mod m2 */
2398f9fbec18Smcpowers MP_CHECKOK( mp_sub(&evenPart, &oddPart, &tmp1) );
2399f9fbec18Smcpowers MP_CHECKOK( mp_mul(&tmp1, &C2, &tmp2) );
2400f9fbec18Smcpowers s_mp_mod_2d(&tmp2, k);
2401f9fbec18Smcpowers while (MP_SIGN(&tmp2) != MP_ZPOS) {
2402f9fbec18Smcpowers MP_CHECKOK( mp_add(&tmp2, &evenFactor, &tmp2) );
2403f9fbec18Smcpowers }
2404f9fbec18Smcpowers
2405f9fbec18Smcpowers /* compute answer = v1 + u*m1 */
2406f9fbec18Smcpowers MP_CHECKOK( mp_mul(&tmp2, &oddFactor, c) );
2407f9fbec18Smcpowers MP_CHECKOK( mp_add(&oddPart, c, c) );
2408f9fbec18Smcpowers /* not sure this is necessary, but it's low cost if not. */
2409f9fbec18Smcpowers MP_CHECKOK( mp_mod(c, m, c) );
2410f9fbec18Smcpowers
2411f9fbec18Smcpowers CLEANUP:
2412f9fbec18Smcpowers mp_clear(&oddFactor);
2413f9fbec18Smcpowers mp_clear(&evenFactor);
2414f9fbec18Smcpowers mp_clear(&oddPart);
2415f9fbec18Smcpowers mp_clear(&evenPart);
2416f9fbec18Smcpowers mp_clear(&C2);
2417f9fbec18Smcpowers mp_clear(&tmp1);
2418f9fbec18Smcpowers mp_clear(&tmp2);
2419f9fbec18Smcpowers return res;
2420f9fbec18Smcpowers }
2421f9fbec18Smcpowers
2422f9fbec18Smcpowers
2423f9fbec18Smcpowers /* {{{ mp_invmod(a, m, c) */
2424f9fbec18Smcpowers
2425f9fbec18Smcpowers /*
2426f9fbec18Smcpowers mp_invmod(a, m, c)
2427f9fbec18Smcpowers
2428f9fbec18Smcpowers Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
2429f9fbec18Smcpowers This is equivalent to the question of whether (a, m) = 1. If not,
2430f9fbec18Smcpowers MP_UNDEF is returned, and there is no inverse.
2431f9fbec18Smcpowers */
2432f9fbec18Smcpowers
mp_invmod(const mp_int * a,const mp_int * m,mp_int * c)2433f9fbec18Smcpowers mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c)
2434f9fbec18Smcpowers {
2435f9fbec18Smcpowers
2436f9fbec18Smcpowers ARGCHK(a && m && c, MP_BADARG);
2437f9fbec18Smcpowers
2438f9fbec18Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
2439f9fbec18Smcpowers return MP_RANGE;
2440f9fbec18Smcpowers
2441f9fbec18Smcpowers if (mp_isodd(m)) {
2442f9fbec18Smcpowers return s_mp_invmod_odd_m(a, m, c);
2443f9fbec18Smcpowers }
2444f9fbec18Smcpowers if (mp_iseven(a))
2445f9fbec18Smcpowers return MP_UNDEF; /* not invertable */
2446f9fbec18Smcpowers
2447f9fbec18Smcpowers return s_mp_invmod_even_m(a, m, c);
2448f9fbec18Smcpowers
2449f9fbec18Smcpowers } /* end mp_invmod() */
2450f9fbec18Smcpowers
2451f9fbec18Smcpowers /* }}} */
2452f9fbec18Smcpowers #endif /* if MP_NUMTH */
2453f9fbec18Smcpowers
2454f9fbec18Smcpowers /* }}} */
2455f9fbec18Smcpowers
2456f9fbec18Smcpowers /*------------------------------------------------------------------------*/
2457f9fbec18Smcpowers /* {{{ mp_print(mp, ofp) */
2458f9fbec18Smcpowers
2459f9fbec18Smcpowers #if MP_IOFUNC
2460f9fbec18Smcpowers /*
2461f9fbec18Smcpowers mp_print(mp, ofp)
2462f9fbec18Smcpowers
2463f9fbec18Smcpowers Print a textual representation of the given mp_int on the output
2464f9fbec18Smcpowers stream 'ofp'. Output is generated using the internal radix.
2465f9fbec18Smcpowers */
2466f9fbec18Smcpowers
mp_print(mp_int * mp,FILE * ofp)2467f9fbec18Smcpowers void mp_print(mp_int *mp, FILE *ofp)
2468f9fbec18Smcpowers {
2469f9fbec18Smcpowers int ix;
2470f9fbec18Smcpowers
2471f9fbec18Smcpowers if(mp == NULL || ofp == NULL)
2472f9fbec18Smcpowers return;
2473f9fbec18Smcpowers
2474f9fbec18Smcpowers fputc((SIGN(mp) == NEG) ? '-' : '+', ofp);
2475f9fbec18Smcpowers
2476f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
2477f9fbec18Smcpowers fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
2478f9fbec18Smcpowers }
2479f9fbec18Smcpowers
2480f9fbec18Smcpowers } /* end mp_print() */
2481f9fbec18Smcpowers
2482f9fbec18Smcpowers #endif /* if MP_IOFUNC */
2483f9fbec18Smcpowers
2484f9fbec18Smcpowers /* }}} */
2485f9fbec18Smcpowers
2486f9fbec18Smcpowers /*------------------------------------------------------------------------*/
2487f9fbec18Smcpowers /* {{{ More I/O Functions */
2488f9fbec18Smcpowers
2489f9fbec18Smcpowers /* {{{ mp_read_raw(mp, str, len) */
2490f9fbec18Smcpowers
2491*55fea89dSDan Cross /*
2492f9fbec18Smcpowers mp_read_raw(mp, str, len)
2493f9fbec18Smcpowers
2494f9fbec18Smcpowers Read in a raw value (base 256) into the given mp_int
2495f9fbec18Smcpowers */
2496f9fbec18Smcpowers
mp_read_raw(mp_int * mp,char * str,int len)2497f9fbec18Smcpowers mp_err mp_read_raw(mp_int *mp, char *str, int len)
2498f9fbec18Smcpowers {
2499f9fbec18Smcpowers int ix;
2500f9fbec18Smcpowers mp_err res;
2501f9fbec18Smcpowers unsigned char *ustr = (unsigned char *)str;
2502f9fbec18Smcpowers
2503f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
2504f9fbec18Smcpowers
2505f9fbec18Smcpowers mp_zero(mp);
2506f9fbec18Smcpowers
2507f9fbec18Smcpowers /* Get sign from first byte */
2508f9fbec18Smcpowers if(ustr[0])
2509f9fbec18Smcpowers SIGN(mp) = NEG;
2510f9fbec18Smcpowers else
2511f9fbec18Smcpowers SIGN(mp) = ZPOS;
2512f9fbec18Smcpowers
2513f9fbec18Smcpowers /* Read the rest of the digits */
2514f9fbec18Smcpowers for(ix = 1; ix < len; ix++) {
2515f9fbec18Smcpowers if((res = mp_mul_d(mp, 256, mp)) != MP_OKAY)
2516f9fbec18Smcpowers return res;
2517f9fbec18Smcpowers if((res = mp_add_d(mp, ustr[ix], mp)) != MP_OKAY)
2518f9fbec18Smcpowers return res;
2519f9fbec18Smcpowers }
2520f9fbec18Smcpowers
2521f9fbec18Smcpowers return MP_OKAY;
2522f9fbec18Smcpowers
2523f9fbec18Smcpowers } /* end mp_read_raw() */
2524f9fbec18Smcpowers
2525f9fbec18Smcpowers /* }}} */
2526f9fbec18Smcpowers
2527f9fbec18Smcpowers /* {{{ mp_raw_size(mp) */
2528f9fbec18Smcpowers
mp_raw_size(mp_int * mp)2529f9fbec18Smcpowers int mp_raw_size(mp_int *mp)
2530f9fbec18Smcpowers {
2531f9fbec18Smcpowers ARGCHK(mp != NULL, 0);
2532f9fbec18Smcpowers
2533f9fbec18Smcpowers return (USED(mp) * sizeof(mp_digit)) + 1;
2534f9fbec18Smcpowers
2535f9fbec18Smcpowers } /* end mp_raw_size() */
2536f9fbec18Smcpowers
2537f9fbec18Smcpowers /* }}} */
2538f9fbec18Smcpowers
2539f9fbec18Smcpowers /* {{{ mp_toraw(mp, str) */
2540f9fbec18Smcpowers
mp_toraw(mp_int * mp,char * str)2541f9fbec18Smcpowers mp_err mp_toraw(mp_int *mp, char *str)
2542f9fbec18Smcpowers {
2543f9fbec18Smcpowers int ix, jx, pos = 1;
2544f9fbec18Smcpowers
2545f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL, MP_BADARG);
2546f9fbec18Smcpowers
2547f9fbec18Smcpowers str[0] = (char)SIGN(mp);
2548f9fbec18Smcpowers
2549f9fbec18Smcpowers /* Iterate over each digit... */
2550f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
2551f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix);
2552f9fbec18Smcpowers
2553f9fbec18Smcpowers /* Unpack digit bytes, high order first */
2554f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
2555f9fbec18Smcpowers str[pos++] = (char)(d >> (jx * CHAR_BIT));
2556f9fbec18Smcpowers }
2557f9fbec18Smcpowers }
2558f9fbec18Smcpowers
2559f9fbec18Smcpowers return MP_OKAY;
2560f9fbec18Smcpowers
2561f9fbec18Smcpowers } /* end mp_toraw() */
2562f9fbec18Smcpowers
2563f9fbec18Smcpowers /* }}} */
2564f9fbec18Smcpowers
2565f9fbec18Smcpowers /* {{{ mp_read_radix(mp, str, radix) */
2566f9fbec18Smcpowers
2567f9fbec18Smcpowers /*
2568f9fbec18Smcpowers mp_read_radix(mp, str, radix)
2569f9fbec18Smcpowers
2570f9fbec18Smcpowers Read an integer from the given string, and set mp to the resulting
2571f9fbec18Smcpowers value. The input is presumed to be in base 10. Leading non-digit
2572f9fbec18Smcpowers characters are ignored, and the function reads until a non-digit
2573f9fbec18Smcpowers character or the end of the string.
2574f9fbec18Smcpowers */
2575f9fbec18Smcpowers
mp_read_radix(mp_int * mp,const char * str,int radix)2576f9fbec18Smcpowers mp_err mp_read_radix(mp_int *mp, const char *str, int radix)
2577f9fbec18Smcpowers {
2578f9fbec18Smcpowers int ix = 0, val = 0;
2579f9fbec18Smcpowers mp_err res;
2580f9fbec18Smcpowers mp_sign sig = ZPOS;
2581f9fbec18Smcpowers
2582*55fea89dSDan Cross ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX,
2583f9fbec18Smcpowers MP_BADARG);
2584f9fbec18Smcpowers
2585f9fbec18Smcpowers mp_zero(mp);
2586f9fbec18Smcpowers
2587f9fbec18Smcpowers /* Skip leading non-digit characters until a digit or '-' or '+' */
2588*55fea89dSDan Cross while(str[ix] &&
2589*55fea89dSDan Cross (s_mp_tovalue(str[ix], radix) < 0) &&
2590f9fbec18Smcpowers str[ix] != '-' &&
2591f9fbec18Smcpowers str[ix] != '+') {
2592f9fbec18Smcpowers ++ix;
2593f9fbec18Smcpowers }
2594f9fbec18Smcpowers
2595f9fbec18Smcpowers if(str[ix] == '-') {
2596f9fbec18Smcpowers sig = NEG;
2597f9fbec18Smcpowers ++ix;
2598f9fbec18Smcpowers } else if(str[ix] == '+') {
2599f9fbec18Smcpowers sig = ZPOS; /* this is the default anyway... */
2600f9fbec18Smcpowers ++ix;
2601f9fbec18Smcpowers }
2602f9fbec18Smcpowers
2603f9fbec18Smcpowers while((val = s_mp_tovalue(str[ix], radix)) >= 0) {
2604f9fbec18Smcpowers if((res = s_mp_mul_d(mp, radix)) != MP_OKAY)
2605f9fbec18Smcpowers return res;
2606f9fbec18Smcpowers if((res = s_mp_add_d(mp, val)) != MP_OKAY)
2607f9fbec18Smcpowers return res;
2608f9fbec18Smcpowers ++ix;
2609f9fbec18Smcpowers }
2610f9fbec18Smcpowers
2611f9fbec18Smcpowers if(s_mp_cmp_d(mp, 0) == MP_EQ)
2612f9fbec18Smcpowers SIGN(mp) = ZPOS;
2613f9fbec18Smcpowers else
2614f9fbec18Smcpowers SIGN(mp) = sig;
2615f9fbec18Smcpowers
2616f9fbec18Smcpowers return MP_OKAY;
2617f9fbec18Smcpowers
2618f9fbec18Smcpowers } /* end mp_read_radix() */
2619f9fbec18Smcpowers
mp_read_variable_radix(mp_int * a,const char * str,int default_radix)2620f9fbec18Smcpowers mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix)
2621f9fbec18Smcpowers {
2622f9fbec18Smcpowers int radix = default_radix;
2623f9fbec18Smcpowers int cx;
2624f9fbec18Smcpowers mp_sign sig = ZPOS;
2625f9fbec18Smcpowers mp_err res;
2626f9fbec18Smcpowers
2627f9fbec18Smcpowers /* Skip leading non-digit characters until a digit or '-' or '+' */
2628*55fea89dSDan Cross while ((cx = *str) != 0 &&
2629*55fea89dSDan Cross (s_mp_tovalue(cx, radix) < 0) &&
2630f9fbec18Smcpowers cx != '-' &&
2631f9fbec18Smcpowers cx != '+') {
2632f9fbec18Smcpowers ++str;
2633f9fbec18Smcpowers }
2634f9fbec18Smcpowers
2635f9fbec18Smcpowers if (cx == '-') {
2636f9fbec18Smcpowers sig = NEG;
2637f9fbec18Smcpowers ++str;
2638f9fbec18Smcpowers } else if (cx == '+') {
2639f9fbec18Smcpowers sig = ZPOS; /* this is the default anyway... */
2640f9fbec18Smcpowers ++str;
2641f9fbec18Smcpowers }
2642f9fbec18Smcpowers
2643f9fbec18Smcpowers if (str[0] == '0') {
2644f9fbec18Smcpowers if ((str[1] | 0x20) == 'x') {
2645f9fbec18Smcpowers radix = 16;
2646f9fbec18Smcpowers str += 2;
2647f9fbec18Smcpowers } else {
2648f9fbec18Smcpowers radix = 8;
2649f9fbec18Smcpowers str++;
2650f9fbec18Smcpowers }
2651f9fbec18Smcpowers }
2652f9fbec18Smcpowers res = mp_read_radix(a, str, radix);
2653f9fbec18Smcpowers if (res == MP_OKAY) {
2654f9fbec18Smcpowers MP_SIGN(a) = (s_mp_cmp_d(a, 0) == MP_EQ) ? ZPOS : sig;
2655f9fbec18Smcpowers }
2656f9fbec18Smcpowers return res;
2657f9fbec18Smcpowers }
2658f9fbec18Smcpowers
2659f9fbec18Smcpowers /* }}} */
2660f9fbec18Smcpowers
2661f9fbec18Smcpowers /* {{{ mp_radix_size(mp, radix) */
2662f9fbec18Smcpowers
mp_radix_size(mp_int * mp,int radix)2663f9fbec18Smcpowers int mp_radix_size(mp_int *mp, int radix)
2664f9fbec18Smcpowers {
2665f9fbec18Smcpowers int bits;
2666f9fbec18Smcpowers
2667f9fbec18Smcpowers if(!mp || radix < 2 || radix > MAX_RADIX)
2668f9fbec18Smcpowers return 0;
2669f9fbec18Smcpowers
2670f9fbec18Smcpowers bits = USED(mp) * DIGIT_BIT - 1;
2671*55fea89dSDan Cross
2672f9fbec18Smcpowers return s_mp_outlen(bits, radix);
2673f9fbec18Smcpowers
2674f9fbec18Smcpowers } /* end mp_radix_size() */
2675f9fbec18Smcpowers
2676f9fbec18Smcpowers /* }}} */
2677f9fbec18Smcpowers
2678f9fbec18Smcpowers /* {{{ mp_toradix(mp, str, radix) */
2679f9fbec18Smcpowers
mp_toradix(mp_int * mp,char * str,int radix)2680f9fbec18Smcpowers mp_err mp_toradix(mp_int *mp, char *str, int radix)
2681f9fbec18Smcpowers {
2682f9fbec18Smcpowers int ix, pos = 0;
2683f9fbec18Smcpowers
2684f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL, MP_BADARG);
2685f9fbec18Smcpowers ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
2686f9fbec18Smcpowers
2687f9fbec18Smcpowers if(mp_cmp_z(mp) == MP_EQ) {
2688f9fbec18Smcpowers str[0] = '0';
2689f9fbec18Smcpowers str[1] = '\0';
2690f9fbec18Smcpowers } else {
2691f9fbec18Smcpowers mp_err res;
2692f9fbec18Smcpowers mp_int tmp;
2693f9fbec18Smcpowers mp_sign sgn;
2694f9fbec18Smcpowers mp_digit rem, rdx = (mp_digit)radix;
2695f9fbec18Smcpowers char ch;
2696f9fbec18Smcpowers
2697f9fbec18Smcpowers if((res = mp_init_copy(&tmp, mp)) != MP_OKAY)
2698f9fbec18Smcpowers return res;
2699f9fbec18Smcpowers
2700f9fbec18Smcpowers /* Save sign for later, and take absolute value */
2701f9fbec18Smcpowers sgn = SIGN(&tmp); SIGN(&tmp) = ZPOS;
2702f9fbec18Smcpowers
2703f9fbec18Smcpowers /* Generate output digits in reverse order */
2704f9fbec18Smcpowers while(mp_cmp_z(&tmp) != 0) {
2705f9fbec18Smcpowers if((res = mp_div_d(&tmp, rdx, &tmp, &rem)) != MP_OKAY) {
2706f9fbec18Smcpowers mp_clear(&tmp);
2707f9fbec18Smcpowers return res;
2708f9fbec18Smcpowers }
2709f9fbec18Smcpowers
2710f9fbec18Smcpowers /* Generate digits, use capital letters */
2711f9fbec18Smcpowers ch = s_mp_todigit(rem, radix, 0);
2712f9fbec18Smcpowers
2713f9fbec18Smcpowers str[pos++] = ch;
2714f9fbec18Smcpowers }
2715f9fbec18Smcpowers
2716f9fbec18Smcpowers /* Add - sign if original value was negative */
2717f9fbec18Smcpowers if(sgn == NEG)
2718f9fbec18Smcpowers str[pos++] = '-';
2719f9fbec18Smcpowers
2720f9fbec18Smcpowers /* Add trailing NUL to end the string */
2721f9fbec18Smcpowers str[pos--] = '\0';
2722f9fbec18Smcpowers
2723f9fbec18Smcpowers /* Reverse the digits and sign indicator */
2724f9fbec18Smcpowers ix = 0;
2725f9fbec18Smcpowers while(ix < pos) {
2726f9fbec18Smcpowers char tmp = str[ix];
2727f9fbec18Smcpowers
2728f9fbec18Smcpowers str[ix] = str[pos];
2729f9fbec18Smcpowers str[pos] = tmp;
2730f9fbec18Smcpowers ++ix;
2731f9fbec18Smcpowers --pos;
2732f9fbec18Smcpowers }
2733*55fea89dSDan Cross
2734f9fbec18Smcpowers mp_clear(&tmp);
2735f9fbec18Smcpowers }
2736f9fbec18Smcpowers
2737f9fbec18Smcpowers return MP_OKAY;
2738f9fbec18Smcpowers
2739f9fbec18Smcpowers } /* end mp_toradix() */
2740f9fbec18Smcpowers
2741f9fbec18Smcpowers /* }}} */
2742f9fbec18Smcpowers
2743f9fbec18Smcpowers /* {{{ mp_tovalue(ch, r) */
2744f9fbec18Smcpowers
mp_tovalue(char ch,int r)2745f9fbec18Smcpowers int mp_tovalue(char ch, int r)
2746f9fbec18Smcpowers {
2747f9fbec18Smcpowers return s_mp_tovalue(ch, r);
2748f9fbec18Smcpowers
2749f9fbec18Smcpowers } /* end mp_tovalue() */
2750f9fbec18Smcpowers
2751f9fbec18Smcpowers /* }}} */
2752f9fbec18Smcpowers
2753f9fbec18Smcpowers /* }}} */
2754f9fbec18Smcpowers
2755f9fbec18Smcpowers /* {{{ mp_strerror(ec) */
2756f9fbec18Smcpowers
2757f9fbec18Smcpowers /*
2758f9fbec18Smcpowers mp_strerror(ec)
2759f9fbec18Smcpowers
2760f9fbec18Smcpowers Return a string describing the meaning of error code 'ec'. The
2761f9fbec18Smcpowers string returned is allocated in static memory, so the caller should
2762f9fbec18Smcpowers not attempt to modify or free the memory associated with this
2763f9fbec18Smcpowers string.
2764f9fbec18Smcpowers */
mp_strerror(mp_err ec)2765f9fbec18Smcpowers const char *mp_strerror(mp_err ec)
2766f9fbec18Smcpowers {
2767f9fbec18Smcpowers int aec = (ec < 0) ? -ec : ec;
2768f9fbec18Smcpowers
2769f9fbec18Smcpowers /* Code values are negative, so the senses of these comparisons
2770f9fbec18Smcpowers are accurate */
2771f9fbec18Smcpowers if(ec < MP_LAST_CODE || ec > MP_OKAY) {
2772f9fbec18Smcpowers return mp_err_string[0]; /* unknown error code */
2773f9fbec18Smcpowers } else {
2774f9fbec18Smcpowers return mp_err_string[aec + 1];
2775f9fbec18Smcpowers }
2776f9fbec18Smcpowers
2777f9fbec18Smcpowers } /* end mp_strerror() */
2778f9fbec18Smcpowers
2779f9fbec18Smcpowers /* }}} */
2780f9fbec18Smcpowers
2781f9fbec18Smcpowers /*========================================================================*/
2782f9fbec18Smcpowers /*------------------------------------------------------------------------*/
2783f9fbec18Smcpowers /* Static function definitions (internal use only) */
2784f9fbec18Smcpowers
2785f9fbec18Smcpowers /* {{{ Memory management */
2786f9fbec18Smcpowers
2787f9fbec18Smcpowers /* {{{ s_mp_grow(mp, min) */
2788f9fbec18Smcpowers
2789f9fbec18Smcpowers /* Make sure there are at least 'min' digits allocated to mp */
s_mp_grow(mp_int * mp,mp_size min)2790f9fbec18Smcpowers mp_err s_mp_grow(mp_int *mp, mp_size min)
2791f9fbec18Smcpowers {
2792f9fbec18Smcpowers if(min > ALLOC(mp)) {
2793f9fbec18Smcpowers mp_digit *tmp;
2794f9fbec18Smcpowers
2795f9fbec18Smcpowers /* Set min to next nearest default precision block size */
2796f9fbec18Smcpowers min = MP_ROUNDUP(min, s_mp_defprec);
2797f9fbec18Smcpowers
2798f9fbec18Smcpowers if((tmp = s_mp_alloc(min, sizeof(mp_digit), FLAG(mp))) == NULL)
2799f9fbec18Smcpowers return MP_MEM;
2800f9fbec18Smcpowers
2801f9fbec18Smcpowers s_mp_copy(DIGITS(mp), tmp, USED(mp));
2802f9fbec18Smcpowers
2803f9fbec18Smcpowers #if MP_CRYPTO
2804f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
2805f9fbec18Smcpowers #endif
2806f9fbec18Smcpowers s_mp_free(DIGITS(mp), ALLOC(mp));
2807f9fbec18Smcpowers DIGITS(mp) = tmp;
2808f9fbec18Smcpowers ALLOC(mp) = min;
2809f9fbec18Smcpowers }
2810f9fbec18Smcpowers
2811f9fbec18Smcpowers return MP_OKAY;
2812f9fbec18Smcpowers
2813f9fbec18Smcpowers } /* end s_mp_grow() */
2814f9fbec18Smcpowers
2815f9fbec18Smcpowers /* }}} */
2816f9fbec18Smcpowers
2817f9fbec18Smcpowers /* {{{ s_mp_pad(mp, min) */
2818f9fbec18Smcpowers
2819f9fbec18Smcpowers /* Make sure the used size of mp is at least 'min', growing if needed */
s_mp_pad(mp_int * mp,mp_size min)2820f9fbec18Smcpowers mp_err s_mp_pad(mp_int *mp, mp_size min)
2821f9fbec18Smcpowers {
2822f9fbec18Smcpowers if(min > USED(mp)) {
2823f9fbec18Smcpowers mp_err res;
2824f9fbec18Smcpowers
2825f9fbec18Smcpowers /* Make sure there is room to increase precision */
2826f9fbec18Smcpowers if (min > ALLOC(mp)) {
2827f9fbec18Smcpowers if ((res = s_mp_grow(mp, min)) != MP_OKAY)
2828f9fbec18Smcpowers return res;
2829f9fbec18Smcpowers } else {
2830f9fbec18Smcpowers s_mp_setz(DIGITS(mp) + USED(mp), min - USED(mp));
2831f9fbec18Smcpowers }
2832f9fbec18Smcpowers
2833f9fbec18Smcpowers /* Increase precision; should already be 0-filled */
2834f9fbec18Smcpowers USED(mp) = min;
2835f9fbec18Smcpowers }
2836f9fbec18Smcpowers
2837f9fbec18Smcpowers return MP_OKAY;
2838f9fbec18Smcpowers
2839f9fbec18Smcpowers } /* end s_mp_pad() */
2840f9fbec18Smcpowers
2841f9fbec18Smcpowers /* }}} */
2842f9fbec18Smcpowers
2843f9fbec18Smcpowers /* {{{ s_mp_setz(dp, count) */
2844f9fbec18Smcpowers
2845f9fbec18Smcpowers #if MP_MACRO == 0
2846f9fbec18Smcpowers /* Set 'count' digits pointed to by dp to be zeroes */
s_mp_setz(mp_digit * dp,mp_size count)2847f9fbec18Smcpowers void s_mp_setz(mp_digit *dp, mp_size count)
2848f9fbec18Smcpowers {
2849f9fbec18Smcpowers #if MP_MEMSET == 0
2850f9fbec18Smcpowers int ix;
2851f9fbec18Smcpowers
2852f9fbec18Smcpowers for(ix = 0; ix < count; ix++)
2853f9fbec18Smcpowers dp[ix] = 0;
2854f9fbec18Smcpowers #else
2855f9fbec18Smcpowers memset(dp, 0, count * sizeof(mp_digit));
2856f9fbec18Smcpowers #endif
2857f9fbec18Smcpowers
2858f9fbec18Smcpowers } /* end s_mp_setz() */
2859f9fbec18Smcpowers #endif
2860f9fbec18Smcpowers
2861f9fbec18Smcpowers /* }}} */
2862f9fbec18Smcpowers
2863f9fbec18Smcpowers /* {{{ s_mp_copy(sp, dp, count) */
2864f9fbec18Smcpowers
2865f9fbec18Smcpowers #if MP_MACRO == 0
2866f9fbec18Smcpowers /* Copy 'count' digits from sp to dp */
s_mp_copy(const mp_digit * sp,mp_digit * dp,mp_size count)2867f9fbec18Smcpowers void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count)
2868f9fbec18Smcpowers {
2869f9fbec18Smcpowers #if MP_MEMCPY == 0
2870f9fbec18Smcpowers int ix;
2871f9fbec18Smcpowers
2872f9fbec18Smcpowers for(ix = 0; ix < count; ix++)
2873f9fbec18Smcpowers dp[ix] = sp[ix];
2874f9fbec18Smcpowers #else
2875f9fbec18Smcpowers memcpy(dp, sp, count * sizeof(mp_digit));
2876f9fbec18Smcpowers #endif
2877f9fbec18Smcpowers
2878f9fbec18Smcpowers } /* end s_mp_copy() */
2879f9fbec18Smcpowers #endif
2880f9fbec18Smcpowers
2881f9fbec18Smcpowers /* }}} */
2882f9fbec18Smcpowers
2883f9fbec18Smcpowers /* {{{ s_mp_alloc(nb, ni, kmflag) */
2884f9fbec18Smcpowers
2885f9fbec18Smcpowers #if MP_MACRO == 0
2886f9fbec18Smcpowers /* Allocate ni records of nb bytes each, and return a pointer to that */
s_mp_alloc(size_t nb,size_t ni,int kmflag)2887f9fbec18Smcpowers void *s_mp_alloc(size_t nb, size_t ni, int kmflag)
2888f9fbec18Smcpowers {
2889f9fbec18Smcpowers ++mp_allocs;
2890f9fbec18Smcpowers #ifdef _KERNEL
2891f2ba9e96SDina K Nimeh return kmem_zalloc(nb * ni, kmflag);
2892f9fbec18Smcpowers #else
2893f9fbec18Smcpowers return calloc(nb, ni);
2894f9fbec18Smcpowers #endif
2895f9fbec18Smcpowers
2896f9fbec18Smcpowers } /* end s_mp_alloc() */
2897f9fbec18Smcpowers #endif
2898f9fbec18Smcpowers
2899f9fbec18Smcpowers /* }}} */
2900f9fbec18Smcpowers
2901f9fbec18Smcpowers /* {{{ s_mp_free(ptr) */
2902f9fbec18Smcpowers
2903f9fbec18Smcpowers #if MP_MACRO == 0
2904f9fbec18Smcpowers /* Free the memory pointed to by ptr */
s_mp_free(void * ptr,mp_size alloc)2905f9fbec18Smcpowers void s_mp_free(void *ptr, mp_size alloc)
2906f9fbec18Smcpowers {
2907f9fbec18Smcpowers if(ptr) {
2908f9fbec18Smcpowers ++mp_frees;
2909f9fbec18Smcpowers #ifdef _KERNEL
2910f9fbec18Smcpowers kmem_free(ptr, alloc * sizeof (mp_digit));
2911f9fbec18Smcpowers #else
2912f9fbec18Smcpowers free(ptr);
2913f9fbec18Smcpowers #endif
2914f9fbec18Smcpowers }
2915f9fbec18Smcpowers } /* end s_mp_free() */
2916f9fbec18Smcpowers #endif
2917f9fbec18Smcpowers
2918f9fbec18Smcpowers /* }}} */
2919f9fbec18Smcpowers
2920f9fbec18Smcpowers /* {{{ s_mp_clamp(mp) */
2921f9fbec18Smcpowers
2922f9fbec18Smcpowers #if MP_MACRO == 0
2923f9fbec18Smcpowers /* Remove leading zeroes from the given value */
s_mp_clamp(mp_int * mp)2924f9fbec18Smcpowers void s_mp_clamp(mp_int *mp)
2925f9fbec18Smcpowers {
2926f9fbec18Smcpowers mp_size used = MP_USED(mp);
2927f9fbec18Smcpowers while (used > 1 && DIGIT(mp, used - 1) == 0)
2928f9fbec18Smcpowers --used;
2929f9fbec18Smcpowers MP_USED(mp) = used;
2930f9fbec18Smcpowers } /* end s_mp_clamp() */
2931f9fbec18Smcpowers #endif
2932f9fbec18Smcpowers
2933f9fbec18Smcpowers /* }}} */
2934f9fbec18Smcpowers
2935f9fbec18Smcpowers /* {{{ s_mp_exch(a, b) */
2936f9fbec18Smcpowers
2937f9fbec18Smcpowers /* Exchange the data for a and b; (b, a) = (a, b) */
s_mp_exch(mp_int * a,mp_int * b)2938f9fbec18Smcpowers void s_mp_exch(mp_int *a, mp_int *b)
2939f9fbec18Smcpowers {
2940f9fbec18Smcpowers mp_int tmp;
2941f9fbec18Smcpowers
2942f9fbec18Smcpowers tmp = *a;
2943f9fbec18Smcpowers *a = *b;
2944f9fbec18Smcpowers *b = tmp;
2945f9fbec18Smcpowers
2946f9fbec18Smcpowers } /* end s_mp_exch() */
2947f9fbec18Smcpowers
2948f9fbec18Smcpowers /* }}} */
2949f9fbec18Smcpowers
2950f9fbec18Smcpowers /* }}} */
2951f9fbec18Smcpowers
2952f9fbec18Smcpowers /* {{{ Arithmetic helpers */
2953f9fbec18Smcpowers
2954f9fbec18Smcpowers /* {{{ s_mp_lshd(mp, p) */
2955f9fbec18Smcpowers
2956*55fea89dSDan Cross /*
2957f9fbec18Smcpowers Shift mp leftward by p digits, growing if needed, and zero-filling
2958f9fbec18Smcpowers the in-shifted digits at the right end. This is a convenient
2959f9fbec18Smcpowers alternative to multiplication by powers of the radix
2960f9fbec18Smcpowers The value of USED(mp) must already have been set to the value for
2961f9fbec18Smcpowers the shifted result.
2962*55fea89dSDan Cross */
2963f9fbec18Smcpowers
s_mp_lshd(mp_int * mp,mp_size p)2964f9fbec18Smcpowers mp_err s_mp_lshd(mp_int *mp, mp_size p)
2965f9fbec18Smcpowers {
2966f9fbec18Smcpowers mp_err res;
2967f9fbec18Smcpowers mp_size pos;
2968f9fbec18Smcpowers int ix;
2969f9fbec18Smcpowers
2970f9fbec18Smcpowers if(p == 0)
2971f9fbec18Smcpowers return MP_OKAY;
2972f9fbec18Smcpowers
2973f9fbec18Smcpowers if (MP_USED(mp) == 1 && MP_DIGIT(mp, 0) == 0)
2974f9fbec18Smcpowers return MP_OKAY;
2975f9fbec18Smcpowers
2976f9fbec18Smcpowers if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
2977f9fbec18Smcpowers return res;
2978f9fbec18Smcpowers
2979f9fbec18Smcpowers pos = USED(mp) - 1;
2980f9fbec18Smcpowers
2981f9fbec18Smcpowers /* Shift all the significant figures over as needed */
2982*55fea89dSDan Cross for(ix = pos - p; ix >= 0; ix--)
2983f9fbec18Smcpowers DIGIT(mp, ix + p) = DIGIT(mp, ix);
2984f9fbec18Smcpowers
2985f9fbec18Smcpowers /* Fill the bottom digits with zeroes */
2986f9fbec18Smcpowers for(ix = 0; ix < p; ix++)
2987f9fbec18Smcpowers DIGIT(mp, ix) = 0;
2988f9fbec18Smcpowers
2989f9fbec18Smcpowers return MP_OKAY;
2990f9fbec18Smcpowers
2991f9fbec18Smcpowers } /* end s_mp_lshd() */
2992f9fbec18Smcpowers
2993f9fbec18Smcpowers /* }}} */
2994f9fbec18Smcpowers
2995f9fbec18Smcpowers /* {{{ s_mp_mul_2d(mp, d) */
2996f9fbec18Smcpowers
2997f9fbec18Smcpowers /*
2998f9fbec18Smcpowers Multiply the integer by 2^d, where d is a number of bits. This
2999f9fbec18Smcpowers amounts to a bitwise shift of the value.
3000f9fbec18Smcpowers */
s_mp_mul_2d(mp_int * mp,mp_digit d)3001f9fbec18Smcpowers mp_err s_mp_mul_2d(mp_int *mp, mp_digit d)
3002f9fbec18Smcpowers {
3003f9fbec18Smcpowers mp_err res;
3004f9fbec18Smcpowers mp_digit dshift, bshift;
3005f9fbec18Smcpowers mp_digit mask;
3006f9fbec18Smcpowers
3007f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG);
3008f9fbec18Smcpowers
3009f9fbec18Smcpowers dshift = d / MP_DIGIT_BIT;
3010f9fbec18Smcpowers bshift = d % MP_DIGIT_BIT;
3011f9fbec18Smcpowers /* bits to be shifted out of the top word */
3012*55fea89dSDan Cross mask = ((mp_digit)~0 << (MP_DIGIT_BIT - bshift));
3013f9fbec18Smcpowers mask &= MP_DIGIT(mp, MP_USED(mp) - 1);
3014f9fbec18Smcpowers
3015f9fbec18Smcpowers if (MP_OKAY != (res = s_mp_pad(mp, MP_USED(mp) + dshift + (mask != 0) )))
3016f9fbec18Smcpowers return res;
3017f9fbec18Smcpowers
3018f9fbec18Smcpowers if (dshift && MP_OKAY != (res = s_mp_lshd(mp, dshift)))
3019f9fbec18Smcpowers return res;
3020f9fbec18Smcpowers
3021*55fea89dSDan Cross if (bshift) {
3022f9fbec18Smcpowers mp_digit *pa = MP_DIGITS(mp);
3023f9fbec18Smcpowers mp_digit *alim = pa + MP_USED(mp);
3024f9fbec18Smcpowers mp_digit prev = 0;
3025f9fbec18Smcpowers
3026f9fbec18Smcpowers for (pa += dshift; pa < alim; ) {
3027f9fbec18Smcpowers mp_digit x = *pa;
3028f9fbec18Smcpowers *pa++ = (x << bshift) | prev;
3029f9fbec18Smcpowers prev = x >> (DIGIT_BIT - bshift);
3030f9fbec18Smcpowers }
3031f9fbec18Smcpowers }
3032f9fbec18Smcpowers
3033f9fbec18Smcpowers s_mp_clamp(mp);
3034f9fbec18Smcpowers return MP_OKAY;
3035f9fbec18Smcpowers } /* end s_mp_mul_2d() */
3036f9fbec18Smcpowers
3037f9fbec18Smcpowers /* {{{ s_mp_rshd(mp, p) */
3038f9fbec18Smcpowers
3039*55fea89dSDan Cross /*
3040f9fbec18Smcpowers Shift mp rightward by p digits. Maintains the invariant that
3041f9fbec18Smcpowers digits above the precision are all zero. Digits shifted off the
3042f9fbec18Smcpowers end are lost. Cannot fail.
3043f9fbec18Smcpowers */
3044f9fbec18Smcpowers
s_mp_rshd(mp_int * mp,mp_size p)3045f9fbec18Smcpowers void s_mp_rshd(mp_int *mp, mp_size p)
3046f9fbec18Smcpowers {
3047f9fbec18Smcpowers mp_size ix;
3048f9fbec18Smcpowers mp_digit *src, *dst;
3049f9fbec18Smcpowers
3050f9fbec18Smcpowers if(p == 0)
3051f9fbec18Smcpowers return;
3052f9fbec18Smcpowers
3053f9fbec18Smcpowers /* Shortcut when all digits are to be shifted off */
3054f9fbec18Smcpowers if(p >= USED(mp)) {
3055f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
3056f9fbec18Smcpowers USED(mp) = 1;
3057f9fbec18Smcpowers SIGN(mp) = ZPOS;
3058f9fbec18Smcpowers return;
3059f9fbec18Smcpowers }
3060f9fbec18Smcpowers
3061f9fbec18Smcpowers /* Shift all the significant figures over as needed */
3062f9fbec18Smcpowers dst = MP_DIGITS(mp);
3063f9fbec18Smcpowers src = dst + p;
3064f9fbec18Smcpowers for (ix = USED(mp) - p; ix > 0; ix--)
3065f9fbec18Smcpowers *dst++ = *src++;
3066f9fbec18Smcpowers
3067f9fbec18Smcpowers MP_USED(mp) -= p;
3068f9fbec18Smcpowers /* Fill the top digits with zeroes */
3069f9fbec18Smcpowers while (p-- > 0)
3070f9fbec18Smcpowers *dst++ = 0;
3071f9fbec18Smcpowers
3072f9fbec18Smcpowers #if 0
3073f9fbec18Smcpowers /* Strip off any leading zeroes */
3074f9fbec18Smcpowers s_mp_clamp(mp);
3075f9fbec18Smcpowers #endif
3076f9fbec18Smcpowers
3077f9fbec18Smcpowers } /* end s_mp_rshd() */
3078f9fbec18Smcpowers
3079f9fbec18Smcpowers /* }}} */
3080f9fbec18Smcpowers
3081f9fbec18Smcpowers /* {{{ s_mp_div_2(mp) */
3082f9fbec18Smcpowers
3083f9fbec18Smcpowers /* Divide by two -- take advantage of radix properties to do it fast */
s_mp_div_2(mp_int * mp)3084f9fbec18Smcpowers void s_mp_div_2(mp_int *mp)
3085f9fbec18Smcpowers {
3086f9fbec18Smcpowers s_mp_div_2d(mp, 1);
3087f9fbec18Smcpowers
3088f9fbec18Smcpowers } /* end s_mp_div_2() */
3089f9fbec18Smcpowers
3090f9fbec18Smcpowers /* }}} */
3091f9fbec18Smcpowers
3092f9fbec18Smcpowers /* {{{ s_mp_mul_2(mp) */
3093f9fbec18Smcpowers
s_mp_mul_2(mp_int * mp)3094f9fbec18Smcpowers mp_err s_mp_mul_2(mp_int *mp)
3095f9fbec18Smcpowers {
3096f9fbec18Smcpowers mp_digit *pd;
3097f9fbec18Smcpowers int ix, used;
3098f9fbec18Smcpowers mp_digit kin = 0;
3099f9fbec18Smcpowers
3100f9fbec18Smcpowers /* Shift digits leftward by 1 bit */
3101f9fbec18Smcpowers used = MP_USED(mp);
3102f9fbec18Smcpowers pd = MP_DIGITS(mp);
3103f9fbec18Smcpowers for (ix = 0; ix < used; ix++) {
3104f9fbec18Smcpowers mp_digit d = *pd;
3105f9fbec18Smcpowers *pd++ = (d << 1) | kin;
3106f9fbec18Smcpowers kin = (d >> (DIGIT_BIT - 1));
3107f9fbec18Smcpowers }
3108f9fbec18Smcpowers
3109f9fbec18Smcpowers /* Deal with rollover from last digit */
3110f9fbec18Smcpowers if (kin) {
3111f9fbec18Smcpowers if (ix >= ALLOC(mp)) {
3112f9fbec18Smcpowers mp_err res;
3113f9fbec18Smcpowers if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
3114f9fbec18Smcpowers return res;
3115f9fbec18Smcpowers }
3116f9fbec18Smcpowers
3117f9fbec18Smcpowers DIGIT(mp, ix) = kin;
3118f9fbec18Smcpowers USED(mp) += 1;
3119f9fbec18Smcpowers }
3120f9fbec18Smcpowers
3121f9fbec18Smcpowers return MP_OKAY;
3122f9fbec18Smcpowers
3123f9fbec18Smcpowers } /* end s_mp_mul_2() */
3124f9fbec18Smcpowers
3125f9fbec18Smcpowers /* }}} */
3126f9fbec18Smcpowers
3127f9fbec18Smcpowers /* {{{ s_mp_mod_2d(mp, d) */
3128f9fbec18Smcpowers
3129f9fbec18Smcpowers /*
3130f9fbec18Smcpowers Remainder the integer by 2^d, where d is a number of bits. This
3131f9fbec18Smcpowers amounts to a bitwise AND of the value, and does not require the full
3132f9fbec18Smcpowers division code
3133f9fbec18Smcpowers */
s_mp_mod_2d(mp_int * mp,mp_digit d)3134f9fbec18Smcpowers void s_mp_mod_2d(mp_int *mp, mp_digit d)
3135f9fbec18Smcpowers {
3136f9fbec18Smcpowers mp_size ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
3137f9fbec18Smcpowers mp_size ix;
3138f9fbec18Smcpowers mp_digit dmask;
3139f9fbec18Smcpowers
3140f9fbec18Smcpowers if(ndig >= USED(mp))
3141f9fbec18Smcpowers return;
3142f9fbec18Smcpowers
3143f9fbec18Smcpowers /* Flush all the bits above 2^d in its digit */
3144f9fbec18Smcpowers dmask = ((mp_digit)1 << nbit) - 1;
3145f9fbec18Smcpowers DIGIT(mp, ndig) &= dmask;
3146f9fbec18Smcpowers
3147f9fbec18Smcpowers /* Flush all digits above the one with 2^d in it */
3148f9fbec18Smcpowers for(ix = ndig + 1; ix < USED(mp); ix++)
3149f9fbec18Smcpowers DIGIT(mp, ix) = 0;
3150f9fbec18Smcpowers
3151f9fbec18Smcpowers s_mp_clamp(mp);
3152f9fbec18Smcpowers
3153f9fbec18Smcpowers } /* end s_mp_mod_2d() */
3154f9fbec18Smcpowers
3155f9fbec18Smcpowers /* }}} */
3156f9fbec18Smcpowers
3157f9fbec18Smcpowers /* {{{ s_mp_div_2d(mp, d) */
3158f9fbec18Smcpowers
3159f9fbec18Smcpowers /*
3160f9fbec18Smcpowers Divide the integer by 2^d, where d is a number of bits. This
3161f9fbec18Smcpowers amounts to a bitwise shift of the value, and does not require the
3162f9fbec18Smcpowers full division code (used in Barrett reduction, see below)
3163f9fbec18Smcpowers */
s_mp_div_2d(mp_int * mp,mp_digit d)3164f9fbec18Smcpowers void s_mp_div_2d(mp_int *mp, mp_digit d)
3165f9fbec18Smcpowers {
3166f9fbec18Smcpowers int ix;
3167f9fbec18Smcpowers mp_digit save, next, mask;
3168f9fbec18Smcpowers
3169f9fbec18Smcpowers s_mp_rshd(mp, d / DIGIT_BIT);
3170f9fbec18Smcpowers d %= DIGIT_BIT;
3171f9fbec18Smcpowers if (d) {
3172f9fbec18Smcpowers mask = ((mp_digit)1 << d) - 1;
3173f9fbec18Smcpowers save = 0;
3174f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
3175f9fbec18Smcpowers next = DIGIT(mp, ix) & mask;
3176f9fbec18Smcpowers DIGIT(mp, ix) = (DIGIT(mp, ix) >> d) | (save << (DIGIT_BIT - d));
3177f9fbec18Smcpowers save = next;
3178f9fbec18Smcpowers }
3179f9fbec18Smcpowers }
3180f9fbec18Smcpowers s_mp_clamp(mp);
3181f9fbec18Smcpowers
3182f9fbec18Smcpowers } /* end s_mp_div_2d() */
3183f9fbec18Smcpowers
3184f9fbec18Smcpowers /* }}} */
3185f9fbec18Smcpowers
3186f9fbec18Smcpowers /* {{{ s_mp_norm(a, b, *d) */
3187f9fbec18Smcpowers
3188f9fbec18Smcpowers /*
3189f9fbec18Smcpowers s_mp_norm(a, b, *d)
3190f9fbec18Smcpowers
3191f9fbec18Smcpowers Normalize a and b for division, where b is the divisor. In order
3192f9fbec18Smcpowers that we might make good guesses for quotient digits, we want the
3193f9fbec18Smcpowers leading digit of b to be at least half the radix, which we
3194*55fea89dSDan Cross accomplish by multiplying a and b by a power of 2. The exponent
3195*55fea89dSDan Cross (shift count) is placed in *pd, so that the remainder can be shifted
3196f9fbec18Smcpowers back at the end of the division process.
3197f9fbec18Smcpowers */
3198f9fbec18Smcpowers
s_mp_norm(mp_int * a,mp_int * b,mp_digit * pd)3199f9fbec18Smcpowers mp_err s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd)
3200f9fbec18Smcpowers {
3201f9fbec18Smcpowers mp_digit d;
3202f9fbec18Smcpowers mp_digit mask;
3203f9fbec18Smcpowers mp_digit b_msd;
3204f9fbec18Smcpowers mp_err res = MP_OKAY;
3205f9fbec18Smcpowers
3206f9fbec18Smcpowers d = 0;
3207f9fbec18Smcpowers mask = DIGIT_MAX & ~(DIGIT_MAX >> 1); /* mask is msb of digit */
3208f9fbec18Smcpowers b_msd = DIGIT(b, USED(b) - 1);
3209f9fbec18Smcpowers while (!(b_msd & mask)) {
3210f9fbec18Smcpowers b_msd <<= 1;
3211f9fbec18Smcpowers ++d;
3212f9fbec18Smcpowers }
3213f9fbec18Smcpowers
3214f9fbec18Smcpowers if (d) {
3215f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(a, d) );
3216f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(b, d) );
3217f9fbec18Smcpowers }
3218f9fbec18Smcpowers
3219f9fbec18Smcpowers *pd = d;
3220f9fbec18Smcpowers CLEANUP:
3221f9fbec18Smcpowers return res;
3222f9fbec18Smcpowers
3223f9fbec18Smcpowers } /* end s_mp_norm() */
3224f9fbec18Smcpowers
3225f9fbec18Smcpowers /* }}} */
3226f9fbec18Smcpowers
3227f9fbec18Smcpowers /* }}} */
3228f9fbec18Smcpowers
3229f9fbec18Smcpowers /* {{{ Primitive digit arithmetic */
3230f9fbec18Smcpowers
3231f9fbec18Smcpowers /* {{{ s_mp_add_d(mp, d) */
3232f9fbec18Smcpowers
3233f9fbec18Smcpowers /* Add d to |mp| in place */
s_mp_add_d(mp_int * mp,mp_digit d)3234f9fbec18Smcpowers mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */
3235f9fbec18Smcpowers {
3236f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3237f9fbec18Smcpowers mp_word w, k = 0;
3238f9fbec18Smcpowers mp_size ix = 1;
3239f9fbec18Smcpowers
3240f9fbec18Smcpowers w = (mp_word)DIGIT(mp, 0) + d;
3241f9fbec18Smcpowers DIGIT(mp, 0) = ACCUM(w);
3242f9fbec18Smcpowers k = CARRYOUT(w);
3243f9fbec18Smcpowers
3244f9fbec18Smcpowers while(ix < USED(mp) && k) {
3245f9fbec18Smcpowers w = (mp_word)DIGIT(mp, ix) + k;
3246f9fbec18Smcpowers DIGIT(mp, ix) = ACCUM(w);
3247f9fbec18Smcpowers k = CARRYOUT(w);
3248f9fbec18Smcpowers ++ix;
3249f9fbec18Smcpowers }
3250f9fbec18Smcpowers
3251f9fbec18Smcpowers if(k != 0) {
3252f9fbec18Smcpowers mp_err res;
3253f9fbec18Smcpowers
3254f9fbec18Smcpowers if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
3255f9fbec18Smcpowers return res;
3256f9fbec18Smcpowers
3257f9fbec18Smcpowers DIGIT(mp, ix) = (mp_digit)k;
3258f9fbec18Smcpowers }
3259f9fbec18Smcpowers
3260f9fbec18Smcpowers return MP_OKAY;
3261f9fbec18Smcpowers #else
3262f9fbec18Smcpowers mp_digit * pmp = MP_DIGITS(mp);
3263f9fbec18Smcpowers mp_digit sum, mp_i, carry = 0;
3264f9fbec18Smcpowers mp_err res = MP_OKAY;
3265f9fbec18Smcpowers int used = (int)MP_USED(mp);
3266f9fbec18Smcpowers
3267f9fbec18Smcpowers mp_i = *pmp;
3268f9fbec18Smcpowers *pmp++ = sum = d + mp_i;
3269f9fbec18Smcpowers carry = (sum < d);
3270f9fbec18Smcpowers while (carry && --used > 0) {
3271f9fbec18Smcpowers mp_i = *pmp;
3272f9fbec18Smcpowers *pmp++ = sum = carry + mp_i;
3273f9fbec18Smcpowers carry = !sum;
3274f9fbec18Smcpowers }
3275f9fbec18Smcpowers if (carry && !used) {
3276f9fbec18Smcpowers /* mp is growing */
3277f9fbec18Smcpowers used = MP_USED(mp);
3278f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(mp, used + 1) );
3279f9fbec18Smcpowers MP_DIGIT(mp, used) = carry;
3280f9fbec18Smcpowers }
3281f9fbec18Smcpowers CLEANUP:
3282f9fbec18Smcpowers return res;
3283f9fbec18Smcpowers #endif
3284f9fbec18Smcpowers } /* end s_mp_add_d() */
3285f9fbec18Smcpowers
3286f9fbec18Smcpowers /* }}} */
3287f9fbec18Smcpowers
3288f9fbec18Smcpowers /* {{{ s_mp_sub_d(mp, d) */
3289f9fbec18Smcpowers
3290f9fbec18Smcpowers /* Subtract d from |mp| in place, assumes |mp| > d */
s_mp_sub_d(mp_int * mp,mp_digit d)3291f9fbec18Smcpowers mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */
3292f9fbec18Smcpowers {
3293f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3294f9fbec18Smcpowers mp_word w, b = 0;
3295f9fbec18Smcpowers mp_size ix = 1;
3296f9fbec18Smcpowers
3297f9fbec18Smcpowers /* Compute initial subtraction */
3298f9fbec18Smcpowers w = (RADIX + (mp_word)DIGIT(mp, 0)) - d;
3299f9fbec18Smcpowers b = CARRYOUT(w) ? 0 : 1;
3300f9fbec18Smcpowers DIGIT(mp, 0) = ACCUM(w);
3301f9fbec18Smcpowers
3302f9fbec18Smcpowers /* Propagate borrows leftward */
3303f9fbec18Smcpowers while(b && ix < USED(mp)) {
3304f9fbec18Smcpowers w = (RADIX + (mp_word)DIGIT(mp, ix)) - b;
3305f9fbec18Smcpowers b = CARRYOUT(w) ? 0 : 1;
3306f9fbec18Smcpowers DIGIT(mp, ix) = ACCUM(w);
3307f9fbec18Smcpowers ++ix;
3308f9fbec18Smcpowers }
3309f9fbec18Smcpowers
3310f9fbec18Smcpowers /* Remove leading zeroes */
3311f9fbec18Smcpowers s_mp_clamp(mp);
3312f9fbec18Smcpowers
3313f9fbec18Smcpowers /* If we have a borrow out, it's a violation of the input invariant */
3314f9fbec18Smcpowers if(b)
3315f9fbec18Smcpowers return MP_RANGE;
3316f9fbec18Smcpowers else
3317f9fbec18Smcpowers return MP_OKAY;
3318f9fbec18Smcpowers #else
3319f9fbec18Smcpowers mp_digit *pmp = MP_DIGITS(mp);
3320f9fbec18Smcpowers mp_digit mp_i, diff, borrow;
3321f9fbec18Smcpowers mp_size used = MP_USED(mp);
3322f9fbec18Smcpowers
3323f9fbec18Smcpowers mp_i = *pmp;
3324f9fbec18Smcpowers *pmp++ = diff = mp_i - d;
3325f9fbec18Smcpowers borrow = (diff > mp_i);
3326f9fbec18Smcpowers while (borrow && --used) {
3327f9fbec18Smcpowers mp_i = *pmp;
3328f9fbec18Smcpowers *pmp++ = diff = mp_i - borrow;
3329f9fbec18Smcpowers borrow = (diff > mp_i);
3330f9fbec18Smcpowers }
3331f9fbec18Smcpowers s_mp_clamp(mp);
3332f9fbec18Smcpowers return (borrow && !used) ? MP_RANGE : MP_OKAY;
3333f9fbec18Smcpowers #endif
3334f9fbec18Smcpowers } /* end s_mp_sub_d() */
3335f9fbec18Smcpowers
3336f9fbec18Smcpowers /* }}} */
3337f9fbec18Smcpowers
3338f9fbec18Smcpowers /* {{{ s_mp_mul_d(a, d) */
3339f9fbec18Smcpowers
3340f9fbec18Smcpowers /* Compute a = a * d, single digit multiplication */
s_mp_mul_d(mp_int * a,mp_digit d)3341f9fbec18Smcpowers mp_err s_mp_mul_d(mp_int *a, mp_digit d)
3342f9fbec18Smcpowers {
3343f9fbec18Smcpowers mp_err res;
3344f9fbec18Smcpowers mp_size used;
3345f9fbec18Smcpowers int pow;
3346f9fbec18Smcpowers
3347f9fbec18Smcpowers if (!d) {
3348f9fbec18Smcpowers mp_zero(a);
3349f9fbec18Smcpowers return MP_OKAY;
3350f9fbec18Smcpowers }
3351f9fbec18Smcpowers if (d == 1)
3352f9fbec18Smcpowers return MP_OKAY;
3353f9fbec18Smcpowers if (0 <= (pow = s_mp_ispow2d(d))) {
3354f9fbec18Smcpowers return s_mp_mul_2d(a, (mp_digit)pow);
3355f9fbec18Smcpowers }
3356f9fbec18Smcpowers
3357f9fbec18Smcpowers used = MP_USED(a);
3358f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(a, used + 1) );
3359f9fbec18Smcpowers
3360f9fbec18Smcpowers s_mpv_mul_d(MP_DIGITS(a), used, d, MP_DIGITS(a));
3361f9fbec18Smcpowers
3362f9fbec18Smcpowers s_mp_clamp(a);
3363f9fbec18Smcpowers
3364f9fbec18Smcpowers CLEANUP:
3365f9fbec18Smcpowers return res;
3366*55fea89dSDan Cross
3367f9fbec18Smcpowers } /* end s_mp_mul_d() */
3368f9fbec18Smcpowers
3369f9fbec18Smcpowers /* }}} */
3370f9fbec18Smcpowers
3371f9fbec18Smcpowers /* {{{ s_mp_div_d(mp, d, r) */
3372f9fbec18Smcpowers
3373f9fbec18Smcpowers /*
3374f9fbec18Smcpowers s_mp_div_d(mp, d, r)
3375f9fbec18Smcpowers
3376f9fbec18Smcpowers Compute the quotient mp = mp / d and remainder r = mp mod d, for a
3377f9fbec18Smcpowers single digit d. If r is null, the remainder will be discarded.
3378f9fbec18Smcpowers */
3379f9fbec18Smcpowers
s_mp_div_d(mp_int * mp,mp_digit d,mp_digit * r)3380f9fbec18Smcpowers mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
3381f9fbec18Smcpowers {
3382f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
3383f9fbec18Smcpowers mp_word w = 0, q;
3384f9fbec18Smcpowers #else
3385f9fbec18Smcpowers mp_digit w, q;
3386f9fbec18Smcpowers #endif
3387f9fbec18Smcpowers int ix;
3388f9fbec18Smcpowers mp_err res;
3389f9fbec18Smcpowers mp_int quot;
3390f9fbec18Smcpowers mp_int rem;
3391f9fbec18Smcpowers
3392f9fbec18Smcpowers if(d == 0)
3393f9fbec18Smcpowers return MP_RANGE;
3394f9fbec18Smcpowers if (d == 1) {
3395f9fbec18Smcpowers if (r)
3396f9fbec18Smcpowers *r = 0;
3397f9fbec18Smcpowers return MP_OKAY;
3398f9fbec18Smcpowers }
3399f9fbec18Smcpowers /* could check for power of 2 here, but mp_div_d does that. */
3400f9fbec18Smcpowers if (MP_USED(mp) == 1) {
3401f9fbec18Smcpowers mp_digit n = MP_DIGIT(mp,0);
3402f9fbec18Smcpowers mp_digit rem;
3403f9fbec18Smcpowers
3404f9fbec18Smcpowers q = n / d;
3405f9fbec18Smcpowers rem = n % d;
3406f9fbec18Smcpowers MP_DIGIT(mp,0) = q;
3407f9fbec18Smcpowers if (r)
3408f9fbec18Smcpowers *r = rem;
3409f9fbec18Smcpowers return MP_OKAY;
3410f9fbec18Smcpowers }
3411f9fbec18Smcpowers
3412f9fbec18Smcpowers MP_DIGITS(&rem) = 0;
3413f9fbec18Smcpowers MP_DIGITS(") = 0;
3414f9fbec18Smcpowers /* Make room for the quotient */
3415f9fbec18Smcpowers MP_CHECKOK( mp_init_size(", USED(mp), FLAG(mp)) );
3416f9fbec18Smcpowers
3417f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
3418f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
3419f9fbec18Smcpowers w = (w << DIGIT_BIT) | DIGIT(mp, ix);
3420f9fbec18Smcpowers
3421f9fbec18Smcpowers if(w >= d) {
3422f9fbec18Smcpowers q = w / d;
3423f9fbec18Smcpowers w = w % d;
3424f9fbec18Smcpowers } else {
3425f9fbec18Smcpowers q = 0;
3426f9fbec18Smcpowers }
3427f9fbec18Smcpowers
3428f9fbec18Smcpowers s_mp_lshd(", 1);
3429f9fbec18Smcpowers DIGIT(", 0) = (mp_digit)q;
3430f9fbec18Smcpowers }
3431f9fbec18Smcpowers #else
3432f9fbec18Smcpowers {
3433f9fbec18Smcpowers mp_digit p;
3434f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D)
3435f9fbec18Smcpowers mp_digit norm;
3436f9fbec18Smcpowers #endif
3437f9fbec18Smcpowers
3438f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&rem, mp) );
3439f9fbec18Smcpowers
3440f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D)
3441f9fbec18Smcpowers MP_DIGIT(", 0) = d;
3442f9fbec18Smcpowers MP_CHECKOK( s_mp_norm(&rem, ", &norm) );
3443f9fbec18Smcpowers if (norm)
3444f9fbec18Smcpowers d <<= norm;
3445f9fbec18Smcpowers MP_DIGIT(", 0) = 0;
3446f9fbec18Smcpowers #endif
3447f9fbec18Smcpowers
3448f9fbec18Smcpowers p = 0;
3449f9fbec18Smcpowers for (ix = USED(&rem) - 1; ix >= 0; ix--) {
3450f9fbec18Smcpowers w = DIGIT(&rem, ix);
3451f9fbec18Smcpowers
3452f9fbec18Smcpowers if (p) {
3453f9fbec18Smcpowers MP_CHECKOK( s_mpv_div_2dx1d(p, w, d, &q, &w) );
3454f9fbec18Smcpowers } else if (w >= d) {
3455f9fbec18Smcpowers q = w / d;
3456f9fbec18Smcpowers w = w % d;
3457f9fbec18Smcpowers } else {
3458f9fbec18Smcpowers q = 0;
3459f9fbec18Smcpowers }
3460f9fbec18Smcpowers
3461f9fbec18Smcpowers MP_CHECKOK( s_mp_lshd(", 1) );
3462f9fbec18Smcpowers DIGIT(", 0) = q;
3463f9fbec18Smcpowers p = w;
3464f9fbec18Smcpowers }
3465f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D)
3466f9fbec18Smcpowers if (norm)
3467f9fbec18Smcpowers w >>= norm;
3468f9fbec18Smcpowers #endif
3469f9fbec18Smcpowers }
3470f9fbec18Smcpowers #endif
3471f9fbec18Smcpowers
3472f9fbec18Smcpowers /* Deliver the remainder, if desired */
3473f9fbec18Smcpowers if(r)
3474f9fbec18Smcpowers *r = (mp_digit)w;
3475f9fbec18Smcpowers
3476f9fbec18Smcpowers s_mp_clamp(");
3477f9fbec18Smcpowers mp_exch(", mp);
3478f9fbec18Smcpowers CLEANUP:
3479f9fbec18Smcpowers mp_clear(");
3480f9fbec18Smcpowers mp_clear(&rem);
3481f9fbec18Smcpowers
3482f9fbec18Smcpowers return res;
3483f9fbec18Smcpowers } /* end s_mp_div_d() */
3484f9fbec18Smcpowers
3485f9fbec18Smcpowers /* }}} */
3486f9fbec18Smcpowers
3487f9fbec18Smcpowers
3488f9fbec18Smcpowers /* }}} */
3489f9fbec18Smcpowers
3490f9fbec18Smcpowers /* {{{ Primitive full arithmetic */
3491f9fbec18Smcpowers
3492f9fbec18Smcpowers /* {{{ s_mp_add(a, b) */
3493f9fbec18Smcpowers
3494f9fbec18Smcpowers /* Compute a = |a| + |b| */
s_mp_add(mp_int * a,const mp_int * b)3495f9fbec18Smcpowers mp_err s_mp_add(mp_int *a, const mp_int *b) /* magnitude addition */
3496f9fbec18Smcpowers {
3497f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3498f9fbec18Smcpowers mp_word w = 0;
3499f9fbec18Smcpowers #else
3500f9fbec18Smcpowers mp_digit d, sum, carry = 0;
3501f9fbec18Smcpowers #endif
3502f9fbec18Smcpowers mp_digit *pa, *pb;
3503f9fbec18Smcpowers mp_size ix;
3504f9fbec18Smcpowers mp_size used;
3505f9fbec18Smcpowers mp_err res;
3506f9fbec18Smcpowers
3507f9fbec18Smcpowers /* Make sure a has enough precision for the output value */
3508f9fbec18Smcpowers if((USED(b) > USED(a)) && (res = s_mp_pad(a, USED(b))) != MP_OKAY)
3509f9fbec18Smcpowers return res;
3510f9fbec18Smcpowers
3511f9fbec18Smcpowers /*
3512f9fbec18Smcpowers Add up all digits up to the precision of b. If b had initially
3513f9fbec18Smcpowers the same precision as a, or greater, we took care of it by the
3514f9fbec18Smcpowers padding step above, so there is no problem. If b had initially
3515f9fbec18Smcpowers less precision, we'll have to make sure the carry out is duly
3516f9fbec18Smcpowers propagated upward among the higher-order digits of the sum.
3517f9fbec18Smcpowers */
3518f9fbec18Smcpowers pa = MP_DIGITS(a);
3519f9fbec18Smcpowers pb = MP_DIGITS(b);
3520f9fbec18Smcpowers used = MP_USED(b);
3521f9fbec18Smcpowers for(ix = 0; ix < used; ix++) {
3522f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3523f9fbec18Smcpowers w = w + *pa + *pb++;
3524f9fbec18Smcpowers *pa++ = ACCUM(w);
3525f9fbec18Smcpowers w = CARRYOUT(w);
3526f9fbec18Smcpowers #else
3527f9fbec18Smcpowers d = *pa;
3528f9fbec18Smcpowers sum = d + *pb++;
3529f9fbec18Smcpowers d = (sum < d); /* detect overflow */
3530f9fbec18Smcpowers *pa++ = sum += carry;
3531f9fbec18Smcpowers carry = d + (sum < carry); /* detect overflow */
3532f9fbec18Smcpowers #endif
3533f9fbec18Smcpowers }
3534f9fbec18Smcpowers
3535f9fbec18Smcpowers /* If we run out of 'b' digits before we're actually done, make
3536*55fea89dSDan Cross sure the carries get propagated upward...
3537f9fbec18Smcpowers */
3538f9fbec18Smcpowers used = MP_USED(a);
3539f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3540f9fbec18Smcpowers while (w && ix < used) {
3541f9fbec18Smcpowers w = w + *pa;
3542f9fbec18Smcpowers *pa++ = ACCUM(w);
3543f9fbec18Smcpowers w = CARRYOUT(w);
3544f9fbec18Smcpowers ++ix;
3545f9fbec18Smcpowers }
3546f9fbec18Smcpowers #else
3547f9fbec18Smcpowers while (carry && ix < used) {
3548f9fbec18Smcpowers sum = carry + *pa;
3549f9fbec18Smcpowers *pa++ = sum;
3550f9fbec18Smcpowers carry = !sum;
3551f9fbec18Smcpowers ++ix;
3552f9fbec18Smcpowers }
3553f9fbec18Smcpowers #endif
3554f9fbec18Smcpowers
3555f9fbec18Smcpowers /* If there's an overall carry out, increase precision and include
3556f9fbec18Smcpowers it. We could have done this initially, but why touch the memory
3557f9fbec18Smcpowers allocator unless we're sure we have to?
3558f9fbec18Smcpowers */
3559f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3560f9fbec18Smcpowers if (w) {
3561f9fbec18Smcpowers if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
3562f9fbec18Smcpowers return res;
3563f9fbec18Smcpowers
3564f9fbec18Smcpowers DIGIT(a, ix) = (mp_digit)w;
3565f9fbec18Smcpowers }
3566f9fbec18Smcpowers #else
3567f9fbec18Smcpowers if (carry) {
3568f9fbec18Smcpowers if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
3569f9fbec18Smcpowers return res;
3570f9fbec18Smcpowers
3571f9fbec18Smcpowers DIGIT(a, used) = carry;
3572f9fbec18Smcpowers }
3573f9fbec18Smcpowers #endif
3574f9fbec18Smcpowers
3575f9fbec18Smcpowers return MP_OKAY;
3576f9fbec18Smcpowers } /* end s_mp_add() */
3577f9fbec18Smcpowers
3578f9fbec18Smcpowers /* }}} */
3579f9fbec18Smcpowers
3580f9fbec18Smcpowers /* Compute c = |a| + |b| */ /* magnitude addition */
s_mp_add_3arg(const mp_int * a,const mp_int * b,mp_int * c)3581*55fea89dSDan Cross mp_err s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c)
3582f9fbec18Smcpowers {
3583f9fbec18Smcpowers mp_digit *pa, *pb, *pc;
3584f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3585f9fbec18Smcpowers mp_word w = 0;
3586f9fbec18Smcpowers #else
3587f9fbec18Smcpowers mp_digit sum, carry = 0, d;
3588f9fbec18Smcpowers #endif
3589f9fbec18Smcpowers mp_size ix;
3590f9fbec18Smcpowers mp_size used;
3591f9fbec18Smcpowers mp_err res;
3592f9fbec18Smcpowers
3593f9fbec18Smcpowers MP_SIGN(c) = MP_SIGN(a);
3594f9fbec18Smcpowers if (MP_USED(a) < MP_USED(b)) {
3595f9fbec18Smcpowers const mp_int *xch = a;
3596f9fbec18Smcpowers a = b;
3597f9fbec18Smcpowers b = xch;
3598f9fbec18Smcpowers }
3599f9fbec18Smcpowers
3600f9fbec18Smcpowers /* Make sure a has enough precision for the output value */
3601f9fbec18Smcpowers if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
3602f9fbec18Smcpowers return res;
3603f9fbec18Smcpowers
3604f9fbec18Smcpowers /*
3605f9fbec18Smcpowers Add up all digits up to the precision of b. If b had initially
3606f9fbec18Smcpowers the same precision as a, or greater, we took care of it by the
3607f9fbec18Smcpowers exchange step above, so there is no problem. If b had initially
3608f9fbec18Smcpowers less precision, we'll have to make sure the carry out is duly
3609f9fbec18Smcpowers propagated upward among the higher-order digits of the sum.
3610f9fbec18Smcpowers */
3611f9fbec18Smcpowers pa = MP_DIGITS(a);
3612f9fbec18Smcpowers pb = MP_DIGITS(b);
3613f9fbec18Smcpowers pc = MP_DIGITS(c);
3614f9fbec18Smcpowers used = MP_USED(b);
3615f9fbec18Smcpowers for (ix = 0; ix < used; ix++) {
3616f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3617f9fbec18Smcpowers w = w + *pa++ + *pb++;
3618f9fbec18Smcpowers *pc++ = ACCUM(w);
3619f9fbec18Smcpowers w = CARRYOUT(w);
3620f9fbec18Smcpowers #else
3621f9fbec18Smcpowers d = *pa++;
3622f9fbec18Smcpowers sum = d + *pb++;
3623f9fbec18Smcpowers d = (sum < d); /* detect overflow */
3624f9fbec18Smcpowers *pc++ = sum += carry;
3625f9fbec18Smcpowers carry = d + (sum < carry); /* detect overflow */
3626f9fbec18Smcpowers #endif
3627f9fbec18Smcpowers }
3628f9fbec18Smcpowers
3629f9fbec18Smcpowers /* If we run out of 'b' digits before we're actually done, make
3630*55fea89dSDan Cross sure the carries get propagated upward...
3631f9fbec18Smcpowers */
3632f9fbec18Smcpowers for (used = MP_USED(a); ix < used; ++ix) {
3633f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3634f9fbec18Smcpowers w = w + *pa++;
3635f9fbec18Smcpowers *pc++ = ACCUM(w);
3636f9fbec18Smcpowers w = CARRYOUT(w);
3637f9fbec18Smcpowers #else
3638f9fbec18Smcpowers *pc++ = sum = carry + *pa++;
3639f9fbec18Smcpowers carry = (sum < carry);
3640f9fbec18Smcpowers #endif
3641f9fbec18Smcpowers }
3642f9fbec18Smcpowers
3643f9fbec18Smcpowers /* If there's an overall carry out, increase precision and include
3644f9fbec18Smcpowers it. We could have done this initially, but why touch the memory
3645f9fbec18Smcpowers allocator unless we're sure we have to?
3646f9fbec18Smcpowers */
3647f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3648f9fbec18Smcpowers if (w) {
3649f9fbec18Smcpowers if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
3650f9fbec18Smcpowers return res;
3651f9fbec18Smcpowers
3652f9fbec18Smcpowers DIGIT(c, used) = (mp_digit)w;
3653f9fbec18Smcpowers ++used;
3654f9fbec18Smcpowers }
3655f9fbec18Smcpowers #else
3656f9fbec18Smcpowers if (carry) {
3657f9fbec18Smcpowers if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
3658f9fbec18Smcpowers return res;
3659f9fbec18Smcpowers
3660f9fbec18Smcpowers DIGIT(c, used) = carry;
3661f9fbec18Smcpowers ++used;
3662f9fbec18Smcpowers }
3663f9fbec18Smcpowers #endif
3664f9fbec18Smcpowers MP_USED(c) = used;
3665f9fbec18Smcpowers return MP_OKAY;
3666f9fbec18Smcpowers }
3667f9fbec18Smcpowers /* {{{ s_mp_add_offset(a, b, offset) */
3668f9fbec18Smcpowers
3669f9fbec18Smcpowers /* Compute a = |a| + ( |b| * (RADIX ** offset) ) */
s_mp_add_offset(mp_int * a,mp_int * b,mp_size offset)3670*55fea89dSDan Cross mp_err s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset)
3671f9fbec18Smcpowers {
3672f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3673f9fbec18Smcpowers mp_word w, k = 0;
3674f9fbec18Smcpowers #else
3675f9fbec18Smcpowers mp_digit d, sum, carry = 0;
3676f9fbec18Smcpowers #endif
3677f9fbec18Smcpowers mp_size ib;
3678f9fbec18Smcpowers mp_size ia;
3679f9fbec18Smcpowers mp_size lim;
3680f9fbec18Smcpowers mp_err res;
3681f9fbec18Smcpowers
3682f9fbec18Smcpowers /* Make sure a has enough precision for the output value */
3683f9fbec18Smcpowers lim = MP_USED(b) + offset;
3684f9fbec18Smcpowers if((lim > USED(a)) && (res = s_mp_pad(a, lim)) != MP_OKAY)
3685f9fbec18Smcpowers return res;
3686f9fbec18Smcpowers
3687f9fbec18Smcpowers /*
3688f9fbec18Smcpowers Add up all digits up to the precision of b. If b had initially
3689f9fbec18Smcpowers the same precision as a, or greater, we took care of it by the
3690f9fbec18Smcpowers padding step above, so there is no problem. If b had initially
3691f9fbec18Smcpowers less precision, we'll have to make sure the carry out is duly
3692f9fbec18Smcpowers propagated upward among the higher-order digits of the sum.
3693f9fbec18Smcpowers */
3694f9fbec18Smcpowers lim = USED(b);
3695f9fbec18Smcpowers for(ib = 0, ia = offset; ib < lim; ib++, ia++) {
3696f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3697f9fbec18Smcpowers w = (mp_word)DIGIT(a, ia) + DIGIT(b, ib) + k;
3698f9fbec18Smcpowers DIGIT(a, ia) = ACCUM(w);
3699f9fbec18Smcpowers k = CARRYOUT(w);
3700f9fbec18Smcpowers #else
3701f9fbec18Smcpowers d = MP_DIGIT(a, ia);
3702f9fbec18Smcpowers sum = d + MP_DIGIT(b, ib);
3703f9fbec18Smcpowers d = (sum < d);
3704f9fbec18Smcpowers MP_DIGIT(a,ia) = sum += carry;
3705f9fbec18Smcpowers carry = d + (sum < carry);
3706f9fbec18Smcpowers #endif
3707f9fbec18Smcpowers }
3708f9fbec18Smcpowers
3709f9fbec18Smcpowers /* If we run out of 'b' digits before we're actually done, make
3710*55fea89dSDan Cross sure the carries get propagated upward...
3711f9fbec18Smcpowers */
3712f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3713f9fbec18Smcpowers for (lim = MP_USED(a); k && (ia < lim); ++ia) {
3714f9fbec18Smcpowers w = (mp_word)DIGIT(a, ia) + k;
3715f9fbec18Smcpowers DIGIT(a, ia) = ACCUM(w);
3716f9fbec18Smcpowers k = CARRYOUT(w);
3717f9fbec18Smcpowers }
3718f9fbec18Smcpowers #else
3719f9fbec18Smcpowers for (lim = MP_USED(a); carry && (ia < lim); ++ia) {
3720f9fbec18Smcpowers d = MP_DIGIT(a, ia);
3721f9fbec18Smcpowers MP_DIGIT(a,ia) = sum = d + carry;
3722f9fbec18Smcpowers carry = (sum < d);
3723f9fbec18Smcpowers }
3724f9fbec18Smcpowers #endif
3725f9fbec18Smcpowers
3726f9fbec18Smcpowers /* If there's an overall carry out, increase precision and include
3727f9fbec18Smcpowers it. We could have done this initially, but why touch the memory
3728f9fbec18Smcpowers allocator unless we're sure we have to?
3729f9fbec18Smcpowers */
3730f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
3731f9fbec18Smcpowers if(k) {
3732f9fbec18Smcpowers if((res = s_mp_pad(a, USED(a) + 1)) != MP_OKAY)
3733f9fbec18Smcpowers return res;
3734f9fbec18Smcpowers
3735f9fbec18Smcpowers DIGIT(a, ia) = (mp_digit)k;
3736f9fbec18Smcpowers }
3737f9fbec18Smcpowers #else
3738f9fbec18Smcpowers if (carry) {
3739f9fbec18Smcpowers if((res = s_mp_pad(a, lim + 1)) != MP_OKAY)
3740f9fbec18Smcpowers return res;
3741f9fbec18Smcpowers
3742f9fbec18Smcpowers DIGIT(a, lim) = carry;
3743f9fbec18Smcpowers }
3744f9fbec18Smcpowers #endif
3745f9fbec18Smcpowers s_mp_clamp(a);
3746f9fbec18Smcpowers
3747f9fbec18Smcpowers return MP_OKAY;
3748f9fbec18Smcpowers
3749f9fbec18Smcpowers } /* end s_mp_add_offset() */
3750f9fbec18Smcpowers
3751f9fbec18Smcpowers /* }}} */
3752f9fbec18Smcpowers
3753f9fbec18Smcpowers /* {{{ s_mp_sub(a, b) */
3754f9fbec18Smcpowers
3755f9fbec18Smcpowers /* Compute a = |a| - |b|, assumes |a| >= |b| */
s_mp_sub(mp_int * a,const mp_int * b)3756f9fbec18Smcpowers mp_err s_mp_sub(mp_int *a, const mp_int *b) /* magnitude subtract */
3757f9fbec18Smcpowers {
3758f9fbec18Smcpowers mp_digit *pa, *pb, *limit;
3759f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3760f9fbec18Smcpowers mp_sword w = 0;
3761f9fbec18Smcpowers #else
3762f9fbec18Smcpowers mp_digit d, diff, borrow = 0;
3763f9fbec18Smcpowers #endif
3764f9fbec18Smcpowers
3765f9fbec18Smcpowers /*
3766f9fbec18Smcpowers Subtract and propagate borrow. Up to the precision of b, this
3767f9fbec18Smcpowers accounts for the digits of b; after that, we just make sure the
3768f9fbec18Smcpowers carries get to the right place. This saves having to pad b out to
3769f9fbec18Smcpowers the precision of a just to make the loops work right...
3770f9fbec18Smcpowers */
3771f9fbec18Smcpowers pa = MP_DIGITS(a);
3772f9fbec18Smcpowers pb = MP_DIGITS(b);
3773f9fbec18Smcpowers limit = pb + MP_USED(b);
3774f9fbec18Smcpowers while (pb < limit) {
3775f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3776f9fbec18Smcpowers w = w + *pa - *pb++;
3777f9fbec18Smcpowers *pa++ = ACCUM(w);
3778f9fbec18Smcpowers w >>= MP_DIGIT_BIT;
3779f9fbec18Smcpowers #else
3780f9fbec18Smcpowers d = *pa;
3781f9fbec18Smcpowers diff = d - *pb++;
3782f9fbec18Smcpowers d = (diff > d); /* detect borrow */
3783f9fbec18Smcpowers if (borrow && --diff == MP_DIGIT_MAX)
3784f9fbec18Smcpowers ++d;
3785f9fbec18Smcpowers *pa++ = diff;
3786*55fea89dSDan Cross borrow = d;
3787f9fbec18Smcpowers #endif
3788f9fbec18Smcpowers }
3789f9fbec18Smcpowers limit = MP_DIGITS(a) + MP_USED(a);
3790f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3791f9fbec18Smcpowers while (w && pa < limit) {
3792f9fbec18Smcpowers w = w + *pa;
3793f9fbec18Smcpowers *pa++ = ACCUM(w);
3794f9fbec18Smcpowers w >>= MP_DIGIT_BIT;
3795f9fbec18Smcpowers }
3796f9fbec18Smcpowers #else
3797f9fbec18Smcpowers while (borrow && pa < limit) {
3798f9fbec18Smcpowers d = *pa;
3799f9fbec18Smcpowers *pa++ = diff = d - borrow;
3800f9fbec18Smcpowers borrow = (diff > d);
3801f9fbec18Smcpowers }
3802f9fbec18Smcpowers #endif
3803f9fbec18Smcpowers
3804f9fbec18Smcpowers /* Clobber any leading zeroes we created */
3805f9fbec18Smcpowers s_mp_clamp(a);
3806f9fbec18Smcpowers
3807*55fea89dSDan Cross /*
3808f9fbec18Smcpowers If there was a borrow out, then |b| > |a| in violation
3809f9fbec18Smcpowers of our input invariant. We've already done the work,
3810f9fbec18Smcpowers but we'll at least complain about it...
3811f9fbec18Smcpowers */
3812f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3813f9fbec18Smcpowers return w ? MP_RANGE : MP_OKAY;
3814f9fbec18Smcpowers #else
3815f9fbec18Smcpowers return borrow ? MP_RANGE : MP_OKAY;
3816f9fbec18Smcpowers #endif
3817f9fbec18Smcpowers } /* end s_mp_sub() */
3818f9fbec18Smcpowers
3819f9fbec18Smcpowers /* }}} */
3820f9fbec18Smcpowers
3821f9fbec18Smcpowers /* Compute c = |a| - |b|, assumes |a| >= |b| */ /* magnitude subtract */
s_mp_sub_3arg(const mp_int * a,const mp_int * b,mp_int * c)3822*55fea89dSDan Cross mp_err s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c)
3823f9fbec18Smcpowers {
3824f9fbec18Smcpowers mp_digit *pa, *pb, *pc;
3825f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3826f9fbec18Smcpowers mp_sword w = 0;
3827f9fbec18Smcpowers #else
3828f9fbec18Smcpowers mp_digit d, diff, borrow = 0;
3829f9fbec18Smcpowers #endif
3830f9fbec18Smcpowers int ix, limit;
3831f9fbec18Smcpowers mp_err res;
3832f9fbec18Smcpowers
3833f9fbec18Smcpowers MP_SIGN(c) = MP_SIGN(a);
3834f9fbec18Smcpowers
3835f9fbec18Smcpowers /* Make sure a has enough precision for the output value */
3836f9fbec18Smcpowers if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
3837f9fbec18Smcpowers return res;
3838f9fbec18Smcpowers
3839f9fbec18Smcpowers /*
3840f9fbec18Smcpowers Subtract and propagate borrow. Up to the precision of b, this
3841f9fbec18Smcpowers accounts for the digits of b; after that, we just make sure the
3842f9fbec18Smcpowers carries get to the right place. This saves having to pad b out to
3843f9fbec18Smcpowers the precision of a just to make the loops work right...
3844f9fbec18Smcpowers */
3845f9fbec18Smcpowers pa = MP_DIGITS(a);
3846f9fbec18Smcpowers pb = MP_DIGITS(b);
3847f9fbec18Smcpowers pc = MP_DIGITS(c);
3848f9fbec18Smcpowers limit = MP_USED(b);
3849f9fbec18Smcpowers for (ix = 0; ix < limit; ++ix) {
3850f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3851f9fbec18Smcpowers w = w + *pa++ - *pb++;
3852f9fbec18Smcpowers *pc++ = ACCUM(w);
3853f9fbec18Smcpowers w >>= MP_DIGIT_BIT;
3854f9fbec18Smcpowers #else
3855f9fbec18Smcpowers d = *pa++;
3856f9fbec18Smcpowers diff = d - *pb++;
3857f9fbec18Smcpowers d = (diff > d);
3858f9fbec18Smcpowers if (borrow && --diff == MP_DIGIT_MAX)
3859f9fbec18Smcpowers ++d;
3860f9fbec18Smcpowers *pc++ = diff;
3861f9fbec18Smcpowers borrow = d;
3862f9fbec18Smcpowers #endif
3863f9fbec18Smcpowers }
3864f9fbec18Smcpowers for (limit = MP_USED(a); ix < limit; ++ix) {
3865f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3866f9fbec18Smcpowers w = w + *pa++;
3867f9fbec18Smcpowers *pc++ = ACCUM(w);
3868f9fbec18Smcpowers w >>= MP_DIGIT_BIT;
3869f9fbec18Smcpowers #else
3870f9fbec18Smcpowers d = *pa++;
3871f9fbec18Smcpowers *pc++ = diff = d - borrow;
3872f9fbec18Smcpowers borrow = (diff > d);
3873f9fbec18Smcpowers #endif
3874f9fbec18Smcpowers }
3875f9fbec18Smcpowers
3876f9fbec18Smcpowers /* Clobber any leading zeroes we created */
3877f9fbec18Smcpowers MP_USED(c) = ix;
3878f9fbec18Smcpowers s_mp_clamp(c);
3879f9fbec18Smcpowers
3880*55fea89dSDan Cross /*
3881f9fbec18Smcpowers If there was a borrow out, then |b| > |a| in violation
3882f9fbec18Smcpowers of our input invariant. We've already done the work,
3883f9fbec18Smcpowers but we'll at least complain about it...
3884f9fbec18Smcpowers */
3885f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
3886f9fbec18Smcpowers return w ? MP_RANGE : MP_OKAY;
3887f9fbec18Smcpowers #else
3888f9fbec18Smcpowers return borrow ? MP_RANGE : MP_OKAY;
3889f9fbec18Smcpowers #endif
3890f9fbec18Smcpowers }
3891f9fbec18Smcpowers /* {{{ s_mp_mul(a, b) */
3892f9fbec18Smcpowers
3893f9fbec18Smcpowers /* Compute a = |a| * |b| */
s_mp_mul(mp_int * a,const mp_int * b)3894f9fbec18Smcpowers mp_err s_mp_mul(mp_int *a, const mp_int *b)
3895f9fbec18Smcpowers {
3896f9fbec18Smcpowers return mp_mul(a, b, a);
3897f9fbec18Smcpowers } /* end s_mp_mul() */
3898f9fbec18Smcpowers
3899f9fbec18Smcpowers /* }}} */
3900f9fbec18Smcpowers
3901f9fbec18Smcpowers #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
3902f9fbec18Smcpowers /* This trick works on Sparc V8 CPUs with the Workshop compilers. */
3903f9fbec18Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \
3904f9fbec18Smcpowers { unsigned long long product = (unsigned long long)a * b; \
3905f9fbec18Smcpowers Plo = (mp_digit)product; \
3906f9fbec18Smcpowers Phi = (mp_digit)(product >> MP_DIGIT_BIT); }
3907f9fbec18Smcpowers #elif defined(OSF1)
3908f9fbec18Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \
3909f9fbec18Smcpowers { Plo = asm ("mulq %a0, %a1, %v0", a, b);\
3910f9fbec18Smcpowers Phi = asm ("umulh %a0, %a1, %v0", a, b); }
3911f9fbec18Smcpowers #else
3912f9fbec18Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \
3913f9fbec18Smcpowers { mp_digit a0b1, a1b0; \
3914f9fbec18Smcpowers Plo = (a & MP_HALF_DIGIT_MAX) * (b & MP_HALF_DIGIT_MAX); \
3915f9fbec18Smcpowers Phi = (a >> MP_HALF_DIGIT_BIT) * (b >> MP_HALF_DIGIT_BIT); \
3916f9fbec18Smcpowers a0b1 = (a & MP_HALF_DIGIT_MAX) * (b >> MP_HALF_DIGIT_BIT); \
3917f9fbec18Smcpowers a1b0 = (a >> MP_HALF_DIGIT_BIT) * (b & MP_HALF_DIGIT_MAX); \
3918f9fbec18Smcpowers a1b0 += a0b1; \
3919f9fbec18Smcpowers Phi += a1b0 >> MP_HALF_DIGIT_BIT; \
3920f9fbec18Smcpowers if (a1b0 < a0b1) \
3921f9fbec18Smcpowers Phi += MP_HALF_RADIX; \
3922f9fbec18Smcpowers a1b0 <<= MP_HALF_DIGIT_BIT; \
3923f9fbec18Smcpowers Plo += a1b0; \
3924f9fbec18Smcpowers if (Plo < a1b0) \
3925f9fbec18Smcpowers ++Phi; \
3926f9fbec18Smcpowers }
3927f9fbec18Smcpowers #endif
3928f9fbec18Smcpowers
3929f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_MULTIPLY)
3930f9fbec18Smcpowers /* c = a * b */
s_mpv_mul_d(const mp_digit * a,mp_size a_len,mp_digit b,mp_digit * c)3931f9fbec18Smcpowers void s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
3932f9fbec18Smcpowers {
3933f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
3934f9fbec18Smcpowers mp_digit d = 0;
3935f9fbec18Smcpowers
3936f9fbec18Smcpowers /* Inner product: Digits of a */
3937f9fbec18Smcpowers while (a_len--) {
3938f9fbec18Smcpowers mp_word w = ((mp_word)b * *a++) + d;
3939f9fbec18Smcpowers *c++ = ACCUM(w);
3940f9fbec18Smcpowers d = CARRYOUT(w);
3941f9fbec18Smcpowers }
3942f9fbec18Smcpowers *c = d;
3943f9fbec18Smcpowers #else
3944f9fbec18Smcpowers mp_digit carry = 0;
3945f9fbec18Smcpowers while (a_len--) {
3946f9fbec18Smcpowers mp_digit a_i = *a++;
3947f9fbec18Smcpowers mp_digit a0b0, a1b1;
3948f9fbec18Smcpowers
3949f9fbec18Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0);
3950f9fbec18Smcpowers
3951f9fbec18Smcpowers a0b0 += carry;
3952f9fbec18Smcpowers if (a0b0 < carry)
3953f9fbec18Smcpowers ++a1b1;
3954f9fbec18Smcpowers *c++ = a0b0;
3955f9fbec18Smcpowers carry = a1b1;
3956f9fbec18Smcpowers }
3957f9fbec18Smcpowers *c = carry;
3958f9fbec18Smcpowers #endif
3959f9fbec18Smcpowers }
3960f9fbec18Smcpowers
3961f9fbec18Smcpowers /* c += a * b */
s_mpv_mul_d_add(const mp_digit * a,mp_size a_len,mp_digit b,mp_digit * c)3962*55fea89dSDan Cross void s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b,
3963f9fbec18Smcpowers mp_digit *c)
3964f9fbec18Smcpowers {
3965f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
3966f9fbec18Smcpowers mp_digit d = 0;
3967f9fbec18Smcpowers
3968f9fbec18Smcpowers /* Inner product: Digits of a */
3969f9fbec18Smcpowers while (a_len--) {
3970f9fbec18Smcpowers mp_word w = ((mp_word)b * *a++) + *c + d;
3971f9fbec18Smcpowers *c++ = ACCUM(w);
3972f9fbec18Smcpowers d = CARRYOUT(w);
3973f9fbec18Smcpowers }
3974f9fbec18Smcpowers *c = d;
3975f9fbec18Smcpowers #else
3976f9fbec18Smcpowers mp_digit carry = 0;
3977f9fbec18Smcpowers while (a_len--) {
3978f9fbec18Smcpowers mp_digit a_i = *a++;
3979f9fbec18Smcpowers mp_digit a0b0, a1b1;
3980f9fbec18Smcpowers
3981f9fbec18Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0);
3982f9fbec18Smcpowers
3983f9fbec18Smcpowers a0b0 += carry;
3984f9fbec18Smcpowers if (a0b0 < carry)
3985f9fbec18Smcpowers ++a1b1;
3986f9fbec18Smcpowers a0b0 += a_i = *c;
3987f9fbec18Smcpowers if (a0b0 < a_i)
3988f9fbec18Smcpowers ++a1b1;
3989f9fbec18Smcpowers *c++ = a0b0;
3990f9fbec18Smcpowers carry = a1b1;
3991f9fbec18Smcpowers }
3992f9fbec18Smcpowers *c = carry;
3993f9fbec18Smcpowers #endif
3994f9fbec18Smcpowers }
3995f9fbec18Smcpowers
3996f9fbec18Smcpowers /* Presently, this is only used by the Montgomery arithmetic code. */
3997f9fbec18Smcpowers /* c += a * b */
s_mpv_mul_d_add_prop(const mp_digit * a,mp_size a_len,mp_digit b,mp_digit * c)3998f9fbec18Smcpowers void s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
3999f9fbec18Smcpowers {
4000f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
4001f9fbec18Smcpowers mp_digit d = 0;
4002f9fbec18Smcpowers
4003f9fbec18Smcpowers /* Inner product: Digits of a */
4004f9fbec18Smcpowers while (a_len--) {
4005f9fbec18Smcpowers mp_word w = ((mp_word)b * *a++) + *c + d;
4006f9fbec18Smcpowers *c++ = ACCUM(w);
4007f9fbec18Smcpowers d = CARRYOUT(w);
4008f9fbec18Smcpowers }
4009f9fbec18Smcpowers
4010f9fbec18Smcpowers while (d) {
4011f9fbec18Smcpowers mp_word w = (mp_word)*c + d;
4012f9fbec18Smcpowers *c++ = ACCUM(w);
4013f9fbec18Smcpowers d = CARRYOUT(w);
4014f9fbec18Smcpowers }
4015f9fbec18Smcpowers #else
4016f9fbec18Smcpowers mp_digit carry = 0;
4017f9fbec18Smcpowers while (a_len--) {
4018f9fbec18Smcpowers mp_digit a_i = *a++;
4019f9fbec18Smcpowers mp_digit a0b0, a1b1;
4020f9fbec18Smcpowers
4021f9fbec18Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0);
4022f9fbec18Smcpowers
4023f9fbec18Smcpowers a0b0 += carry;
4024f9fbec18Smcpowers if (a0b0 < carry)
4025f9fbec18Smcpowers ++a1b1;
4026f9fbec18Smcpowers
4027f9fbec18Smcpowers a0b0 += a_i = *c;
4028f9fbec18Smcpowers if (a0b0 < a_i)
4029f9fbec18Smcpowers ++a1b1;
4030f9fbec18Smcpowers
4031f9fbec18Smcpowers *c++ = a0b0;
4032f9fbec18Smcpowers carry = a1b1;
4033f9fbec18Smcpowers }
4034f9fbec18Smcpowers while (carry) {
4035f9fbec18Smcpowers mp_digit c_i = *c;
4036f9fbec18Smcpowers carry += c_i;
4037f9fbec18Smcpowers *c++ = carry;
4038f9fbec18Smcpowers carry = carry < c_i;
4039f9fbec18Smcpowers }
4040f9fbec18Smcpowers #endif
4041f9fbec18Smcpowers }
4042f9fbec18Smcpowers #endif
4043f9fbec18Smcpowers
4044f9fbec18Smcpowers #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
4045f9fbec18Smcpowers /* This trick works on Sparc V8 CPUs with the Workshop compilers. */
4046f9fbec18Smcpowers #define MP_SQR_D(a, Phi, Plo) \
4047f9fbec18Smcpowers { unsigned long long square = (unsigned long long)a * a; \
4048f9fbec18Smcpowers Plo = (mp_digit)square; \
4049f9fbec18Smcpowers Phi = (mp_digit)(square >> MP_DIGIT_BIT); }
4050f9fbec18Smcpowers #elif defined(OSF1)
4051f9fbec18Smcpowers #define MP_SQR_D(a, Phi, Plo) \
4052f9fbec18Smcpowers { Plo = asm ("mulq %a0, %a0, %v0", a);\
4053f9fbec18Smcpowers Phi = asm ("umulh %a0, %a0, %v0", a); }
4054f9fbec18Smcpowers #else
4055f9fbec18Smcpowers #define MP_SQR_D(a, Phi, Plo) \
4056f9fbec18Smcpowers { mp_digit Pmid; \
4057f9fbec18Smcpowers Plo = (a & MP_HALF_DIGIT_MAX) * (a & MP_HALF_DIGIT_MAX); \
4058f9fbec18Smcpowers Phi = (a >> MP_HALF_DIGIT_BIT) * (a >> MP_HALF_DIGIT_BIT); \
4059f9fbec18Smcpowers Pmid = (a & MP_HALF_DIGIT_MAX) * (a >> MP_HALF_DIGIT_BIT); \
4060f9fbec18Smcpowers Phi += Pmid >> (MP_HALF_DIGIT_BIT - 1); \
4061f9fbec18Smcpowers Pmid <<= (MP_HALF_DIGIT_BIT + 1); \
4062f9fbec18Smcpowers Plo += Pmid; \
4063f9fbec18Smcpowers if (Plo < Pmid) \
4064f9fbec18Smcpowers ++Phi; \
4065f9fbec18Smcpowers }
4066f9fbec18Smcpowers #endif
4067f9fbec18Smcpowers
4068f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_SQUARE)
4069f9fbec18Smcpowers /* Add the squares of the digits of a to the digits of b. */
s_mpv_sqr_add_prop(const mp_digit * pa,mp_size a_len,mp_digit * ps)4070f9fbec18Smcpowers void s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps)
4071f9fbec18Smcpowers {
4072f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
4073f9fbec18Smcpowers mp_word w;
4074f9fbec18Smcpowers mp_digit d;
4075f9fbec18Smcpowers mp_size ix;
4076f9fbec18Smcpowers
4077f9fbec18Smcpowers w = 0;
4078f9fbec18Smcpowers #define ADD_SQUARE(n) \
4079f9fbec18Smcpowers d = pa[n]; \
4080f9fbec18Smcpowers w += (d * (mp_word)d) + ps[2*n]; \
4081f9fbec18Smcpowers ps[2*n] = ACCUM(w); \
4082f9fbec18Smcpowers w = (w >> DIGIT_BIT) + ps[2*n+1]; \
4083f9fbec18Smcpowers ps[2*n+1] = ACCUM(w); \
4084f9fbec18Smcpowers w = (w >> DIGIT_BIT)
4085f9fbec18Smcpowers
4086f9fbec18Smcpowers for (ix = a_len; ix >= 4; ix -= 4) {
4087f9fbec18Smcpowers ADD_SQUARE(0);
4088f9fbec18Smcpowers ADD_SQUARE(1);
4089f9fbec18Smcpowers ADD_SQUARE(2);
4090f9fbec18Smcpowers ADD_SQUARE(3);
4091f9fbec18Smcpowers pa += 4;
4092f9fbec18Smcpowers ps += 8;
4093f9fbec18Smcpowers }
4094f9fbec18Smcpowers if (ix) {
4095f9fbec18Smcpowers ps += 2*ix;
4096f9fbec18Smcpowers pa += ix;
4097f9fbec18Smcpowers switch (ix) {
4098f9fbec18Smcpowers case 3: ADD_SQUARE(-3); /* FALLTHRU */
4099f9fbec18Smcpowers case 2: ADD_SQUARE(-2); /* FALLTHRU */
4100f9fbec18Smcpowers case 1: ADD_SQUARE(-1); /* FALLTHRU */
4101f9fbec18Smcpowers case 0: break;
4102f9fbec18Smcpowers }
4103f9fbec18Smcpowers }
4104f9fbec18Smcpowers while (w) {
4105f9fbec18Smcpowers w += *ps;
4106f9fbec18Smcpowers *ps++ = ACCUM(w);
4107f9fbec18Smcpowers w = (w >> DIGIT_BIT);
4108f9fbec18Smcpowers }
4109f9fbec18Smcpowers #else
4110f9fbec18Smcpowers mp_digit carry = 0;
4111f9fbec18Smcpowers while (a_len--) {
4112f9fbec18Smcpowers mp_digit a_i = *pa++;
4113f9fbec18Smcpowers mp_digit a0a0, a1a1;
4114f9fbec18Smcpowers
4115f9fbec18Smcpowers MP_SQR_D(a_i, a1a1, a0a0);
4116f9fbec18Smcpowers
4117f9fbec18Smcpowers /* here a1a1 and a0a0 constitute a_i ** 2 */
4118f9fbec18Smcpowers a0a0 += carry;
4119f9fbec18Smcpowers if (a0a0 < carry)
4120f9fbec18Smcpowers ++a1a1;
4121f9fbec18Smcpowers
4122f9fbec18Smcpowers /* now add to ps */
4123f9fbec18Smcpowers a0a0 += a_i = *ps;
4124f9fbec18Smcpowers if (a0a0 < a_i)
4125f9fbec18Smcpowers ++a1a1;
4126f9fbec18Smcpowers *ps++ = a0a0;
4127f9fbec18Smcpowers a1a1 += a_i = *ps;
4128f9fbec18Smcpowers carry = (a1a1 < a_i);
4129f9fbec18Smcpowers *ps++ = a1a1;
4130f9fbec18Smcpowers }
4131f9fbec18Smcpowers while (carry) {
4132f9fbec18Smcpowers mp_digit s_i = *ps;
4133f9fbec18Smcpowers carry += s_i;
4134f9fbec18Smcpowers *ps++ = carry;
4135f9fbec18Smcpowers carry = carry < s_i;
4136f9fbec18Smcpowers }
4137f9fbec18Smcpowers #endif
4138f9fbec18Smcpowers }
4139f9fbec18Smcpowers #endif
4140f9fbec18Smcpowers
4141f9fbec18Smcpowers #if (defined(MP_NO_MP_WORD) || defined(MP_NO_DIV_WORD)) \
4142f9fbec18Smcpowers && !defined(MP_ASSEMBLY_DIV_2DX1D)
4143f9fbec18Smcpowers /*
4144*55fea89dSDan Cross ** Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized
4145f9fbec18Smcpowers ** so its high bit is 1. This code is from NSPR.
4146f9fbec18Smcpowers */
s_mpv_div_2dx1d(mp_digit Nhi,mp_digit Nlo,mp_digit divisor,mp_digit * qp,mp_digit * rp)4147*55fea89dSDan Cross mp_err s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor,
4148f9fbec18Smcpowers mp_digit *qp, mp_digit *rp)
4149f9fbec18Smcpowers {
4150f9fbec18Smcpowers mp_digit d1, d0, q1, q0;
4151f9fbec18Smcpowers mp_digit r1, r0, m;
4152f9fbec18Smcpowers
4153f9fbec18Smcpowers d1 = divisor >> MP_HALF_DIGIT_BIT;
4154f9fbec18Smcpowers d0 = divisor & MP_HALF_DIGIT_MAX;
4155f9fbec18Smcpowers r1 = Nhi % d1;
4156f9fbec18Smcpowers q1 = Nhi / d1;
4157f9fbec18Smcpowers m = q1 * d0;
4158f9fbec18Smcpowers r1 = (r1 << MP_HALF_DIGIT_BIT) | (Nlo >> MP_HALF_DIGIT_BIT);
4159f9fbec18Smcpowers if (r1 < m) {
4160f9fbec18Smcpowers q1--, r1 += divisor;
4161f9fbec18Smcpowers if (r1 >= divisor && r1 < m) {
4162f9fbec18Smcpowers q1--, r1 += divisor;
4163f9fbec18Smcpowers }
4164f9fbec18Smcpowers }
4165f9fbec18Smcpowers r1 -= m;
4166f9fbec18Smcpowers r0 = r1 % d1;
4167f9fbec18Smcpowers q0 = r1 / d1;
4168f9fbec18Smcpowers m = q0 * d0;
4169f9fbec18Smcpowers r0 = (r0 << MP_HALF_DIGIT_BIT) | (Nlo & MP_HALF_DIGIT_MAX);
4170f9fbec18Smcpowers if (r0 < m) {
4171f9fbec18Smcpowers q0--, r0 += divisor;
4172f9fbec18Smcpowers if (r0 >= divisor && r0 < m) {
4173f9fbec18Smcpowers q0--, r0 += divisor;
4174f9fbec18Smcpowers }
4175f9fbec18Smcpowers }
4176f9fbec18Smcpowers if (qp)
4177f9fbec18Smcpowers *qp = (q1 << MP_HALF_DIGIT_BIT) | q0;
4178f9fbec18Smcpowers if (rp)
4179f9fbec18Smcpowers *rp = r0 - m;
4180f9fbec18Smcpowers return MP_OKAY;
4181f9fbec18Smcpowers }
4182f9fbec18Smcpowers #endif
4183f9fbec18Smcpowers
4184f9fbec18Smcpowers #if MP_SQUARE
4185f9fbec18Smcpowers /* {{{ s_mp_sqr(a) */
4186f9fbec18Smcpowers
s_mp_sqr(mp_int * a)4187f9fbec18Smcpowers mp_err s_mp_sqr(mp_int *a)
4188f9fbec18Smcpowers {
4189f9fbec18Smcpowers mp_err res;
4190f9fbec18Smcpowers mp_int tmp;
4191f9fbec18Smcpowers
4192f9fbec18Smcpowers if((res = mp_init_size(&tmp, 2 * USED(a), FLAG(a))) != MP_OKAY)
4193f9fbec18Smcpowers return res;
4194f9fbec18Smcpowers res = mp_sqr(a, &tmp);
4195f9fbec18Smcpowers if (res == MP_OKAY) {
4196f9fbec18Smcpowers s_mp_exch(&tmp, a);
4197f9fbec18Smcpowers }
4198f9fbec18Smcpowers mp_clear(&tmp);
4199f9fbec18Smcpowers return res;
4200f9fbec18Smcpowers }
4201f9fbec18Smcpowers
4202f9fbec18Smcpowers /* }}} */
4203f9fbec18Smcpowers #endif
4204f9fbec18Smcpowers
4205f9fbec18Smcpowers /* {{{ s_mp_div(a, b) */
4206f9fbec18Smcpowers
4207f9fbec18Smcpowers /*
4208f9fbec18Smcpowers s_mp_div(a, b)
4209f9fbec18Smcpowers
4210f9fbec18Smcpowers Compute a = a / b and b = a mod b. Assumes b > a.
4211f9fbec18Smcpowers */
4212f9fbec18Smcpowers
s_mp_div(mp_int * rem,mp_int * div,mp_int * quot)4213f9fbec18Smcpowers mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */
4214f9fbec18Smcpowers mp_int *div, /* i: divisor */
4215f9fbec18Smcpowers mp_int *quot) /* i: 0; o: quotient */
4216f9fbec18Smcpowers {
4217f9fbec18Smcpowers mp_int part, t;
4218f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
4219f9fbec18Smcpowers mp_word q_msd;
4220f9fbec18Smcpowers #else
4221f9fbec18Smcpowers mp_digit q_msd;
4222f9fbec18Smcpowers #endif
4223f9fbec18Smcpowers mp_err res;
4224f9fbec18Smcpowers mp_digit d;
4225f9fbec18Smcpowers mp_digit div_msd;
4226f9fbec18Smcpowers int ix;
4227f9fbec18Smcpowers
4228f9fbec18Smcpowers if(mp_cmp_z(div) == 0)
4229f9fbec18Smcpowers return MP_RANGE;
4230f9fbec18Smcpowers
4231f9fbec18Smcpowers /* Shortcut if divisor is power of two */
4232f9fbec18Smcpowers if((ix = s_mp_ispow2(div)) >= 0) {
4233f9fbec18Smcpowers MP_CHECKOK( mp_copy(rem, quot) );
4234f9fbec18Smcpowers s_mp_div_2d(quot, (mp_digit)ix);
4235f9fbec18Smcpowers s_mp_mod_2d(rem, (mp_digit)ix);
4236f9fbec18Smcpowers
4237f9fbec18Smcpowers return MP_OKAY;
4238f9fbec18Smcpowers }
4239f9fbec18Smcpowers
4240f9fbec18Smcpowers DIGITS(&t) = 0;
4241f9fbec18Smcpowers MP_SIGN(rem) = ZPOS;
4242f9fbec18Smcpowers MP_SIGN(div) = ZPOS;
4243f9fbec18Smcpowers
4244f9fbec18Smcpowers /* A working temporary for division */
4245f9fbec18Smcpowers MP_CHECKOK( mp_init_size(&t, MP_ALLOC(rem), FLAG(rem)));
4246f9fbec18Smcpowers
4247f9fbec18Smcpowers /* Normalize to optimize guessing */
4248f9fbec18Smcpowers MP_CHECKOK( s_mp_norm(rem, div, &d) );
4249f9fbec18Smcpowers
4250f9fbec18Smcpowers part = *rem;
4251f9fbec18Smcpowers
4252f9fbec18Smcpowers /* Perform the division itself...woo! */
4253f9fbec18Smcpowers MP_USED(quot) = MP_ALLOC(quot);
4254f9fbec18Smcpowers
4255f9fbec18Smcpowers /* Find a partial substring of rem which is at least div */
4256f9fbec18Smcpowers /* If we didn't find one, we're finished dividing */
4257f9fbec18Smcpowers while (MP_USED(rem) > MP_USED(div) || s_mp_cmp(rem, div) >= 0) {
4258f9fbec18Smcpowers int i;
4259f9fbec18Smcpowers int unusedRem;
4260f9fbec18Smcpowers
4261f9fbec18Smcpowers unusedRem = MP_USED(rem) - MP_USED(div);
4262f9fbec18Smcpowers MP_DIGITS(&part) = MP_DIGITS(rem) + unusedRem;
4263f9fbec18Smcpowers MP_ALLOC(&part) = MP_ALLOC(rem) - unusedRem;
4264f9fbec18Smcpowers MP_USED(&part) = MP_USED(div);
4265f9fbec18Smcpowers if (s_mp_cmp(&part, div) < 0) {
4266f9fbec18Smcpowers -- unusedRem;
4267f9fbec18Smcpowers #if MP_ARGCHK == 2
4268f9fbec18Smcpowers assert(unusedRem >= 0);
4269f9fbec18Smcpowers #endif
4270f9fbec18Smcpowers -- MP_DIGITS(&part);
4271f9fbec18Smcpowers ++ MP_USED(&part);
4272f9fbec18Smcpowers ++ MP_ALLOC(&part);
4273f9fbec18Smcpowers }
4274f9fbec18Smcpowers
4275f9fbec18Smcpowers /* Compute a guess for the next quotient digit */
4276f9fbec18Smcpowers q_msd = MP_DIGIT(&part, MP_USED(&part) - 1);
4277f9fbec18Smcpowers div_msd = MP_DIGIT(div, MP_USED(div) - 1);
4278f9fbec18Smcpowers if (q_msd >= div_msd) {
4279f9fbec18Smcpowers q_msd = 1;
4280f9fbec18Smcpowers } else if (MP_USED(&part) > 1) {
4281f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
4282f9fbec18Smcpowers q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2);
4283f9fbec18Smcpowers q_msd /= div_msd;
4284f9fbec18Smcpowers if (q_msd == RADIX)
4285f9fbec18Smcpowers --q_msd;
4286f9fbec18Smcpowers #else
4287f9fbec18Smcpowers mp_digit r;
4288*55fea89dSDan Cross MP_CHECKOK( s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2),
4289f9fbec18Smcpowers div_msd, &q_msd, &r) );
4290f9fbec18Smcpowers #endif
4291f9fbec18Smcpowers } else {
4292f9fbec18Smcpowers q_msd = 0;
4293f9fbec18Smcpowers }
4294f9fbec18Smcpowers #if MP_ARGCHK == 2
4295f9fbec18Smcpowers assert(q_msd > 0); /* This case should never occur any more. */
4296f9fbec18Smcpowers #endif
4297f9fbec18Smcpowers if (q_msd <= 0)
4298f9fbec18Smcpowers break;
4299f9fbec18Smcpowers
4300f9fbec18Smcpowers /* See what that multiplies out to */
4301f9fbec18Smcpowers mp_copy(div, &t);
4302f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_d(&t, (mp_digit)q_msd) );
4303f9fbec18Smcpowers
4304*55fea89dSDan Cross /*
4305f9fbec18Smcpowers If it's too big, back it off. We should not have to do this
4306f9fbec18Smcpowers more than once, or, in rare cases, twice. Knuth describes a
4307f9fbec18Smcpowers method by which this could be reduced to a maximum of once, but
4308f9fbec18Smcpowers I didn't implement that here.
4309f9fbec18Smcpowers * When using s_mpv_div_2dx1d, we may have to do this 3 times.
4310f9fbec18Smcpowers */
4311f9fbec18Smcpowers for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) {
4312f9fbec18Smcpowers --q_msd;
4313f9fbec18Smcpowers s_mp_sub(&t, div); /* t -= div */
4314f9fbec18Smcpowers }
4315f9fbec18Smcpowers if (i < 0) {
4316f9fbec18Smcpowers res = MP_RANGE;
4317f9fbec18Smcpowers goto CLEANUP;
4318f9fbec18Smcpowers }
4319f9fbec18Smcpowers
4320f9fbec18Smcpowers /* At this point, q_msd should be the right next digit */
4321f9fbec18Smcpowers MP_CHECKOK( s_mp_sub(&part, &t) ); /* part -= t */
4322f9fbec18Smcpowers s_mp_clamp(rem);
4323f9fbec18Smcpowers
4324f9fbec18Smcpowers /*
4325f9fbec18Smcpowers Include the digit in the quotient. We allocated enough memory
4326f9fbec18Smcpowers for any quotient we could ever possibly get, so we should not
4327f9fbec18Smcpowers have to check for failures here
4328f9fbec18Smcpowers */
4329f9fbec18Smcpowers MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd;
4330f9fbec18Smcpowers }
4331f9fbec18Smcpowers
4332f9fbec18Smcpowers /* Denormalize remainder */
4333f9fbec18Smcpowers if (d) {
4334f9fbec18Smcpowers s_mp_div_2d(rem, d);
4335f9fbec18Smcpowers }
4336f9fbec18Smcpowers
4337f9fbec18Smcpowers s_mp_clamp(quot);
4338f9fbec18Smcpowers
4339f9fbec18Smcpowers CLEANUP:
4340f9fbec18Smcpowers mp_clear(&t);
4341f9fbec18Smcpowers
4342f9fbec18Smcpowers return res;
4343f9fbec18Smcpowers
4344f9fbec18Smcpowers } /* end s_mp_div() */
4345f9fbec18Smcpowers
4346f9fbec18Smcpowers
4347f9fbec18Smcpowers /* }}} */
4348f9fbec18Smcpowers
4349f9fbec18Smcpowers /* {{{ s_mp_2expt(a, k) */
4350f9fbec18Smcpowers
s_mp_2expt(mp_int * a,mp_digit k)4351f9fbec18Smcpowers mp_err s_mp_2expt(mp_int *a, mp_digit k)
4352f9fbec18Smcpowers {
4353f9fbec18Smcpowers mp_err res;
4354f9fbec18Smcpowers mp_size dig, bit;
4355f9fbec18Smcpowers
4356f9fbec18Smcpowers dig = k / DIGIT_BIT;
4357f9fbec18Smcpowers bit = k % DIGIT_BIT;
4358f9fbec18Smcpowers
4359f9fbec18Smcpowers mp_zero(a);
4360f9fbec18Smcpowers if((res = s_mp_pad(a, dig + 1)) != MP_OKAY)
4361f9fbec18Smcpowers return res;
4362*55fea89dSDan Cross
4363f9fbec18Smcpowers DIGIT(a, dig) |= ((mp_digit)1 << bit);
4364f9fbec18Smcpowers
4365f9fbec18Smcpowers return MP_OKAY;
4366f9fbec18Smcpowers
4367f9fbec18Smcpowers } /* end s_mp_2expt() */
4368f9fbec18Smcpowers
4369f9fbec18Smcpowers /* }}} */
4370f9fbec18Smcpowers
4371f9fbec18Smcpowers /* {{{ s_mp_reduce(x, m, mu) */
4372f9fbec18Smcpowers
4373f9fbec18Smcpowers /*
4374f9fbec18Smcpowers Compute Barrett reduction, x (mod m), given a precomputed value for
4375f9fbec18Smcpowers mu = b^2k / m, where b = RADIX and k = #digits(m). This should be
4376f9fbec18Smcpowers faster than straight division, when many reductions by the same
4377f9fbec18Smcpowers value of m are required (such as in modular exponentiation). This
4378f9fbec18Smcpowers can nearly halve the time required to do modular exponentiation,
4379f9fbec18Smcpowers as compared to using the full integer divide to reduce.
4380f9fbec18Smcpowers
4381f9fbec18Smcpowers This algorithm was derived from the _Handbook of Applied
4382f9fbec18Smcpowers Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
4383*55fea89dSDan Cross pp. 603-604.
4384f9fbec18Smcpowers */
4385f9fbec18Smcpowers
s_mp_reduce(mp_int * x,const mp_int * m,const mp_int * mu)4386f9fbec18Smcpowers mp_err s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
4387f9fbec18Smcpowers {
4388f9fbec18Smcpowers mp_int q;
4389f9fbec18Smcpowers mp_err res;
4390f9fbec18Smcpowers
4391f9fbec18Smcpowers if((res = mp_init_copy(&q, x)) != MP_OKAY)
4392f9fbec18Smcpowers return res;
4393f9fbec18Smcpowers
4394f9fbec18Smcpowers s_mp_rshd(&q, USED(m) - 1); /* q1 = x / b^(k-1) */
4395f9fbec18Smcpowers s_mp_mul(&q, mu); /* q2 = q1 * mu */
4396f9fbec18Smcpowers s_mp_rshd(&q, USED(m) + 1); /* q3 = q2 / b^(k+1) */
4397f9fbec18Smcpowers
4398f9fbec18Smcpowers /* x = x mod b^(k+1), quick (no division) */
4399f9fbec18Smcpowers s_mp_mod_2d(x, DIGIT_BIT * (USED(m) + 1));
4400f9fbec18Smcpowers
4401f9fbec18Smcpowers /* q = q * m mod b^(k+1), quick (no division) */
4402f9fbec18Smcpowers s_mp_mul(&q, m);
4403f9fbec18Smcpowers s_mp_mod_2d(&q, DIGIT_BIT * (USED(m) + 1));
4404f9fbec18Smcpowers
4405f9fbec18Smcpowers /* x = x - q */
4406f9fbec18Smcpowers if((res = mp_sub(x, &q, x)) != MP_OKAY)
4407f9fbec18Smcpowers goto CLEANUP;
4408f9fbec18Smcpowers
4409f9fbec18Smcpowers /* If x < 0, add b^(k+1) to it */
4410f9fbec18Smcpowers if(mp_cmp_z(x) < 0) {
4411f9fbec18Smcpowers mp_set(&q, 1);
4412f9fbec18Smcpowers if((res = s_mp_lshd(&q, USED(m) + 1)) != MP_OKAY)
4413f9fbec18Smcpowers goto CLEANUP;
4414f9fbec18Smcpowers if((res = mp_add(x, &q, x)) != MP_OKAY)
4415f9fbec18Smcpowers goto CLEANUP;
4416f9fbec18Smcpowers }
4417f9fbec18Smcpowers
4418f9fbec18Smcpowers /* Back off if it's too big */
4419f9fbec18Smcpowers while(mp_cmp(x, m) >= 0) {
4420f9fbec18Smcpowers if((res = s_mp_sub(x, m)) != MP_OKAY)
4421f9fbec18Smcpowers break;
4422f9fbec18Smcpowers }
4423f9fbec18Smcpowers
4424f9fbec18Smcpowers CLEANUP:
4425f9fbec18Smcpowers mp_clear(&q);
4426f9fbec18Smcpowers
4427f9fbec18Smcpowers return res;
4428f9fbec18Smcpowers
4429f9fbec18Smcpowers } /* end s_mp_reduce() */
4430f9fbec18Smcpowers
4431f9fbec18Smcpowers /* }}} */
4432f9fbec18Smcpowers
4433f9fbec18Smcpowers /* }}} */
4434f9fbec18Smcpowers
4435f9fbec18Smcpowers /* {{{ Primitive comparisons */
4436f9fbec18Smcpowers
4437f9fbec18Smcpowers /* {{{ s_mp_cmp(a, b) */
4438f9fbec18Smcpowers
4439f9fbec18Smcpowers /* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b */
s_mp_cmp(const mp_int * a,const mp_int * b)4440f9fbec18Smcpowers int s_mp_cmp(const mp_int *a, const mp_int *b)
4441f9fbec18Smcpowers {
4442f9fbec18Smcpowers mp_size used_a = MP_USED(a);
4443f9fbec18Smcpowers {
4444f9fbec18Smcpowers mp_size used_b = MP_USED(b);
4445f9fbec18Smcpowers
4446f9fbec18Smcpowers if (used_a > used_b)
4447f9fbec18Smcpowers goto IS_GT;
4448f9fbec18Smcpowers if (used_a < used_b)
4449f9fbec18Smcpowers goto IS_LT;
4450f9fbec18Smcpowers }
4451f9fbec18Smcpowers {
4452f9fbec18Smcpowers mp_digit *pa, *pb;
4453f9fbec18Smcpowers mp_digit da = 0, db = 0;
4454f9fbec18Smcpowers
4455f9fbec18Smcpowers #define CMP_AB(n) if ((da = pa[n]) != (db = pb[n])) goto done
4456f9fbec18Smcpowers
4457f9fbec18Smcpowers pa = MP_DIGITS(a) + used_a;
4458f9fbec18Smcpowers pb = MP_DIGITS(b) + used_a;
4459f9fbec18Smcpowers while (used_a >= 4) {
4460f9fbec18Smcpowers pa -= 4;
4461f9fbec18Smcpowers pb -= 4;
4462f9fbec18Smcpowers used_a -= 4;
4463f9fbec18Smcpowers CMP_AB(3);
4464f9fbec18Smcpowers CMP_AB(2);
4465f9fbec18Smcpowers CMP_AB(1);
4466f9fbec18Smcpowers CMP_AB(0);
4467f9fbec18Smcpowers }
4468*55fea89dSDan Cross while (used_a-- > 0 && ((da = *--pa) == (db = *--pb)))
4469f9fbec18Smcpowers /* do nothing */;
4470f9fbec18Smcpowers done:
4471f9fbec18Smcpowers if (da > db)
4472f9fbec18Smcpowers goto IS_GT;
4473*55fea89dSDan Cross if (da < db)
4474f9fbec18Smcpowers goto IS_LT;
4475f9fbec18Smcpowers }
4476f9fbec18Smcpowers return MP_EQ;
4477f9fbec18Smcpowers IS_LT:
4478f9fbec18Smcpowers return MP_LT;
4479f9fbec18Smcpowers IS_GT:
4480f9fbec18Smcpowers return MP_GT;
4481f9fbec18Smcpowers } /* end s_mp_cmp() */
4482f9fbec18Smcpowers
4483f9fbec18Smcpowers /* }}} */
4484f9fbec18Smcpowers
4485f9fbec18Smcpowers /* {{{ s_mp_cmp_d(a, d) */
4486f9fbec18Smcpowers
4487f9fbec18Smcpowers /* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d */
s_mp_cmp_d(const mp_int * a,mp_digit d)4488f9fbec18Smcpowers int s_mp_cmp_d(const mp_int *a, mp_digit d)
4489f9fbec18Smcpowers {
4490f9fbec18Smcpowers if(USED(a) > 1)
4491f9fbec18Smcpowers return MP_GT;
4492f9fbec18Smcpowers
4493f9fbec18Smcpowers if(DIGIT(a, 0) < d)
4494f9fbec18Smcpowers return MP_LT;
4495f9fbec18Smcpowers else if(DIGIT(a, 0) > d)
4496f9fbec18Smcpowers return MP_GT;
4497f9fbec18Smcpowers else
4498f9fbec18Smcpowers return MP_EQ;
4499f9fbec18Smcpowers
4500f9fbec18Smcpowers } /* end s_mp_cmp_d() */
4501f9fbec18Smcpowers
4502f9fbec18Smcpowers /* }}} */
4503f9fbec18Smcpowers
4504f9fbec18Smcpowers /* {{{ s_mp_ispow2(v) */
4505f9fbec18Smcpowers
4506f9fbec18Smcpowers /*
4507f9fbec18Smcpowers Returns -1 if the value is not a power of two; otherwise, it returns
4508f9fbec18Smcpowers k such that v = 2^k, i.e. lg(v).
4509f9fbec18Smcpowers */
s_mp_ispow2(const mp_int * v)4510f9fbec18Smcpowers int s_mp_ispow2(const mp_int *v)
4511f9fbec18Smcpowers {
4512f9fbec18Smcpowers mp_digit d;
4513f9fbec18Smcpowers int extra = 0, ix;
4514f9fbec18Smcpowers
4515f9fbec18Smcpowers ix = MP_USED(v) - 1;
4516f9fbec18Smcpowers d = MP_DIGIT(v, ix); /* most significant digit of v */
4517f9fbec18Smcpowers
4518f9fbec18Smcpowers extra = s_mp_ispow2d(d);
4519f9fbec18Smcpowers if (extra < 0 || ix == 0)
4520f9fbec18Smcpowers return extra;
4521f9fbec18Smcpowers
4522f9fbec18Smcpowers while (--ix >= 0) {
4523f9fbec18Smcpowers if (DIGIT(v, ix) != 0)
4524f9fbec18Smcpowers return -1; /* not a power of two */
4525f9fbec18Smcpowers extra += MP_DIGIT_BIT;
4526f9fbec18Smcpowers }
4527f9fbec18Smcpowers
4528f9fbec18Smcpowers return extra;
4529f9fbec18Smcpowers
4530f9fbec18Smcpowers } /* end s_mp_ispow2() */
4531f9fbec18Smcpowers
4532f9fbec18Smcpowers /* }}} */
4533f9fbec18Smcpowers
4534f9fbec18Smcpowers /* {{{ s_mp_ispow2d(d) */
4535f9fbec18Smcpowers
s_mp_ispow2d(mp_digit d)4536f9fbec18Smcpowers int s_mp_ispow2d(mp_digit d)
4537f9fbec18Smcpowers {
4538f9fbec18Smcpowers if ((d != 0) && ((d & (d-1)) == 0)) { /* d is a power of 2 */
4539f9fbec18Smcpowers int pow = 0;
4540f9fbec18Smcpowers #if defined (MP_USE_UINT_DIGIT)
4541f9fbec18Smcpowers if (d & 0xffff0000U)
4542f9fbec18Smcpowers pow += 16;
4543f9fbec18Smcpowers if (d & 0xff00ff00U)
4544f9fbec18Smcpowers pow += 8;
4545f9fbec18Smcpowers if (d & 0xf0f0f0f0U)
4546f9fbec18Smcpowers pow += 4;
4547f9fbec18Smcpowers if (d & 0xccccccccU)
4548f9fbec18Smcpowers pow += 2;
4549f9fbec18Smcpowers if (d & 0xaaaaaaaaU)
4550f9fbec18Smcpowers pow += 1;
4551f9fbec18Smcpowers #elif defined(MP_USE_LONG_LONG_DIGIT)
4552f9fbec18Smcpowers if (d & 0xffffffff00000000ULL)
4553f9fbec18Smcpowers pow += 32;
4554f9fbec18Smcpowers if (d & 0xffff0000ffff0000ULL)
4555f9fbec18Smcpowers pow += 16;
4556f9fbec18Smcpowers if (d & 0xff00ff00ff00ff00ULL)
4557f9fbec18Smcpowers pow += 8;
4558f9fbec18Smcpowers if (d & 0xf0f0f0f0f0f0f0f0ULL)
4559f9fbec18Smcpowers pow += 4;
4560f9fbec18Smcpowers if (d & 0xccccccccccccccccULL)
4561f9fbec18Smcpowers pow += 2;
4562f9fbec18Smcpowers if (d & 0xaaaaaaaaaaaaaaaaULL)
4563f9fbec18Smcpowers pow += 1;
4564f9fbec18Smcpowers #elif defined(MP_USE_LONG_DIGIT)
4565f9fbec18Smcpowers if (d & 0xffffffff00000000UL)
4566f9fbec18Smcpowers pow += 32;
4567f9fbec18Smcpowers if (d & 0xffff0000ffff0000UL)
4568f9fbec18Smcpowers pow += 16;
4569f9fbec18Smcpowers if (d & 0xff00ff00ff00ff00UL)
4570f9fbec18Smcpowers pow += 8;
4571f9fbec18Smcpowers if (d & 0xf0f0f0f0f0f0f0f0UL)
4572f9fbec18Smcpowers pow += 4;
4573f9fbec18Smcpowers if (d & 0xccccccccccccccccUL)
4574f9fbec18Smcpowers pow += 2;
4575f9fbec18Smcpowers if (d & 0xaaaaaaaaaaaaaaaaUL)
4576f9fbec18Smcpowers pow += 1;
4577f9fbec18Smcpowers #else
4578f9fbec18Smcpowers #error "unknown type for mp_digit"
4579f9fbec18Smcpowers #endif
4580f9fbec18Smcpowers return pow;
4581f9fbec18Smcpowers }
4582f9fbec18Smcpowers return -1;
4583f9fbec18Smcpowers
4584f9fbec18Smcpowers } /* end s_mp_ispow2d() */
4585f9fbec18Smcpowers
4586f9fbec18Smcpowers /* }}} */
4587f9fbec18Smcpowers
4588f9fbec18Smcpowers /* }}} */
4589f9fbec18Smcpowers
4590f9fbec18Smcpowers /* {{{ Primitive I/O helpers */
4591f9fbec18Smcpowers
4592f9fbec18Smcpowers /* {{{ s_mp_tovalue(ch, r) */
4593f9fbec18Smcpowers
4594f9fbec18Smcpowers /*
4595f9fbec18Smcpowers Convert the given character to its digit value, in the given radix.
4596f9fbec18Smcpowers If the given character is not understood in the given radix, -1 is
4597f9fbec18Smcpowers returned. Otherwise the digit's numeric value is returned.
4598f9fbec18Smcpowers
4599f9fbec18Smcpowers The results will be odd if you use a radix < 2 or > 62, you are
4600f9fbec18Smcpowers expected to know what you're up to.
4601f9fbec18Smcpowers */
s_mp_tovalue(char ch,int r)4602f9fbec18Smcpowers int s_mp_tovalue(char ch, int r)
4603f9fbec18Smcpowers {
4604f9fbec18Smcpowers int val, xch;
4605*55fea89dSDan Cross
4606f9fbec18Smcpowers if(r > 36)
4607f9fbec18Smcpowers xch = ch;
4608f9fbec18Smcpowers else
4609f9fbec18Smcpowers xch = toupper(ch);
4610f9fbec18Smcpowers
4611f9fbec18Smcpowers if(isdigit(xch))
4612f9fbec18Smcpowers val = xch - '0';
4613f9fbec18Smcpowers else if(isupper(xch))
4614f9fbec18Smcpowers val = xch - 'A' + 10;
4615f9fbec18Smcpowers else if(islower(xch))
4616f9fbec18Smcpowers val = xch - 'a' + 36;
4617f9fbec18Smcpowers else if(xch == '+')
4618f9fbec18Smcpowers val = 62;
4619f9fbec18Smcpowers else if(xch == '/')
4620f9fbec18Smcpowers val = 63;
4621*55fea89dSDan Cross else
4622f9fbec18Smcpowers return -1;
4623f9fbec18Smcpowers
4624f9fbec18Smcpowers if(val < 0 || val >= r)
4625f9fbec18Smcpowers return -1;
4626f9fbec18Smcpowers
4627f9fbec18Smcpowers return val;
4628f9fbec18Smcpowers
4629f9fbec18Smcpowers } /* end s_mp_tovalue() */
4630f9fbec18Smcpowers
4631f9fbec18Smcpowers /* }}} */
4632f9fbec18Smcpowers
4633f9fbec18Smcpowers /* {{{ s_mp_todigit(val, r, low) */
4634f9fbec18Smcpowers
4635f9fbec18Smcpowers /*
4636f9fbec18Smcpowers Convert val to a radix-r digit, if possible. If val is out of range
4637f9fbec18Smcpowers for r, returns zero. Otherwise, returns an ASCII character denoting
4638f9fbec18Smcpowers the value in the given radix.
4639f9fbec18Smcpowers
4640f9fbec18Smcpowers The results may be odd if you use a radix < 2 or > 64, you are
4641f9fbec18Smcpowers expected to know what you're doing.
4642f9fbec18Smcpowers */
4643*55fea89dSDan Cross
s_mp_todigit(mp_digit val,int r,int low)4644f9fbec18Smcpowers char s_mp_todigit(mp_digit val, int r, int low)
4645f9fbec18Smcpowers {
4646f9fbec18Smcpowers char ch;
4647f9fbec18Smcpowers
4648f9fbec18Smcpowers if(val >= r)
4649f9fbec18Smcpowers return 0;
4650f9fbec18Smcpowers
4651f9fbec18Smcpowers ch = s_dmap_1[val];
4652f9fbec18Smcpowers
4653f9fbec18Smcpowers if(r <= 36 && low)
4654f9fbec18Smcpowers ch = tolower(ch);
4655f9fbec18Smcpowers
4656f9fbec18Smcpowers return ch;
4657f9fbec18Smcpowers
4658f9fbec18Smcpowers } /* end s_mp_todigit() */
4659f9fbec18Smcpowers
4660f9fbec18Smcpowers /* }}} */
4661f9fbec18Smcpowers
4662f9fbec18Smcpowers /* {{{ s_mp_outlen(bits, radix) */
4663f9fbec18Smcpowers
4664*55fea89dSDan Cross /*
4665f9fbec18Smcpowers Return an estimate for how long a string is needed to hold a radix
4666f9fbec18Smcpowers r representation of a number with 'bits' significant bits, plus an
4667f9fbec18Smcpowers extra for a zero terminator (assuming C style strings here)
4668f9fbec18Smcpowers */
s_mp_outlen(int bits,int r)4669f9fbec18Smcpowers int s_mp_outlen(int bits, int r)
4670f9fbec18Smcpowers {
4671f9fbec18Smcpowers return (int)((double)bits * LOG_V_2(r) + 1.5) + 1;
4672f9fbec18Smcpowers
4673f9fbec18Smcpowers } /* end s_mp_outlen() */
4674f9fbec18Smcpowers
4675f9fbec18Smcpowers /* }}} */
4676f9fbec18Smcpowers
4677f9fbec18Smcpowers /* }}} */
4678f9fbec18Smcpowers
4679f9fbec18Smcpowers /* {{{ mp_read_unsigned_octets(mp, str, len) */
4680f9fbec18Smcpowers /* mp_read_unsigned_octets(mp, str, len)
4681f9fbec18Smcpowers Read in a raw value (base 256) into the given mp_int
4682f9fbec18Smcpowers No sign bit, number is positive. Leading zeros ignored.
4683f9fbec18Smcpowers */
4684f9fbec18Smcpowers
4685*55fea89dSDan Cross mp_err
mp_read_unsigned_octets(mp_int * mp,const unsigned char * str,mp_size len)4686f9fbec18Smcpowers mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len)
4687f9fbec18Smcpowers {
4688f9fbec18Smcpowers int count;
4689f9fbec18Smcpowers mp_err res;
4690f9fbec18Smcpowers mp_digit d;
4691f9fbec18Smcpowers
4692f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
4693f9fbec18Smcpowers
4694f9fbec18Smcpowers mp_zero(mp);
4695f9fbec18Smcpowers
4696f9fbec18Smcpowers count = len % sizeof(mp_digit);
4697f9fbec18Smcpowers if (count) {
4698f9fbec18Smcpowers for (d = 0; count-- > 0; --len) {
4699f9fbec18Smcpowers d = (d << 8) | *str++;
4700f9fbec18Smcpowers }
4701f9fbec18Smcpowers MP_DIGIT(mp, 0) = d;
4702f9fbec18Smcpowers }
4703f9fbec18Smcpowers
4704f9fbec18Smcpowers /* Read the rest of the digits */
4705f9fbec18Smcpowers for(; len > 0; len -= sizeof(mp_digit)) {
4706f9fbec18Smcpowers for (d = 0, count = sizeof(mp_digit); count > 0; --count) {
4707f9fbec18Smcpowers d = (d << 8) | *str++;
4708f9fbec18Smcpowers }
4709f9fbec18Smcpowers if (MP_EQ == mp_cmp_z(mp)) {
4710f9fbec18Smcpowers if (!d)
4711f9fbec18Smcpowers continue;
4712f9fbec18Smcpowers } else {
4713f9fbec18Smcpowers if((res = s_mp_lshd(mp, 1)) != MP_OKAY)
4714f9fbec18Smcpowers return res;
4715f9fbec18Smcpowers }
4716f9fbec18Smcpowers MP_DIGIT(mp, 0) = d;
4717f9fbec18Smcpowers }
4718f9fbec18Smcpowers return MP_OKAY;
4719f9fbec18Smcpowers } /* end mp_read_unsigned_octets() */
4720f9fbec18Smcpowers /* }}} */
4721f9fbec18Smcpowers
4722f9fbec18Smcpowers /* {{{ mp_unsigned_octet_size(mp) */
4723*55fea89dSDan Cross int
mp_unsigned_octet_size(const mp_int * mp)4724f9fbec18Smcpowers mp_unsigned_octet_size(const mp_int *mp)
4725f9fbec18Smcpowers {
4726f9fbec18Smcpowers int bytes;
4727f9fbec18Smcpowers int ix;
4728f9fbec18Smcpowers mp_digit d = 0;
4729f9fbec18Smcpowers
4730f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG);
4731f9fbec18Smcpowers ARGCHK(MP_ZPOS == SIGN(mp), MP_BADARG);
4732f9fbec18Smcpowers
4733f9fbec18Smcpowers bytes = (USED(mp) * sizeof(mp_digit));
4734f9fbec18Smcpowers
4735f9fbec18Smcpowers /* subtract leading zeros. */
4736f9fbec18Smcpowers /* Iterate over each digit... */
4737f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
4738f9fbec18Smcpowers d = DIGIT(mp, ix);
4739*55fea89dSDan Cross if (d)
4740f9fbec18Smcpowers break;
4741f9fbec18Smcpowers bytes -= sizeof(d);
4742f9fbec18Smcpowers }
4743f9fbec18Smcpowers if (!bytes)
4744f9fbec18Smcpowers return 1;
4745f9fbec18Smcpowers
4746f9fbec18Smcpowers /* Have MSD, check digit bytes, high order first */
4747f9fbec18Smcpowers for(ix = sizeof(mp_digit) - 1; ix >= 0; ix--) {
4748f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (ix * CHAR_BIT));
4749*55fea89dSDan Cross if (x)
4750f9fbec18Smcpowers break;
4751f9fbec18Smcpowers --bytes;
4752f9fbec18Smcpowers }
4753f9fbec18Smcpowers return bytes;
4754f9fbec18Smcpowers } /* end mp_unsigned_octet_size() */
4755f9fbec18Smcpowers /* }}} */
4756f9fbec18Smcpowers
4757f9fbec18Smcpowers /* {{{ mp_to_unsigned_octets(mp, str) */
4758f9fbec18Smcpowers /* output a buffer of big endian octets no longer than specified. */
4759*55fea89dSDan Cross mp_err
mp_to_unsigned_octets(const mp_int * mp,unsigned char * str,mp_size maxlen)4760f9fbec18Smcpowers mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
4761f9fbec18Smcpowers {
4762f9fbec18Smcpowers int ix, pos = 0;
4763f9fbec18Smcpowers int bytes;
4764f9fbec18Smcpowers
4765f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
4766f9fbec18Smcpowers
4767f9fbec18Smcpowers bytes = mp_unsigned_octet_size(mp);
4768f9fbec18Smcpowers ARGCHK(bytes <= maxlen, MP_BADARG);
4769f9fbec18Smcpowers
4770f9fbec18Smcpowers /* Iterate over each digit... */
4771f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
4772f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix);
4773f9fbec18Smcpowers int jx;
4774f9fbec18Smcpowers
4775f9fbec18Smcpowers /* Unpack digit bytes, high order first */
4776f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
4777f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
4778f9fbec18Smcpowers if (!pos && !x) /* suppress leading zeros */
4779f9fbec18Smcpowers continue;
4780f9fbec18Smcpowers str[pos++] = x;
4781f9fbec18Smcpowers }
4782f9fbec18Smcpowers }
4783f9fbec18Smcpowers if (!pos)
4784f9fbec18Smcpowers str[pos++] = 0;
4785f9fbec18Smcpowers return pos;
4786f9fbec18Smcpowers } /* end mp_to_unsigned_octets() */
4787f9fbec18Smcpowers /* }}} */
4788f9fbec18Smcpowers
4789f9fbec18Smcpowers /* {{{ mp_to_signed_octets(mp, str) */
4790f9fbec18Smcpowers /* output a buffer of big endian octets no longer than specified. */
4791*55fea89dSDan Cross mp_err
mp_to_signed_octets(const mp_int * mp,unsigned char * str,mp_size maxlen)4792f9fbec18Smcpowers mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
4793f9fbec18Smcpowers {
4794f9fbec18Smcpowers int ix, pos = 0;
4795f9fbec18Smcpowers int bytes;
4796f9fbec18Smcpowers
4797f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
4798f9fbec18Smcpowers
4799f9fbec18Smcpowers bytes = mp_unsigned_octet_size(mp);
4800f9fbec18Smcpowers ARGCHK(bytes <= maxlen, MP_BADARG);
4801f9fbec18Smcpowers
4802f9fbec18Smcpowers /* Iterate over each digit... */
4803f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
4804f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix);
4805f9fbec18Smcpowers int jx;
4806f9fbec18Smcpowers
4807f9fbec18Smcpowers /* Unpack digit bytes, high order first */
4808f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
4809f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
4810f9fbec18Smcpowers if (!pos) {
4811f9fbec18Smcpowers if (!x) /* suppress leading zeros */
4812f9fbec18Smcpowers continue;
4813f9fbec18Smcpowers if (x & 0x80) { /* add one leading zero to make output positive. */
4814f9fbec18Smcpowers ARGCHK(bytes + 1 <= maxlen, MP_BADARG);
4815f9fbec18Smcpowers if (bytes + 1 > maxlen)
4816f9fbec18Smcpowers return MP_BADARG;
4817f9fbec18Smcpowers str[pos++] = 0;
4818f9fbec18Smcpowers }
4819f9fbec18Smcpowers }
4820f9fbec18Smcpowers str[pos++] = x;
4821f9fbec18Smcpowers }
4822f9fbec18Smcpowers }
4823f9fbec18Smcpowers if (!pos)
4824f9fbec18Smcpowers str[pos++] = 0;
4825f9fbec18Smcpowers return pos;
4826f9fbec18Smcpowers } /* end mp_to_signed_octets() */
4827f9fbec18Smcpowers /* }}} */
4828f9fbec18Smcpowers
4829f9fbec18Smcpowers /* {{{ mp_to_fixlen_octets(mp, str) */
4830f9fbec18Smcpowers /* output a buffer of big endian octets exactly as long as requested. */
4831*55fea89dSDan Cross mp_err
mp_to_fixlen_octets(const mp_int * mp,unsigned char * str,mp_size length)4832f9fbec18Smcpowers mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length)
4833f9fbec18Smcpowers {
4834f9fbec18Smcpowers int ix, pos = 0;
4835f9fbec18Smcpowers int bytes;
4836f9fbec18Smcpowers
4837f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
4838f9fbec18Smcpowers
4839f9fbec18Smcpowers bytes = mp_unsigned_octet_size(mp);
4840f9fbec18Smcpowers ARGCHK(bytes <= length, MP_BADARG);
4841f9fbec18Smcpowers
4842f9fbec18Smcpowers /* place any needed leading zeros */
4843f9fbec18Smcpowers for (;length > bytes; --length) {
4844f9fbec18Smcpowers *str++ = 0;
4845f9fbec18Smcpowers }
4846f9fbec18Smcpowers
4847f9fbec18Smcpowers /* Iterate over each digit... */
4848f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
4849f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix);
4850f9fbec18Smcpowers int jx;
4851f9fbec18Smcpowers
4852f9fbec18Smcpowers /* Unpack digit bytes, high order first */
4853f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
4854f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
4855f9fbec18Smcpowers if (!pos && !x) /* suppress leading zeros */
4856f9fbec18Smcpowers continue;
4857f9fbec18Smcpowers str[pos++] = x;
4858f9fbec18Smcpowers }
4859f9fbec18Smcpowers }
4860f9fbec18Smcpowers if (!pos)
4861f9fbec18Smcpowers str[pos++] = 0;
4862f9fbec18Smcpowers return MP_OKAY;
4863f9fbec18Smcpowers } /* end mp_to_fixlen_octets() */
4864f9fbec18Smcpowers /* }}} */
4865f9fbec18Smcpowers
4866f9fbec18Smcpowers
4867f9fbec18Smcpowers /*------------------------------------------------------------------------*/
4868f9fbec18Smcpowers /* HERE THERE BE DRAGONS */
4869f2ba9e96SDina K Nimeh /* END CSTYLED */
4870