andre@0: /*
andre@0:  *  mpi.c
andre@0:  *
andre@0:  *  Arbitrary precision integer arithmetic library
andre@0:  *
andre@0:  * This Source Code Form is subject to the terms of the Mozilla Public
andre@0:  * License, v. 2.0. If a copy of the MPL was not distributed with this
andre@0:  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
andre@0: 
andre@0: #include "mpi-priv.h"
andre@0: #if defined(OSF1)
andre@0: #include <c_asm.h>
andre@0: #endif
andre@0: 
andre@0: #if defined(__arm__) && \
andre@0:     ((defined(__thumb__) && !defined(__thumb2__)) || defined(__ARM_ARCH_3__))
andre@0: /* 16-bit thumb or ARM v3 doesn't work inlined assember version */
andre@0: #undef MP_ASSEMBLY_MULTIPLY
andre@0: #undef MP_ASSEMBLY_SQUARE
andre@0: #endif
andre@0: 
andre@0: #if MP_LOGTAB
andre@0: /*
andre@0:   A table of the logs of 2 for various bases (the 0 and 1 entries of
andre@0:   this table are meaningless and should not be referenced).  
andre@0: 
andre@0:   This table is used to compute output lengths for the mp_toradix()
andre@0:   function.  Since a number n in radix r takes up about log_r(n)
andre@0:   digits, we estimate the output size by taking the least integer
andre@0:   greater than log_r(n), where:
andre@0: 
andre@0:   log_r(n) = log_2(n) * log_r(2)
andre@0: 
andre@0:   This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
andre@0:   which are the output bases supported.  
andre@0:  */
andre@0: #include "logtab.h"
andre@0: #endif
andre@0: 
andre@0: /* {{{ Constant strings */
andre@0: 
andre@0: /* Constant strings returned by mp_strerror() */
andre@0: static const char *mp_err_string[] = {
andre@0:   "unknown result code",     /* say what?            */
andre@0:   "boolean true",            /* MP_OKAY, MP_YES      */
andre@0:   "boolean false",           /* MP_NO                */
andre@0:   "out of memory",           /* MP_MEM               */
andre@0:   "argument out of range",   /* MP_RANGE             */
andre@0:   "invalid input parameter", /* MP_BADARG            */
andre@0:   "result is undefined"      /* MP_UNDEF             */
andre@0: };
andre@0: 
andre@0: /* Value to digit maps for radix conversion   */
andre@0: 
andre@0: /* s_dmap_1 - standard digits and letters */
andre@0: static const char *s_dmap_1 = 
andre@0:   "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: unsigned long mp_allocs;
andre@0: unsigned long mp_frees;
andre@0: unsigned long mp_copies;
andre@0: 
andre@0: /* {{{ Default precision manipulation */
andre@0: 
andre@0: /* Default precision for newly created mp_int's      */
andre@0: static mp_size s_mp_defprec = MP_DEFPREC;
andre@0: 
andre@0: mp_size mp_get_prec(void)
andre@0: {
andre@0:   return s_mp_defprec;
andre@0: 
andre@0: } /* end mp_get_prec() */
andre@0: 
andre@0: void         mp_set_prec(mp_size prec)
andre@0: {
andre@0:   if(prec == 0)
andre@0:     s_mp_defprec = MP_DEFPREC;
andre@0:   else
andre@0:     s_mp_defprec = prec;
andre@0: 
andre@0: } /* end mp_set_prec() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ mp_init(mp) */
andre@0: 
andre@0: /*
andre@0:   mp_init(mp)
andre@0: 
andre@0:   Initialize a new zero-valued mp_int.  Returns MP_OKAY if successful,
andre@0:   MP_MEM if memory could not be allocated for the structure.
andre@0:  */
andre@0: 
andre@0: mp_err mp_init(mp_int *mp)
andre@0: {
andre@0:   return mp_init_size(mp, s_mp_defprec);
andre@0: 
andre@0: } /* end mp_init() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_init_size(mp, prec) */
andre@0: 
andre@0: /*
andre@0:   mp_init_size(mp, prec)
andre@0: 
andre@0:   Initialize a new zero-valued mp_int with at least the given
andre@0:   precision; returns MP_OKAY if successful, or MP_MEM if memory could
andre@0:   not be allocated for the structure.
andre@0:  */
andre@0: 
andre@0: mp_err mp_init_size(mp_int *mp, mp_size prec)
andre@0: {
andre@0:   ARGCHK(mp != NULL && prec > 0, MP_BADARG);
andre@0: 
andre@0:   prec = MP_ROUNDUP(prec, s_mp_defprec);
andre@0:   if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL)
andre@0:     return MP_MEM;
andre@0: 
andre@0:   SIGN(mp) = ZPOS;
andre@0:   USED(mp) = 1;
andre@0:   ALLOC(mp) = prec;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_init_size() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_init_copy(mp, from) */
andre@0: 
andre@0: /*
andre@0:   mp_init_copy(mp, from)
andre@0: 
andre@0:   Initialize mp as an exact copy of from.  Returns MP_OKAY if
andre@0:   successful, MP_MEM if memory could not be allocated for the new
andre@0:   structure.
andre@0:  */
andre@0: 
andre@0: mp_err mp_init_copy(mp_int *mp, const mp_int *from)
andre@0: {
andre@0:   ARGCHK(mp != NULL && from != NULL, MP_BADARG);
andre@0: 
andre@0:   if(mp == from)
andre@0:     return MP_OKAY;
andre@0: 
andre@0:   if((DIGITS(mp) = s_mp_alloc(ALLOC(from), sizeof(mp_digit))) == NULL)
andre@0:     return MP_MEM;
andre@0: 
andre@0:   s_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
andre@0:   USED(mp) = USED(from);
andre@0:   ALLOC(mp) = ALLOC(from);
andre@0:   SIGN(mp) = SIGN(from);
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_init_copy() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_copy(from, to) */
andre@0: 
andre@0: /*
andre@0:   mp_copy(from, to)
andre@0: 
andre@0:   Copies the mp_int 'from' to the mp_int 'to'.  It is presumed that
andre@0:   'to' has already been initialized (if not, use mp_init_copy()
andre@0:   instead). If 'from' and 'to' are identical, nothing happens.
andre@0:  */
andre@0: 
andre@0: mp_err mp_copy(const mp_int *from, mp_int *to)
andre@0: {
andre@0:   ARGCHK(from != NULL && to != NULL, MP_BADARG);
andre@0: 
andre@0:   if(from == to)
andre@0:     return MP_OKAY;
andre@0: 
andre@0:   { /* copy */
andre@0:     mp_digit   *tmp;
andre@0: 
andre@0:     /*
andre@0:       If the allocated buffer in 'to' already has enough space to hold
andre@0:       all the used digits of 'from', we'll re-use it to avoid hitting
andre@0:       the memory allocater more than necessary; otherwise, we'd have
andre@0:       to grow anyway, so we just allocate a hunk and make the copy as
andre@0:       usual
andre@0:      */
andre@0:     if(ALLOC(to) >= USED(from)) {
andre@0:       s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
andre@0:       s_mp_copy(DIGITS(from), DIGITS(to), USED(from));
andre@0:       
andre@0:     } else {
andre@0:       if((tmp = s_mp_alloc(ALLOC(from), sizeof(mp_digit))) == NULL)
andre@0: 	return MP_MEM;
andre@0: 
andre@0:       s_mp_copy(DIGITS(from), tmp, USED(from));
andre@0: 
andre@0:       if(DIGITS(to) != NULL) {
andre@0: #if MP_CRYPTO
andre@0: 	s_mp_setz(DIGITS(to), ALLOC(to));
andre@0: #endif
andre@0: 	s_mp_free(DIGITS(to));
andre@0:       }
andre@0: 
andre@0:       DIGITS(to) = tmp;
andre@0:       ALLOC(to) = ALLOC(from);
andre@0:     }
andre@0: 
andre@0:     /* Copy the precision and sign from the original */
andre@0:     USED(to) = USED(from);
andre@0:     SIGN(to) = SIGN(from);
andre@0:   } /* end copy */
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_copy() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_exch(mp1, mp2) */
andre@0: 
andre@0: /*
andre@0:   mp_exch(mp1, mp2)
andre@0: 
andre@0:   Exchange mp1 and mp2 without allocating any intermediate memory
andre@0:   (well, unless you count the stack space needed for this call and the
andre@0:   locals it creates...).  This cannot fail.
andre@0:  */
andre@0: 
andre@0: void mp_exch(mp_int *mp1, mp_int *mp2)
andre@0: {
andre@0: #if MP_ARGCHK == 2
andre@0:   assert(mp1 != NULL && mp2 != NULL);
andre@0: #else
andre@0:   if(mp1 == NULL || mp2 == NULL)
andre@0:     return;
andre@0: #endif
andre@0: 
andre@0:   s_mp_exch(mp1, mp2);
andre@0: 
andre@0: } /* end mp_exch() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_clear(mp) */
andre@0: 
andre@0: /*
andre@0:   mp_clear(mp)
andre@0: 
andre@0:   Release the storage used by an mp_int, and void its fields so that
andre@0:   if someone calls mp_clear() again for the same int later, we won't
andre@0:   get tollchocked.
andre@0:  */
andre@0: 
andre@0: void   mp_clear(mp_int *mp)
andre@0: {
andre@0:   if(mp == NULL)
andre@0:     return;
andre@0: 
andre@0:   if(DIGITS(mp) != NULL) {
andre@0: #if MP_CRYPTO
andre@0:     s_mp_setz(DIGITS(mp), ALLOC(mp));
andre@0: #endif
andre@0:     s_mp_free(DIGITS(mp));
andre@0:     DIGITS(mp) = NULL;
andre@0:   }
andre@0: 
andre@0:   USED(mp) = 0;
andre@0:   ALLOC(mp) = 0;
andre@0: 
andre@0: } /* end mp_clear() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_zero(mp) */
andre@0: 
andre@0: /*
andre@0:   mp_zero(mp) 
andre@0: 
andre@0:   Set mp to zero.  Does not change the allocated size of the structure,
andre@0:   and therefore cannot fail (except on a bad argument, which we ignore)
andre@0:  */
andre@0: void   mp_zero(mp_int *mp)
andre@0: {
andre@0:   if(mp == NULL)
andre@0:     return;
andre@0: 
andre@0:   s_mp_setz(DIGITS(mp), ALLOC(mp));
andre@0:   USED(mp) = 1;
andre@0:   SIGN(mp) = ZPOS;
andre@0: 
andre@0: } /* end mp_zero() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_set(mp, d) */
andre@0: 
andre@0: void   mp_set(mp_int *mp, mp_digit d)
andre@0: {
andre@0:   if(mp == NULL)
andre@0:     return;
andre@0: 
andre@0:   mp_zero(mp);
andre@0:   DIGIT(mp, 0) = d;
andre@0: 
andre@0: } /* end mp_set() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_set_int(mp, z) */
andre@0: 
andre@0: mp_err mp_set_int(mp_int *mp, long z)
andre@0: {
andre@0:   int            ix;
andre@0:   unsigned long  v = labs(z);
andre@0:   mp_err         res;
andre@0: 
andre@0:   ARGCHK(mp != NULL, MP_BADARG);
andre@0: 
andre@0:   mp_zero(mp);
andre@0:   if(z == 0)
andre@0:     return MP_OKAY;  /* shortcut for zero */
andre@0: 
andre@0:   if (sizeof v <= sizeof(mp_digit)) {
andre@0:     DIGIT(mp,0) = v;
andre@0:   } else {
andre@0:     for (ix = sizeof(long) - 1; ix >= 0; ix--) {
andre@0:       if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
andre@0: 	return res;
andre@0: 
andre@0:       res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
andre@0:       if (res != MP_OKAY)
andre@0: 	return res;
andre@0:     }
andre@0:   }
andre@0:   if(z < 0)
andre@0:     SIGN(mp) = NEG;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_set_int() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_set_ulong(mp, z) */
andre@0: 
andre@0: mp_err mp_set_ulong(mp_int *mp, unsigned long z)
andre@0: {
andre@0:   int            ix;
andre@0:   mp_err         res;
andre@0: 
andre@0:   ARGCHK(mp != NULL, MP_BADARG);
andre@0: 
andre@0:   mp_zero(mp);
andre@0:   if(z == 0)
andre@0:     return MP_OKAY;  /* shortcut for zero */
andre@0: 
andre@0:   if (sizeof z <= sizeof(mp_digit)) {
andre@0:     DIGIT(mp,0) = z;
andre@0:   } else {
andre@0:     for (ix = sizeof(long) - 1; ix >= 0; ix--) {
andre@0:       if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
andre@0: 	return res;
andre@0: 
andre@0:       res = s_mp_add_d(mp, (mp_digit)((z >> (ix * CHAR_BIT)) & UCHAR_MAX));
andre@0:       if (res != MP_OKAY)
andre@0: 	return res;
andre@0:     }
andre@0:   }
andre@0:   return MP_OKAY;
andre@0: } /* end mp_set_ulong() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ Digit arithmetic */
andre@0: 
andre@0: /* {{{ mp_add_d(a, d, b) */
andre@0: 
andre@0: /*
andre@0:   mp_add_d(a, d, b)
andre@0: 
andre@0:   Compute the sum b = a + d, for a single digit d.  Respects the sign of
andre@0:   its primary addend (single digits are unsigned anyway).
andre@0:  */
andre@0: 
andre@0: mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b)
andre@0: {
andre@0:   mp_int   tmp;
andre@0:   mp_err   res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   if(SIGN(&tmp) == ZPOS) {
andre@0:     if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   } else if(s_mp_cmp_d(&tmp, d) >= 0) {
andre@0:     if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   } else {
andre@0:     mp_neg(&tmp, &tmp);
andre@0: 
andre@0:     DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
andre@0:   }
andre@0: 
andre@0:   if(s_mp_cmp_d(&tmp, 0) == 0)
andre@0:     SIGN(&tmp) = ZPOS;
andre@0: 
andre@0:   s_mp_exch(&tmp, b);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&tmp);
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_add_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_sub_d(a, d, b) */
andre@0: 
andre@0: /*
andre@0:   mp_sub_d(a, d, b)
andre@0: 
andre@0:   Compute the difference b = a - d, for a single digit d.  Respects the
andre@0:   sign of its subtrahend (single digits are unsigned anyway).
andre@0:  */
andre@0: 
andre@0: mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b)
andre@0: {
andre@0:   mp_int   tmp;
andre@0:   mp_err   res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   if(SIGN(&tmp) == NEG) {
andre@0:     if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   } else if(s_mp_cmp_d(&tmp, d) >= 0) {
andre@0:     if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   } else {
andre@0:     mp_neg(&tmp, &tmp);
andre@0: 
andre@0:     DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
andre@0:     SIGN(&tmp) = NEG;
andre@0:   }
andre@0: 
andre@0:   if(s_mp_cmp_d(&tmp, 0) == 0)
andre@0:     SIGN(&tmp) = ZPOS;
andre@0: 
andre@0:   s_mp_exch(&tmp, b);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&tmp);
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_sub_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_mul_d(a, d, b) */
andre@0: 
andre@0: /*
andre@0:   mp_mul_d(a, d, b)
andre@0: 
andre@0:   Compute the product b = a * d, for a single digit d.  Respects the sign
andre@0:   of its multiplicand (single digits are unsigned anyway)
andre@0:  */
andre@0: 
andre@0: mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL, MP_BADARG);
andre@0: 
andre@0:   if(d == 0) {
andre@0:     mp_zero(b);
andre@0:     return MP_OKAY;
andre@0:   }
andre@0: 
andre@0:   if((res = mp_copy(a, b)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   res = s_mp_mul_d(b, d);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_mul_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_mul_2(a, c) */
andre@0: 
andre@0: mp_err mp_mul_2(const mp_int *a, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_copy(a, c)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   return s_mp_mul_2(c);
andre@0: 
andre@0: } /* end mp_mul_2() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_div_d(a, d, q, r) */
andre@0: 
andre@0: /*
andre@0:   mp_div_d(a, d, q, r)
andre@0: 
andre@0:   Compute the quotient q = a / d and remainder r = a mod d, for a
andre@0:   single digit d.  Respects the sign of its divisor (single digits are
andre@0:   unsigned anyway).
andre@0:  */
andre@0: 
andre@0: mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r)
andre@0: {
andre@0:   mp_err   res;
andre@0:   mp_int   qp;
andre@0:   mp_digit rem;
andre@0:   int      pow;
andre@0: 
andre@0:   ARGCHK(a != NULL, MP_BADARG);
andre@0: 
andre@0:   if(d == 0)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   /* Shortcut for powers of two ... */
andre@0:   if((pow = s_mp_ispow2d(d)) >= 0) {
andre@0:     mp_digit  mask;
andre@0: 
andre@0:     mask = ((mp_digit)1 << pow) - 1;
andre@0:     rem = DIGIT(a, 0) & mask;
andre@0: 
andre@0:     if(q) {
andre@0:       mp_copy(a, q);
andre@0:       s_mp_div_2d(q, pow);
andre@0:     }
andre@0: 
andre@0:     if(r)
andre@0:       *r = rem;
andre@0: 
andre@0:     return MP_OKAY;
andre@0:   }
andre@0: 
andre@0:   if((res = mp_init_copy(&qp, a)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   res = s_mp_div_d(&qp, d, &rem);
andre@0: 
andre@0:   if(s_mp_cmp_d(&qp, 0) == 0)
andre@0:     SIGN(q) = ZPOS;
andre@0: 
andre@0:   if(r)
andre@0:     *r = rem;
andre@0: 
andre@0:   if(q)
andre@0:     s_mp_exch(&qp, q);
andre@0: 
andre@0:   mp_clear(&qp);
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_div_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_div_2(a, c) */
andre@0: 
andre@0: /*
andre@0:   mp_div_2(a, c)
andre@0: 
andre@0:   Compute c = a / 2, disregarding the remainder.
andre@0:  */
andre@0: 
andre@0: mp_err mp_div_2(const mp_int *a, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_copy(a, c)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   s_mp_div_2(c);
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_div_2() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_expt_d(a, d, b) */
andre@0: 
andre@0: mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c)
andre@0: {
andre@0:   mp_int   s, x;
andre@0:   mp_err   res;
andre@0: 
andre@0:   ARGCHK(a != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_init(&s)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_init_copy(&x, a)) != MP_OKAY)
andre@0:     goto X;
andre@0: 
andre@0:   DIGIT(&s, 0) = 1;
andre@0: 
andre@0:   while(d != 0) {
andre@0:     if(d & 1) {
andre@0:       if((res = s_mp_mul(&s, &x)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:     }
andre@0: 
andre@0:     d /= 2;
andre@0: 
andre@0:     if((res = s_mp_sqr(&x)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   }
andre@0: 
andre@0:   s_mp_exch(&s, c);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&x);
andre@0: X:
andre@0:   mp_clear(&s);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_expt_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ Full arithmetic */
andre@0: 
andre@0: /* {{{ mp_abs(a, b) */
andre@0: 
andre@0: /*
andre@0:   mp_abs(a, b)
andre@0: 
andre@0:   Compute b = |a|.  'a' and 'b' may be identical.
andre@0:  */
andre@0: 
andre@0: mp_err mp_abs(const mp_int *a, mp_int *b)
andre@0: {
andre@0:   mp_err   res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_copy(a, b)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   SIGN(b) = ZPOS;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_abs() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_neg(a, b) */
andre@0: 
andre@0: /*
andre@0:   mp_neg(a, b)
andre@0: 
andre@0:   Compute b = -a.  'a' and 'b' may be identical.
andre@0:  */
andre@0: 
andre@0: mp_err mp_neg(const mp_int *a, mp_int *b)
andre@0: {
andre@0:   mp_err   res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_copy(a, b)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   if(s_mp_cmp_d(b, 0) == MP_EQ) 
andre@0:     SIGN(b) = ZPOS;
andre@0:   else 
andre@0:     SIGN(b) = (SIGN(b) == NEG) ? ZPOS : NEG;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_neg() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_add(a, b, c) */
andre@0: 
andre@0: /*
andre@0:   mp_add(a, b, c)
andre@0: 
andre@0:   Compute c = a + b.  All parameters may be identical.
andre@0:  */
andre@0: 
andre@0: mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if(SIGN(a) == SIGN(b)) { /* same sign:  add values, keep sign */
andre@0:     MP_CHECKOK( s_mp_add_3arg(a, b, c) );
andre@0:   } else if(s_mp_cmp(a, b) >= 0) {  /* different sign: |a| >= |b|   */
andre@0:     MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
andre@0:   } else {                          /* different sign: |a|  < |b|   */
andre@0:     MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
andre@0:   }
andre@0: 
andre@0:   if (s_mp_cmp_d(c, 0) == MP_EQ)
andre@0:     SIGN(c) = ZPOS;
andre@0: 
andre@0: CLEANUP:
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_add() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_sub(a, b, c) */
andre@0: 
andre@0: /*
andre@0:   mp_sub(a, b, c)
andre@0: 
andre@0:   Compute c = a - b.  All parameters may be identical.
andre@0:  */
andre@0: 
andre@0: mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0:   int     magDiff;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if (a == b) {
andre@0:     mp_zero(c);
andre@0:     return MP_OKAY;
andre@0:   }
andre@0: 
andre@0:   if (MP_SIGN(a) != MP_SIGN(b)) {
andre@0:     MP_CHECKOK( s_mp_add_3arg(a, b, c) );
andre@0:   } else if (!(magDiff = s_mp_cmp(a, b))) {
andre@0:     mp_zero(c);
andre@0:     res = MP_OKAY;
andre@0:   } else if (magDiff > 0) {
andre@0:     MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
andre@0:   } else {
andre@0:     MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
andre@0:     MP_SIGN(c) = !MP_SIGN(a);
andre@0:   }
andre@0: 
andre@0:   if (s_mp_cmp_d(c, 0) == MP_EQ)
andre@0:     MP_SIGN(c) = MP_ZPOS;
andre@0: 
andre@0: CLEANUP:
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_sub() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_mul(a, b, c) */
andre@0: 
andre@0: /*
andre@0:   mp_mul(a, b, c)
andre@0: 
andre@0:   Compute c = a * b.  All parameters may be identical.
andre@0:  */
andre@0: mp_err   mp_mul(const mp_int *a, const mp_int *b, mp_int * c)
andre@0: {
andre@0:   mp_digit *pb;
andre@0:   mp_int   tmp;
andre@0:   mp_err   res;
andre@0:   mp_size  ib;
andre@0:   mp_size  useda, usedb;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if (a == c) {
andre@0:     if ((res = mp_init_copy(&tmp, a)) != MP_OKAY)
andre@0:       return res;
andre@0:     if (a == b) 
andre@0:       b = &tmp;
andre@0:     a = &tmp;
andre@0:   } else if (b == c) {
andre@0:     if ((res = mp_init_copy(&tmp, b)) != MP_OKAY)
andre@0:       return res;
andre@0:     b = &tmp;
andre@0:   } else {
andre@0:     MP_DIGITS(&tmp) = 0;
andre@0:   }
andre@0: 
andre@0:   if (MP_USED(a) < MP_USED(b)) {
andre@0:     const mp_int *xch = b;	/* switch a and b, to do fewer outer loops */
andre@0:     b = a;
andre@0:     a = xch;
andre@0:   }
andre@0: 
andre@0:   MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
andre@0:   if((res = s_mp_pad(c, USED(a) + USED(b))) != MP_OKAY)
andre@0:     goto CLEANUP;
andre@0: 
andre@0: #ifdef NSS_USE_COMBA
andre@0:   if ((MP_USED(a) == MP_USED(b)) && IS_POWER_OF_2(MP_USED(b))) {
andre@0:       if (MP_USED(a) == 4) {
andre@0:           s_mp_mul_comba_4(a, b, c);
andre@0:           goto CLEANUP;
andre@0:       }
andre@0:       if (MP_USED(a) == 8) {
andre@0:           s_mp_mul_comba_8(a, b, c);
andre@0:           goto CLEANUP;
andre@0:       }
andre@0:       if (MP_USED(a) == 16) {
andre@0:           s_mp_mul_comba_16(a, b, c);
andre@0:           goto CLEANUP;
andre@0:       }
andre@0:       if (MP_USED(a) == 32) {
andre@0:           s_mp_mul_comba_32(a, b, c);
andre@0:           goto CLEANUP;
andre@0:       } 
andre@0:   }
andre@0: #endif
andre@0: 
andre@0:   pb = MP_DIGITS(b);
andre@0:   s_mpv_mul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c));
andre@0: 
andre@0:   /* Outer loop:  Digits of b */
andre@0:   useda = MP_USED(a);
andre@0:   usedb = MP_USED(b);
andre@0:   for (ib = 1; ib < usedb; ib++) {
andre@0:     mp_digit b_i    = *pb++;
andre@0: 
andre@0:     /* Inner product:  Digits of a */
andre@0:     if (b_i)
andre@0:       s_mpv_mul_d_add(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
andre@0:     else
andre@0:       MP_DIGIT(c, ib + useda) = b_i;
andre@0:   }
andre@0: 
andre@0:   s_mp_clamp(c);
andre@0: 
andre@0:   if(SIGN(a) == SIGN(b) || s_mp_cmp_d(c, 0) == MP_EQ)
andre@0:     SIGN(c) = ZPOS;
andre@0:   else
andre@0:     SIGN(c) = NEG;
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&tmp);
andre@0:   return res;
andre@0: } /* end mp_mul() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_sqr(a, sqr) */
andre@0: 
andre@0: #if MP_SQUARE
andre@0: /*
andre@0:   Computes the square of a.  This can be done more
andre@0:   efficiently than a general multiplication, because many of the
andre@0:   computation steps are redundant when squaring.  The inner product
andre@0:   step is a bit more complicated, but we save a fair number of
andre@0:   iterations of the multiplication loop.
andre@0:  */
andre@0: 
andre@0: /* sqr = a^2;   Caller provides both a and tmp; */
andre@0: mp_err   mp_sqr(const mp_int *a, mp_int *sqr)
andre@0: {
andre@0:   mp_digit *pa;
andre@0:   mp_digit d;
andre@0:   mp_err   res;
andre@0:   mp_size  ix;
andre@0:   mp_int   tmp;
andre@0:   int      count;
andre@0: 
andre@0:   ARGCHK(a != NULL && sqr != NULL, MP_BADARG);
andre@0: 
andre@0:   if (a == sqr) {
andre@0:     if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
andre@0:       return res;
andre@0:     a = &tmp;
andre@0:   } else {
andre@0:     DIGITS(&tmp) = 0;
andre@0:     res = MP_OKAY;
andre@0:   }
andre@0: 
andre@0:   ix = 2 * MP_USED(a);
andre@0:   if (ix > MP_ALLOC(sqr)) {
andre@0:     MP_USED(sqr) = 1; 
andre@0:     MP_CHECKOK( s_mp_grow(sqr, ix) );
andre@0:   } 
andre@0:   MP_USED(sqr) = ix;
andre@0:   MP_DIGIT(sqr, 0) = 0;
andre@0: 
andre@0: #ifdef NSS_USE_COMBA
andre@0:   if (IS_POWER_OF_2(MP_USED(a))) {
andre@0:       if (MP_USED(a) == 4) {
andre@0:           s_mp_sqr_comba_4(a, sqr);
andre@0:           goto CLEANUP;
andre@0:       }
andre@0:       if (MP_USED(a) == 8) {
andre@0:           s_mp_sqr_comba_8(a, sqr);
andre@0:           goto CLEANUP;
andre@0:       }
andre@0:       if (MP_USED(a) == 16) {
andre@0:           s_mp_sqr_comba_16(a, sqr);
andre@0:           goto CLEANUP;
andre@0:       }
andre@0:       if (MP_USED(a) == 32) {
andre@0:           s_mp_sqr_comba_32(a, sqr);
andre@0:           goto CLEANUP;
andre@0:       } 
andre@0:   }
andre@0: #endif
andre@0: 
andre@0:   pa = MP_DIGITS(a);
andre@0:   count = MP_USED(a) - 1;
andre@0:   if (count > 0) {
andre@0:     d = *pa++;
andre@0:     s_mpv_mul_d(pa, count, d, MP_DIGITS(sqr) + 1);
andre@0:     for (ix = 3; --count > 0; ix += 2) {
andre@0:       d = *pa++;
andre@0:       s_mpv_mul_d_add(pa, count, d, MP_DIGITS(sqr) + ix);
andre@0:     } /* for(ix ...) */
andre@0:     MP_DIGIT(sqr, MP_USED(sqr)-1) = 0; /* above loop stopped short of this. */
andre@0: 
andre@0:     /* now sqr *= 2 */
andre@0:     s_mp_mul_2(sqr);
andre@0:   } else {
andre@0:     MP_DIGIT(sqr, 1) = 0;
andre@0:   }
andre@0: 
andre@0:   /* now add the squares of the digits of a to sqr. */
andre@0:   s_mpv_sqr_add_prop(MP_DIGITS(a), MP_USED(a), MP_DIGITS(sqr));
andre@0: 
andre@0:   SIGN(sqr) = ZPOS;
andre@0:   s_mp_clamp(sqr);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&tmp);
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_sqr() */
andre@0: #endif
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_div(a, b, q, r) */
andre@0: 
andre@0: /*
andre@0:   mp_div(a, b, q, r)
andre@0: 
andre@0:   Compute q = a / b and r = a mod b.  Input parameters may be re-used
andre@0:   as output parameters.  If q or r is NULL, that portion of the
andre@0:   computation will be discarded (although it will still be computed)
andre@0:  */
andre@0: mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r)
andre@0: {
andre@0:   mp_err   res;
andre@0:   mp_int   *pQ, *pR;
andre@0:   mp_int   qtmp, rtmp, btmp;
andre@0:   int      cmp;
andre@0:   mp_sign  signA;
andre@0:   mp_sign  signB;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL, MP_BADARG);
andre@0:   
andre@0:   signA = MP_SIGN(a);
andre@0:   signB = MP_SIGN(b);
andre@0: 
andre@0:   if(mp_cmp_z(b) == MP_EQ)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   DIGITS(&qtmp) = 0;
andre@0:   DIGITS(&rtmp) = 0;
andre@0:   DIGITS(&btmp) = 0;
andre@0: 
andre@0:   /* Set up some temporaries... */
andre@0:   if (!r || r == a || r == b) {
andre@0:     MP_CHECKOK( mp_init_copy(&rtmp, a) );
andre@0:     pR = &rtmp;
andre@0:   } else {
andre@0:     MP_CHECKOK( mp_copy(a, r) );
andre@0:     pR = r;
andre@0:   }
andre@0: 
andre@0:   if (!q || q == a || q == b) {
andre@0:     MP_CHECKOK( mp_init_size(&qtmp, MP_USED(a)) );
andre@0:     pQ = &qtmp;
andre@0:   } else {
andre@0:     MP_CHECKOK( s_mp_pad(q, MP_USED(a)) );
andre@0:     pQ = q;
andre@0:     mp_zero(pQ);
andre@0:   }
andre@0: 
andre@0:   /*
andre@0:     If |a| <= |b|, we can compute the solution without division;
andre@0:     otherwise, we actually do the work required.
andre@0:    */
andre@0:   if ((cmp = s_mp_cmp(a, b)) <= 0) {
andre@0:     if (cmp) {
andre@0:       /* r was set to a above. */
andre@0:       mp_zero(pQ);
andre@0:     } else {
andre@0:       mp_set(pQ, 1);
andre@0:       mp_zero(pR);
andre@0:     }
andre@0:   } else {
andre@0:     MP_CHECKOK( mp_init_copy(&btmp, b) );
andre@0:     MP_CHECKOK( s_mp_div(pR, &btmp, pQ) );
andre@0:   }
andre@0: 
andre@0:   /* Compute the signs for the output  */
andre@0:   MP_SIGN(pR) = signA;   /* Sr = Sa              */
andre@0:   /* Sq = ZPOS if Sa == Sb */ /* Sq = NEG if Sa != Sb */
andre@0:   MP_SIGN(pQ) = (signA == signB) ? ZPOS : NEG;
andre@0: 
andre@0:   if(s_mp_cmp_d(pQ, 0) == MP_EQ)
andre@0:     SIGN(pQ) = ZPOS;
andre@0:   if(s_mp_cmp_d(pR, 0) == MP_EQ)
andre@0:     SIGN(pR) = ZPOS;
andre@0: 
andre@0:   /* Copy output, if it is needed      */
andre@0:   if(q && q != pQ) 
andre@0:     s_mp_exch(pQ, q);
andre@0: 
andre@0:   if(r && r != pR) 
andre@0:     s_mp_exch(pR, r);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&btmp);
andre@0:   mp_clear(&rtmp);
andre@0:   mp_clear(&qtmp);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_div() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_div_2d(a, d, q, r) */
andre@0: 
andre@0: mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL, MP_BADARG);
andre@0: 
andre@0:   if(q) {
andre@0:     if((res = mp_copy(a, q)) != MP_OKAY)
andre@0:       return res;
andre@0:   }
andre@0:   if(r) {
andre@0:     if((res = mp_copy(a, r)) != MP_OKAY)
andre@0:       return res;
andre@0:   }
andre@0:   if(q) {
andre@0:     s_mp_div_2d(q, d);
andre@0:   }
andre@0:   if(r) {
andre@0:     s_mp_mod_2d(r, d);
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_div_2d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_expt(a, b, c) */
andre@0: 
andre@0: /*
andre@0:   mp_expt(a, b, c)
andre@0: 
andre@0:   Compute c = a ** b, that is, raise a to the b power.  Uses a
andre@0:   standard iterative square-and-multiply technique.
andre@0:  */
andre@0: 
andre@0: mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c)
andre@0: {
andre@0:   mp_int   s, x;
andre@0:   mp_err   res;
andre@0:   mp_digit d;
andre@0:   int      dig, bit;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if(mp_cmp_z(b) < 0)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   if((res = mp_init(&s)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   mp_set(&s, 1);
andre@0: 
andre@0:   if((res = mp_init_copy(&x, a)) != MP_OKAY)
andre@0:     goto X;
andre@0: 
andre@0:   /* Loop over low-order digits in ascending order */
andre@0:   for(dig = 0; dig < (USED(b) - 1); dig++) {
andre@0:     d = DIGIT(b, dig);
andre@0: 
andre@0:     /* Loop over bits of each non-maximal digit */
andre@0:     for(bit = 0; bit < DIGIT_BIT; bit++) {
andre@0:       if(d & 1) {
andre@0: 	if((res = s_mp_mul(&s, &x)) != MP_OKAY) 
andre@0: 	  goto CLEANUP;
andre@0:       }
andre@0: 
andre@0:       d >>= 1;
andre@0:       
andre@0:       if((res = s_mp_sqr(&x)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:     }
andre@0:   }
andre@0: 
andre@0:   /* Consider now the last digit... */
andre@0:   d = DIGIT(b, dig);
andre@0: 
andre@0:   while(d) {
andre@0:     if(d & 1) {
andre@0:       if((res = s_mp_mul(&s, &x)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:     }
andre@0: 
andre@0:     d >>= 1;
andre@0: 
andre@0:     if((res = s_mp_sqr(&x)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   }
andre@0:   
andre@0:   if(mp_iseven(b))
andre@0:     SIGN(&s) = SIGN(a);
andre@0: 
andre@0:   res = mp_copy(&s, c);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&x);
andre@0: X:
andre@0:   mp_clear(&s);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_expt() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_2expt(a, k) */
andre@0: 
andre@0: /* Compute a = 2^k */
andre@0: 
andre@0: mp_err mp_2expt(mp_int *a, mp_digit k)
andre@0: {
andre@0:   ARGCHK(a != NULL, MP_BADARG);
andre@0: 
andre@0:   return s_mp_2expt(a, k);
andre@0: 
andre@0: } /* end mp_2expt() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_mod(a, m, c) */
andre@0: 
andre@0: /*
andre@0:   mp_mod(a, m, c)
andre@0: 
andre@0:   Compute c = a (mod m).  Result will always be 0 <= c < m.
andre@0:  */
andre@0: 
andre@0: mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0:   int     mag;
andre@0: 
andre@0:   ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if(SIGN(m) == NEG)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   /*
andre@0:      If |a| > m, we need to divide to get the remainder and take the
andre@0:      absolute value.  
andre@0: 
andre@0:      If |a| < m, we don't need to do any division, just copy and adjust
andre@0:      the sign (if a is negative).
andre@0: 
andre@0:      If |a| == m, we can simply set the result to zero.
andre@0: 
andre@0:      This order is intended to minimize the average path length of the
andre@0:      comparison chain on common workloads -- the most frequent cases are
andre@0:      that |a| != m, so we do those first.
andre@0:    */
andre@0:   if((mag = s_mp_cmp(a, m)) > 0) {
andre@0:     if((res = mp_div(a, m, NULL, c)) != MP_OKAY)
andre@0:       return res;
andre@0:     
andre@0:     if(SIGN(c) == NEG) {
andre@0:       if((res = mp_add(c, m, c)) != MP_OKAY)
andre@0: 	return res;
andre@0:     }
andre@0: 
andre@0:   } else if(mag < 0) {
andre@0:     if((res = mp_copy(a, c)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     if(mp_cmp_z(a) < 0) {
andre@0:       if((res = mp_add(c, m, c)) != MP_OKAY)
andre@0: 	return res;
andre@0: 
andre@0:     }
andre@0:     
andre@0:   } else {
andre@0:     mp_zero(c);
andre@0: 
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_mod() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_mod_d(a, d, c) */
andre@0: 
andre@0: /*
andre@0:   mp_mod_d(a, d, c)
andre@0: 
andre@0:   Compute c = a (mod d).  Result will always be 0 <= c < d
andre@0:  */
andre@0: mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c)
andre@0: {
andre@0:   mp_err   res;
andre@0:   mp_digit rem;
andre@0: 
andre@0:   ARGCHK(a != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if(s_mp_cmp_d(a, d) > 0) {
andre@0:     if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:   } else {
andre@0:     if(SIGN(a) == NEG)
andre@0:       rem = d - DIGIT(a, 0);
andre@0:     else
andre@0:       rem = DIGIT(a, 0);
andre@0:   }
andre@0: 
andre@0:   if(c)
andre@0:     *c = rem;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_mod_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_sqrt(a, b) */
andre@0: 
andre@0: /*
andre@0:   mp_sqrt(a, b)
andre@0: 
andre@0:   Compute the integer square root of a, and store the result in b.
andre@0:   Uses an integer-arithmetic version of Newton's iterative linear
andre@0:   approximation technique to determine this value; the result has the
andre@0:   following two properties:
andre@0: 
andre@0:      b^2 <= a
andre@0:      (b+1)^2 >= a
andre@0: 
andre@0:   It is a range error to pass a negative value.
andre@0:  */
andre@0: mp_err mp_sqrt(const mp_int *a, mp_int *b)
andre@0: {
andre@0:   mp_int   x, t;
andre@0:   mp_err   res;
andre@0:   mp_size  used;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL, MP_BADARG);
andre@0: 
andre@0:   /* Cannot take square root of a negative value */
andre@0:   if(SIGN(a) == NEG)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   /* Special cases for zero and one, trivial     */
andre@0:   if(mp_cmp_d(a, 1) <= 0)
andre@0:     return mp_copy(a, b);
andre@0:     
andre@0:   /* Initialize the temporaries we'll use below  */
andre@0:   if((res = mp_init_size(&t, USED(a))) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   /* Compute an initial guess for the iteration as a itself */
andre@0:   if((res = mp_init_copy(&x, a)) != MP_OKAY)
andre@0:     goto X;
andre@0: 
andre@0:   used = MP_USED(&x);
andre@0:   if (used > 1) {
andre@0:     s_mp_rshd(&x, used / 2);
andre@0:   }
andre@0: 
andre@0:   for(;;) {
andre@0:     /* t = (x * x) - a */
andre@0:     mp_copy(&x, &t);      /* can't fail, t is big enough for original x */
andre@0:     if((res = mp_sqr(&t, &t)) != MP_OKAY ||
andre@0:        (res = mp_sub(&t, a, &t)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0: 
andre@0:     /* t = t / 2x       */
andre@0:     s_mp_mul_2(&x);
andre@0:     if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:     s_mp_div_2(&x);
andre@0: 
andre@0:     /* Terminate the loop, if the quotient is zero */
andre@0:     if(mp_cmp_z(&t) == MP_EQ)
andre@0:       break;
andre@0: 
andre@0:     /* x = x - t       */
andre@0:     if((res = mp_sub(&x, &t, &x)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0: 
andre@0:   }
andre@0: 
andre@0:   /* Copy result to output parameter */
andre@0:   mp_sub_d(&x, 1, &x);
andre@0:   s_mp_exch(&x, b);
andre@0: 
andre@0:  CLEANUP:
andre@0:   mp_clear(&x);
andre@0:  X:
andre@0:   mp_clear(&t); 
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_sqrt() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ Modular arithmetic */
andre@0: 
andre@0: #if MP_MODARITH
andre@0: /* {{{ mp_addmod(a, b, m, c) */
andre@0: 
andre@0: /*
andre@0:   mp_addmod(a, b, m, c)
andre@0: 
andre@0:   Compute c = (a + b) mod m
andre@0:  */
andre@0: 
andre@0: mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_add(a, b, c)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_mod(c, m, c)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: }
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_submod(a, b, m, c) */
andre@0: 
andre@0: /*
andre@0:   mp_submod(a, b, m, c)
andre@0: 
andre@0:   Compute c = (a - b) mod m
andre@0:  */
andre@0: 
andre@0: mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_sub(a, b, c)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_mod(c, m, c)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: }
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_mulmod(a, b, m, c) */
andre@0: 
andre@0: /*
andre@0:   mp_mulmod(a, b, m, c)
andre@0: 
andre@0:   Compute c = (a * b) mod m
andre@0:  */
andre@0: 
andre@0: mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_mul(a, b, c)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_mod(c, m, c)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: }
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_sqrmod(a, m, c) */
andre@0: 
andre@0: #if MP_SQUARE
andre@0: mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_sqr(a, c)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_mod(c, m, c)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_sqrmod() */
andre@0: #endif
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_exptmod(a, b, m, c) */
andre@0: 
andre@0: /*
andre@0:   s_mp_exptmod(a, b, m, c)
andre@0: 
andre@0:   Compute c = (a ** b) mod m.  Uses a standard square-and-multiply
andre@0:   method with modular reductions at each step. (This is basically the
andre@0:   same code as mp_expt(), except for the addition of the reductions)
andre@0:   
andre@0:   The modular reductions are done using Barrett's algorithm (see
andre@0:   s_mp_reduce() below for details)
andre@0:  */
andre@0: 
andre@0: mp_err s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_int   s, x, mu;
andre@0:   mp_err   res;
andre@0:   mp_digit d;
andre@0:   int      dig, bit;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   if((res = mp_init(&s)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_init_copy(&x, a)) != MP_OKAY ||
andre@0:      (res = mp_mod(&x, m, &x)) != MP_OKAY)
andre@0:     goto X;
andre@0:   if((res = mp_init(&mu)) != MP_OKAY)
andre@0:     goto MU;
andre@0: 
andre@0:   mp_set(&s, 1);
andre@0: 
andre@0:   /* mu = b^2k / m */
andre@0:   s_mp_add_d(&mu, 1); 
andre@0:   s_mp_lshd(&mu, 2 * USED(m));
andre@0:   if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
andre@0:     goto CLEANUP;
andre@0: 
andre@0:   /* Loop over digits of b in ascending order, except highest order */
andre@0:   for(dig = 0; dig < (USED(b) - 1); dig++) {
andre@0:     d = DIGIT(b, dig);
andre@0: 
andre@0:     /* Loop over the bits of the lower-order digits */
andre@0:     for(bit = 0; bit < DIGIT_BIT; bit++) {
andre@0:       if(d & 1) {
andre@0: 	if((res = s_mp_mul(&s, &x)) != MP_OKAY)
andre@0: 	  goto CLEANUP;
andre@0: 	if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
andre@0: 	  goto CLEANUP;
andre@0:       }
andre@0: 
andre@0:       d >>= 1;
andre@0: 
andre@0:       if((res = s_mp_sqr(&x)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:       if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:     }
andre@0:   }
andre@0: 
andre@0:   /* Now do the last digit... */
andre@0:   d = DIGIT(b, dig);
andre@0: 
andre@0:   while(d) {
andre@0:     if(d & 1) {
andre@0:       if((res = s_mp_mul(&s, &x)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:       if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:     }
andre@0: 
andre@0:     d >>= 1;
andre@0: 
andre@0:     if((res = s_mp_sqr(&x)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:     if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   }
andre@0: 
andre@0:   s_mp_exch(&s, c);
andre@0: 
andre@0:  CLEANUP:
andre@0:   mp_clear(&mu);
andre@0:  MU:
andre@0:   mp_clear(&x);
andre@0:  X:
andre@0:   mp_clear(&s);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end s_mp_exptmod() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_exptmod_d(a, d, m, c) */
andre@0: 
andre@0: mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_int   s, x;
andre@0:   mp_err   res;
andre@0: 
andre@0:   ARGCHK(a != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if((res = mp_init(&s)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_init_copy(&x, a)) != MP_OKAY)
andre@0:     goto X;
andre@0: 
andre@0:   mp_set(&s, 1);
andre@0: 
andre@0:   while(d != 0) {
andre@0:     if(d & 1) {
andre@0:       if((res = s_mp_mul(&s, &x)) != MP_OKAY ||
andre@0: 	 (res = mp_mod(&s, m, &s)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0:     }
andre@0: 
andre@0:     d /= 2;
andre@0: 
andre@0:     if((res = s_mp_sqr(&x)) != MP_OKAY ||
andre@0:        (res = mp_mod(&x, m, &x)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   }
andre@0: 
andre@0:   s_mp_exch(&s, c);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&x);
andre@0: X:
andre@0:   mp_clear(&s);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_exptmod_d() */
andre@0: 
andre@0: /* }}} */
andre@0: #endif /* if MP_MODARITH */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ Comparison functions */
andre@0: 
andre@0: /* {{{ mp_cmp_z(a) */
andre@0: 
andre@0: /*
andre@0:   mp_cmp_z(a)
andre@0: 
andre@0:   Compare a <=> 0.  Returns <0 if a<0, 0 if a=0, >0 if a>0.
andre@0:  */
andre@0: 
andre@0: int    mp_cmp_z(const mp_int *a)
andre@0: {
andre@0:   if(SIGN(a) == NEG)
andre@0:     return MP_LT;
andre@0:   else if(USED(a) == 1 && DIGIT(a, 0) == 0)
andre@0:     return MP_EQ;
andre@0:   else
andre@0:     return MP_GT;
andre@0: 
andre@0: } /* end mp_cmp_z() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_cmp_d(a, d) */
andre@0: 
andre@0: /*
andre@0:   mp_cmp_d(a, d)
andre@0: 
andre@0:   Compare a <=> d.  Returns <0 if a<d, 0 if a=d, >0 if a>d
andre@0:  */
andre@0: 
andre@0: int    mp_cmp_d(const mp_int *a, mp_digit d)
andre@0: {
andre@0:   ARGCHK(a != NULL, MP_EQ);
andre@0: 
andre@0:   if(SIGN(a) == NEG)
andre@0:     return MP_LT;
andre@0: 
andre@0:   return s_mp_cmp_d(a, d);
andre@0: 
andre@0: } /* end mp_cmp_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_cmp(a, b) */
andre@0: 
andre@0: int    mp_cmp(const mp_int *a, const mp_int *b)
andre@0: {
andre@0:   ARGCHK(a != NULL && b != NULL, MP_EQ);
andre@0: 
andre@0:   if(SIGN(a) == SIGN(b)) {
andre@0:     int  mag;
andre@0: 
andre@0:     if((mag = s_mp_cmp(a, b)) == MP_EQ)
andre@0:       return MP_EQ;
andre@0: 
andre@0:     if(SIGN(a) == ZPOS)
andre@0:       return mag;
andre@0:     else
andre@0:       return -mag;
andre@0: 
andre@0:   } else if(SIGN(a) == ZPOS) {
andre@0:     return MP_GT;
andre@0:   } else {
andre@0:     return MP_LT;
andre@0:   }
andre@0: 
andre@0: } /* end mp_cmp() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_cmp_mag(a, b) */
andre@0: 
andre@0: /*
andre@0:   mp_cmp_mag(a, b)
andre@0: 
andre@0:   Compares |a| <=> |b|, and returns an appropriate comparison result
andre@0:  */
andre@0: 
andre@0: int    mp_cmp_mag(mp_int *a, mp_int *b)
andre@0: {
andre@0:   ARGCHK(a != NULL && b != NULL, MP_EQ);
andre@0: 
andre@0:   return s_mp_cmp(a, b);
andre@0: 
andre@0: } /* end mp_cmp_mag() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_cmp_int(a, z) */
andre@0: 
andre@0: /*
andre@0:   This just converts z to an mp_int, and uses the existing comparison
andre@0:   routines.  This is sort of inefficient, but it's not clear to me how
andre@0:   frequently this wil get used anyway.  For small positive constants,
andre@0:   you can always use mp_cmp_d(), and for zero, there is mp_cmp_z().
andre@0:  */
andre@0: int    mp_cmp_int(const mp_int *a, long z)
andre@0: {
andre@0:   mp_int  tmp;
andre@0:   int     out;
andre@0: 
andre@0:   ARGCHK(a != NULL, MP_EQ);
andre@0:   
andre@0:   mp_init(&tmp); mp_set_int(&tmp, z);
andre@0:   out = mp_cmp(a, &tmp);
andre@0:   mp_clear(&tmp);
andre@0: 
andre@0:   return out;
andre@0: 
andre@0: } /* end mp_cmp_int() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_isodd(a) */
andre@0: 
andre@0: /*
andre@0:   mp_isodd(a)
andre@0: 
andre@0:   Returns a true (non-zero) value if a is odd, false (zero) otherwise.
andre@0:  */
andre@0: int    mp_isodd(const mp_int *a)
andre@0: {
andre@0:   ARGCHK(a != NULL, 0);
andre@0: 
andre@0:   return (int)(DIGIT(a, 0) & 1);
andre@0: 
andre@0: } /* end mp_isodd() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_iseven(a) */
andre@0: 
andre@0: int    mp_iseven(const mp_int *a)
andre@0: {
andre@0:   return !mp_isodd(a);
andre@0: 
andre@0: } /* end mp_iseven() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ Number theoretic functions */
andre@0: 
andre@0: #if MP_NUMTH
andre@0: /* {{{ mp_gcd(a, b, c) */
andre@0: 
andre@0: /*
andre@0:   Like the old mp_gcd() function, except computes the GCD using the
andre@0:   binary algorithm due to Josef Stein in 1961 (via Knuth).
andre@0:  */
andre@0: mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c)
andre@0: {
andre@0:   mp_err   res;
andre@0:   mp_int   u, v, t;
andre@0:   mp_size  k = 0;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ)
andre@0:       return MP_RANGE;
andre@0:   if(mp_cmp_z(a) == MP_EQ) {
andre@0:     return mp_copy(b, c);
andre@0:   } else if(mp_cmp_z(b) == MP_EQ) {
andre@0:     return mp_copy(a, c);
andre@0:   }
andre@0: 
andre@0:   if((res = mp_init(&t)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_init_copy(&u, a)) != MP_OKAY)
andre@0:     goto U;
andre@0:   if((res = mp_init_copy(&v, b)) != MP_OKAY)
andre@0:     goto V;
andre@0: 
andre@0:   SIGN(&u) = ZPOS;
andre@0:   SIGN(&v) = ZPOS;
andre@0: 
andre@0:   /* Divide out common factors of 2 until at least 1 of a, b is even */
andre@0:   while(mp_iseven(&u) && mp_iseven(&v)) {
andre@0:     s_mp_div_2(&u);
andre@0:     s_mp_div_2(&v);
andre@0:     ++k;
andre@0:   }
andre@0: 
andre@0:   /* Initialize t */
andre@0:   if(mp_isodd(&u)) {
andre@0:     if((res = mp_copy(&v, &t)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:     
andre@0:     /* t = -v */
andre@0:     if(SIGN(&v) == ZPOS)
andre@0:       SIGN(&t) = NEG;
andre@0:     else
andre@0:       SIGN(&t) = ZPOS;
andre@0:     
andre@0:   } else {
andre@0:     if((res = mp_copy(&u, &t)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0: 
andre@0:   }
andre@0: 
andre@0:   for(;;) {
andre@0:     while(mp_iseven(&t)) {
andre@0:       s_mp_div_2(&t);
andre@0:     }
andre@0: 
andre@0:     if(mp_cmp_z(&t) == MP_GT) {
andre@0:       if((res = mp_copy(&t, &u)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0: 
andre@0:     } else {
andre@0:       if((res = mp_copy(&t, &v)) != MP_OKAY)
andre@0: 	goto CLEANUP;
andre@0: 
andre@0:       /* v = -t */
andre@0:       if(SIGN(&t) == ZPOS)
andre@0: 	SIGN(&v) = NEG;
andre@0:       else
andre@0: 	SIGN(&v) = ZPOS;
andre@0:     }
andre@0: 
andre@0:     if((res = mp_sub(&u, &v, &t)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0: 
andre@0:     if(s_mp_cmp_d(&t, 0) == MP_EQ)
andre@0:       break;
andre@0:   }
andre@0: 
andre@0:   s_mp_2expt(&v, k);       /* v = 2^k   */
andre@0:   res = mp_mul(&u, &v, c); /* c = u * v */
andre@0: 
andre@0:  CLEANUP:
andre@0:   mp_clear(&v);
andre@0:  V:
andre@0:   mp_clear(&u);
andre@0:  U:
andre@0:   mp_clear(&t);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_gcd() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_lcm(a, b, c) */
andre@0: 
andre@0: /* We compute the least common multiple using the rule:
andre@0: 
andre@0:    ab = [a, b](a, b)
andre@0: 
andre@0:    ... by computing the product, and dividing out the gcd.
andre@0:  */
andre@0: 
andre@0: mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c)
andre@0: {
andre@0:   mp_int  gcd, prod;
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
andre@0: 
andre@0:   /* Set up temporaries */
andre@0:   if((res = mp_init(&gcd)) != MP_OKAY)
andre@0:     return res;
andre@0:   if((res = mp_init(&prod)) != MP_OKAY)
andre@0:     goto GCD;
andre@0: 
andre@0:   if((res = mp_mul(a, b, &prod)) != MP_OKAY)
andre@0:     goto CLEANUP;
andre@0:   if((res = mp_gcd(a, b, &gcd)) != MP_OKAY)
andre@0:     goto CLEANUP;
andre@0: 
andre@0:   res = mp_div(&prod, &gcd, c, NULL);
andre@0: 
andre@0:  CLEANUP:
andre@0:   mp_clear(&prod);
andre@0:  GCD:
andre@0:   mp_clear(&gcd);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_lcm() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_xgcd(a, b, g, x, y) */
andre@0: 
andre@0: /*
andre@0:   mp_xgcd(a, b, g, x, y)
andre@0: 
andre@0:   Compute g = (a, b) and values x and y satisfying Bezout's identity
andre@0:   (that is, ax + by = g).  This uses the binary extended GCD algorithm
andre@0:   based on the Stein algorithm used for mp_gcd()
andre@0:   See algorithm 14.61 in Handbook of Applied Cryptogrpahy.
andre@0:  */
andre@0: 
andre@0: mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y)
andre@0: {
andre@0:   mp_int   gx, xc, yc, u, v, A, B, C, D;
andre@0:   mp_int  *clean[9];
andre@0:   mp_err   res;
andre@0:   int      last = -1;
andre@0: 
andre@0:   if(mp_cmp_z(b) == 0)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   /* Initialize all these variables we need */
andre@0:   MP_CHECKOK( mp_init(&u) );
andre@0:   clean[++last] = &u;
andre@0:   MP_CHECKOK( mp_init(&v) );
andre@0:   clean[++last] = &v;
andre@0:   MP_CHECKOK( mp_init(&gx) );
andre@0:   clean[++last] = &gx;
andre@0:   MP_CHECKOK( mp_init(&A) );
andre@0:   clean[++last] = &A;
andre@0:   MP_CHECKOK( mp_init(&B) );
andre@0:   clean[++last] = &B;
andre@0:   MP_CHECKOK( mp_init(&C) );
andre@0:   clean[++last] = &C;
andre@0:   MP_CHECKOK( mp_init(&D) );
andre@0:   clean[++last] = &D;
andre@0:   MP_CHECKOK( mp_init_copy(&xc, a) );
andre@0:   clean[++last] = &xc;
andre@0:   mp_abs(&xc, &xc);
andre@0:   MP_CHECKOK( mp_init_copy(&yc, b) );
andre@0:   clean[++last] = &yc;
andre@0:   mp_abs(&yc, &yc);
andre@0: 
andre@0:   mp_set(&gx, 1);
andre@0: 
andre@0:   /* Divide by two until at least one of them is odd */
andre@0:   while(mp_iseven(&xc) && mp_iseven(&yc)) {
andre@0:     mp_size nx = mp_trailing_zeros(&xc);
andre@0:     mp_size ny = mp_trailing_zeros(&yc);
andre@0:     mp_size n  = MP_MIN(nx, ny);
andre@0:     s_mp_div_2d(&xc,n);
andre@0:     s_mp_div_2d(&yc,n);
andre@0:     MP_CHECKOK( s_mp_mul_2d(&gx,n) );
andre@0:   }
andre@0: 
andre@0:   mp_copy(&xc, &u);
andre@0:   mp_copy(&yc, &v);
andre@0:   mp_set(&A, 1); mp_set(&D, 1);
andre@0: 
andre@0:   /* Loop through binary GCD algorithm */
andre@0:   do {
andre@0:     while(mp_iseven(&u)) {
andre@0:       s_mp_div_2(&u);
andre@0: 
andre@0:       if(mp_iseven(&A) && mp_iseven(&B)) {
andre@0: 	s_mp_div_2(&A); s_mp_div_2(&B);
andre@0:       } else {
andre@0: 	MP_CHECKOK( mp_add(&A, &yc, &A) );
andre@0: 	s_mp_div_2(&A);
andre@0: 	MP_CHECKOK( mp_sub(&B, &xc, &B) );
andre@0: 	s_mp_div_2(&B);
andre@0:       }
andre@0:     }
andre@0: 
andre@0:     while(mp_iseven(&v)) {
andre@0:       s_mp_div_2(&v);
andre@0: 
andre@0:       if(mp_iseven(&C) && mp_iseven(&D)) {
andre@0: 	s_mp_div_2(&C); s_mp_div_2(&D);
andre@0:       } else {
andre@0: 	MP_CHECKOK( mp_add(&C, &yc, &C) );
andre@0: 	s_mp_div_2(&C);
andre@0: 	MP_CHECKOK( mp_sub(&D, &xc, &D) );
andre@0: 	s_mp_div_2(&D);
andre@0:       }
andre@0:     }
andre@0: 
andre@0:     if(mp_cmp(&u, &v) >= 0) {
andre@0:       MP_CHECKOK( mp_sub(&u, &v, &u) );
andre@0:       MP_CHECKOK( mp_sub(&A, &C, &A) );
andre@0:       MP_CHECKOK( mp_sub(&B, &D, &B) );
andre@0:     } else {
andre@0:       MP_CHECKOK( mp_sub(&v, &u, &v) );
andre@0:       MP_CHECKOK( mp_sub(&C, &A, &C) );
andre@0:       MP_CHECKOK( mp_sub(&D, &B, &D) );
andre@0:     }
andre@0:   } while (mp_cmp_z(&u) != 0);
andre@0: 
andre@0:   /* copy results to output */
andre@0:   if(x)
andre@0:     MP_CHECKOK( mp_copy(&C, x) );
andre@0: 
andre@0:   if(y)
andre@0:     MP_CHECKOK( mp_copy(&D, y) );
andre@0:       
andre@0:   if(g)
andre@0:     MP_CHECKOK( mp_mul(&gx, &v, g) );
andre@0: 
andre@0:  CLEANUP:
andre@0:   while(last >= 0)
andre@0:     mp_clear(clean[last--]);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end mp_xgcd() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: mp_size mp_trailing_zeros(const mp_int *mp)
andre@0: {
andre@0:   mp_digit d;
andre@0:   mp_size  n = 0;
andre@0:   int      ix;
andre@0: 
andre@0:   if (!mp || !MP_DIGITS(mp) || !mp_cmp_z(mp))
andre@0:     return n;
andre@0: 
andre@0:   for (ix = 0; !(d = MP_DIGIT(mp,ix)) && (ix < MP_USED(mp)); ++ix)
andre@0:     n += MP_DIGIT_BIT;
andre@0:   if (!d)
andre@0:     return 0;	/* shouldn't happen, but ... */
andre@0: #if !defined(MP_USE_UINT_DIGIT)
andre@0:   if (!(d & 0xffffffffU)) {
andre@0:     d >>= 32;
andre@0:     n  += 32;
andre@0:   }
andre@0: #endif
andre@0:   if (!(d & 0xffffU)) {
andre@0:     d >>= 16;
andre@0:     n  += 16;
andre@0:   }
andre@0:   if (!(d & 0xffU)) {
andre@0:     d >>= 8;
andre@0:     n  += 8;
andre@0:   }
andre@0:   if (!(d & 0xfU)) {
andre@0:     d >>= 4;
andre@0:     n  += 4;
andre@0:   }
andre@0:   if (!(d & 0x3U)) {
andre@0:     d >>= 2;
andre@0:     n  += 2;
andre@0:   }
andre@0:   if (!(d & 0x1U)) {
andre@0:     d >>= 1;
andre@0:     n  += 1;
andre@0:   }
andre@0: #if MP_ARGCHK == 2
andre@0:   assert(0 != (d & 1));
andre@0: #endif
andre@0:   return n;
andre@0: }
andre@0: 
andre@0: /* Given a and prime p, computes c and k such that a*c == 2**k (mod p).
andre@0: ** Returns k (positive) or error (negative).
andre@0: ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
andre@0: ** by Richard Schroeppel (a.k.a. Captain Nemo).
andre@0: */
andre@0: mp_err s_mp_almost_inverse(const mp_int *a, const mp_int *p, mp_int *c)
andre@0: {
andre@0:   mp_err res;
andre@0:   mp_err k    = 0;
andre@0:   mp_int d, f, g;
andre@0: 
andre@0:   ARGCHK(a && p && c, MP_BADARG);
andre@0: 
andre@0:   MP_DIGITS(&d) = 0;
andre@0:   MP_DIGITS(&f) = 0;
andre@0:   MP_DIGITS(&g) = 0;
andre@0:   MP_CHECKOK( mp_init(&d) );
andre@0:   MP_CHECKOK( mp_init_copy(&f, a) );	/* f = a */
andre@0:   MP_CHECKOK( mp_init_copy(&g, p) );	/* g = p */
andre@0: 
andre@0:   mp_set(c, 1);
andre@0:   mp_zero(&d);
andre@0: 
andre@0:   if (mp_cmp_z(&f) == 0) {
andre@0:     res = MP_UNDEF;
andre@0:   } else 
andre@0:   for (;;) {
andre@0:     int diff_sign;
andre@0:     while (mp_iseven(&f)) {
andre@0:       mp_size n = mp_trailing_zeros(&f);
andre@0:       if (!n) {
andre@0: 	res = MP_UNDEF;
andre@0: 	goto CLEANUP;
andre@0:       }
andre@0:       s_mp_div_2d(&f, n);
andre@0:       MP_CHECKOK( s_mp_mul_2d(&d, n) );
andre@0:       k += n;
andre@0:     }
andre@0:     if (mp_cmp_d(&f, 1) == MP_EQ) {	/* f == 1 */
andre@0:       res = k;
andre@0:       break;
andre@0:     }
andre@0:     diff_sign = mp_cmp(&f, &g);
andre@0:     if (diff_sign < 0) {		/* f < g */
andre@0:       s_mp_exch(&f, &g);
andre@0:       s_mp_exch(c, &d);
andre@0:     } else if (diff_sign == 0) {		/* f == g */
andre@0:       res = MP_UNDEF;		/* a and p are not relatively prime */
andre@0:       break;
andre@0:     }
andre@0:     if ((MP_DIGIT(&f,0) % 4) == (MP_DIGIT(&g,0) % 4)) {
andre@0:       MP_CHECKOK( mp_sub(&f, &g, &f) );	/* f = f - g */
andre@0:       MP_CHECKOK( mp_sub(c,  &d,  c) );	/* c = c - d */
andre@0:     } else {
andre@0:       MP_CHECKOK( mp_add(&f, &g, &f) );	/* f = f + g */
andre@0:       MP_CHECKOK( mp_add(c,  &d,  c) );	/* c = c + d */
andre@0:     }
andre@0:   }
andre@0:   if (res >= 0) {
andre@0:     while (MP_SIGN(c) != MP_ZPOS) {
andre@0:       MP_CHECKOK( mp_add(c, p, c) );
andre@0:     }
andre@0:     res = k;
andre@0:   }
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&d);
andre@0:   mp_clear(&f);
andre@0:   mp_clear(&g);
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: /* Compute T = (P ** -1) mod MP_RADIX.  Also works for 16-bit mp_digits.
andre@0: ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
andre@0: ** by Richard Schroeppel (a.k.a. Captain Nemo).
andre@0: */
andre@0: mp_digit  s_mp_invmod_radix(mp_digit P)
andre@0: {
andre@0:   mp_digit T = P;
andre@0:   T *= 2 - (P * T);
andre@0:   T *= 2 - (P * T);
andre@0:   T *= 2 - (P * T);
andre@0:   T *= 2 - (P * T);
andre@0: #if !defined(MP_USE_UINT_DIGIT)
andre@0:   T *= 2 - (P * T);
andre@0:   T *= 2 - (P * T);
andre@0: #endif
andre@0:   return T;
andre@0: }
andre@0: 
andre@0: /* Given c, k, and prime p, where a*c == 2**k (mod p), 
andre@0: ** Compute x = (a ** -1) mod p.  This is similar to Montgomery reduction.
andre@0: ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
andre@0: ** by Richard Schroeppel (a.k.a. Captain Nemo).
andre@0: */
andre@0: mp_err  s_mp_fixup_reciprocal(const mp_int *c, const mp_int *p, int k, mp_int *x)
andre@0: {
andre@0:   int      k_orig = k;
andre@0:   mp_digit r;
andre@0:   mp_size  ix;
andre@0:   mp_err   res;
andre@0: 
andre@0:   if (mp_cmp_z(c) < 0) {		/* c < 0 */
andre@0:     MP_CHECKOK( mp_add(c, p, x) );	/* x = c + p */
andre@0:   } else {
andre@0:     MP_CHECKOK( mp_copy(c, x) );	/* x = c */
andre@0:   }
andre@0: 
andre@0:   /* make sure x is large enough */
andre@0:   ix = MP_HOWMANY(k, MP_DIGIT_BIT) + MP_USED(p) + 1;
andre@0:   ix = MP_MAX(ix, MP_USED(x));
andre@0:   MP_CHECKOK( s_mp_pad(x, ix) );
andre@0: 
andre@0:   r = 0 - s_mp_invmod_radix(MP_DIGIT(p,0));
andre@0: 
andre@0:   for (ix = 0; k > 0; ix++) {
andre@0:     int      j = MP_MIN(k, MP_DIGIT_BIT);
andre@0:     mp_digit v = r * MP_DIGIT(x, ix);
andre@0:     if (j < MP_DIGIT_BIT) {
andre@0:       v &= ((mp_digit)1 << j) - 1;	/* v = v mod (2 ** j) */
andre@0:     }
andre@0:     s_mp_mul_d_add_offset(p, v, x, ix); /* x += p * v * (RADIX ** ix) */
andre@0:     k -= j;
andre@0:   }
andre@0:   s_mp_clamp(x);
andre@0:   s_mp_div_2d(x, k_orig);
andre@0:   res = MP_OKAY;
andre@0: 
andre@0: CLEANUP:
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: /* compute mod inverse using Schroeppel's method, only if m is odd */
andre@0: mp_err s_mp_invmod_odd_m(const mp_int *a, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   int k;
andre@0:   mp_err  res;
andre@0:   mp_int  x;
andre@0: 
andre@0:   ARGCHK(a && m && c, MP_BADARG);
andre@0: 
andre@0:   if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
andre@0:     return MP_RANGE;
andre@0:   if (mp_iseven(m))
andre@0:     return MP_UNDEF;
andre@0: 
andre@0:   MP_DIGITS(&x) = 0;
andre@0: 
andre@0:   if (a == c) {
andre@0:     if ((res = mp_init_copy(&x, a)) != MP_OKAY)
andre@0:       return res;
andre@0:     if (a == m) 
andre@0:       m = &x;
andre@0:     a = &x;
andre@0:   } else if (m == c) {
andre@0:     if ((res = mp_init_copy(&x, m)) != MP_OKAY)
andre@0:       return res;
andre@0:     m = &x;
andre@0:   } else {
andre@0:     MP_DIGITS(&x) = 0;
andre@0:   }
andre@0: 
andre@0:   MP_CHECKOK( s_mp_almost_inverse(a, m, c) );
andre@0:   k = res;
andre@0:   MP_CHECKOK( s_mp_fixup_reciprocal(c, m, k, c) );
andre@0: CLEANUP:
andre@0:   mp_clear(&x);
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: /* Known good algorithm for computing modular inverse.  But slow. */
andre@0: mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_int  g, x;
andre@0:   mp_err  res;
andre@0: 
andre@0:   ARGCHK(a && m && c, MP_BADARG);
andre@0: 
andre@0:   if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   MP_DIGITS(&g) = 0;
andre@0:   MP_DIGITS(&x) = 0;
andre@0:   MP_CHECKOK( mp_init(&x) );
andre@0:   MP_CHECKOK( mp_init(&g) );
andre@0: 
andre@0:   MP_CHECKOK( mp_xgcd(a, m, &g, &x, NULL) );
andre@0: 
andre@0:   if (mp_cmp_d(&g, 1) != MP_EQ) {
andre@0:     res = MP_UNDEF;
andre@0:     goto CLEANUP;
andre@0:   }
andre@0: 
andre@0:   res = mp_mod(&x, m, c);
andre@0:   SIGN(c) = SIGN(a);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&x);
andre@0:   mp_clear(&g);
andre@0: 
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: /* modular inverse where modulus is 2**k. */
andre@0: /* c = a**-1 mod 2**k */
andre@0: mp_err s_mp_invmod_2d(const mp_int *a, mp_size k, mp_int *c)
andre@0: {
andre@0:   mp_err res;
andre@0:   mp_size ix = k + 4;
andre@0:   mp_int t0, t1, val, tmp, two2k;
andre@0: 
andre@0:   static const mp_digit d2 = 2;
andre@0:   static const mp_int two = { MP_ZPOS, 1, 1, (mp_digit *)&d2 };
andre@0: 
andre@0:   if (mp_iseven(a))
andre@0:     return MP_UNDEF;
andre@0:   if (k <= MP_DIGIT_BIT) {
andre@0:     mp_digit i = s_mp_invmod_radix(MP_DIGIT(a,0));
andre@0:     if (k < MP_DIGIT_BIT)
andre@0:       i &= ((mp_digit)1 << k) - (mp_digit)1;
andre@0:     mp_set(c, i);
andre@0:     return MP_OKAY;
andre@0:   }
andre@0:   MP_DIGITS(&t0) = 0;
andre@0:   MP_DIGITS(&t1) = 0;
andre@0:   MP_DIGITS(&val) = 0;
andre@0:   MP_DIGITS(&tmp) = 0;
andre@0:   MP_DIGITS(&two2k) = 0;
andre@0:   MP_CHECKOK( mp_init_copy(&val, a) );
andre@0:   s_mp_mod_2d(&val, k);
andre@0:   MP_CHECKOK( mp_init_copy(&t0, &val) );
andre@0:   MP_CHECKOK( mp_init_copy(&t1, &t0)  );
andre@0:   MP_CHECKOK( mp_init(&tmp) );
andre@0:   MP_CHECKOK( mp_init(&two2k) );
andre@0:   MP_CHECKOK( s_mp_2expt(&two2k, k) );
andre@0:   do {
andre@0:     MP_CHECKOK( mp_mul(&val, &t1, &tmp)  );
andre@0:     MP_CHECKOK( mp_sub(&two, &tmp, &tmp) );
andre@0:     MP_CHECKOK( mp_mul(&t1, &tmp, &t1)   );
andre@0:     s_mp_mod_2d(&t1, k);
andre@0:     while (MP_SIGN(&t1) != MP_ZPOS) {
andre@0:       MP_CHECKOK( mp_add(&t1, &two2k, &t1) );
andre@0:     }
andre@0:     if (mp_cmp(&t1, &t0) == MP_EQ) 
andre@0:       break;
andre@0:     MP_CHECKOK( mp_copy(&t1, &t0) );
andre@0:   } while (--ix > 0);
andre@0:   if (!ix) {
andre@0:     res = MP_UNDEF;
andre@0:   } else {
andre@0:     mp_exch(c, &t1);
andre@0:   }
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&t0);
andre@0:   mp_clear(&t1);
andre@0:   mp_clear(&val);
andre@0:   mp_clear(&tmp);
andre@0:   mp_clear(&two2k);
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: mp_err s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c)
andre@0: {
andre@0:   mp_err res;
andre@0:   mp_size k;
andre@0:   mp_int oddFactor, evenFactor;	/* factors of the modulus */
andre@0:   mp_int oddPart, evenPart;	/* parts to combine via CRT. */
andre@0:   mp_int C2, tmp1, tmp2;
andre@0: 
andre@0:   /*static const mp_digit d1 = 1; */
andre@0:   /*static const mp_int one = { MP_ZPOS, 1, 1, (mp_digit *)&d1 }; */
andre@0: 
andre@0:   if ((res = s_mp_ispow2(m)) >= 0) {
andre@0:     k = res;
andre@0:     return s_mp_invmod_2d(a, k, c);
andre@0:   }
andre@0:   MP_DIGITS(&oddFactor) = 0;
andre@0:   MP_DIGITS(&evenFactor) = 0;
andre@0:   MP_DIGITS(&oddPart) = 0;
andre@0:   MP_DIGITS(&evenPart) = 0;
andre@0:   MP_DIGITS(&C2)     = 0;
andre@0:   MP_DIGITS(&tmp1)   = 0;
andre@0:   MP_DIGITS(&tmp2)   = 0;
andre@0: 
andre@0:   MP_CHECKOK( mp_init_copy(&oddFactor, m) );    /* oddFactor = m */
andre@0:   MP_CHECKOK( mp_init(&evenFactor) );
andre@0:   MP_CHECKOK( mp_init(&oddPart) );
andre@0:   MP_CHECKOK( mp_init(&evenPart) );
andre@0:   MP_CHECKOK( mp_init(&C2)     );
andre@0:   MP_CHECKOK( mp_init(&tmp1)   );
andre@0:   MP_CHECKOK( mp_init(&tmp2)   );
andre@0: 
andre@0:   k = mp_trailing_zeros(m);
andre@0:   s_mp_div_2d(&oddFactor, k);
andre@0:   MP_CHECKOK( s_mp_2expt(&evenFactor, k) );
andre@0: 
andre@0:   /* compute a**-1 mod oddFactor. */
andre@0:   MP_CHECKOK( s_mp_invmod_odd_m(a, &oddFactor, &oddPart) );
andre@0:   /* compute a**-1 mod evenFactor, where evenFactor == 2**k. */
andre@0:   MP_CHECKOK( s_mp_invmod_2d(   a,       k,    &evenPart) );
andre@0: 
andre@0:   /* Use Chinese Remainer theorem to compute a**-1 mod m. */
andre@0:   /* let m1 = oddFactor,  v1 = oddPart, 
andre@0:    * let m2 = evenFactor, v2 = evenPart.
andre@0:    */
andre@0: 
andre@0:   /* Compute C2 = m1**-1 mod m2. */
andre@0:   MP_CHECKOK( s_mp_invmod_2d(&oddFactor, k,    &C2) );
andre@0: 
andre@0:   /* compute u = (v2 - v1)*C2 mod m2 */
andre@0:   MP_CHECKOK( mp_sub(&evenPart, &oddPart,   &tmp1) );
andre@0:   MP_CHECKOK( mp_mul(&tmp1,     &C2,        &tmp2) );
andre@0:   s_mp_mod_2d(&tmp2, k);
andre@0:   while (MP_SIGN(&tmp2) != MP_ZPOS) {
andre@0:     MP_CHECKOK( mp_add(&tmp2, &evenFactor, &tmp2) );
andre@0:   }
andre@0: 
andre@0:   /* compute answer = v1 + u*m1 */
andre@0:   MP_CHECKOK( mp_mul(&tmp2,     &oddFactor, c) );
andre@0:   MP_CHECKOK( mp_add(&oddPart,  c,          c) );
andre@0:   /* not sure this is necessary, but it's low cost if not. */
andre@0:   MP_CHECKOK( mp_mod(c,         m,          c) );
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&oddFactor);
andre@0:   mp_clear(&evenFactor);
andre@0:   mp_clear(&oddPart);
andre@0:   mp_clear(&evenPart);
andre@0:   mp_clear(&C2);
andre@0:   mp_clear(&tmp1);
andre@0:   mp_clear(&tmp2);
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: 
andre@0: /* {{{ mp_invmod(a, m, c) */
andre@0: 
andre@0: /*
andre@0:   mp_invmod(a, m, c)
andre@0: 
andre@0:   Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
andre@0:   This is equivalent to the question of whether (a, m) = 1.  If not,
andre@0:   MP_UNDEF is returned, and there is no inverse.
andre@0:  */
andre@0: 
andre@0: mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c)
andre@0: {
andre@0: 
andre@0:   ARGCHK(a && m && c, MP_BADARG);
andre@0: 
andre@0:   if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   if (mp_isodd(m)) {
andre@0:     return s_mp_invmod_odd_m(a, m, c);
andre@0:   }
andre@0:   if (mp_iseven(a))
andre@0:     return MP_UNDEF;	/* not invertable */
andre@0: 
andre@0:   return s_mp_invmod_even_m(a, m, c);
andre@0: 
andre@0: } /* end mp_invmod() */
andre@0: 
andre@0: /* }}} */
andre@0: #endif /* if MP_NUMTH */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ mp_print(mp, ofp) */
andre@0: 
andre@0: #if MP_IOFUNC
andre@0: /*
andre@0:   mp_print(mp, ofp)
andre@0: 
andre@0:   Print a textual representation of the given mp_int on the output
andre@0:   stream 'ofp'.  Output is generated using the internal radix.
andre@0:  */
andre@0: 
andre@0: void   mp_print(mp_int *mp, FILE *ofp)
andre@0: {
andre@0:   int   ix;
andre@0: 
andre@0:   if(mp == NULL || ofp == NULL)
andre@0:     return;
andre@0: 
andre@0:   fputc((SIGN(mp) == NEG) ? '-' : '+', ofp);
andre@0: 
andre@0:   for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:     fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
andre@0:   }
andre@0: 
andre@0: } /* end mp_print() */
andre@0: 
andre@0: #endif /* if MP_IOFUNC */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* {{{ More I/O Functions */
andre@0: 
andre@0: /* {{{ mp_read_raw(mp, str, len) */
andre@0: 
andre@0: /* 
andre@0:    mp_read_raw(mp, str, len)
andre@0: 
andre@0:    Read in a raw value (base 256) into the given mp_int
andre@0:  */
andre@0: 
andre@0: mp_err  mp_read_raw(mp_int *mp, char *str, int len)
andre@0: {
andre@0:   int            ix;
andre@0:   mp_err         res;
andre@0:   unsigned char *ustr = (unsigned char *)str;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
andre@0: 
andre@0:   mp_zero(mp);
andre@0: 
andre@0:   /* Get sign from first byte */
andre@0:   if(ustr[0])
andre@0:     SIGN(mp) = NEG;
andre@0:   else
andre@0:     SIGN(mp) = ZPOS;
andre@0: 
andre@0:   /* Read the rest of the digits */
andre@0:   for(ix = 1; ix < len; ix++) {
andre@0:     if((res = mp_mul_d(mp, 256, mp)) != MP_OKAY)
andre@0:       return res;
andre@0:     if((res = mp_add_d(mp, ustr[ix], mp)) != MP_OKAY)
andre@0:       return res;
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_read_raw() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_raw_size(mp) */
andre@0: 
andre@0: int    mp_raw_size(mp_int *mp)
andre@0: {
andre@0:   ARGCHK(mp != NULL, 0);
andre@0: 
andre@0:   return (USED(mp) * sizeof(mp_digit)) + 1;
andre@0: 
andre@0: } /* end mp_raw_size() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_toraw(mp, str) */
andre@0: 
andre@0: mp_err mp_toraw(mp_int *mp, char *str)
andre@0: {
andre@0:   int  ix, jx, pos = 1;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL, MP_BADARG);
andre@0: 
andre@0:   str[0] = (char)SIGN(mp);
andre@0: 
andre@0:   /* Iterate over each digit... */
andre@0:   for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:     mp_digit  d = DIGIT(mp, ix);
andre@0: 
andre@0:     /* Unpack digit bytes, high order first */
andre@0:     for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
andre@0:       str[pos++] = (char)(d >> (jx * CHAR_BIT));
andre@0:     }
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_toraw() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_read_radix(mp, str, radix) */
andre@0: 
andre@0: /*
andre@0:   mp_read_radix(mp, str, radix)
andre@0: 
andre@0:   Read an integer from the given string, and set mp to the resulting
andre@0:   value.  The input is presumed to be in base 10.  Leading non-digit
andre@0:   characters are ignored, and the function reads until a non-digit
andre@0:   character or the end of the string.
andre@0:  */
andre@0: 
andre@0: mp_err  mp_read_radix(mp_int *mp, const char *str, int radix)
andre@0: {
andre@0:   int     ix = 0, val = 0;
andre@0:   mp_err  res;
andre@0:   mp_sign sig = ZPOS;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, 
andre@0: 	 MP_BADARG);
andre@0: 
andre@0:   mp_zero(mp);
andre@0: 
andre@0:   /* Skip leading non-digit characters until a digit or '-' or '+' */
andre@0:   while(str[ix] && 
andre@0: 	(s_mp_tovalue(str[ix], radix) < 0) && 
andre@0: 	str[ix] != '-' &&
andre@0: 	str[ix] != '+') {
andre@0:     ++ix;
andre@0:   }
andre@0: 
andre@0:   if(str[ix] == '-') {
andre@0:     sig = NEG;
andre@0:     ++ix;
andre@0:   } else if(str[ix] == '+') {
andre@0:     sig = ZPOS; /* this is the default anyway... */
andre@0:     ++ix;
andre@0:   }
andre@0: 
andre@0:   while((val = s_mp_tovalue(str[ix], radix)) >= 0) {
andre@0:     if((res = s_mp_mul_d(mp, radix)) != MP_OKAY)
andre@0:       return res;
andre@0:     if((res = s_mp_add_d(mp, val)) != MP_OKAY)
andre@0:       return res;
andre@0:     ++ix;
andre@0:   }
andre@0: 
andre@0:   if(s_mp_cmp_d(mp, 0) == MP_EQ)
andre@0:     SIGN(mp) = ZPOS;
andre@0:   else
andre@0:     SIGN(mp) = sig;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_read_radix() */
andre@0: 
andre@0: mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix)
andre@0: {
andre@0:   int     radix = default_radix;
andre@0:   int     cx;
andre@0:   mp_sign sig   = ZPOS;
andre@0:   mp_err  res;
andre@0: 
andre@0:   /* Skip leading non-digit characters until a digit or '-' or '+' */
andre@0:   while ((cx = *str) != 0 && 
andre@0: 	(s_mp_tovalue(cx, radix) < 0) && 
andre@0: 	cx != '-' &&
andre@0: 	cx != '+') {
andre@0:     ++str;
andre@0:   }
andre@0: 
andre@0:   if (cx == '-') {
andre@0:     sig = NEG;
andre@0:     ++str;
andre@0:   } else if (cx == '+') {
andre@0:     sig = ZPOS; /* this is the default anyway... */
andre@0:     ++str;
andre@0:   }
andre@0: 
andre@0:   if (str[0] == '0') {
andre@0:     if ((str[1] | 0x20) == 'x') {
andre@0:       radix = 16;
andre@0:       str += 2;
andre@0:     } else {
andre@0:       radix = 8;
andre@0:       str++;
andre@0:     }
andre@0:   }
andre@0:   res = mp_read_radix(a, str, radix);
andre@0:   if (res == MP_OKAY) {
andre@0:     MP_SIGN(a) = (s_mp_cmp_d(a, 0) == MP_EQ) ? ZPOS : sig;
andre@0:   }
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_radix_size(mp, radix) */
andre@0: 
andre@0: int    mp_radix_size(mp_int *mp, int radix)
andre@0: {
andre@0:   int  bits;
andre@0: 
andre@0:   if(!mp || radix < 2 || radix > MAX_RADIX)
andre@0:     return 0;
andre@0: 
andre@0:   bits = USED(mp) * DIGIT_BIT - 1;
andre@0:  
andre@0:   return s_mp_outlen(bits, radix);
andre@0: 
andre@0: } /* end mp_radix_size() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_toradix(mp, str, radix) */
andre@0: 
andre@0: mp_err mp_toradix(mp_int *mp, char *str, int radix)
andre@0: {
andre@0:   int  ix, pos = 0;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL, MP_BADARG);
andre@0:   ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
andre@0: 
andre@0:   if(mp_cmp_z(mp) == MP_EQ) {
andre@0:     str[0] = '0';
andre@0:     str[1] = '\0';
andre@0:   } else {
andre@0:     mp_err   res;
andre@0:     mp_int   tmp;
andre@0:     mp_sign  sgn;
andre@0:     mp_digit rem, rdx = (mp_digit)radix;
andre@0:     char     ch;
andre@0: 
andre@0:     if((res = mp_init_copy(&tmp, mp)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     /* Save sign for later, and take absolute value */
andre@0:     sgn = SIGN(&tmp); SIGN(&tmp) = ZPOS;
andre@0: 
andre@0:     /* Generate output digits in reverse order      */
andre@0:     while(mp_cmp_z(&tmp) != 0) {
andre@0:       if((res = mp_div_d(&tmp, rdx, &tmp, &rem)) != MP_OKAY) {
andre@0: 	mp_clear(&tmp);
andre@0: 	return res;
andre@0:       }
andre@0: 
andre@0:       /* Generate digits, use capital letters */
andre@0:       ch = s_mp_todigit(rem, radix, 0);
andre@0: 
andre@0:       str[pos++] = ch;
andre@0:     }
andre@0: 
andre@0:     /* Add - sign if original value was negative */
andre@0:     if(sgn == NEG)
andre@0:       str[pos++] = '-';
andre@0: 
andre@0:     /* Add trailing NUL to end the string        */
andre@0:     str[pos--] = '\0';
andre@0: 
andre@0:     /* Reverse the digits and sign indicator     */
andre@0:     ix = 0;
andre@0:     while(ix < pos) {
andre@0:       char tmp = str[ix];
andre@0: 
andre@0:       str[ix] = str[pos];
andre@0:       str[pos] = tmp;
andre@0:       ++ix;
andre@0:       --pos;
andre@0:     }
andre@0:     
andre@0:     mp_clear(&tmp);
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end mp_toradix() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_tovalue(ch, r) */
andre@0: 
andre@0: int    mp_tovalue(char ch, int r)
andre@0: {
andre@0:   return s_mp_tovalue(ch, r);
andre@0: 
andre@0: } /* end mp_tovalue() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_strerror(ec) */
andre@0: 
andre@0: /*
andre@0:   mp_strerror(ec)
andre@0: 
andre@0:   Return a string describing the meaning of error code 'ec'.  The
andre@0:   string returned is allocated in static memory, so the caller should
andre@0:   not attempt to modify or free the memory associated with this
andre@0:   string.
andre@0:  */
andre@0: const char  *mp_strerror(mp_err ec)
andre@0: {
andre@0:   int   aec = (ec < 0) ? -ec : ec;
andre@0: 
andre@0:   /* Code values are negative, so the senses of these comparisons
andre@0:      are accurate */
andre@0:   if(ec < MP_LAST_CODE || ec > MP_OKAY) {
andre@0:     return mp_err_string[0];  /* unknown error code */
andre@0:   } else {
andre@0:     return mp_err_string[aec + 1];
andre@0:   }
andre@0: 
andre@0: } /* end mp_strerror() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /*========================================================================*/
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* Static function definitions (internal use only)                        */
andre@0: 
andre@0: /* {{{ Memory management */
andre@0: 
andre@0: /* {{{ s_mp_grow(mp, min) */
andre@0: 
andre@0: /* Make sure there are at least 'min' digits allocated to mp              */
andre@0: mp_err   s_mp_grow(mp_int *mp, mp_size min)
andre@0: {
andre@0:   if(min > ALLOC(mp)) {
andre@0:     mp_digit   *tmp;
andre@0: 
andre@0:     /* Set min to next nearest default precision block size */
andre@0:     min = MP_ROUNDUP(min, s_mp_defprec);
andre@0: 
andre@0:     if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL)
andre@0:       return MP_MEM;
andre@0: 
andre@0:     s_mp_copy(DIGITS(mp), tmp, USED(mp));
andre@0: 
andre@0: #if MP_CRYPTO
andre@0:     s_mp_setz(DIGITS(mp), ALLOC(mp));
andre@0: #endif
andre@0:     s_mp_free(DIGITS(mp));
andre@0:     DIGITS(mp) = tmp;
andre@0:     ALLOC(mp) = min;
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end s_mp_grow() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_pad(mp, min) */
andre@0: 
andre@0: /* Make sure the used size of mp is at least 'min', growing if needed     */
andre@0: mp_err   s_mp_pad(mp_int *mp, mp_size min)
andre@0: {
andre@0:   if(min > USED(mp)) {
andre@0:     mp_err  res;
andre@0: 
andre@0:     /* Make sure there is room to increase precision  */
andre@0:     if (min > ALLOC(mp)) {
andre@0:       if ((res = s_mp_grow(mp, min)) != MP_OKAY)
andre@0: 	return res;
andre@0:     } else {
andre@0:       s_mp_setz(DIGITS(mp) + USED(mp), min - USED(mp));
andre@0:     }
andre@0: 
andre@0:     /* Increase precision; should already be 0-filled */
andre@0:     USED(mp) = min;
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end s_mp_pad() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_setz(dp, count) */
andre@0: 
andre@0: #if MP_MACRO == 0
andre@0: /* Set 'count' digits pointed to by dp to be zeroes                       */
andre@0: void s_mp_setz(mp_digit *dp, mp_size count)
andre@0: {
andre@0: #if MP_MEMSET == 0
andre@0:   int  ix;
andre@0: 
andre@0:   for(ix = 0; ix < count; ix++)
andre@0:     dp[ix] = 0;
andre@0: #else
andre@0:   memset(dp, 0, count * sizeof(mp_digit));
andre@0: #endif
andre@0: 
andre@0: } /* end s_mp_setz() */
andre@0: #endif
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_copy(sp, dp, count) */
andre@0: 
andre@0: #if MP_MACRO == 0
andre@0: /* Copy 'count' digits from sp to dp                                      */
andre@0: void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count)
andre@0: {
andre@0: #if MP_MEMCPY == 0
andre@0:   int  ix;
andre@0: 
andre@0:   for(ix = 0; ix < count; ix++)
andre@0:     dp[ix] = sp[ix];
andre@0: #else
andre@0:   memcpy(dp, sp, count * sizeof(mp_digit));
andre@0: #endif
andre@0:   ++mp_copies;
andre@0: 
andre@0: } /* end s_mp_copy() */
andre@0: #endif
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_alloc(nb, ni) */
andre@0: 
andre@0: #if MP_MACRO == 0
andre@0: /* Allocate ni records of nb bytes each, and return a pointer to that     */
andre@0: void    *s_mp_alloc(size_t nb, size_t ni)
andre@0: {
andre@0:   ++mp_allocs;
andre@0:   return calloc(nb, ni);
andre@0: 
andre@0: } /* end s_mp_alloc() */
andre@0: #endif
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_free(ptr) */
andre@0: 
andre@0: #if MP_MACRO == 0
andre@0: /* Free the memory pointed to by ptr                                      */
andre@0: void     s_mp_free(void *ptr)
andre@0: {
andre@0:   if(ptr) {
andre@0:     ++mp_frees;
andre@0:     free(ptr);
andre@0:   }
andre@0: } /* end s_mp_free() */
andre@0: #endif
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_clamp(mp) */
andre@0: 
andre@0: #if MP_MACRO == 0
andre@0: /* Remove leading zeroes from the given value                             */
andre@0: void     s_mp_clamp(mp_int *mp)
andre@0: {
andre@0:   mp_size used = MP_USED(mp);
andre@0:   while (used > 1 && DIGIT(mp, used - 1) == 0)
andre@0:     --used;
andre@0:   MP_USED(mp) = used;
andre@0: } /* end s_mp_clamp() */
andre@0: #endif
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_exch(a, b) */
andre@0: 
andre@0: /* Exchange the data for a and b; (b, a) = (a, b)                         */
andre@0: void     s_mp_exch(mp_int *a, mp_int *b)
andre@0: {
andre@0:   mp_int   tmp;
andre@0: 
andre@0:   tmp = *a;
andre@0:   *a = *b;
andre@0:   *b = tmp;
andre@0: 
andre@0: } /* end s_mp_exch() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ Arithmetic helpers */
andre@0: 
andre@0: /* {{{ s_mp_lshd(mp, p) */
andre@0: 
andre@0: /* 
andre@0:    Shift mp leftward by p digits, growing if needed, and zero-filling
andre@0:    the in-shifted digits at the right end.  This is a convenient
andre@0:    alternative to multiplication by powers of the radix
andre@0:  */   
andre@0: 
andre@0: mp_err   s_mp_lshd(mp_int *mp, mp_size p)
andre@0: {
andre@0:   mp_err  res;
andre@0:   mp_size pos;
andre@0:   int     ix;
andre@0: 
andre@0:   if(p == 0)
andre@0:     return MP_OKAY;
andre@0: 
andre@0:   if (MP_USED(mp) == 1 && MP_DIGIT(mp, 0) == 0)
andre@0:     return MP_OKAY;
andre@0: 
andre@0:   if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   pos = USED(mp) - 1;
andre@0: 
andre@0:   /* Shift all the significant figures over as needed */
andre@0:   for(ix = pos - p; ix >= 0; ix--) 
andre@0:     DIGIT(mp, ix + p) = DIGIT(mp, ix);
andre@0: 
andre@0:   /* Fill the bottom digits with zeroes */
andre@0:   for(ix = 0; ix < p; ix++)
andre@0:     DIGIT(mp, ix) = 0;
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end s_mp_lshd() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_mul_2d(mp, d) */
andre@0: 
andre@0: /*
andre@0:   Multiply the integer by 2^d, where d is a number of bits.  This
andre@0:   amounts to a bitwise shift of the value.
andre@0:  */
andre@0: mp_err   s_mp_mul_2d(mp_int *mp, mp_digit d)
andre@0: {
andre@0:   mp_err   res;
andre@0:   mp_digit dshift, bshift;
andre@0:   mp_digit mask;
andre@0: 
andre@0:   ARGCHK(mp != NULL,  MP_BADARG);
andre@0: 
andre@0:   dshift = d / MP_DIGIT_BIT;
andre@0:   bshift = d % MP_DIGIT_BIT;
andre@0:   /* bits to be shifted out of the top word */
andre@0:   mask   = ((mp_digit)~0 << (MP_DIGIT_BIT - bshift)); 
andre@0:   mask  &= MP_DIGIT(mp, MP_USED(mp) - 1);
andre@0: 
andre@0:   if (MP_OKAY != (res = s_mp_pad(mp, MP_USED(mp) + dshift + (mask != 0) )))
andre@0:     return res;
andre@0: 
andre@0:   if (dshift && MP_OKAY != (res = s_mp_lshd(mp, dshift)))
andre@0:     return res;
andre@0: 
andre@0:   if (bshift) { 
andre@0:     mp_digit *pa = MP_DIGITS(mp);
andre@0:     mp_digit *alim = pa + MP_USED(mp);
andre@0:     mp_digit  prev = 0;
andre@0: 
andre@0:     for (pa += dshift; pa < alim; ) {
andre@0:       mp_digit x = *pa;
andre@0:       *pa++ = (x << bshift) | prev;
andre@0:       prev = x >> (DIGIT_BIT - bshift);
andre@0:     }
andre@0:   }
andre@0: 
andre@0:   s_mp_clamp(mp);
andre@0:   return MP_OKAY;
andre@0: } /* end s_mp_mul_2d() */
andre@0: 
andre@0: /* {{{ s_mp_rshd(mp, p) */
andre@0: 
andre@0: /* 
andre@0:    Shift mp rightward by p digits.  Maintains the invariant that
andre@0:    digits above the precision are all zero.  Digits shifted off the
andre@0:    end are lost.  Cannot fail.
andre@0:  */
andre@0: 
andre@0: void     s_mp_rshd(mp_int *mp, mp_size p)
andre@0: {
andre@0:   mp_size  ix;
andre@0:   mp_digit *src, *dst;
andre@0: 
andre@0:   if(p == 0)
andre@0:     return;
andre@0: 
andre@0:   /* Shortcut when all digits are to be shifted off */
andre@0:   if(p >= USED(mp)) {
andre@0:     s_mp_setz(DIGITS(mp), ALLOC(mp));
andre@0:     USED(mp) = 1;
andre@0:     SIGN(mp) = ZPOS;
andre@0:     return;
andre@0:   }
andre@0: 
andre@0:   /* Shift all the significant figures over as needed */
andre@0:   dst = MP_DIGITS(mp);
andre@0:   src = dst + p;
andre@0:   for (ix = USED(mp) - p; ix > 0; ix--)
andre@0:     *dst++ = *src++;
andre@0: 
andre@0:   MP_USED(mp) -= p;
andre@0:   /* Fill the top digits with zeroes */
andre@0:   while (p-- > 0)
andre@0:     *dst++ = 0;
andre@0: 
andre@0: #if 0
andre@0:   /* Strip off any leading zeroes    */
andre@0:   s_mp_clamp(mp);
andre@0: #endif
andre@0: 
andre@0: } /* end s_mp_rshd() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_div_2(mp) */
andre@0: 
andre@0: /* Divide by two -- take advantage of radix properties to do it fast      */
andre@0: void     s_mp_div_2(mp_int *mp)
andre@0: {
andre@0:   s_mp_div_2d(mp, 1);
andre@0: 
andre@0: } /* end s_mp_div_2() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_mul_2(mp) */
andre@0: 
andre@0: mp_err s_mp_mul_2(mp_int *mp)
andre@0: {
andre@0:   mp_digit *pd;
andre@0:   int      ix, used;
andre@0:   mp_digit kin = 0;
andre@0: 
andre@0:   /* Shift digits leftward by 1 bit */
andre@0:   used = MP_USED(mp);
andre@0:   pd = MP_DIGITS(mp);
andre@0:   for (ix = 0; ix < used; ix++) {
andre@0:     mp_digit d = *pd;
andre@0:     *pd++ = (d << 1) | kin;
andre@0:     kin = (d >> (DIGIT_BIT - 1));
andre@0:   }
andre@0: 
andre@0:   /* Deal with rollover from last digit */
andre@0:   if (kin) {
andre@0:     if (ix >= ALLOC(mp)) {
andre@0:       mp_err res;
andre@0:       if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
andre@0: 	return res;
andre@0:     }
andre@0: 
andre@0:     DIGIT(mp, ix) = kin;
andre@0:     USED(mp) += 1;
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end s_mp_mul_2() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_mod_2d(mp, d) */
andre@0: 
andre@0: /*
andre@0:   Remainder the integer by 2^d, where d is a number of bits.  This
andre@0:   amounts to a bitwise AND of the value, and does not require the full
andre@0:   division code
andre@0:  */
andre@0: void     s_mp_mod_2d(mp_int *mp, mp_digit d)
andre@0: {
andre@0:   mp_size  ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
andre@0:   mp_size  ix;
andre@0:   mp_digit dmask;
andre@0: 
andre@0:   if(ndig >= USED(mp))
andre@0:     return;
andre@0: 
andre@0:   /* Flush all the bits above 2^d in its digit */
andre@0:   dmask = ((mp_digit)1 << nbit) - 1;
andre@0:   DIGIT(mp, ndig) &= dmask;
andre@0: 
andre@0:   /* Flush all digits above the one with 2^d in it */
andre@0:   for(ix = ndig + 1; ix < USED(mp); ix++)
andre@0:     DIGIT(mp, ix) = 0;
andre@0: 
andre@0:   s_mp_clamp(mp);
andre@0: 
andre@0: } /* end s_mp_mod_2d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_div_2d(mp, d) */
andre@0: 
andre@0: /*
andre@0:   Divide the integer by 2^d, where d is a number of bits.  This
andre@0:   amounts to a bitwise shift of the value, and does not require the
andre@0:   full division code (used in Barrett reduction, see below)
andre@0:  */
andre@0: void     s_mp_div_2d(mp_int *mp, mp_digit d)
andre@0: {
andre@0:   int       ix;
andre@0:   mp_digit  save, next, mask;
andre@0: 
andre@0:   s_mp_rshd(mp, d / DIGIT_BIT);
andre@0:   d %= DIGIT_BIT;
andre@0:   if (d) {
andre@0:     mask = ((mp_digit)1 << d) - 1;
andre@0:     save = 0;
andre@0:     for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:       next = DIGIT(mp, ix) & mask;
andre@0:       DIGIT(mp, ix) = (DIGIT(mp, ix) >> d) | (save << (DIGIT_BIT - d));
andre@0:       save = next;
andre@0:     }
andre@0:   }
andre@0:   s_mp_clamp(mp);
andre@0: 
andre@0: } /* end s_mp_div_2d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_norm(a, b, *d) */
andre@0: 
andre@0: /*
andre@0:   s_mp_norm(a, b, *d)
andre@0: 
andre@0:   Normalize a and b for division, where b is the divisor.  In order
andre@0:   that we might make good guesses for quotient digits, we want the
andre@0:   leading digit of b to be at least half the radix, which we
andre@0:   accomplish by multiplying a and b by a power of 2.  The exponent 
andre@0:   (shift count) is placed in *pd, so that the remainder can be shifted 
andre@0:   back at the end of the division process.
andre@0:  */
andre@0: 
andre@0: mp_err   s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd)
andre@0: {
andre@0:   mp_digit  d;
andre@0:   mp_digit  mask;
andre@0:   mp_digit  b_msd;
andre@0:   mp_err    res    = MP_OKAY;
andre@0: 
andre@0:   d = 0;
andre@0:   mask  = DIGIT_MAX & ~(DIGIT_MAX >> 1);	/* mask is msb of digit */
andre@0:   b_msd = DIGIT(b, USED(b) - 1);
andre@0:   while (!(b_msd & mask)) {
andre@0:     b_msd <<= 1;
andre@0:     ++d;
andre@0:   }
andre@0: 
andre@0:   if (d) {
andre@0:     MP_CHECKOK( s_mp_mul_2d(a, d) );
andre@0:     MP_CHECKOK( s_mp_mul_2d(b, d) );
andre@0:   }
andre@0: 
andre@0:   *pd = d;
andre@0: CLEANUP:
andre@0:   return res;
andre@0: 
andre@0: } /* end s_mp_norm() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ Primitive digit arithmetic */
andre@0: 
andre@0: /* {{{ s_mp_add_d(mp, d) */
andre@0: 
andre@0: /* Add d to |mp| in place                                                 */
andre@0: mp_err   s_mp_add_d(mp_int *mp, mp_digit d)    /* unsigned digit addition */
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   mp_word   w, k = 0;
andre@0:   mp_size   ix = 1;
andre@0: 
andre@0:   w = (mp_word)DIGIT(mp, 0) + d;
andre@0:   DIGIT(mp, 0) = ACCUM(w);
andre@0:   k = CARRYOUT(w);
andre@0: 
andre@0:   while(ix < USED(mp) && k) {
andre@0:     w = (mp_word)DIGIT(mp, ix) + k;
andre@0:     DIGIT(mp, ix) = ACCUM(w);
andre@0:     k = CARRYOUT(w);
andre@0:     ++ix;
andre@0:   }
andre@0: 
andre@0:   if(k != 0) {
andre@0:     mp_err  res;
andre@0: 
andre@0:     if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     DIGIT(mp, ix) = (mp_digit)k;
andre@0:   }
andre@0: 
andre@0:   return MP_OKAY;
andre@0: #else
andre@0:   mp_digit * pmp = MP_DIGITS(mp);
andre@0:   mp_digit sum, mp_i, carry = 0;
andre@0:   mp_err   res = MP_OKAY;
andre@0:   int used = (int)MP_USED(mp);
andre@0: 
andre@0:   mp_i = *pmp;
andre@0:   *pmp++ = sum = d + mp_i;
andre@0:   carry = (sum < d);
andre@0:   while (carry && --used > 0) {
andre@0:     mp_i = *pmp;
andre@0:     *pmp++ = sum = carry + mp_i;
andre@0:     carry = !sum;
andre@0:   }
andre@0:   if (carry && !used) {
andre@0:     /* mp is growing */
andre@0:     used = MP_USED(mp);
andre@0:     MP_CHECKOK( s_mp_pad(mp, used + 1) );
andre@0:     MP_DIGIT(mp, used) = carry;
andre@0:   }
andre@0: CLEANUP:
andre@0:   return res;
andre@0: #endif
andre@0: } /* end s_mp_add_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_sub_d(mp, d) */
andre@0: 
andre@0: /* Subtract d from |mp| in place, assumes |mp| > d                        */
andre@0: mp_err   s_mp_sub_d(mp_int *mp, mp_digit d)    /* unsigned digit subtract */
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:   mp_word   w, b = 0;
andre@0:   mp_size   ix = 1;
andre@0: 
andre@0:   /* Compute initial subtraction    */
andre@0:   w = (RADIX + (mp_word)DIGIT(mp, 0)) - d;
andre@0:   b = CARRYOUT(w) ? 0 : 1;
andre@0:   DIGIT(mp, 0) = ACCUM(w);
andre@0: 
andre@0:   /* Propagate borrows leftward     */
andre@0:   while(b && ix < USED(mp)) {
andre@0:     w = (RADIX + (mp_word)DIGIT(mp, ix)) - b;
andre@0:     b = CARRYOUT(w) ? 0 : 1;
andre@0:     DIGIT(mp, ix) = ACCUM(w);
andre@0:     ++ix;
andre@0:   }
andre@0: 
andre@0:   /* Remove leading zeroes          */
andre@0:   s_mp_clamp(mp);
andre@0: 
andre@0:   /* If we have a borrow out, it's a violation of the input invariant */
andre@0:   if(b)
andre@0:     return MP_RANGE;
andre@0:   else
andre@0:     return MP_OKAY;
andre@0: #else
andre@0:   mp_digit *pmp = MP_DIGITS(mp);
andre@0:   mp_digit mp_i, diff, borrow;
andre@0:   mp_size  used = MP_USED(mp);
andre@0: 
andre@0:   mp_i = *pmp;
andre@0:   *pmp++ = diff = mp_i - d;
andre@0:   borrow = (diff > mp_i);
andre@0:   while (borrow && --used) {
andre@0:     mp_i = *pmp;
andre@0:     *pmp++ = diff = mp_i - borrow;
andre@0:     borrow = (diff > mp_i);
andre@0:   }
andre@0:   s_mp_clamp(mp);
andre@0:   return (borrow && !used) ? MP_RANGE : MP_OKAY;
andre@0: #endif
andre@0: } /* end s_mp_sub_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_mul_d(a, d) */
andre@0: 
andre@0: /* Compute a = a * d, single digit multiplication                         */
andre@0: mp_err   s_mp_mul_d(mp_int *a, mp_digit d)
andre@0: {
andre@0:   mp_err  res;
andre@0:   mp_size used;
andre@0:   int     pow;
andre@0: 
andre@0:   if (!d) {
andre@0:     mp_zero(a);
andre@0:     return MP_OKAY;
andre@0:   }
andre@0:   if (d == 1)
andre@0:     return MP_OKAY;
andre@0:   if (0 <= (pow = s_mp_ispow2d(d))) {
andre@0:     return s_mp_mul_2d(a, (mp_digit)pow);
andre@0:   }
andre@0: 
andre@0:   used = MP_USED(a);
andre@0:   MP_CHECKOK( s_mp_pad(a, used + 1) );
andre@0: 
andre@0:   s_mpv_mul_d(MP_DIGITS(a), used, d, MP_DIGITS(a));
andre@0: 
andre@0:   s_mp_clamp(a);
andre@0: 
andre@0: CLEANUP:
andre@0:   return res;
andre@0:   
andre@0: } /* end s_mp_mul_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_div_d(mp, d, r) */
andre@0: 
andre@0: /*
andre@0:   s_mp_div_d(mp, d, r)
andre@0: 
andre@0:   Compute the quotient mp = mp / d and remainder r = mp mod d, for a
andre@0:   single digit d.  If r is null, the remainder will be discarded.
andre@0:  */
andre@0: 
andre@0: mp_err   s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
andre@0:   mp_word   w = 0, q;
andre@0: #else
andre@0:   mp_digit  w, q;
andre@0: #endif
andre@0:   int       ix;
andre@0:   mp_err    res;
andre@0:   mp_int    quot;
andre@0:   mp_int    rem;
andre@0: 
andre@0:   if(d == 0)
andre@0:     return MP_RANGE;
andre@0:   if (d == 1) {
andre@0:     if (r)
andre@0:       *r = 0;
andre@0:     return MP_OKAY;
andre@0:   }
andre@0:   /* could check for power of 2 here, but mp_div_d does that. */
andre@0:   if (MP_USED(mp) == 1) {
andre@0:     mp_digit n   = MP_DIGIT(mp,0);
andre@0:     mp_digit rem;
andre@0: 
andre@0:     q   = n / d;
andre@0:     rem = n % d;
andre@0:     MP_DIGIT(mp,0) = q;
andre@0:     if (r)
andre@0:       *r = rem;
andre@0:     return MP_OKAY;
andre@0:   }
andre@0: 
andre@0:   MP_DIGITS(&rem)  = 0;
andre@0:   MP_DIGITS(&quot) = 0;
andre@0:   /* Make room for the quotient */
andre@0:   MP_CHECKOK( mp_init_size(&quot, USED(mp)) );
andre@0: 
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
andre@0:   for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:     w = (w << DIGIT_BIT) | DIGIT(mp, ix);
andre@0: 
andre@0:     if(w >= d) {
andre@0:       q = w / d;
andre@0:       w = w % d;
andre@0:     } else {
andre@0:       q = 0;
andre@0:     }
andre@0: 
andre@0:     s_mp_lshd(&quot, 1);
andre@0:     DIGIT(&quot, 0) = (mp_digit)q;
andre@0:   }
andre@0: #else
andre@0:   {
andre@0:     mp_digit p;
andre@0: #if !defined(MP_ASSEMBLY_DIV_2DX1D)
andre@0:     mp_digit norm;
andre@0: #endif
andre@0: 
andre@0:     MP_CHECKOK( mp_init_copy(&rem, mp) );
andre@0: 
andre@0: #if !defined(MP_ASSEMBLY_DIV_2DX1D)
andre@0:     MP_DIGIT(&quot, 0) = d;
andre@0:     MP_CHECKOK( s_mp_norm(&rem, &quot, &norm) );
andre@0:     if (norm)
andre@0:       d <<= norm;
andre@0:     MP_DIGIT(&quot, 0) = 0;
andre@0: #endif
andre@0: 
andre@0:     p = 0;
andre@0:     for (ix = USED(&rem) - 1; ix >= 0; ix--) {
andre@0:       w = DIGIT(&rem, ix);
andre@0: 
andre@0:       if (p) {
andre@0:         MP_CHECKOK( s_mpv_div_2dx1d(p, w, d, &q, &w) );
andre@0:       } else if (w >= d) {
andre@0: 	q = w / d;
andre@0: 	w = w % d;
andre@0:       } else {
andre@0: 	q = 0;
andre@0:       }
andre@0: 
andre@0:       MP_CHECKOK( s_mp_lshd(&quot, 1) );
andre@0:       DIGIT(&quot, 0) = q;
andre@0:       p = w;
andre@0:     }
andre@0: #if !defined(MP_ASSEMBLY_DIV_2DX1D)
andre@0:     if (norm)
andre@0:       w >>= norm;
andre@0: #endif
andre@0:   }
andre@0: #endif
andre@0: 
andre@0:   /* Deliver the remainder, if desired */
andre@0:   if(r)
andre@0:     *r = (mp_digit)w;
andre@0: 
andre@0:   s_mp_clamp(&quot);
andre@0:   mp_exch(&quot, mp);
andre@0: CLEANUP:
andre@0:   mp_clear(&quot);
andre@0:   mp_clear(&rem);
andre@0: 
andre@0:   return res;
andre@0: } /* end s_mp_div_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ Primitive full arithmetic */
andre@0: 
andre@0: /* {{{ s_mp_add(a, b) */
andre@0: 
andre@0: /* Compute a = |a| + |b|                                                  */
andre@0: mp_err   s_mp_add(mp_int *a, const mp_int *b)  /* magnitude addition      */
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   mp_word   w = 0;
andre@0: #else
andre@0:   mp_digit  d, sum, carry = 0;
andre@0: #endif
andre@0:   mp_digit *pa, *pb;
andre@0:   mp_size   ix;
andre@0:   mp_size   used;
andre@0:   mp_err    res;
andre@0: 
andre@0:   /* Make sure a has enough precision for the output value */
andre@0:   if((USED(b) > USED(a)) && (res = s_mp_pad(a, USED(b))) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   /*
andre@0:     Add up all digits up to the precision of b.  If b had initially
andre@0:     the same precision as a, or greater, we took care of it by the
andre@0:     padding step above, so there is no problem.  If b had initially
andre@0:     less precision, we'll have to make sure the carry out is duly
andre@0:     propagated upward among the higher-order digits of the sum.
andre@0:    */
andre@0:   pa = MP_DIGITS(a);
andre@0:   pb = MP_DIGITS(b);
andre@0:   used = MP_USED(b);
andre@0:   for(ix = 0; ix < used; ix++) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:     w = w + *pa + *pb++;
andre@0:     *pa++ = ACCUM(w);
andre@0:     w = CARRYOUT(w);
andre@0: #else
andre@0:     d = *pa;
andre@0:     sum = d + *pb++;
andre@0:     d = (sum < d);			/* detect overflow */
andre@0:     *pa++ = sum += carry;
andre@0:     carry = d + (sum < carry);		/* detect overflow */
andre@0: #endif
andre@0:   }
andre@0: 
andre@0:   /* If we run out of 'b' digits before we're actually done, make
andre@0:      sure the carries get propagated upward...  
andre@0:    */
andre@0:   used = MP_USED(a);
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   while (w && ix < used) {
andre@0:     w = w + *pa;
andre@0:     *pa++ = ACCUM(w);
andre@0:     w = CARRYOUT(w);
andre@0:     ++ix;
andre@0:   }
andre@0: #else
andre@0:   while (carry && ix < used) {
andre@0:     sum = carry + *pa;
andre@0:     *pa++ = sum;
andre@0:     carry = !sum;
andre@0:     ++ix;
andre@0:   }
andre@0: #endif
andre@0: 
andre@0:   /* If there's an overall carry out, increase precision and include
andre@0:      it.  We could have done this initially, but why touch the memory
andre@0:      allocator unless we're sure we have to?
andre@0:    */
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   if (w) {
andre@0:     if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     DIGIT(a, ix) = (mp_digit)w;
andre@0:   }
andre@0: #else
andre@0:   if (carry) {
andre@0:     if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     DIGIT(a, used) = carry;
andre@0:   }
andre@0: #endif
andre@0: 
andre@0:   return MP_OKAY;
andre@0: } /* end s_mp_add() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* Compute c = |a| + |b|         */ /* magnitude addition      */
andre@0: mp_err   s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c)  
andre@0: {
andre@0:   mp_digit *pa, *pb, *pc;
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   mp_word   w = 0;
andre@0: #else
andre@0:   mp_digit  sum, carry = 0, d;
andre@0: #endif
andre@0:   mp_size   ix;
andre@0:   mp_size   used;
andre@0:   mp_err    res;
andre@0: 
andre@0:   MP_SIGN(c) = MP_SIGN(a);
andre@0:   if (MP_USED(a) < MP_USED(b)) {
andre@0:     const mp_int *xch = a;
andre@0:     a = b;
andre@0:     b = xch;
andre@0:   }
andre@0: 
andre@0:   /* Make sure a has enough precision for the output value */
andre@0:   if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
andre@0:     return res;
andre@0: 
andre@0:   /*
andre@0:     Add up all digits up to the precision of b.  If b had initially
andre@0:     the same precision as a, or greater, we took care of it by the
andre@0:     exchange step above, so there is no problem.  If b had initially
andre@0:     less precision, we'll have to make sure the carry out is duly
andre@0:     propagated upward among the higher-order digits of the sum.
andre@0:    */
andre@0:   pa = MP_DIGITS(a);
andre@0:   pb = MP_DIGITS(b);
andre@0:   pc = MP_DIGITS(c);
andre@0:   used = MP_USED(b);
andre@0:   for (ix = 0; ix < used; ix++) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:     w = w + *pa++ + *pb++;
andre@0:     *pc++ = ACCUM(w);
andre@0:     w = CARRYOUT(w);
andre@0: #else
andre@0:     d = *pa++;
andre@0:     sum = d + *pb++;
andre@0:     d = (sum < d);			/* detect overflow */
andre@0:     *pc++ = sum += carry;
andre@0:     carry = d + (sum < carry);		/* detect overflow */
andre@0: #endif
andre@0:   }
andre@0: 
andre@0:   /* If we run out of 'b' digits before we're actually done, make
andre@0:      sure the carries get propagated upward...  
andre@0:    */
andre@0:   for (used = MP_USED(a); ix < used; ++ix) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:     w = w + *pa++;
andre@0:     *pc++ = ACCUM(w);
andre@0:     w = CARRYOUT(w);
andre@0: #else
andre@0:     *pc++ = sum = carry + *pa++;
andre@0:     carry = (sum < carry);
andre@0: #endif
andre@0:   }
andre@0: 
andre@0:   /* If there's an overall carry out, increase precision and include
andre@0:      it.  We could have done this initially, but why touch the memory
andre@0:      allocator unless we're sure we have to?
andre@0:    */
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   if (w) {
andre@0:     if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     DIGIT(c, used) = (mp_digit)w;
andre@0:     ++used;
andre@0:   }
andre@0: #else
andre@0:   if (carry) {
andre@0:     if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     DIGIT(c, used) = carry;
andre@0:     ++used;
andre@0:   }
andre@0: #endif
andre@0:   MP_USED(c) = used;
andre@0:   return MP_OKAY;
andre@0: }
andre@0: /* {{{ s_mp_add_offset(a, b, offset) */
andre@0: 
andre@0: /* Compute a = |a| + ( |b| * (RADIX ** offset) )             */
andre@0: mp_err   s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset)   
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   mp_word   w, k = 0;
andre@0: #else
andre@0:   mp_digit  d, sum, carry = 0;
andre@0: #endif
andre@0:   mp_size   ib;
andre@0:   mp_size   ia;
andre@0:   mp_size   lim;
andre@0:   mp_err    res;
andre@0: 
andre@0:   /* Make sure a has enough precision for the output value */
andre@0:   lim = MP_USED(b) + offset;
andre@0:   if((lim > USED(a)) && (res = s_mp_pad(a, lim)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   /*
andre@0:     Add up all digits up to the precision of b.  If b had initially
andre@0:     the same precision as a, or greater, we took care of it by the
andre@0:     padding step above, so there is no problem.  If b had initially
andre@0:     less precision, we'll have to make sure the carry out is duly
andre@0:     propagated upward among the higher-order digits of the sum.
andre@0:    */
andre@0:   lim = USED(b);
andre@0:   for(ib = 0, ia = offset; ib < lim; ib++, ia++) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:     w = (mp_word)DIGIT(a, ia) + DIGIT(b, ib) + k;
andre@0:     DIGIT(a, ia) = ACCUM(w);
andre@0:     k = CARRYOUT(w);
andre@0: #else
andre@0:     d = MP_DIGIT(a, ia);
andre@0:     sum = d + MP_DIGIT(b, ib);
andre@0:     d = (sum < d);
andre@0:     MP_DIGIT(a,ia) = sum += carry;
andre@0:     carry = d + (sum < carry);
andre@0: #endif
andre@0:   }
andre@0: 
andre@0:   /* If we run out of 'b' digits before we're actually done, make
andre@0:      sure the carries get propagated upward...  
andre@0:    */
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   for (lim = MP_USED(a); k && (ia < lim); ++ia) {
andre@0:     w = (mp_word)DIGIT(a, ia) + k;
andre@0:     DIGIT(a, ia) = ACCUM(w);
andre@0:     k = CARRYOUT(w);
andre@0:   }
andre@0: #else
andre@0:   for (lim = MP_USED(a); carry && (ia < lim); ++ia) {
andre@0:     d = MP_DIGIT(a, ia);
andre@0:     MP_DIGIT(a,ia) = sum = d + carry;
andre@0:     carry = (sum < d);
andre@0:   }
andre@0: #endif
andre@0: 
andre@0:   /* If there's an overall carry out, increase precision and include
andre@0:      it.  We could have done this initially, but why touch the memory
andre@0:      allocator unless we're sure we have to?
andre@0:    */
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
andre@0:   if(k) {
andre@0:     if((res = s_mp_pad(a, USED(a) + 1)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     DIGIT(a, ia) = (mp_digit)k;
andre@0:   }
andre@0: #else
andre@0:   if (carry) {
andre@0:     if((res = s_mp_pad(a, lim + 1)) != MP_OKAY)
andre@0:       return res;
andre@0: 
andre@0:     DIGIT(a, lim) = carry;
andre@0:   }
andre@0: #endif
andre@0:   s_mp_clamp(a);
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end s_mp_add_offset() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_sub(a, b) */
andre@0: 
andre@0: /* Compute a = |a| - |b|, assumes |a| >= |b|                              */
andre@0: mp_err   s_mp_sub(mp_int *a, const mp_int *b)  /* magnitude subtract      */
andre@0: {
andre@0:   mp_digit *pa, *pb, *limit;
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:   mp_sword  w = 0;
andre@0: #else
andre@0:   mp_digit  d, diff, borrow = 0;
andre@0: #endif
andre@0: 
andre@0:   /*
andre@0:     Subtract and propagate borrow.  Up to the precision of b, this
andre@0:     accounts for the digits of b; after that, we just make sure the
andre@0:     carries get to the right place.  This saves having to pad b out to
andre@0:     the precision of a just to make the loops work right...
andre@0:    */
andre@0:   pa = MP_DIGITS(a);
andre@0:   pb = MP_DIGITS(b);
andre@0:   limit = pb + MP_USED(b);
andre@0:   while (pb < limit) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:     w = w + *pa - *pb++;
andre@0:     *pa++ = ACCUM(w);
andre@0:     w >>= MP_DIGIT_BIT;
andre@0: #else
andre@0:     d = *pa;
andre@0:     diff = d - *pb++;
andre@0:     d = (diff > d);				/* detect borrow */
andre@0:     if (borrow && --diff == MP_DIGIT_MAX)
andre@0:       ++d;
andre@0:     *pa++ = diff;
andre@0:     borrow = d;	
andre@0: #endif
andre@0:   }
andre@0:   limit = MP_DIGITS(a) + MP_USED(a);
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:   while (w && pa < limit) {
andre@0:     w = w + *pa;
andre@0:     *pa++ = ACCUM(w);
andre@0:     w >>= MP_DIGIT_BIT;
andre@0:   }
andre@0: #else
andre@0:   while (borrow && pa < limit) {
andre@0:     d = *pa;
andre@0:     *pa++ = diff = d - borrow;
andre@0:     borrow = (diff > d);
andre@0:   }
andre@0: #endif
andre@0: 
andre@0:   /* Clobber any leading zeroes we created    */
andre@0:   s_mp_clamp(a);
andre@0: 
andre@0:   /* 
andre@0:      If there was a borrow out, then |b| > |a| in violation
andre@0:      of our input invariant.  We've already done the work,
andre@0:      but we'll at least complain about it...
andre@0:    */
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:   return w ? MP_RANGE : MP_OKAY;
andre@0: #else
andre@0:   return borrow ? MP_RANGE : MP_OKAY;
andre@0: #endif
andre@0: } /* end s_mp_sub() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* Compute c = |a| - |b|, assumes |a| >= |b| */ /* magnitude subtract      */
andre@0: mp_err   s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c)  
andre@0: {
andre@0:   mp_digit *pa, *pb, *pc;
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:   mp_sword  w = 0;
andre@0: #else
andre@0:   mp_digit  d, diff, borrow = 0;
andre@0: #endif
andre@0:   int       ix, limit;
andre@0:   mp_err    res;
andre@0: 
andre@0:   MP_SIGN(c) = MP_SIGN(a);
andre@0: 
andre@0:   /* Make sure a has enough precision for the output value */
andre@0:   if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
andre@0:     return res;
andre@0: 
andre@0:   /*
andre@0:     Subtract and propagate borrow.  Up to the precision of b, this
andre@0:     accounts for the digits of b; after that, we just make sure the
andre@0:     carries get to the right place.  This saves having to pad b out to
andre@0:     the precision of a just to make the loops work right...
andre@0:    */
andre@0:   pa = MP_DIGITS(a);
andre@0:   pb = MP_DIGITS(b);
andre@0:   pc = MP_DIGITS(c);
andre@0:   limit = MP_USED(b);
andre@0:   for (ix = 0; ix < limit; ++ix) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:     w = w + *pa++ - *pb++;
andre@0:     *pc++ = ACCUM(w);
andre@0:     w >>= MP_DIGIT_BIT;
andre@0: #else
andre@0:     d = *pa++;
andre@0:     diff = d - *pb++;
andre@0:     d = (diff > d);
andre@0:     if (borrow && --diff == MP_DIGIT_MAX)
andre@0:       ++d;
andre@0:     *pc++ = diff;
andre@0:     borrow = d;
andre@0: #endif
andre@0:   }
andre@0:   for (limit = MP_USED(a); ix < limit; ++ix) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:     w = w + *pa++;
andre@0:     *pc++ = ACCUM(w);
andre@0:     w >>= MP_DIGIT_BIT;
andre@0: #else
andre@0:     d = *pa++;
andre@0:     *pc++ = diff = d - borrow;
andre@0:     borrow = (diff > d);
andre@0: #endif
andre@0:   }
andre@0: 
andre@0:   /* Clobber any leading zeroes we created    */
andre@0:   MP_USED(c) = ix;
andre@0:   s_mp_clamp(c);
andre@0: 
andre@0:   /* 
andre@0:      If there was a borrow out, then |b| > |a| in violation
andre@0:      of our input invariant.  We've already done the work,
andre@0:      but we'll at least complain about it...
andre@0:    */
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
andre@0:   return w ? MP_RANGE : MP_OKAY;
andre@0: #else
andre@0:   return borrow ? MP_RANGE : MP_OKAY;
andre@0: #endif
andre@0: }
andre@0: /* {{{ s_mp_mul(a, b) */
andre@0: 
andre@0: /* Compute a = |a| * |b|                                                  */
andre@0: mp_err   s_mp_mul(mp_int *a, const mp_int *b)
andre@0: {
andre@0:   return mp_mul(a, b, a);
andre@0: } /* end s_mp_mul() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
andre@0: /* This trick works on Sparc V8 CPUs with the Workshop compilers. */
andre@0: #define MP_MUL_DxD(a, b, Phi, Plo) \
andre@0:   { unsigned long long product = (unsigned long long)a * b; \
andre@0:     Plo = (mp_digit)product; \
andre@0:     Phi = (mp_digit)(product >> MP_DIGIT_BIT); }
andre@0: #elif defined(OSF1)
andre@0: #define MP_MUL_DxD(a, b, Phi, Plo) \
andre@0:   { Plo = asm ("mulq %a0, %a1, %v0", a, b);\
andre@0:     Phi = asm ("umulh %a0, %a1, %v0", a, b); }
andre@0: #else
andre@0: #define MP_MUL_DxD(a, b, Phi, Plo) \
andre@0:   { mp_digit a0b1, a1b0; \
andre@0:     Plo = (a & MP_HALF_DIGIT_MAX) * (b & MP_HALF_DIGIT_MAX); \
andre@0:     Phi = (a >> MP_HALF_DIGIT_BIT) * (b >> MP_HALF_DIGIT_BIT); \
andre@0:     a0b1 = (a & MP_HALF_DIGIT_MAX) * (b >> MP_HALF_DIGIT_BIT); \
andre@0:     a1b0 = (a >> MP_HALF_DIGIT_BIT) * (b & MP_HALF_DIGIT_MAX); \
andre@0:     a1b0 += a0b1; \
andre@0:     Phi += a1b0 >> MP_HALF_DIGIT_BIT; \
andre@0:     if (a1b0 < a0b1)  \
andre@0:       Phi += MP_HALF_RADIX; \
andre@0:     a1b0 <<= MP_HALF_DIGIT_BIT; \
andre@0:     Plo += a1b0; \
andre@0:     if (Plo < a1b0) \
andre@0:       ++Phi; \
andre@0:   }
andre@0: #endif
andre@0: 
andre@0: #if !defined(MP_ASSEMBLY_MULTIPLY)
andre@0: /* c = a * b */
andre@0: void s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
andre@0:   mp_digit   d = 0;
andre@0: 
andre@0:   /* Inner product:  Digits of a */
andre@0:   while (a_len--) {
andre@0:     mp_word w = ((mp_word)b * *a++) + d;
andre@0:     *c++ = ACCUM(w);
andre@0:     d = CARRYOUT(w);
andre@0:   }
andre@0:   *c = d;
andre@0: #else
andre@0:   mp_digit carry = 0;
andre@0:   while (a_len--) {
andre@0:     mp_digit a_i = *a++;
andre@0:     mp_digit a0b0, a1b1;
andre@0: 
andre@0:     MP_MUL_DxD(a_i, b, a1b1, a0b0);
andre@0: 
andre@0:     a0b0 += carry;
andre@0:     if (a0b0 < carry)
andre@0:       ++a1b1;
andre@0:     *c++ = a0b0;
andre@0:     carry = a1b1;
andre@0:   }
andre@0:   *c = carry;
andre@0: #endif
andre@0: }
andre@0: 
andre@0: /* c += a * b */
andre@0: void s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, 
andre@0: 			      mp_digit *c)
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
andre@0:   mp_digit   d = 0;
andre@0: 
andre@0:   /* Inner product:  Digits of a */
andre@0:   while (a_len--) {
andre@0:     mp_word w = ((mp_word)b * *a++) + *c + d;
andre@0:     *c++ = ACCUM(w);
andre@0:     d = CARRYOUT(w);
andre@0:   }
andre@0:   *c = d;
andre@0: #else
andre@0:   mp_digit carry = 0;
andre@0:   while (a_len--) {
andre@0:     mp_digit a_i = *a++;
andre@0:     mp_digit a0b0, a1b1;
andre@0: 
andre@0:     MP_MUL_DxD(a_i, b, a1b1, a0b0);
andre@0: 
andre@0:     a0b0 += carry;
andre@0:     if (a0b0 < carry)
andre@0:       ++a1b1;
andre@0:     a0b0 += a_i = *c;
andre@0:     if (a0b0 < a_i)
andre@0:       ++a1b1;
andre@0:     *c++ = a0b0;
andre@0:     carry = a1b1;
andre@0:   }
andre@0:   *c = carry;
andre@0: #endif
andre@0: }
andre@0: 
andre@0: /* Presently, this is only used by the Montgomery arithmetic code. */
andre@0: /* c += a * b */
andre@0: void s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
andre@0:   mp_digit   d = 0;
andre@0: 
andre@0:   /* Inner product:  Digits of a */
andre@0:   while (a_len--) {
andre@0:     mp_word w = ((mp_word)b * *a++) + *c + d;
andre@0:     *c++ = ACCUM(w);
andre@0:     d = CARRYOUT(w);
andre@0:   }
andre@0: 
andre@0:   while (d) {
andre@0:     mp_word w = (mp_word)*c + d;
andre@0:     *c++ = ACCUM(w);
andre@0:     d = CARRYOUT(w);
andre@0:   }
andre@0: #else
andre@0:   mp_digit carry = 0;
andre@0:   while (a_len--) {
andre@0:     mp_digit a_i = *a++;
andre@0:     mp_digit a0b0, a1b1;
andre@0: 
andre@0:     MP_MUL_DxD(a_i, b, a1b1, a0b0);
andre@0: 
andre@0:     a0b0 += carry;
andre@0:     if (a0b0 < carry)
andre@0:       ++a1b1;
andre@0: 
andre@0:     a0b0 += a_i = *c;
andre@0:     if (a0b0 < a_i)
andre@0:       ++a1b1;
andre@0: 
andre@0:     *c++ = a0b0;
andre@0:     carry = a1b1;
andre@0:   }
andre@0:   while (carry) {
andre@0:     mp_digit c_i = *c;
andre@0:     carry += c_i;
andre@0:     *c++ = carry;
andre@0:     carry = carry < c_i;
andre@0:   }
andre@0: #endif
andre@0: }
andre@0: #endif
andre@0: 
andre@0: #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
andre@0: /* This trick works on Sparc V8 CPUs with the Workshop compilers. */
andre@0: #define MP_SQR_D(a, Phi, Plo) \
andre@0:   { unsigned long long square = (unsigned long long)a * a; \
andre@0:     Plo = (mp_digit)square; \
andre@0:     Phi = (mp_digit)(square >> MP_DIGIT_BIT); }
andre@0: #elif defined(OSF1)
andre@0: #define MP_SQR_D(a, Phi, Plo) \
andre@0:   { Plo = asm ("mulq  %a0, %a0, %v0", a);\
andre@0:     Phi = asm ("umulh %a0, %a0, %v0", a); }
andre@0: #else
andre@0: #define MP_SQR_D(a, Phi, Plo) \
andre@0:   { mp_digit Pmid; \
andre@0:     Plo  = (a  & MP_HALF_DIGIT_MAX) * (a  & MP_HALF_DIGIT_MAX); \
andre@0:     Phi  = (a >> MP_HALF_DIGIT_BIT) * (a >> MP_HALF_DIGIT_BIT); \
andre@0:     Pmid = (a  & MP_HALF_DIGIT_MAX) * (a >> MP_HALF_DIGIT_BIT); \
andre@0:     Phi += Pmid >> (MP_HALF_DIGIT_BIT - 1);  \
andre@0:     Pmid <<= (MP_HALF_DIGIT_BIT + 1);  \
andre@0:     Plo += Pmid;  \
andre@0:     if (Plo < Pmid)  \
andre@0:       ++Phi;  \
andre@0:   }
andre@0: #endif
andre@0: 
andre@0: #if !defined(MP_ASSEMBLY_SQUARE)
andre@0: /* Add the squares of the digits of a to the digits of b. */
andre@0: void s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps)
andre@0: {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
andre@0:   mp_word  w;
andre@0:   mp_digit d;
andre@0:   mp_size  ix;
andre@0: 
andre@0:   w  = 0;
andre@0: #define ADD_SQUARE(n) \
andre@0:     d = pa[n]; \
andre@0:     w += (d * (mp_word)d) + ps[2*n]; \
andre@0:     ps[2*n] = ACCUM(w); \
andre@0:     w = (w >> DIGIT_BIT) + ps[2*n+1]; \
andre@0:     ps[2*n+1] = ACCUM(w); \
andre@0:     w = (w >> DIGIT_BIT)
andre@0: 
andre@0:   for (ix = a_len; ix >= 4; ix -= 4) {
andre@0:     ADD_SQUARE(0);
andre@0:     ADD_SQUARE(1);
andre@0:     ADD_SQUARE(2);
andre@0:     ADD_SQUARE(3);
andre@0:     pa += 4;
andre@0:     ps += 8;
andre@0:   }
andre@0:   if (ix) {
andre@0:     ps += 2*ix;
andre@0:     pa += ix;
andre@0:     switch (ix) {
andre@0:     case 3: ADD_SQUARE(-3); /* FALLTHRU */
andre@0:     case 2: ADD_SQUARE(-2); /* FALLTHRU */
andre@0:     case 1: ADD_SQUARE(-1); /* FALLTHRU */
andre@0:     case 0: break;
andre@0:     }
andre@0:   }
andre@0:   while (w) {
andre@0:     w += *ps;
andre@0:     *ps++ = ACCUM(w);
andre@0:     w = (w >> DIGIT_BIT);
andre@0:   }
andre@0: #else
andre@0:   mp_digit carry = 0;
andre@0:   while (a_len--) {
andre@0:     mp_digit a_i = *pa++;
andre@0:     mp_digit a0a0, a1a1;
andre@0: 
andre@0:     MP_SQR_D(a_i, a1a1, a0a0);
andre@0: 
andre@0:     /* here a1a1 and a0a0 constitute a_i ** 2 */
andre@0:     a0a0 += carry;
andre@0:     if (a0a0 < carry)
andre@0:       ++a1a1;
andre@0: 
andre@0:     /* now add to ps */
andre@0:     a0a0 += a_i = *ps;
andre@0:     if (a0a0 < a_i)
andre@0:       ++a1a1;
andre@0:     *ps++ = a0a0;
andre@0:     a1a1 += a_i = *ps;
andre@0:     carry = (a1a1 < a_i);
andre@0:     *ps++ = a1a1;
andre@0:   }
andre@0:   while (carry) {
andre@0:     mp_digit s_i = *ps;
andre@0:     carry += s_i;
andre@0:     *ps++ = carry;
andre@0:     carry = carry < s_i;
andre@0:   }
andre@0: #endif
andre@0: }
andre@0: #endif
andre@0: 
andre@0: #if (defined(MP_NO_MP_WORD) || defined(MP_NO_DIV_WORD)) \
andre@0: && !defined(MP_ASSEMBLY_DIV_2DX1D)
andre@0: /*
andre@0: ** Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized 
andre@0: ** so its high bit is 1.   This code is from NSPR.
andre@0: */
andre@0: mp_err s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor, 
andre@0: 		       mp_digit *qp, mp_digit *rp)
andre@0: {
andre@0:     mp_digit d1, d0, q1, q0;
andre@0:     mp_digit r1, r0, m;
andre@0: 
andre@0:     d1 = divisor >> MP_HALF_DIGIT_BIT;
andre@0:     d0 = divisor & MP_HALF_DIGIT_MAX;
andre@0:     r1 = Nhi % d1;
andre@0:     q1 = Nhi / d1;
andre@0:     m = q1 * d0;
andre@0:     r1 = (r1 << MP_HALF_DIGIT_BIT) | (Nlo >> MP_HALF_DIGIT_BIT);
andre@0:     if (r1 < m) {
andre@0:         q1--, r1 += divisor;
andre@0:         if (r1 >= divisor && r1 < m) {
andre@0: 	    q1--, r1 += divisor;
andre@0: 	}
andre@0:     }
andre@0:     r1 -= m;
andre@0:     r0 = r1 % d1;
andre@0:     q0 = r1 / d1;
andre@0:     m = q0 * d0;
andre@0:     r0 = (r0 << MP_HALF_DIGIT_BIT) | (Nlo & MP_HALF_DIGIT_MAX);
andre@0:     if (r0 < m) {
andre@0:         q0--, r0 += divisor;
andre@0:         if (r0 >= divisor && r0 < m) {
andre@0: 	    q0--, r0 += divisor;
andre@0: 	}
andre@0:     }
andre@0:     if (qp)
andre@0: 	*qp = (q1 << MP_HALF_DIGIT_BIT) | q0;
andre@0:     if (rp)
andre@0: 	*rp = r0 - m;
andre@0:     return MP_OKAY;
andre@0: }
andre@0: #endif
andre@0: 
andre@0: #if MP_SQUARE
andre@0: /* {{{ s_mp_sqr(a) */
andre@0: 
andre@0: mp_err   s_mp_sqr(mp_int *a)
andre@0: {
andre@0:   mp_err   res;
andre@0:   mp_int   tmp;
andre@0: 
andre@0:   if((res = mp_init_size(&tmp, 2 * USED(a))) != MP_OKAY)
andre@0:     return res;
andre@0:   res = mp_sqr(a, &tmp);
andre@0:   if (res == MP_OKAY) {
andre@0:     s_mp_exch(&tmp, a);
andre@0:   }
andre@0:   mp_clear(&tmp);
andre@0:   return res;
andre@0: }
andre@0: 
andre@0: /* }}} */
andre@0: #endif
andre@0: 
andre@0: /* {{{ s_mp_div(a, b) */
andre@0: 
andre@0: /*
andre@0:   s_mp_div(a, b)
andre@0: 
andre@0:   Compute a = a / b and b = a mod b.  Assumes b > a.
andre@0:  */
andre@0: 
andre@0: mp_err   s_mp_div(mp_int *rem, 	/* i: dividend, o: remainder */
andre@0:                   mp_int *div, 	/* i: divisor                */
andre@0: 		  mp_int *quot)	/* i: 0;        o: quotient  */
andre@0: {
andre@0:   mp_int   part, t;
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
andre@0:   mp_word  q_msd;
andre@0: #else
andre@0:   mp_digit q_msd;
andre@0: #endif
andre@0:   mp_err   res;
andre@0:   mp_digit d;
andre@0:   mp_digit div_msd;
andre@0:   int      ix;
andre@0: 
andre@0:   if(mp_cmp_z(div) == 0)
andre@0:     return MP_RANGE;
andre@0: 
andre@0:   DIGITS(&t) = 0;
andre@0:   /* Shortcut if divisor is power of two */
andre@0:   if((ix = s_mp_ispow2(div)) >= 0) {
andre@0:     MP_CHECKOK( mp_copy(rem, quot) );
andre@0:     s_mp_div_2d(quot, (mp_digit)ix);
andre@0:     s_mp_mod_2d(rem,  (mp_digit)ix);
andre@0: 
andre@0:     return MP_OKAY;
andre@0:   }
andre@0: 
andre@0:   MP_SIGN(rem) = ZPOS;
andre@0:   MP_SIGN(div) = ZPOS;
andre@0: 
andre@0:   /* A working temporary for division     */
andre@0:   MP_CHECKOK( mp_init_size(&t, MP_ALLOC(rem)));
andre@0: 
andre@0:   /* Normalize to optimize guessing       */
andre@0:   MP_CHECKOK( s_mp_norm(rem, div, &d) );
andre@0: 
andre@0:   part = *rem;
andre@0: 
andre@0:   /* Perform the division itself...woo!   */
andre@0:   MP_USED(quot) = MP_ALLOC(quot);
andre@0: 
andre@0:   /* Find a partial substring of rem which is at least div */
andre@0:   /* If we didn't find one, we're finished dividing    */
andre@0:   while (MP_USED(rem) > MP_USED(div) || s_mp_cmp(rem, div) >= 0) {
andre@0:     int i;
andre@0:     int unusedRem;
andre@0: 
andre@0:     unusedRem = MP_USED(rem) - MP_USED(div);
andre@0:     MP_DIGITS(&part) = MP_DIGITS(rem) + unusedRem;
andre@0:     MP_ALLOC(&part)  = MP_ALLOC(rem)  - unusedRem;
andre@0:     MP_USED(&part)   = MP_USED(div);
andre@0:     if (s_mp_cmp(&part, div) < 0) {
andre@0:       -- unusedRem;
andre@0: #if MP_ARGCHK == 2
andre@0:       assert(unusedRem >= 0);
andre@0: #endif
andre@0:       -- MP_DIGITS(&part);
andre@0:       ++ MP_USED(&part);
andre@0:       ++ MP_ALLOC(&part);
andre@0:     }
andre@0: 
andre@0:     /* Compute a guess for the next quotient digit       */
andre@0:     q_msd = MP_DIGIT(&part, MP_USED(&part) - 1);
andre@0:     div_msd = MP_DIGIT(div, MP_USED(div) - 1);
andre@0:     if (q_msd >= div_msd) {
andre@0:       q_msd = 1;
andre@0:     } else if (MP_USED(&part) > 1) {
andre@0: #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
andre@0:       q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2);
andre@0:       q_msd /= div_msd;
andre@0:       if (q_msd == RADIX)
andre@0:         --q_msd;
andre@0: #else
andre@0:       mp_digit r;
andre@0:       MP_CHECKOK( s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2), 
andre@0: 				  div_msd, &q_msd, &r) );
andre@0: #endif
andre@0:     } else {
andre@0:       q_msd = 0;
andre@0:     }
andre@0: #if MP_ARGCHK == 2
andre@0:     assert(q_msd > 0); /* This case should never occur any more. */
andre@0: #endif
andre@0:     if (q_msd <= 0)
andre@0:       break;
andre@0: 
andre@0:     /* See what that multiplies out to                   */
andre@0:     mp_copy(div, &t);
andre@0:     MP_CHECKOK( s_mp_mul_d(&t, (mp_digit)q_msd) );
andre@0: 
andre@0:     /* 
andre@0:        If it's too big, back it off.  We should not have to do this
andre@0:        more than once, or, in rare cases, twice.  Knuth describes a
andre@0:        method by which this could be reduced to a maximum of once, but
andre@0:        I didn't implement that here.
andre@0:      * When using s_mpv_div_2dx1d, we may have to do this 3 times.
andre@0:      */
andre@0:     for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) {
andre@0:       --q_msd;
andre@0:       s_mp_sub(&t, div);	/* t -= div */
andre@0:     }
andre@0:     if (i < 0) {
andre@0:       res = MP_RANGE;
andre@0:       goto CLEANUP;
andre@0:     }
andre@0: 
andre@0:     /* At this point, q_msd should be the right next digit   */
andre@0:     MP_CHECKOK( s_mp_sub(&part, &t) );	/* part -= t */
andre@0:     s_mp_clamp(rem);
andre@0: 
andre@0:     /*
andre@0:       Include the digit in the quotient.  We allocated enough memory
andre@0:       for any quotient we could ever possibly get, so we should not
andre@0:       have to check for failures here
andre@0:      */
andre@0:     MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd;
andre@0:   }
andre@0: 
andre@0:   /* Denormalize remainder                */
andre@0:   if (d) {
andre@0:     s_mp_div_2d(rem, d);
andre@0:   }
andre@0: 
andre@0:   s_mp_clamp(quot);
andre@0: 
andre@0: CLEANUP:
andre@0:   mp_clear(&t);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end s_mp_div() */
andre@0: 
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_2expt(a, k) */
andre@0: 
andre@0: mp_err   s_mp_2expt(mp_int *a, mp_digit k)
andre@0: {
andre@0:   mp_err    res;
andre@0:   mp_size   dig, bit;
andre@0: 
andre@0:   dig = k / DIGIT_BIT;
andre@0:   bit = k % DIGIT_BIT;
andre@0: 
andre@0:   mp_zero(a);
andre@0:   if((res = s_mp_pad(a, dig + 1)) != MP_OKAY)
andre@0:     return res;
andre@0:   
andre@0:   DIGIT(a, dig) |= ((mp_digit)1 << bit);
andre@0: 
andre@0:   return MP_OKAY;
andre@0: 
andre@0: } /* end s_mp_2expt() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_reduce(x, m, mu) */
andre@0: 
andre@0: /*
andre@0:   Compute Barrett reduction, x (mod m), given a precomputed value for
andre@0:   mu = b^2k / m, where b = RADIX and k = #digits(m).  This should be
andre@0:   faster than straight division, when many reductions by the same
andre@0:   value of m are required (such as in modular exponentiation).  This
andre@0:   can nearly halve the time required to do modular exponentiation,
andre@0:   as compared to using the full integer divide to reduce.
andre@0: 
andre@0:   This algorithm was derived from the _Handbook of Applied
andre@0:   Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
andre@0:   pp. 603-604.  
andre@0:  */
andre@0: 
andre@0: mp_err   s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
andre@0: {
andre@0:   mp_int   q;
andre@0:   mp_err   res;
andre@0: 
andre@0:   if((res = mp_init_copy(&q, x)) != MP_OKAY)
andre@0:     return res;
andre@0: 
andre@0:   s_mp_rshd(&q, USED(m) - 1);  /* q1 = x / b^(k-1)  */
andre@0:   s_mp_mul(&q, mu);            /* q2 = q1 * mu      */
andre@0:   s_mp_rshd(&q, USED(m) + 1);  /* q3 = q2 / b^(k+1) */
andre@0: 
andre@0:   /* x = x mod b^(k+1), quick (no division) */
andre@0:   s_mp_mod_2d(x, DIGIT_BIT * (USED(m) + 1));
andre@0: 
andre@0:   /* q = q * m mod b^(k+1), quick (no division) */
andre@0:   s_mp_mul(&q, m);
andre@0:   s_mp_mod_2d(&q, DIGIT_BIT * (USED(m) + 1));
andre@0: 
andre@0:   /* x = x - q */
andre@0:   if((res = mp_sub(x, &q, x)) != MP_OKAY)
andre@0:     goto CLEANUP;
andre@0: 
andre@0:   /* If x < 0, add b^(k+1) to it */
andre@0:   if(mp_cmp_z(x) < 0) {
andre@0:     mp_set(&q, 1);
andre@0:     if((res = s_mp_lshd(&q, USED(m) + 1)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:     if((res = mp_add(x, &q, x)) != MP_OKAY)
andre@0:       goto CLEANUP;
andre@0:   }
andre@0: 
andre@0:   /* Back off if it's too big */
andre@0:   while(mp_cmp(x, m) >= 0) {
andre@0:     if((res = s_mp_sub(x, m)) != MP_OKAY)
andre@0:       break;
andre@0:   }
andre@0: 
andre@0:  CLEANUP:
andre@0:   mp_clear(&q);
andre@0: 
andre@0:   return res;
andre@0: 
andre@0: } /* end s_mp_reduce() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ Primitive comparisons */
andre@0: 
andre@0: /* {{{ s_mp_cmp(a, b) */
andre@0: 
andre@0: /* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b           */
andre@0: int      s_mp_cmp(const mp_int *a, const mp_int *b)
andre@0: {
andre@0:   mp_size used_a = MP_USED(a);
andre@0:   {
andre@0:     mp_size used_b = MP_USED(b);
andre@0: 
andre@0:     if (used_a > used_b)
andre@0:       goto IS_GT;
andre@0:     if (used_a < used_b)
andre@0:       goto IS_LT;
andre@0:   }
andre@0:   {
andre@0:     mp_digit *pa, *pb;
andre@0:     mp_digit da = 0, db = 0;
andre@0: 
andre@0: #define CMP_AB(n) if ((da = pa[n]) != (db = pb[n])) goto done
andre@0: 
andre@0:     pa = MP_DIGITS(a) + used_a;
andre@0:     pb = MP_DIGITS(b) + used_a;
andre@0:     while (used_a >= 4) {
andre@0:       pa     -= 4;
andre@0:       pb     -= 4;
andre@0:       used_a -= 4;
andre@0:       CMP_AB(3);
andre@0:       CMP_AB(2);
andre@0:       CMP_AB(1);
andre@0:       CMP_AB(0);
andre@0:     }
andre@0:     while (used_a-- > 0 && ((da = *--pa) == (db = *--pb))) 
andre@0:       /* do nothing */;
andre@0: done:
andre@0:     if (da > db)
andre@0:       goto IS_GT;
andre@0:     if (da < db) 
andre@0:       goto IS_LT;
andre@0:   }
andre@0:   return MP_EQ;
andre@0: IS_LT:
andre@0:   return MP_LT;
andre@0: IS_GT:
andre@0:   return MP_GT;
andre@0: } /* end s_mp_cmp() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_cmp_d(a, d) */
andre@0: 
andre@0: /* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d             */
andre@0: int      s_mp_cmp_d(const mp_int *a, mp_digit d)
andre@0: {
andre@0:   if(USED(a) > 1)
andre@0:     return MP_GT;
andre@0: 
andre@0:   if(DIGIT(a, 0) < d)
andre@0:     return MP_LT;
andre@0:   else if(DIGIT(a, 0) > d)
andre@0:     return MP_GT;
andre@0:   else
andre@0:     return MP_EQ;
andre@0: 
andre@0: } /* end s_mp_cmp_d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_ispow2(v) */
andre@0: 
andre@0: /*
andre@0:   Returns -1 if the value is not a power of two; otherwise, it returns
andre@0:   k such that v = 2^k, i.e. lg(v).
andre@0:  */
andre@0: int      s_mp_ispow2(const mp_int *v)
andre@0: {
andre@0:   mp_digit d;
andre@0:   int      extra = 0, ix;
andre@0: 
andre@0:   ix = MP_USED(v) - 1;
andre@0:   d = MP_DIGIT(v, ix); /* most significant digit of v */
andre@0: 
andre@0:   extra = s_mp_ispow2d(d);
andre@0:   if (extra < 0 || ix == 0)
andre@0:     return extra;
andre@0: 
andre@0:   while (--ix >= 0) {
andre@0:     if (DIGIT(v, ix) != 0)
andre@0:       return -1; /* not a power of two */
andre@0:     extra += MP_DIGIT_BIT;
andre@0:   }
andre@0: 
andre@0:   return extra;
andre@0: 
andre@0: } /* end s_mp_ispow2() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_ispow2d(d) */
andre@0: 
andre@0: int      s_mp_ispow2d(mp_digit d)
andre@0: {
andre@0:   if ((d != 0) && ((d & (d-1)) == 0)) { /* d is a power of 2 */
andre@0:     int pow = 0;
andre@0: #if defined (MP_USE_UINT_DIGIT)
andre@0:     if (d & 0xffff0000U)
andre@0:       pow += 16;
andre@0:     if (d & 0xff00ff00U)
andre@0:       pow += 8;
andre@0:     if (d & 0xf0f0f0f0U)
andre@0:       pow += 4;
andre@0:     if (d & 0xccccccccU)
andre@0:       pow += 2;
andre@0:     if (d & 0xaaaaaaaaU)
andre@0:       pow += 1;
andre@0: #elif defined(MP_USE_LONG_LONG_DIGIT)
andre@0:     if (d & 0xffffffff00000000ULL)
andre@0:       pow += 32;
andre@0:     if (d & 0xffff0000ffff0000ULL)
andre@0:       pow += 16;
andre@0:     if (d & 0xff00ff00ff00ff00ULL)
andre@0:       pow += 8;
andre@0:     if (d & 0xf0f0f0f0f0f0f0f0ULL)
andre@0:       pow += 4;
andre@0:     if (d & 0xccccccccccccccccULL)
andre@0:       pow += 2;
andre@0:     if (d & 0xaaaaaaaaaaaaaaaaULL)
andre@0:       pow += 1;
andre@0: #elif defined(MP_USE_LONG_DIGIT)
andre@0:     if (d & 0xffffffff00000000UL)
andre@0:       pow += 32;
andre@0:     if (d & 0xffff0000ffff0000UL)
andre@0:       pow += 16;
andre@0:     if (d & 0xff00ff00ff00ff00UL)
andre@0:       pow += 8;
andre@0:     if (d & 0xf0f0f0f0f0f0f0f0UL)
andre@0:       pow += 4;
andre@0:     if (d & 0xccccccccccccccccUL)
andre@0:       pow += 2;
andre@0:     if (d & 0xaaaaaaaaaaaaaaaaUL)
andre@0:       pow += 1;
andre@0: #else
andre@0: #error "unknown type for mp_digit"
andre@0: #endif
andre@0:     return pow;
andre@0:   }
andre@0:   return -1;
andre@0: 
andre@0: } /* end s_mp_ispow2d() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ Primitive I/O helpers */
andre@0: 
andre@0: /* {{{ s_mp_tovalue(ch, r) */
andre@0: 
andre@0: /*
andre@0:   Convert the given character to its digit value, in the given radix.
andre@0:   If the given character is not understood in the given radix, -1 is
andre@0:   returned.  Otherwise the digit's numeric value is returned.
andre@0: 
andre@0:   The results will be odd if you use a radix < 2 or > 62, you are
andre@0:   expected to know what you're up to.
andre@0:  */
andre@0: int      s_mp_tovalue(char ch, int r)
andre@0: {
andre@0:   int    val, xch;
andre@0:   
andre@0:   if(r > 36)
andre@0:     xch = ch;
andre@0:   else
andre@0:     xch = toupper(ch);
andre@0: 
andre@0:   if(isdigit(xch))
andre@0:     val = xch - '0';
andre@0:   else if(isupper(xch))
andre@0:     val = xch - 'A' + 10;
andre@0:   else if(islower(xch))
andre@0:     val = xch - 'a' + 36;
andre@0:   else if(xch == '+')
andre@0:     val = 62;
andre@0:   else if(xch == '/')
andre@0:     val = 63;
andre@0:   else 
andre@0:     return -1;
andre@0: 
andre@0:   if(val < 0 || val >= r)
andre@0:     return -1;
andre@0: 
andre@0:   return val;
andre@0: 
andre@0: } /* end s_mp_tovalue() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_todigit(val, r, low) */
andre@0: 
andre@0: /*
andre@0:   Convert val to a radix-r digit, if possible.  If val is out of range
andre@0:   for r, returns zero.  Otherwise, returns an ASCII character denoting
andre@0:   the value in the given radix.
andre@0: 
andre@0:   The results may be odd if you use a radix < 2 or > 64, you are
andre@0:   expected to know what you're doing.
andre@0:  */
andre@0:   
andre@0: char     s_mp_todigit(mp_digit val, int r, int low)
andre@0: {
andre@0:   char   ch;
andre@0: 
andre@0:   if(val >= r)
andre@0:     return 0;
andre@0: 
andre@0:   ch = s_dmap_1[val];
andre@0: 
andre@0:   if(r <= 36 && low)
andre@0:     ch = tolower(ch);
andre@0: 
andre@0:   return ch;
andre@0: 
andre@0: } /* end s_mp_todigit() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ s_mp_outlen(bits, radix) */
andre@0: 
andre@0: /* 
andre@0:    Return an estimate for how long a string is needed to hold a radix
andre@0:    r representation of a number with 'bits' significant bits, plus an
andre@0:    extra for a zero terminator (assuming C style strings here)
andre@0:  */
andre@0: int      s_mp_outlen(int bits, int r)
andre@0: {
andre@0:   return (int)((double)bits * LOG_V_2(r) + 1.5) + 1;
andre@0: 
andre@0: } /* end s_mp_outlen() */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_read_unsigned_octets(mp, str, len) */
andre@0: /* mp_read_unsigned_octets(mp, str, len)
andre@0:    Read in a raw value (base 256) into the given mp_int
andre@0:    No sign bit, number is positive.  Leading zeros ignored.
andre@0:  */
andre@0: 
andre@0: mp_err  
andre@0: mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len)
andre@0: {
andre@0:   int            count;
andre@0:   mp_err         res;
andre@0:   mp_digit       d;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
andre@0: 
andre@0:   mp_zero(mp);
andre@0: 
andre@0:   count = len % sizeof(mp_digit);
andre@0:   if (count) {
andre@0:     for (d = 0; count-- > 0; --len) {
andre@0:       d = (d << 8) | *str++;
andre@0:     }
andre@0:     MP_DIGIT(mp, 0) = d;
andre@0:   }
andre@0: 
andre@0:   /* Read the rest of the digits */
andre@0:   for(; len > 0; len -= sizeof(mp_digit)) {
andre@0:     for (d = 0, count = sizeof(mp_digit); count > 0; --count) {
andre@0:       d = (d << 8) | *str++;
andre@0:     }
andre@0:     if (MP_EQ == mp_cmp_z(mp)) {
andre@0:       if (!d)
andre@0: 	continue;
andre@0:     } else {
andre@0:       if((res = s_mp_lshd(mp, 1)) != MP_OKAY)
andre@0: 	return res;
andre@0:     }
andre@0:     MP_DIGIT(mp, 0) = d;
andre@0:   }
andre@0:   return MP_OKAY;
andre@0: } /* end mp_read_unsigned_octets() */
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_unsigned_octet_size(mp) */
andre@0: int    
andre@0: mp_unsigned_octet_size(const mp_int *mp)
andre@0: {
andre@0:   int  bytes;
andre@0:   int  ix;
andre@0:   mp_digit  d = 0;
andre@0: 
andre@0:   ARGCHK(mp != NULL, MP_BADARG);
andre@0:   ARGCHK(MP_ZPOS == SIGN(mp), MP_BADARG);
andre@0: 
andre@0:   bytes = (USED(mp) * sizeof(mp_digit));
andre@0: 
andre@0:   /* subtract leading zeros. */
andre@0:   /* Iterate over each digit... */
andre@0:   for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:     d = DIGIT(mp, ix);
andre@0:     if (d) 
andre@0: 	break;
andre@0:     bytes -= sizeof(d);
andre@0:   }
andre@0:   if (!bytes)
andre@0:     return 1;
andre@0: 
andre@0:   /* Have MSD, check digit bytes, high order first */
andre@0:   for(ix = sizeof(mp_digit) - 1; ix >= 0; ix--) {
andre@0:     unsigned char x = (unsigned char)(d >> (ix * CHAR_BIT));
andre@0:     if (x) 
andre@0: 	break;
andre@0:     --bytes;
andre@0:   }
andre@0:   return bytes;
andre@0: } /* end mp_unsigned_octet_size() */
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_to_unsigned_octets(mp, str) */
andre@0: /* output a buffer of big endian octets no longer than specified. */
andre@0: mp_err 
andre@0: mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
andre@0: {
andre@0:   int  ix, pos = 0;
andre@0:   int  bytes;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
andre@0: 
andre@0:   bytes = mp_unsigned_octet_size(mp);
andre@0:   ARGCHK(bytes >= 0 && bytes <= maxlen, MP_BADARG);
andre@0: 
andre@0:   /* Iterate over each digit... */
andre@0:   for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:     mp_digit  d = DIGIT(mp, ix);
andre@0:     int       jx;
andre@0: 
andre@0:     /* Unpack digit bytes, high order first */
andre@0:     for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
andre@0:       unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
andre@0:       if (!pos && !x)	/* suppress leading zeros */
andre@0: 	continue;
andre@0:       str[pos++] = x;
andre@0:     }
andre@0:   }
andre@0:   if (!pos)
andre@0:     str[pos++] = 0;
andre@0:   return pos;
andre@0: } /* end mp_to_unsigned_octets() */
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_to_signed_octets(mp, str) */
andre@0: /* output a buffer of big endian octets no longer than specified. */
andre@0: mp_err 
andre@0: mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
andre@0: {
andre@0:   int  ix, pos = 0;
andre@0:   int  bytes;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
andre@0: 
andre@0:   bytes = mp_unsigned_octet_size(mp);
andre@0:   ARGCHK(bytes >= 0 && bytes <= maxlen, MP_BADARG);
andre@0: 
andre@0:   /* Iterate over each digit... */
andre@0:   for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:     mp_digit  d = DIGIT(mp, ix);
andre@0:     int       jx;
andre@0: 
andre@0:     /* Unpack digit bytes, high order first */
andre@0:     for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
andre@0:       unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
andre@0:       if (!pos) {
andre@0: 	if (!x)		/* suppress leading zeros */
andre@0: 	  continue;
andre@0: 	if (x & 0x80) { /* add one leading zero to make output positive.  */
andre@0: 	  ARGCHK(bytes + 1 <= maxlen, MP_BADARG);
andre@0: 	  if (bytes + 1 > maxlen)
andre@0: 	    return MP_BADARG;
andre@0: 	  str[pos++] = 0;
andre@0: 	}
andre@0:       }
andre@0:       str[pos++] = x;
andre@0:     }
andre@0:   }
andre@0:   if (!pos)
andre@0:     str[pos++] = 0;
andre@0:   return pos;
andre@0: } /* end mp_to_signed_octets() */
andre@0: /* }}} */
andre@0: 
andre@0: /* {{{ mp_to_fixlen_octets(mp, str) */
andre@0: /* output a buffer of big endian octets exactly as long as requested. */
andre@0: mp_err 
andre@0: mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length)
andre@0: {
andre@0:   int  ix, pos = 0;
andre@0:   int  bytes;
andre@0: 
andre@0:   ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
andre@0: 
andre@0:   bytes = mp_unsigned_octet_size(mp);
andre@0:   ARGCHK(bytes >= 0 && bytes <= length, MP_BADARG);
andre@0: 
andre@0:   /* place any needed leading zeros */
andre@0:   for (;length > bytes; --length) {
andre@0: 	*str++ = 0;
andre@0:   }
andre@0: 
andre@0:   /* Iterate over each digit... */
andre@0:   for(ix = USED(mp) - 1; ix >= 0; ix--) {
andre@0:     mp_digit  d = DIGIT(mp, ix);
andre@0:     int       jx;
andre@0: 
andre@0:     /* Unpack digit bytes, high order first */
andre@0:     for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
andre@0:       unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
andre@0:       if (!pos && !x)	/* suppress leading zeros */
andre@0: 	continue;
andre@0:       str[pos++] = x;
andre@0:     }
andre@0:   }
andre@0:   if (!pos)
andre@0:     str[pos++] = 0;
andre@0:   return MP_OKAY;
andre@0: } /* end mp_to_fixlen_octets() */
andre@0: /* }}} */
andre@0: 
andre@0: 
andre@0: /*------------------------------------------------------------------------*/
andre@0: /* HERE THERE BE DRAGONS                                                  */