xref: /illumos-gate/usr/src/common/mpi/mpi.c (revision 55fea89d)
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(&quot) = 0;
3414f9fbec18Smcpowers   /* Make room for the quotient */
3415f9fbec18Smcpowers   MP_CHECKOK( mp_init_size(&quot, 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(&quot, 1);
3429f9fbec18Smcpowers     DIGIT(&quot, 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(&quot, 0) = d;
3442f9fbec18Smcpowers     MP_CHECKOK( s_mp_norm(&rem, &quot, &norm) );
3443f9fbec18Smcpowers     if (norm)
3444f9fbec18Smcpowers       d <<= norm;
3445f9fbec18Smcpowers     MP_DIGIT(&quot, 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(&quot, 1) );
3462f9fbec18Smcpowers       DIGIT(&quot, 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(&quot);
3477f9fbec18Smcpowers   mp_exch(&quot, mp);
3478f9fbec18Smcpowers CLEANUP:
3479f9fbec18Smcpowers   mp_clear(&quot);
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