Blame src/mpi/mpi.c

Packit Service 37472d
/*
Packit Service 37472d
  mpi.c
Packit Service 37472d
  
Packit Service 37472d
  by Michael J. Fromberger <http://www.dartmouth.edu/~sting/>
Packit Service 37472d
  Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved
Packit Service 37472d
  
Packit Service 37472d
  Arbitrary precision integer arithmetic library
Packit Service 37472d
Packit Service 37472d
  modified for use in Meanwhile as a convenience library
Packit Service 37472d
*/
Packit Service 37472d
Packit Service 37472d
#include "mpi.h"
Packit Service 37472d
#include <stdlib.h>
Packit Service 37472d
#include <string.h>
Packit Service 37472d
#include <ctype.h>
Packit Service 37472d
Packit Service 37472d
#if MP_DEBUG
Packit Service 37472d
#include <stdio.h>
Packit Service 37472d
Packit Service 37472d
#define DIAG(T,V) {fprintf(stderr,T);mw_mp_print(V,stderr);fputc('\n',stderr);}
Packit Service 37472d
#else
Packit Service 37472d
#define DIAG(T,V)
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* 
Packit Service 37472d
   If MP_LOGTAB is not defined, use the math library to compute the
Packit Service 37472d
   logarithms on the fly.  Otherwise, use the static table below.
Packit Service 37472d
   Pick which works best for your system.
Packit Service 37472d
 */
Packit Service 37472d
#if MP_LOGTAB
Packit Service 37472d
Packit Service 37472d
/* {{{ s_logv_2[] - log table for 2 in various bases */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  A table of the logs of 2 for various bases (the 0 and 1 entries of
Packit Service 37472d
  this table are meaningless and should not be referenced).  
Packit Service 37472d
Packit Service 37472d
  This table is used to compute output lengths for the mw_mp_toradix()
Packit Service 37472d
  function.  Since a number n in radix r takes up about log_r(n)
Packit Service 37472d
  digits, we estimate the output size by taking the least integer
Packit Service 37472d
  greater than log_r(n), where:
Packit Service 37472d
Packit Service 37472d
  log_r(n) = log_2(n) * log_r(2)
Packit Service 37472d
Packit Service 37472d
  This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
Packit Service 37472d
  which are the output bases supported.  
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
#include "logtab.h"
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
#define LOG_V_2(R)  s_logv_2[(R)]
Packit Service 37472d
Packit Service 37472d
#else
Packit Service 37472d
Packit Service 37472d
#include <math.h>
Packit Service 37472d
#define LOG_V_2(R)  (log(2.0)/log(R))
Packit Service 37472d
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* Default precision for newly created mw_mp_int's      */
Packit Service 37472d
static unsigned int s_mw_mp_defprec = MP_DEFPREC;
Packit Service 37472d
Packit Service 37472d
/* {{{ Digit arithmetic macros */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  When adding and multiplying digits, the results can be larger than
Packit Service 37472d
  can be contained in an mw_mp_digit.  Thus, an mw_mp_word is used.  These
Packit Service 37472d
  macros mask off the upper and lower digits of the mw_mp_word (the
Packit Service 37472d
  mw_mp_word may be more than 2 mw_mp_digits wide, but we only concern
Packit Service 37472d
  ourselves with the low-order 2 mw_mp_digits)
Packit Service 37472d
Packit Service 37472d
  If your mw_mp_word DOES have more than 2 mw_mp_digits, you need to
Packit Service 37472d
  uncomment the first line, and comment out the second.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
/* #define  CARRYOUT(W)  (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */
Packit Service 37472d
#define  CARRYOUT(W)  ((W)>>DIGIT_BIT)
Packit Service 37472d
#define  ACCUM(W)     ((W)&MP_DIGIT_MAX)
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Comparison constants */
Packit Service 37472d
Packit Service 37472d
#define  MP_LT       -1
Packit Service 37472d
#define  MP_EQ        0
Packit Service 37472d
#define  MP_GT        1
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Constant strings */
Packit Service 37472d
Packit Service 37472d
/* Constant strings returned by mw_mp_strerror() */
Packit Service 37472d
static const char *mw_mp_err_string[] = {
Packit Service 37472d
  "unknown result code",     /* say what?            */
Packit Service 37472d
  "boolean true",            /* MP_OKAY, MP_YES      */
Packit Service 37472d
  "boolean false",           /* MP_NO                */
Packit Service 37472d
  "out of memory",           /* MP_MEM               */
Packit Service 37472d
  "argument out of range",   /* MP_RANGE             */
Packit Service 37472d
  "invalid input parameter", /* MP_BADARG            */
Packit Service 37472d
  "result is undefined"      /* MP_UNDEF             */
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
/* Value to digit maps for radix conversion   */
Packit Service 37472d
Packit Service 37472d
/* s_dmap_1 - standard digits and letters */
Packit Service 37472d
static const char *s_dmap_1 = 
Packit Service 37472d
  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
Packit Service 37472d
Packit Service 37472d
#if 0
Packit Service 37472d
/* s_dmap_2 - base64 ordering for digits  */
Packit Service 37472d
static const char *s_dmap_2 =
Packit Service 37472d
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Static function declarations */
Packit Service 37472d
Packit Service 37472d
/* 
Packit Service 37472d
   If MP_MACRO is false, these will be defined as actual functions;
Packit Service 37472d
   otherwise, suitable macro definitions will be used.  This works
Packit Service 37472d
   around the fact that ANSI C89 doesn't support an 'inline' keyword
Packit Service 37472d
   (although I hear C9x will ... about bloody time).  At present, the
Packit Service 37472d
   macro definitions are identical to the function bodies, but they'll
Packit Service 37472d
   expand in place, instead of generating a function call.
Packit Service 37472d
Packit Service 37472d
   I chose these particular functions to be made into macros because
Packit Service 37472d
   some profiling showed they are called a lot on a typical workload,
Packit Service 37472d
   and yet they are primarily housekeeping.
Packit Service 37472d
 */
Packit Service 37472d
#if MP_MACRO == 0
Packit Service 37472d
 void     s_mw_mp_setz(mw_mp_digit *dp, mw_mp_size count); /* zero digits           */
Packit Service 37472d
 void     s_mw_mp_copy(mw_mp_digit *sp, mw_mp_digit *dp, mw_mp_size count); /* copy    */
Packit Service 37472d
 void    *s_mw_mp_alloc(size_t nb, size_t ni);       /* general allocator     */
Packit Service 37472d
 void     s_mw_mp_free(void *ptr);                   /* general free function */
Packit Service 37472d
#else
Packit Service 37472d
Packit Service 37472d
 /* Even if these are defined as macros, we need to respect the settings
Packit Service 37472d
    of the MP_MEMSET and MP_MEMCPY configuration options...
Packit Service 37472d
  */
Packit Service 37472d
 #if MP_MEMSET == 0
Packit Service 37472d
  #define  s_mw_mp_setz(dp, count) \
Packit Service 37472d
       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;}
Packit Service 37472d
 #else
Packit Service 37472d
  #define  s_mw_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mw_mp_digit))
Packit Service 37472d
 #endif /* MP_MEMSET */
Packit Service 37472d
Packit Service 37472d
 #if MP_MEMCPY == 0
Packit Service 37472d
  #define  s_mw_mp_copy(sp, dp, count) \
Packit Service 37472d
       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];}
Packit Service 37472d
 #else
Packit Service 37472d
  #define  s_mw_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mw_mp_digit))
Packit Service 37472d
 #endif /* MP_MEMCPY */
Packit Service 37472d
Packit Service 37472d
 #define  s_mw_mp_alloc(nb, ni)  calloc(nb, ni)
Packit Service 37472d
 #define  s_mw_mp_free(ptr) {if(ptr) free(ptr);}
Packit Service 37472d
#endif /* MP_MACRO */
Packit Service 37472d
Packit Service 37472d
mw_mp_err   s_mw_mp_grow(mw_mp_int *mp, mw_mp_size min);   /* increase allocated size */
Packit Service 37472d
mw_mp_err   s_mw_mp_pad(mw_mp_int *mp, mw_mp_size min);    /* left pad with zeroes    */
Packit Service 37472d
Packit Service 37472d
void     s_mw_mp_clamp(mw_mp_int *mp);               /* clip leading zeroes     */
Packit Service 37472d
Packit Service 37472d
void     s_mw_mp_exch(mw_mp_int *a, mw_mp_int *b);      /* swap a and b in place   */
Packit Service 37472d
Packit Service 37472d
mw_mp_err   s_mw_mp_lshd(mw_mp_int *mp, mw_mp_size p);     /* left-shift by p digits  */
Packit Service 37472d
void     s_mw_mp_rshd(mw_mp_int *mp, mw_mp_size p);     /* right-shift by p digits */
Packit Service 37472d
void     s_mw_mp_div_2d(mw_mp_int *mp, mw_mp_digit d);  /* divide by 2^d in place  */
Packit Service 37472d
void     s_mw_mp_mod_2d(mw_mp_int *mp, mw_mp_digit d);  /* modulo 2^d in place     */
Packit Service 37472d
mw_mp_err   s_mw_mp_mul_2d(mw_mp_int *mp, mw_mp_digit d);  /* multiply by 2^d in place*/
Packit Service 37472d
void     s_mw_mp_div_2(mw_mp_int *mp);               /* divide by 2 in place    */
Packit Service 37472d
mw_mp_err   s_mw_mp_mul_2(mw_mp_int *mp);               /* multiply by 2 in place  */
Packit Service 37472d
mw_mp_digit s_mw_mp_norm(mw_mp_int *a, mw_mp_int *b);      /* normalize for division  */
Packit Service 37472d
mw_mp_err   s_mw_mp_add_d(mw_mp_int *mp, mw_mp_digit d);   /* unsigned digit addition */
Packit Service 37472d
mw_mp_err   s_mw_mp_sub_d(mw_mp_int *mp, mw_mp_digit d);   /* unsigned digit subtract */
Packit Service 37472d
mw_mp_err   s_mw_mp_mul_d(mw_mp_int *mp, mw_mp_digit d);   /* unsigned digit multiply */
Packit Service 37472d
mw_mp_err   s_mw_mp_div_d(mw_mp_int *mp, mw_mp_digit d, mw_mp_digit *r);
Packit Service 37472d
		                               /* unsigned digit divide   */
Packit Service 37472d
mw_mp_err   s_mw_mp_reduce(mw_mp_int *x, mw_mp_int *m, mw_mp_int *mu);
Packit Service 37472d
                                               /* Barrett reduction       */
Packit Service 37472d
mw_mp_err   s_mw_mp_add(mw_mp_int *a, mw_mp_int *b);       /* magnitude addition      */
Packit Service 37472d
mw_mp_err   s_mw_mp_sub(mw_mp_int *a, mw_mp_int *b);       /* magnitude subtract      */
Packit Service 37472d
mw_mp_err   s_mw_mp_mul(mw_mp_int *a, mw_mp_int *b);       /* magnitude multiply      */
Packit Service 37472d
#if 0
Packit Service 37472d
void     s_mw_mp_kmul(mw_mp_digit *a, mw_mp_digit *b, mw_mp_digit *out, mw_mp_size len);
Packit Service 37472d
                                               /* multiply buffers in place */
Packit Service 37472d
#endif
Packit Service 37472d
#if MP_SQUARE
Packit Service 37472d
mw_mp_err   s_mw_mp_sqr(mw_mp_int *a);                  /* magnitude square        */
Packit Service 37472d
#else
Packit Service 37472d
#define  s_mw_mp_sqr(a) s_mw_mp_mul(a, a)
Packit Service 37472d
#endif
Packit Service 37472d
mw_mp_err   s_mw_mp_div(mw_mp_int *a, mw_mp_int *b);       /* magnitude divide        */
Packit Service 37472d
mw_mp_err   s_mw_mp_2expt(mw_mp_int *a, mw_mp_digit k);    /* a = 2^k                 */
Packit Service 37472d
int      s_mw_mp_cmp(mw_mp_int *a, mw_mp_int *b);       /* magnitude comparison    */
Packit Service 37472d
int      s_mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d);    /* magnitude digit compare */
Packit Service 37472d
int      s_mw_mp_ispow2(mw_mp_int *v);               /* is v a power of 2?      */
Packit Service 37472d
int      s_mw_mp_ispow2d(mw_mp_digit d);             /* is d a power of 2?      */
Packit Service 37472d
Packit Service 37472d
int      s_mw_mp_tovalue(char ch, int r);          /* convert ch to value    */
Packit Service 37472d
char     s_mw_mp_todigit(int val, int r, int low); /* convert val to digit   */
Packit Service 37472d
int      s_mw_mp_outlen(int bits, int r);          /* output length in bytes */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Default precision manipulation */
Packit Service 37472d
Packit Service 37472d
unsigned int mw_mp_get_prec(void)
Packit Service 37472d
{
Packit Service 37472d
  return s_mw_mp_defprec;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_get_prec() */
Packit Service 37472d
Packit Service 37472d
void         mw_mp_set_prec(unsigned int prec)
Packit Service 37472d
{
Packit Service 37472d
  if(prec == 0)
Packit Service 37472d
    s_mw_mp_defprec = MP_DEFPREC;
Packit Service 37472d
  else
Packit Service 37472d
    s_mw_mp_defprec = prec;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_set_prec() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ mw_mp_init(mp) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_init(mp)
Packit Service 37472d
Packit Service 37472d
  Initialize a new zero-valued mw_mp_int.  Returns MP_OKAY if successful,
Packit Service 37472d
  MP_MEM if memory could not be allocated for the structure.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_init(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  return mw_mp_init_size(mp, s_mw_mp_defprec);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_init() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_init_array(mp[], count) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_init_array(mw_mp_int mp[], int count)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
  int     pos;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp !=NULL && count > 0, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  for(pos = 0; pos < count; ++pos) {
Packit Service 37472d
    if((res = mw_mp_init(&mp[pos])) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
 CLEANUP:
Packit Service 37472d
  while(--pos >= 0) 
Packit Service 37472d
    mw_mp_clear(&mp[pos]);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_init_array() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_init_size(mp, prec) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_init_size(mp, prec)
Packit Service 37472d
Packit Service 37472d
  Initialize a new zero-valued mw_mp_int with at least the given
Packit Service 37472d
  precision; returns MP_OKAY if successful, or MP_MEM if memory could
Packit Service 37472d
  not be allocated for the structure.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_init_size(mw_mp_int *mp, mw_mp_size prec)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(mp != NULL && prec > 0, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((DIGITS(mp) = s_mw_mp_alloc(prec, sizeof(mw_mp_digit))) == NULL)
Packit Service 37472d
    return MP_MEM;
Packit Service 37472d
Packit Service 37472d
  SIGN(mp) = MP_ZPOS;
Packit Service 37472d
  USED(mp) = 1;
Packit Service 37472d
  ALLOC(mp) = prec;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_init_size() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_init_copy(mp, from) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_init_copy(mp, from)
Packit Service 37472d
Packit Service 37472d
  Initialize mp as an exact copy of from.  Returns MP_OKAY if
Packit Service 37472d
  successful, MP_MEM if memory could not be allocated for the new
Packit Service 37472d
  structure.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_init_copy(mw_mp_int *mp, mw_mp_int *from)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(mp != NULL && from != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(mp == from)
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  if((DIGITS(mp) = s_mw_mp_alloc(USED(from), sizeof(mw_mp_digit))) == NULL)
Packit Service 37472d
    return MP_MEM;
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
Packit Service 37472d
  USED(mp) = USED(from);
Packit Service 37472d
  ALLOC(mp) = USED(from);
Packit Service 37472d
  SIGN(mp) = SIGN(from);
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_init_copy() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_copy(from, to) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_copy(from, to)
Packit Service 37472d
Packit Service 37472d
  Copies the mw_mp_int 'from' to the mw_mp_int 'to'.  It is presumed that
Packit Service 37472d
  'to' has already been initialized (if not, use mw_mp_init_copy()
Packit Service 37472d
  instead). If 'from' and 'to' are identical, nothing happens.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_copy(mw_mp_int *from, mw_mp_int *to)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(from != NULL && to != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(from == to)
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  { /* copy */
Packit Service 37472d
    mw_mp_digit   *tmp;
Packit Service 37472d
Packit Service 37472d
    /*
Packit Service 37472d
      If the allocated buffer in 'to' already has enough space to hold
Packit Service 37472d
      all the used digits of 'from', we'll re-use it to avoid hitting
Packit Service 37472d
      the memory allocater more than necessary; otherwise, we'd have
Packit Service 37472d
      to grow anyway, so we just allocate a hunk and make the copy as
Packit Service 37472d
      usual
Packit Service 37472d
     */
Packit Service 37472d
    if(ALLOC(to) >= USED(from)) {
Packit Service 37472d
      s_mw_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
Packit Service 37472d
      s_mw_mp_copy(DIGITS(from), DIGITS(to), USED(from));
Packit Service 37472d
      
Packit Service 37472d
    } else {
Packit Service 37472d
      if((tmp = s_mw_mp_alloc(USED(from), sizeof(mw_mp_digit))) == NULL)
Packit Service 37472d
	return MP_MEM;
Packit Service 37472d
Packit Service 37472d
      s_mw_mp_copy(DIGITS(from), tmp, USED(from));
Packit Service 37472d
Packit Service 37472d
      if(DIGITS(to) != NULL) {
Packit Service 37472d
#if MP_CRYPTO
Packit Service 37472d
	s_mw_mp_setz(DIGITS(to), ALLOC(to));
Packit Service 37472d
#endif
Packit Service 37472d
	s_mw_mp_free(DIGITS(to));
Packit Service 37472d
      }
Packit Service 37472d
Packit Service 37472d
      DIGITS(to) = tmp;
Packit Service 37472d
      ALLOC(to) = USED(from);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    /* Copy the precision and sign from the original */
Packit Service 37472d
    USED(to) = USED(from);
Packit Service 37472d
    SIGN(to) = SIGN(from);
Packit Service 37472d
  } /* end copy */
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_copy() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_exch(mp1, mp2) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_exch(mp1, mp2)
Packit Service 37472d
Packit Service 37472d
  Exchange mp1 and mp2 without allocating any intermediate memory
Packit Service 37472d
  (well, unless you count the stack space needed for this call and the
Packit Service 37472d
  locals it creates...).  This cannot fail.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
void mw_mp_exch(mw_mp_int *mp1, mw_mp_int *mp2)
Packit Service 37472d
{
Packit Service 37472d
#if MP_ARGCHK == 2
Packit Service 37472d
  assert(mp1 != NULL && mp2 != NULL);
Packit Service 37472d
#else
Packit Service 37472d
  if(mp1 == NULL || mp2 == NULL)
Packit Service 37472d
    return;
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_exch(mp1, mp2);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_exch() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_clear(mp) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_clear(mp)
Packit Service 37472d
Packit Service 37472d
  Release the storage used by an mw_mp_int, and void its fields so that
Packit Service 37472d
  if someone calls mw_mp_clear() again for the same int later, we won't
Packit Service 37472d
  get tollchocked.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
void   mw_mp_clear(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  if(mp == NULL)
Packit Service 37472d
    return;
Packit Service 37472d
Packit Service 37472d
  if(DIGITS(mp) != NULL) {
Packit Service 37472d
#if MP_CRYPTO
Packit Service 37472d
    s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
Packit Service 37472d
#endif
Packit Service 37472d
    s_mw_mp_free(DIGITS(mp));
Packit Service 37472d
    DIGITS(mp) = NULL;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  USED(mp) = 0;
Packit Service 37472d
  ALLOC(mp) = 0;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_clear() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_clear_array(mp[], count) */
Packit Service 37472d
Packit Service 37472d
void   mw_mp_clear_array(mw_mp_int mp[], int count)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(mp != NULL && count > 0, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  while(--count >= 0) 
Packit Service 37472d
    mw_mp_clear(&mp[count]);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_clear_array() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_zero(mp) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_zero(mp) 
Packit Service 37472d
Packit Service 37472d
  Set mp to zero.  Does not change the allocated size of the structure,
Packit Service 37472d
  and therefore cannot fail (except on a bad argument, which we ignore)
Packit Service 37472d
 */
Packit Service 37472d
void   mw_mp_zero(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  if(mp == NULL)
Packit Service 37472d
    return;
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
Packit Service 37472d
  USED(mp) = 1;
Packit Service 37472d
  SIGN(mp) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_zero() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_set(mp, d) */
Packit Service 37472d
Packit Service 37472d
void   mw_mp_set(mw_mp_int *mp, mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  if(mp == NULL)
Packit Service 37472d
    return;
Packit Service 37472d
Packit Service 37472d
  mw_mp_zero(mp);
Packit Service 37472d
  DIGIT(mp, 0) = d;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_set() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_set_int(mp, z) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_set_int(mw_mp_int *mp, long z)
Packit Service 37472d
{
Packit Service 37472d
  int            ix;
Packit Service 37472d
  unsigned long  v = abs(z);
Packit Service 37472d
  mw_mp_err         res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  mw_mp_zero(mp);
Packit Service 37472d
  if(z == 0)
Packit Service 37472d
    return MP_OKAY;  /* shortcut for zero */
Packit Service 37472d
Packit Service 37472d
  for(ix = sizeof(long) - 1; ix >= 0; ix--) {
Packit Service 37472d
Packit Service 37472d
    if((res = s_mw_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    res = s_mw_mp_add_d(mp, 
Packit Service 37472d
		     (mw_mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
Packit Service 37472d
    if(res != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(z < 0)
Packit Service 37472d
    SIGN(mp) = MP_NEG;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_set_int() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ Digit arithmetic */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_add_d(a, d, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_add_d(a, d, b)
Packit Service 37472d
Packit Service 37472d
  Compute the sum b = a + d, for a single digit d.  Respects the sign of
Packit Service 37472d
  its primary addend (single digits are unsigned anyway).
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_add_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res = MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, b)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  if(SIGN(b) == MP_ZPOS) {
Packit Service 37472d
    res = s_mw_mp_add_d(b, d);
Packit Service 37472d
  } else if(s_mw_mp_cmw_mp_d(b, d) >= 0) {
Packit Service 37472d
    res = s_mw_mp_sub_d(b, d);
Packit Service 37472d
  } else {
Packit Service 37472d
    SIGN(b) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
    DIGIT(b, 0) = d - DIGIT(b, 0);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_add_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_sub_d(a, d, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_sub_d(a, d, b)
Packit Service 37472d
Packit Service 37472d
  Compute the difference b = a - d, for a single digit d.  Respects the
Packit Service 37472d
  sign of its subtrahend (single digits are unsigned anyway).
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_sub_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, b)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  if(SIGN(b) == MP_NEG) {
Packit Service 37472d
    if((res = s_mw_mp_add_d(b, d)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
  } else if(s_mw_mp_cmw_mp_d(b, d) >= 0) {
Packit Service 37472d
    if((res = s_mw_mp_sub_d(b, d)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    mw_mp_neg(b, b);
Packit Service 37472d
Packit Service 37472d
    DIGIT(b, 0) = d - DIGIT(b, 0);
Packit Service 37472d
    SIGN(b) = MP_NEG;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(s_mw_mp_cmw_mp_d(b, 0) == 0)
Packit Service 37472d
    SIGN(b) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_sub_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_mul_d(a, d, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_mul_d(a, d, b)
Packit Service 37472d
Packit Service 37472d
  Compute the product b = a * d, for a single digit d.  Respects the sign
Packit Service 37472d
  of its multiplicand (single digits are unsigned anyway)
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(d == 0) {
Packit Service 37472d
    mw_mp_zero(b);
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, b)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  res = s_mw_mp_mul_d(b, d);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_mul_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_mul_2(a, c) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_mul_2(mw_mp_int *a, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  return s_mw_mp_mul_2(c);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_mul_2() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_div_d(a, d, q, r) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_div_d(a, d, q, r)
Packit Service 37472d
Packit Service 37472d
  Compute the quotient q = a / d and remainder r = a mod d, for a
Packit Service 37472d
  single digit d.  Respects the sign of its divisor (single digits are
Packit Service 37472d
  unsigned anyway).
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_div_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_digit *r)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_digit rem;
Packit Service 37472d
  int      pow;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(d == 0)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  /* Shortcut for powers of two ... */
Packit Service 37472d
  if((pow = s_mw_mp_ispow2d(d)) >= 0) {
Packit Service 37472d
    mw_mp_digit  mask;
Packit Service 37472d
Packit Service 37472d
    mask = (1 << pow) - 1;
Packit Service 37472d
    rem = DIGIT(a, 0) & mask;
Packit Service 37472d
Packit Service 37472d
    if(q) {
Packit Service 37472d
      mw_mp_copy(a, q);
Packit Service 37472d
      s_mw_mp_div_2d(q, pow);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    if(r)
Packit Service 37472d
      *r = rem;
Packit Service 37472d
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /*
Packit Service 37472d
    If the quotient is actually going to be returned, we'll try to
Packit Service 37472d
    avoid hitting the memory allocator by copying the dividend into it
Packit Service 37472d
    and doing the division there.  This can't be any _worse_ than
Packit Service 37472d
    always copying, and will sometimes be better (since it won't make
Packit Service 37472d
    another copy)
Packit Service 37472d
Packit Service 37472d
    If it's not going to be returned, we need to allocate a temporary
Packit Service 37472d
    to hold the quotient, which will just be discarded.
Packit Service 37472d
   */
Packit Service 37472d
  if(q) {
Packit Service 37472d
    if((res = mw_mp_copy(a, q)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    res = s_mw_mp_div_d(q, d, &rem;;
Packit Service 37472d
    if(s_mw_mp_cmw_mp_d(q, 0) == MP_EQ)
Packit Service 37472d
      SIGN(q) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    mw_mp_int  qp;
Packit Service 37472d
Packit Service 37472d
    if((res = mw_mp_init_copy(&qp, a)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    res = s_mw_mp_div_d(&qp, d, &rem;;
Packit Service 37472d
    if(s_mw_mp_cmw_mp_d(&qp, 0) == 0)
Packit Service 37472d
      SIGN(&qp) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
    mw_mp_clear(&qp);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(r)
Packit Service 37472d
    *r = rem;
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_div_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_div_2(a, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_div_2(a, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a / 2, disregarding the remainder.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_div_2(mw_mp_int *a, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_div_2(c);
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_div_2() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_expt_d(a, d, b) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_expt_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   s, x;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_sign  cs = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init(&s)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
Packit Service 37472d
    goto X;
Packit Service 37472d
Packit Service 37472d
  DIGIT(&s, 0) = 1;
Packit Service 37472d
Packit Service 37472d
  if((d % 2) == 1)
Packit Service 37472d
    cs = SIGN(a);
Packit Service 37472d
Packit Service 37472d
  while(d != 0) {
Packit Service 37472d
    if(d & 1) {
Packit Service 37472d
      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    d >>= 1;
Packit Service 37472d
Packit Service 37472d
    if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  SIGN(&s) = cs;
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_exch(&s, c);
Packit Service 37472d
Packit Service 37472d
CLEANUP:
Packit Service 37472d
  mw_mp_clear(&x);
Packit Service 37472d
X:
Packit Service 37472d
  mw_mp_clear(&s);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_expt_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ Full arithmetic */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_abs(a, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_abs(a, b)
Packit Service 37472d
Packit Service 37472d
  Compute b = |a|.  'a' and 'b' may be identical.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_abs(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, b)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  SIGN(b) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_abs() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_neg(a, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_neg(a, b)
Packit Service 37472d
Packit Service 37472d
  Compute b = -a.  'a' and 'b' may be identical.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_neg(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, b)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  if(s_mw_mp_cmw_mp_d(b, 0) == MP_EQ) 
Packit Service 37472d
    SIGN(b) = MP_ZPOS;
Packit Service 37472d
  else 
Packit Service 37472d
    SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_neg() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_add(a, b, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_add(a, b, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a + b.  All parameters may be identical.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_add(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
  int     cmp;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(SIGN(a) == SIGN(b)) { /* same sign:  add values, keep sign */
Packit Service 37472d
Packit Service 37472d
    /* Commutativity of addition lets us do this in either order,
Packit Service 37472d
       so we avoid having to use a temporary even if the result 
Packit Service 37472d
       is supposed to replace the output
Packit Service 37472d
     */
Packit Service 37472d
    if(c == b) {
Packit Service 37472d
      if((res = s_mw_mp_add(c, a)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
    } else {
Packit Service 37472d
      if(c != a && (res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
Packit Service 37472d
      if((res = s_mw_mp_add(c, b)) != MP_OKAY) 
Packit Service 37472d
	return res;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
  } else if((cmp = s_mw_mp_cmp(a, b)) > 0) {  /* different sign: a > b   */
Packit Service 37472d
Packit Service 37472d
    /* If the output is going to be clobbered, we will use a temporary
Packit Service 37472d
       variable; otherwise, we'll do it without touching the memory 
Packit Service 37472d
       allocator at all, if possible
Packit Service 37472d
     */
Packit Service 37472d
    if(c == b) {
Packit Service 37472d
      mw_mp_int  tmp;
Packit Service 37472d
Packit Service 37472d
      if((res = mw_mp_init_copy(&tmp, a)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
      if((res = s_mw_mp_sub(&tmp, b)) != MP_OKAY) {
Packit Service 37472d
	mw_mp_clear(&tmp);
Packit Service 37472d
	return res;
Packit Service 37472d
      }
Packit Service 37472d
Packit Service 37472d
      s_mw_mp_exch(&tmp, c);
Packit Service 37472d
      mw_mp_clear(&tmp);
Packit Service 37472d
Packit Service 37472d
    } else {
Packit Service 37472d
Packit Service 37472d
      if(c != a && (res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
      if((res = s_mw_mp_sub(c, b)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
  } else if(cmp == 0) {             /* different sign, a == b   */
Packit Service 37472d
Packit Service 37472d
    mw_mp_zero(c);
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  } else {                          /* different sign: a < b    */
Packit Service 37472d
Packit Service 37472d
    /* See above... */
Packit Service 37472d
    if(c == a) {
Packit Service 37472d
      mw_mp_int  tmp;
Packit Service 37472d
Packit Service 37472d
      if((res = mw_mp_init_copy(&tmp, b)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
      if((res = s_mw_mp_sub(&tmp, a)) != MP_OKAY) {
Packit Service 37472d
	mw_mp_clear(&tmp);
Packit Service 37472d
	return res;
Packit Service 37472d
      }
Packit Service 37472d
Packit Service 37472d
      s_mw_mp_exch(&tmp, c);
Packit Service 37472d
      mw_mp_clear(&tmp);
Packit Service 37472d
Packit Service 37472d
    } else {
Packit Service 37472d
Packit Service 37472d
      if(c != b && (res = mw_mp_copy(b, c)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
      if((res = s_mw_mp_sub(c, a)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(USED(c) == 1 && DIGIT(c, 0) == 0)
Packit Service 37472d
    SIGN(c) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_add() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_sub(a, b, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_sub(a, b, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a - b.  All parameters may be identical.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_sub(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
  int     cmp;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(SIGN(a) != SIGN(b)) {
Packit Service 37472d
    if(c == a) {
Packit Service 37472d
      if((res = s_mw_mp_add(c, b)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
    } else {
Packit Service 37472d
      if(c != b && ((res = mw_mp_copy(b, c)) != MP_OKAY))
Packit Service 37472d
	return res;
Packit Service 37472d
      if((res = s_mw_mp_add(c, a)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
      SIGN(c) = SIGN(a);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
  } else if((cmp = s_mw_mp_cmp(a, b)) > 0) { /* Same sign, a > b */
Packit Service 37472d
    if(c == b) {
Packit Service 37472d
      mw_mp_int  tmp;
Packit Service 37472d
Packit Service 37472d
      if((res = mw_mp_init_copy(&tmp, a)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
      if((res = s_mw_mp_sub(&tmp, b)) != MP_OKAY) {
Packit Service 37472d
	mw_mp_clear(&tmp);
Packit Service 37472d
	return res;
Packit Service 37472d
      }
Packit Service 37472d
      s_mw_mp_exch(&tmp, c);
Packit Service 37472d
      mw_mp_clear(&tmp);
Packit Service 37472d
Packit Service 37472d
    } else {
Packit Service 37472d
      if(c != a && ((res = mw_mp_copy(a, c)) != MP_OKAY))
Packit Service 37472d
	return res;
Packit Service 37472d
Packit Service 37472d
      if((res = s_mw_mp_sub(c, b)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
  } else if(cmp == 0) {  /* Same sign, equal magnitude */
Packit Service 37472d
    mw_mp_zero(c);
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  } else {               /* Same sign, b > a */
Packit Service 37472d
    if(c == a) {
Packit Service 37472d
      mw_mp_int  tmp;
Packit Service 37472d
Packit Service 37472d
      if((res = mw_mp_init_copy(&tmp, b)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
Packit Service 37472d
      if((res = s_mw_mp_sub(&tmp, a)) != MP_OKAY) {
Packit Service 37472d
	mw_mp_clear(&tmp);
Packit Service 37472d
	return res;
Packit Service 37472d
      }
Packit Service 37472d
      s_mw_mp_exch(&tmp, c);
Packit Service 37472d
      mw_mp_clear(&tmp);
Packit Service 37472d
Packit Service 37472d
    } else {
Packit Service 37472d
      if(c != b && ((res = mw_mp_copy(b, c)) != MP_OKAY)) 
Packit Service 37472d
	return res;
Packit Service 37472d
Packit Service 37472d
      if((res = s_mw_mp_sub(c, a)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    SIGN(c) = !SIGN(b);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(USED(c) == 1 && DIGIT(c, 0) == 0)
Packit Service 37472d
    SIGN(c) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_sub() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_mul(a, b, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_mul(a, b, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a * b.  All parameters may be identical.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_mul(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_sign  sgn;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG;
Packit Service 37472d
Packit Service 37472d
  if(c == b) {
Packit Service 37472d
    if((res = s_mw_mp_mul(c, a)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    if((res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    if((res = s_mw_mp_mul(c, b)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  if(sgn == MP_ZPOS || s_mw_mp_cmw_mp_d(c, 0) == MP_EQ)
Packit Service 37472d
    SIGN(c) = MP_ZPOS;
Packit Service 37472d
  else
Packit Service 37472d
    SIGN(c) = sgn;
Packit Service 37472d
  
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_mul() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_mul_2d(a, d, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_mul_2d(a, d, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a * 2^d.  a may be the same as c.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_mul_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  if(d == 0)
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  return s_mw_mp_mul_2d(c, d);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_mul() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_sqr(a, b) */
Packit Service 37472d
Packit Service 37472d
#if MP_SQUARE
Packit Service 37472d
mw_mp_err mw_mp_sqr(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_copy(a, b)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  if((res = s_mw_mp_sqr(b)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  SIGN(b) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_sqr() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_div(a, b, q, r) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_div(a, b, q, r)
Packit Service 37472d
Packit Service 37472d
  Compute q = a / b and r = a mod b.  Input parameters may be re-used
Packit Service 37472d
  as output parameters.  If q or r is NULL, that portion of the
Packit Service 37472d
  computation will be discarded (although it will still be computed)
Packit Service 37472d
Packit Service 37472d
  Pay no attention to the hacker behind the curtain.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_div(mw_mp_int *a, mw_mp_int *b, mw_mp_int *q, mw_mp_int *r)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_int   qtmp, rtmp;
Packit Service 37472d
  int      cmp;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(b) == MP_EQ)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  /* If a <= b, we can compute the solution without division, and
Packit Service 37472d
     avoid any memory allocation
Packit Service 37472d
   */
Packit Service 37472d
  if((cmp = s_mw_mp_cmp(a, b)) < 0) {
Packit Service 37472d
    if(r) {
Packit Service 37472d
      if((res = mw_mp_copy(a, r)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    if(q) 
Packit Service 37472d
      mw_mp_zero(q);
Packit Service 37472d
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  } else if(cmp == 0) {
Packit Service 37472d
Packit Service 37472d
    /* Set quotient to 1, with appropriate sign */
Packit Service 37472d
    if(q) {
Packit Service 37472d
      int qneg = (SIGN(a) != SIGN(b));
Packit Service 37472d
Packit Service 37472d
      mw_mp_set(q, 1);
Packit Service 37472d
      if(qneg)
Packit Service 37472d
	SIGN(q) = MP_NEG;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    if(r)
Packit Service 37472d
      mw_mp_zero(r);
Packit Service 37472d
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* If we get here, it means we actually have to do some division */
Packit Service 37472d
Packit Service 37472d
  /* Set up some temporaries... */
Packit Service 37472d
  if((res = mw_mp_init_copy(&qtmp, a)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_init_copy(&rtmp, b)) != MP_OKAY)
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  if((res = s_mw_mp_div(&qtmp, &rtmp)) != MP_OKAY)
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  /* Compute the signs for the output  */
Packit Service 37472d
  SIGN(&rtmp) = SIGN(a); /* Sr = Sa              */
Packit Service 37472d
  if(SIGN(a) == SIGN(b))
Packit Service 37472d
    SIGN(&qtmp) = MP_ZPOS;  /* Sq = MP_ZPOS if Sa = Sb */
Packit Service 37472d
  else
Packit Service 37472d
    SIGN(&qtmp) = MP_NEG;   /* Sq = MP_NEG if Sa != Sb */
Packit Service 37472d
Packit Service 37472d
  if(s_mw_mp_cmw_mp_d(&qtmp, 0) == MP_EQ)
Packit Service 37472d
    SIGN(&qtmp) = MP_ZPOS;
Packit Service 37472d
  if(s_mw_mp_cmw_mp_d(&rtmp, 0) == MP_EQ)
Packit Service 37472d
    SIGN(&rtmp) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  /* Copy output, if it is needed      */
Packit Service 37472d
  if(q) 
Packit Service 37472d
    s_mw_mp_exch(&qtmp, q);
Packit Service 37472d
Packit Service 37472d
  if(r) 
Packit Service 37472d
    s_mw_mp_exch(&rtmp, r);
Packit Service 37472d
Packit Service 37472d
CLEANUP:
Packit Service 37472d
  mw_mp_clear(&rtmp);
Packit Service 37472d
  mw_mp_clear(&qtmp);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_div() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_div_2d(a, d, q, r) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_div_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_int *r)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(q) {
Packit Service 37472d
    if((res = mw_mp_copy(a, q)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    s_mw_mp_div_2d(q, d);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(r) {
Packit Service 37472d
    if((res = mw_mp_copy(a, r)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    s_mw_mp_mod_2d(r, d);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_div_2d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_expt(a, b, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_expt(a, b, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a ** b, that is, raise a to the b power.  Uses a
Packit Service 37472d
  standard iterative square-and-multiply technique.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_expt(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   s, x;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_digit d;
Packit Service 37472d
  int      dig, bit;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(b) < 0)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init(&s)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  mw_mp_set(&s, 1);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
Packit Service 37472d
    goto X;
Packit Service 37472d
Packit Service 37472d
  /* Loop over low-order digits in ascending order */
Packit Service 37472d
  for(dig = 0; dig < (USED(b) - 1); dig++) {
Packit Service 37472d
    d = DIGIT(b, dig);
Packit Service 37472d
Packit Service 37472d
    /* Loop over bits of each non-maximal digit */
Packit Service 37472d
    for(bit = 0; bit < DIGIT_BIT; bit++) {
Packit Service 37472d
      if(d & 1) {
Packit Service 37472d
	if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY) 
Packit Service 37472d
	  goto CLEANUP;
Packit Service 37472d
      }
Packit Service 37472d
Packit Service 37472d
      d >>= 1;
Packit Service 37472d
      
Packit Service 37472d
      if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Consider now the last digit... */
Packit Service 37472d
  d = DIGIT(b, dig);
Packit Service 37472d
Packit Service 37472d
  while(d) {
Packit Service 37472d
    if(d & 1) {
Packit Service 37472d
      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    d >>= 1;
Packit Service 37472d
Packit Service 37472d
    if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  if(mw_mp_iseven(b))
Packit Service 37472d
    SIGN(&s) = SIGN(a);
Packit Service 37472d
Packit Service 37472d
  res = mw_mp_copy(&s, c);
Packit Service 37472d
Packit Service 37472d
CLEANUP:
Packit Service 37472d
  mw_mp_clear(&x);
Packit Service 37472d
X:
Packit Service 37472d
  mw_mp_clear(&s);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_expt() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_2expt(a, k) */
Packit Service 37472d
Packit Service 37472d
/* Compute a = 2^k */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_2expt(mw_mp_int *a, mw_mp_digit k)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(a != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  return s_mw_mp_2expt(a, k);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_2expt() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_mod(a, m, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_mod(a, m, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a (mod m).  Result will always be 0 <= c < m.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_mod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
  int     mag;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(SIGN(m) == MP_NEG)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  /*
Packit Service 37472d
     If |a| > m, we need to divide to get the remainder and take the
Packit Service 37472d
     absolute value.  
Packit Service 37472d
Packit Service 37472d
     If |a| < m, we don't need to do any division, just copy and adjust
Packit Service 37472d
     the sign (if a is negative).
Packit Service 37472d
Packit Service 37472d
     If |a| == m, we can simply set the result to zero.
Packit Service 37472d
Packit Service 37472d
     This order is intended to minimize the average path length of the
Packit Service 37472d
     comparison chain on common workloads -- the most frequent cases are
Packit Service 37472d
     that |a| != m, so we do those first.
Packit Service 37472d
   */
Packit Service 37472d
  if((mag = s_mw_mp_cmp(a, m)) > 0) {
Packit Service 37472d
    if((res = mw_mp_div(a, m, NULL, c)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
    
Packit Service 37472d
    if(SIGN(c) == MP_NEG) {
Packit Service 37472d
      if((res = mw_mp_add(c, m, c)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
  } else if(mag < 0) {
Packit Service 37472d
    if((res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    if(mw_mp_cmw_mp_z(a) < 0) {
Packit Service 37472d
      if((res = mw_mp_add(c, m, c)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
Packit Service 37472d
    }
Packit Service 37472d
    
Packit Service 37472d
  } else {
Packit Service 37472d
    mw_mp_zero(c);
Packit Service 37472d
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_mod() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_mod_d(a, d, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_mod_d(a, d, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a (mod d).  Result will always be 0 <= c < d
Packit Service 37472d
 */
Packit Service 37472d
mw_mp_err mw_mp_mod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_digit *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_digit rem;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(s_mw_mp_cmw_mp_d(a, d) > 0) {
Packit Service 37472d
    if((res = mw_mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    if(SIGN(a) == MP_NEG)
Packit Service 37472d
      rem = d - DIGIT(a, 0);
Packit Service 37472d
    else
Packit Service 37472d
      rem = DIGIT(a, 0);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(c)
Packit Service 37472d
    *c = rem;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_mod_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_sqrt(a, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_sqrt(a, b)
Packit Service 37472d
Packit Service 37472d
  Compute the integer square root of a, and store the result in b.
Packit Service 37472d
  Uses an integer-arithmetic version of Newton's iterative linear
Packit Service 37472d
  approximation technique to determine this value; the result has the
Packit Service 37472d
  following two properties:
Packit Service 37472d
Packit Service 37472d
     b^2 <= a
Packit Service 37472d
     (b+1)^2 >= a
Packit Service 37472d
Packit Service 37472d
  It is a range error to pass a negative value.
Packit Service 37472d
 */
Packit Service 37472d
mw_mp_err mw_mp_sqrt(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   x, t;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  /* Cannot take square root of a negative value */
Packit Service 37472d
  if(SIGN(a) == MP_NEG)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  /* Special cases for zero and one, trivial     */
Packit Service 37472d
  if(mw_mp_cmw_mp_d(a, 0) == MP_EQ || mw_mp_cmw_mp_d(a, 1) == MP_EQ) 
Packit Service 37472d
    return mw_mp_copy(a, b);
Packit Service 37472d
    
Packit Service 37472d
  /* Initialize the temporaries we'll use below  */
Packit Service 37472d
  if((res = mw_mp_init_size(&t, USED(a))) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  /* Compute an initial guess for the iteration as a itself */
Packit Service 37472d
  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
Packit Service 37472d
    goto X;
Packit Service 37472d
Packit Service 37472d
  for(;;) {
Packit Service 37472d
    /* t = (x * x) - a */
Packit Service 37472d
    mw_mp_copy(&x, &t);      /* can't fail, t is big enough for original x */
Packit Service 37472d
    if((res = mw_mp_sqr(&t, &t)) != MP_OKAY ||
Packit Service 37472d
       (res = mw_mp_sub(&t, a, &t)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
    /* t = t / 2x       */
Packit Service 37472d
    s_mw_mp_mul_2(&x);
Packit Service 37472d
    if((res = mw_mp_div(&t, &x, &t, NULL)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
    s_mw_mp_div_2(&x);
Packit Service 37472d
Packit Service 37472d
    /* Terminate the loop, if the quotient is zero */
Packit Service 37472d
    if(mw_mp_cmw_mp_z(&t) == MP_EQ)
Packit Service 37472d
      break;
Packit Service 37472d
Packit Service 37472d
    /* x = x - t       */
Packit Service 37472d
    if((res = mw_mp_sub(&x, &t, &x)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Copy result to output parameter */
Packit Service 37472d
  mw_mp_sub_d(&x, 1, &x);
Packit Service 37472d
  s_mw_mp_exch(&x, b);
Packit Service 37472d
Packit Service 37472d
 CLEANUP:
Packit Service 37472d
  mw_mp_clear(&x);
Packit Service 37472d
 X:
Packit Service 37472d
  mw_mp_clear(&t); 
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_sqrt() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ Modular arithmetic */
Packit Service 37472d
Packit Service 37472d
#if MP_MODARITH
Packit Service 37472d
/* {{{ mw_mp_addmod(a, b, m, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_addmod(a, b, m, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = (a + b) mod m
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_addmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_add(a, b, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_submod(a, b, m, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_submod(a, b, m, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = (a - b) mod m
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_submod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_sub(a, b, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_mulmod(a, b, m, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_mulmod(a, b, m, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = (a * b) mod m
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_mulmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_mul(a, b, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_sqrmod(a, m, c) */
Packit Service 37472d
Packit Service 37472d
#if MP_SQUARE
Packit Service 37472d
mw_mp_err mw_mp_sqrmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_sqr(a, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_mod(c, m, c)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_sqrmod() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_exptmod(a, b, m, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_exptmod(a, b, m, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = (a ** b) mod m.  Uses a standard square-and-multiply
Packit Service 37472d
  method with modular reductions at each step. (This is basically the
Packit Service 37472d
  same code as mw_mp_expt(), except for the addition of the reductions)
Packit Service 37472d
  
Packit Service 37472d
  The modular reductions are done using Barrett's algorithm (see
Packit Service 37472d
  s_mw_mp_reduce() below for details)
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_exptmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   s, x, mu;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_digit d, *db = DIGITS(b);
Packit Service 37472d
  mw_mp_size  ub = USED(b);
Packit Service 37472d
  int      dig, bit;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(b) < 0 || mw_mp_cmw_mp_z(m) <= 0)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init(&s)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
Packit Service 37472d
    goto X;
Packit Service 37472d
  if((res = mw_mp_mod(&x, m, &x)) != MP_OKAY ||
Packit Service 37472d
     (res = mw_mp_init(&mu)) != MP_OKAY)
Packit Service 37472d
    goto MU;
Packit Service 37472d
Packit Service 37472d
  mw_mp_set(&s, 1);
Packit Service 37472d
Packit Service 37472d
  /* mu = b^2k / m */
Packit Service 37472d
  s_mw_mp_add_d(&mu, 1); 
Packit Service 37472d
  s_mw_mp_lshd(&mu, 2 * USED(m));
Packit Service 37472d
  if((res = mw_mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  /* Loop over digits of b in ascending order, except highest order */
Packit Service 37472d
  for(dig = 0; dig < (ub - 1); dig++) {
Packit Service 37472d
    d = *db++;
Packit Service 37472d
Packit Service 37472d
    /* Loop over the bits of the lower-order digits */
Packit Service 37472d
    for(bit = 0; bit < DIGIT_BIT; bit++) {
Packit Service 37472d
      if(d & 1) {
Packit Service 37472d
	if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
Packit Service 37472d
	  goto CLEANUP;
Packit Service 37472d
	if((res = s_mw_mp_reduce(&s, m, &mu)) != MP_OKAY)
Packit Service 37472d
	  goto CLEANUP;
Packit Service 37472d
      }
Packit Service 37472d
Packit Service 37472d
      d >>= 1;
Packit Service 37472d
Packit Service 37472d
      if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
      if((res = s_mw_mp_reduce(&x, m, &mu)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Now do the last digit... */
Packit Service 37472d
  d = *db;
Packit Service 37472d
Packit Service 37472d
  while(d) {
Packit Service 37472d
    if(d & 1) {
Packit Service 37472d
      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
      if((res = s_mw_mp_reduce(&s, m, &mu)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    d >>= 1;
Packit Service 37472d
Packit Service 37472d
    if((res = s_mw_mp_sqr(&x)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
    if((res = s_mw_mp_reduce(&x, m, &mu)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_exch(&s, c);
Packit Service 37472d
Packit Service 37472d
 CLEANUP:
Packit Service 37472d
  mw_mp_clear(&mu);
Packit Service 37472d
 MU:
Packit Service 37472d
  mw_mp_clear(&x);
Packit Service 37472d
 X:
Packit Service 37472d
  mw_mp_clear(&s);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_exptmod() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_exptmod_d(a, d, m, c) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_exptmod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   s, x;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init(&s)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY)
Packit Service 37472d
    goto X;
Packit Service 37472d
Packit Service 37472d
  mw_mp_set(&s, 1);
Packit Service 37472d
Packit Service 37472d
  while(d != 0) {
Packit Service 37472d
    if(d & 1) {
Packit Service 37472d
      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY ||
Packit Service 37472d
	 (res = mw_mp_mod(&s, m, &s)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    d /= 2;
Packit Service 37472d
Packit Service 37472d
    if((res = s_mw_mp_sqr(&x)) != MP_OKAY ||
Packit Service 37472d
       (res = mw_mp_mod(&x, m, &x)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_exch(&s, c);
Packit Service 37472d
Packit Service 37472d
CLEANUP:
Packit Service 37472d
  mw_mp_clear(&x);
Packit Service 37472d
X:
Packit Service 37472d
  mw_mp_clear(&s);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_exptmod_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
#endif /* if MP_MODARITH */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ Comparison functions */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_cmw_mp_z(a) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_cmw_mp_z(a)
Packit Service 37472d
Packit Service 37472d
  Compare a <=> 0.  Returns <0 if a<0, 0 if a=0, >0 if a>0.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_cmw_mp_z(mw_mp_int *a)
Packit Service 37472d
{
Packit Service 37472d
  if(SIGN(a) == MP_NEG)
Packit Service 37472d
    return MP_LT;
Packit Service 37472d
  else if(USED(a) == 1 && DIGIT(a, 0) == 0)
Packit Service 37472d
    return MP_EQ;
Packit Service 37472d
  else
Packit Service 37472d
    return MP_GT;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_cmw_mp_z() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_cmw_mp_d(a, d) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_cmw_mp_d(a, d)
Packit Service 37472d
Packit Service 37472d
  Compare a <=> d.  Returns <0 if a<d, 0 if a=d, >0 if a>d
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(a != NULL, MP_EQ);
Packit Service 37472d
Packit Service 37472d
  if(SIGN(a) == MP_NEG)
Packit Service 37472d
    return MP_LT;
Packit Service 37472d
Packit Service 37472d
  return s_mw_mp_cmw_mp_d(a, d);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_cmw_mp_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_cmp(a, b) */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_cmp(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_EQ);
Packit Service 37472d
Packit Service 37472d
  if(SIGN(a) == SIGN(b)) {
Packit Service 37472d
    int  mag;
Packit Service 37472d
Packit Service 37472d
    if((mag = s_mw_mp_cmp(a, b)) == MP_EQ)
Packit Service 37472d
      return MP_EQ;
Packit Service 37472d
Packit Service 37472d
    if(SIGN(a) == MP_ZPOS)
Packit Service 37472d
      return mag;
Packit Service 37472d
    else
Packit Service 37472d
      return -mag;
Packit Service 37472d
Packit Service 37472d
  } else if(SIGN(a) == MP_ZPOS) {
Packit Service 37472d
    return MP_GT;
Packit Service 37472d
  } else {
Packit Service 37472d
    return MP_LT;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_cmp() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_cmw_mp_mag(a, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_cmw_mp_mag(a, b)
Packit Service 37472d
Packit Service 37472d
  Compares |a| <=> |b|, and returns an appropriate comparison result
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_cmw_mp_mag(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL, MP_EQ);
Packit Service 37472d
Packit Service 37472d
  return s_mw_mp_cmp(a, b);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_cmw_mp_mag() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_cmw_mp_int(a, z) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  This just converts z to an mw_mp_int, and uses the existing comparison
Packit Service 37472d
  routines.  This is sort of inefficient, but it's not clear to me how
Packit Service 37472d
  frequently this wil get used anyway.  For small positive constants,
Packit Service 37472d
  you can always use mw_mp_cmw_mp_d(), and for zero, there is mw_mp_cmw_mp_z().
Packit Service 37472d
 */
Packit Service 37472d
int    mw_mp_cmw_mp_int(mw_mp_int *a, long z)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int  tmp;
Packit Service 37472d
  int     out;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL, MP_EQ);
Packit Service 37472d
  
Packit Service 37472d
  mw_mp_init(&tmp); mw_mp_set_int(&tmp, z);
Packit Service 37472d
  out = mw_mp_cmp(a, &tmp);
Packit Service 37472d
  mw_mp_clear(&tmp);
Packit Service 37472d
Packit Service 37472d
  return out;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_cmw_mp_int() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_isodd(a) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_isodd(a)
Packit Service 37472d
Packit Service 37472d
  Returns a true (non-zero) value if a is odd, false (zero) otherwise.
Packit Service 37472d
 */
Packit Service 37472d
int    mw_mp_isodd(mw_mp_int *a)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(a != NULL, 0);
Packit Service 37472d
Packit Service 37472d
  return (DIGIT(a, 0) & 1);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_isodd() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_iseven(a) */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_iseven(mw_mp_int *a)
Packit Service 37472d
{
Packit Service 37472d
  return !mw_mp_isodd(a);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_iseven() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ Number theoretic functions */
Packit Service 37472d
Packit Service 37472d
#if MP_NUMTH
Packit Service 37472d
/* {{{ mw_mp_gcd(a, b, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Like the old mw_mp_gcd() function, except computes the GCD using the
Packit Service 37472d
  binary algorithm due to Josef Stein in 1961 (via Knuth).
Packit Service 37472d
 */
Packit Service 37472d
mw_mp_err mw_mp_gcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_int   u, v, t;
Packit Service 37472d
  mw_mp_size  k = 0;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(a) == MP_EQ && mw_mp_cmw_mp_z(b) == MP_EQ)
Packit Service 37472d
      return MP_RANGE;
Packit Service 37472d
  if(mw_mp_cmw_mp_z(a) == MP_EQ) {
Packit Service 37472d
    if((res = mw_mp_copy(b, c)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
    SIGN(c) = MP_ZPOS; return MP_OKAY;
Packit Service 37472d
  } else if(mw_mp_cmw_mp_z(b) == MP_EQ) {
Packit Service 37472d
    if((res = mw_mp_copy(a, c)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
    SIGN(c) = MP_ZPOS; return MP_OKAY;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init(&t)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_init_copy(&u, a)) != MP_OKAY)
Packit Service 37472d
    goto U;
Packit Service 37472d
  if((res = mw_mp_init_copy(&v, b)) != MP_OKAY)
Packit Service 37472d
    goto V;
Packit Service 37472d
Packit Service 37472d
  SIGN(&u) = MP_ZPOS;
Packit Service 37472d
  SIGN(&v) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  /* Divide out common factors of 2 until at least 1 of a, b is even */
Packit Service 37472d
  while(mw_mp_iseven(&u) && mw_mp_iseven(&v)) {
Packit Service 37472d
    s_mw_mp_div_2(&u);
Packit Service 37472d
    s_mw_mp_div_2(&v);
Packit Service 37472d
    ++k;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Initialize t */
Packit Service 37472d
  if(mw_mp_isodd(&u)) {
Packit Service 37472d
    if((res = mw_mp_copy(&v, &t)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
    
Packit Service 37472d
    /* t = -v */
Packit Service 37472d
    if(SIGN(&v) == MP_ZPOS)
Packit Service 37472d
      SIGN(&t) = MP_NEG;
Packit Service 37472d
    else
Packit Service 37472d
      SIGN(&t) = MP_ZPOS;
Packit Service 37472d
    
Packit Service 37472d
  } else {
Packit Service 37472d
    if((res = mw_mp_copy(&u, &t)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  for(;;) {
Packit Service 37472d
    while(mw_mp_iseven(&t)) {
Packit Service 37472d
      s_mw_mp_div_2(&t);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    if(mw_mp_cmw_mp_z(&t) == MP_GT) {
Packit Service 37472d
      if((res = mw_mp_copy(&t, &u)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
    } else {
Packit Service 37472d
      if((res = mw_mp_copy(&t, &v)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
      /* v = -t */
Packit Service 37472d
      if(SIGN(&t) == MP_ZPOS)
Packit Service 37472d
	SIGN(&v) = MP_NEG;
Packit Service 37472d
      else
Packit Service 37472d
	SIGN(&v) = MP_ZPOS;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    if((res = mw_mp_sub(&u, &v, &t)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
    if(s_mw_mp_cmw_mp_d(&t, 0) == MP_EQ)
Packit Service 37472d
      break;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_2expt(&v, k);       /* v = 2^k   */
Packit Service 37472d
  res = mw_mp_mul(&u, &v, c); /* c = u * v */
Packit Service 37472d
Packit Service 37472d
 CLEANUP:
Packit Service 37472d
  mw_mp_clear(&v);
Packit Service 37472d
 V:
Packit Service 37472d
  mw_mp_clear(&u);
Packit Service 37472d
 U:
Packit Service 37472d
  mw_mp_clear(&t);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_bgcd() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_lcm(a, b, c) */
Packit Service 37472d
Packit Service 37472d
/* We compute the least common multiple using the rule:
Packit Service 37472d
Packit Service 37472d
   ab = [a, b](a, b)
Packit Service 37472d
Packit Service 37472d
   ... by computing the product, and dividing out the gcd.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_lcm(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int  gcd, prod;
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  /* Set up temporaries */
Packit Service 37472d
  if((res = mw_mp_init(&gcd)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_init(&prod)) != MP_OKAY)
Packit Service 37472d
    goto GCD;
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_mul(a, b, &prod)) != MP_OKAY)
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
  if((res = mw_mp_gcd(a, b, &gcd)) != MP_OKAY)
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  res = mw_mp_div(&prod, &gcd, c, NULL);
Packit Service 37472d
Packit Service 37472d
 CLEANUP:
Packit Service 37472d
  mw_mp_clear(&prod);
Packit Service 37472d
 GCD:
Packit Service 37472d
  mw_mp_clear(&gcd;;
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_lcm() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_xgcd(a, b, g, x, y) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_xgcd(a, b, g, x, y)
Packit Service 37472d
Packit Service 37472d
  Compute g = (a, b) and values x and y satisfying Bezout's identity
Packit Service 37472d
  (that is, ax + by = g).  This uses the extended binary GCD algorithm
Packit Service 37472d
  based on the Stein algorithm used for mw_mp_gcd()
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_xgcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *g, mw_mp_int *x, mw_mp_int *y)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   gx, xc, yc, u, v, A, B, C, D;
Packit Service 37472d
  mw_mp_int  *clean[9];
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  int      last = -1;
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(b) == 0)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  /* Initialize all these variables we need */
Packit Service 37472d
  if((res = mw_mp_init(&u)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &u;
Packit Service 37472d
  if((res = mw_mp_init(&v)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &v;
Packit Service 37472d
  if((res = mw_mp_init(&gx)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &gx;
Packit Service 37472d
  if((res = mw_mp_init(&A)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &A;
Packit Service 37472d
  if((res = mw_mp_init(&B)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &B;
Packit Service 37472d
  if((res = mw_mp_init(&C)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &C;
Packit Service 37472d
  if((res = mw_mp_init(&D)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &D;
Packit Service 37472d
  if((res = mw_mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &xc;
Packit Service 37472d
  mw_mp_abs(&xc, &xc);
Packit Service 37472d
  if((res = mw_mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
  clean[++last] = &yc;
Packit Service 37472d
  mw_mp_abs(&yc, &yc);
Packit Service 37472d
Packit Service 37472d
  mw_mp_set(&gx, 1);
Packit Service 37472d
Packit Service 37472d
  /* Divide by two until at least one of them is even */
Packit Service 37472d
  while(mw_mp_iseven(&xc) && mw_mp_iseven(&yc)) {
Packit Service 37472d
    s_mw_mp_div_2(&xc);
Packit Service 37472d
    s_mw_mp_div_2(&yc);
Packit Service 37472d
    if((res = s_mw_mp_mul_2(&gx)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mw_mp_copy(&xc, &u);
Packit Service 37472d
  mw_mp_copy(&yc, &v);
Packit Service 37472d
  mw_mp_set(&A, 1); mw_mp_set(&D, 1);
Packit Service 37472d
Packit Service 37472d
  /* Loop through binary GCD algorithm */
Packit Service 37472d
  for(;;) {
Packit Service 37472d
    while(mw_mp_iseven(&u)) {
Packit Service 37472d
      s_mw_mp_div_2(&u);
Packit Service 37472d
Packit Service 37472d
      if(mw_mp_iseven(&A) && mw_mp_iseven(&B)) {
Packit Service 37472d
	s_mw_mp_div_2(&A); s_mw_mp_div_2(&B);
Packit Service 37472d
      } else {
Packit Service 37472d
	if((res = mw_mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
	s_mw_mp_div_2(&A);
Packit Service 37472d
	if((res = mw_mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
	s_mw_mp_div_2(&B);
Packit Service 37472d
      }
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    while(mw_mp_iseven(&v)) {
Packit Service 37472d
      s_mw_mp_div_2(&v);
Packit Service 37472d
Packit Service 37472d
      if(mw_mp_iseven(&C) && mw_mp_iseven(&D)) {
Packit Service 37472d
	s_mw_mp_div_2(&C); s_mw_mp_div_2(&D);
Packit Service 37472d
      } else {
Packit Service 37472d
	if((res = mw_mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
	s_mw_mp_div_2(&C);
Packit Service 37472d
	if((res = mw_mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
	s_mw_mp_div_2(&D);
Packit Service 37472d
      }
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    if(mw_mp_cmp(&u, &v) >= 0) {
Packit Service 37472d
      if((res = mw_mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
      if((res = mw_mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
      if((res = mw_mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
    } else {
Packit Service 37472d
      if((res = mw_mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
      if((res = mw_mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
      if((res = mw_mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    /* If we're done, copy results to output */
Packit Service 37472d
    if(mw_mp_cmw_mp_z(&u) == 0) {
Packit Service 37472d
      if(x)
Packit Service 37472d
	if((res = mw_mp_copy(&C, x)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
      if(y)
Packit Service 37472d
	if((res = mw_mp_copy(&D, y)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
      
Packit Service 37472d
      if(g)
Packit Service 37472d
	if((res = mw_mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
      break;
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
 CLEANUP:
Packit Service 37472d
  while(last >= 0)
Packit Service 37472d
    mw_mp_clear(clean[last--]);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_xgcd() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_invmod(a, m, c) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_invmod(a, m, c)
Packit Service 37472d
Packit Service 37472d
  Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
Packit Service 37472d
  This is equivalent to the question of whether (a, m) = 1.  If not,
Packit Service 37472d
  MP_UNDEF is returned, and there is no inverse.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_invmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int  g, x;
Packit Service 37472d
  mw_mp_sign sa;
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(a && m && c, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(a) == 0 || mw_mp_cmw_mp_z(m) == 0)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  sa = SIGN(a);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init(&g)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  if((res = mw_mp_init(&x)) != MP_OKAY)
Packit Service 37472d
    goto X;
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY)
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_d(&g, 1) != MP_EQ) {
Packit Service 37472d
    res = MP_UNDEF;
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  res = mw_mp_mod(&x, m, c);
Packit Service 37472d
  SIGN(c) = sa;
Packit Service 37472d
Packit Service 37472d
CLEANUP:
Packit Service 37472d
  mw_mp_clear(&x);
Packit Service 37472d
X:
Packit Service 37472d
  mw_mp_clear(&g);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_invmod() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
#endif /* if MP_NUMTH */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ mw_mp_print(mp, ofp) */
Packit Service 37472d
Packit Service 37472d
#if MP_IOFUNC
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_print(mp, ofp)
Packit Service 37472d
Packit Service 37472d
  Print a textual representation of the given mw_mp_int on the output
Packit Service 37472d
  stream 'ofp'.  Output is generated using the internal radix.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
void   mw_mp_print(mw_mp_int *mp, FILE *ofp)
Packit Service 37472d
{
Packit Service 37472d
  int   ix;
Packit Service 37472d
Packit Service 37472d
  if(mp == NULL || ofp == NULL)
Packit Service 37472d
    return;
Packit Service 37472d
Packit Service 37472d
  fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp);
Packit Service 37472d
Packit Service 37472d
  for(ix = USED(mp) - 1; ix >= 0; ix--) {
Packit Service 37472d
    fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_print() */
Packit Service 37472d
Packit Service 37472d
#endif /* if MP_IOFUNC */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* {{{ More I/O Functions */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_read_signed_bin(mp, str, len) */
Packit Service 37472d
Packit Service 37472d
/* 
Packit Service 37472d
   mw_mp_read_signed_bin(mp, str, len)
Packit Service 37472d
Packit Service 37472d
   Read in a raw value (base 256) into the given mw_mp_int
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err  mw_mp_read_signed_bin(mw_mp_int *mp, unsigned char *str, int len)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err         res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) {
Packit Service 37472d
    /* Get sign from first byte */
Packit Service 37472d
    if(str[0])
Packit Service 37472d
      SIGN(mp) = MP_NEG;
Packit Service 37472d
    else
Packit Service 37472d
      SIGN(mp) = MP_ZPOS;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_read_signed_bin() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_signed_bin_size(mp) */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_signed_bin_size(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(mp != NULL, 0);
Packit Service 37472d
Packit Service 37472d
  return mw_mp_unsigned_bin_size(mp) + 1;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_signed_bin_size() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_to_signed_bin(mp, str) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_to_signed_bin(mw_mp_int *mp, unsigned char *str)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  /* Caller responsible for allocating enough memory (use mw_mp_raw_size(mp)) */
Packit Service 37472d
  str[0] = (char)SIGN(mp);
Packit Service 37472d
Packit Service 37472d
  return mw_mp_to_unsigned_bin(mp, str + 1);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_to_signed_bin() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_read_unsigned_bin(mp, str, len) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_read_unsigned_bin(mp, str, len)
Packit Service 37472d
Packit Service 37472d
  Read in an unsigned value (base 256) into the given mw_mp_int
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err  mw_mp_read_unsigned_bin(mw_mp_int *mp, unsigned char *str, int len)
Packit Service 37472d
{
Packit Service 37472d
  int     ix;
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  mw_mp_zero(mp);
Packit Service 37472d
Packit Service 37472d
  for(ix = 0; ix < len; ix++) {
Packit Service 37472d
    if((res = s_mw_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    if((res = mw_mp_add_d(mp, str[ix], mp)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
  
Packit Service 37472d
} /* end mw_mp_read_unsigned_bin() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_unsigned_bin_size(mp) */
Packit Service 37472d
Packit Service 37472d
int     mw_mp_unsigned_bin_size(mw_mp_int *mp) 
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_digit   topdig;
Packit Service 37472d
  int        count;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL, 0);
Packit Service 37472d
Packit Service 37472d
  /* Special case for the value zero */
Packit Service 37472d
  if(USED(mp) == 1 && DIGIT(mp, 0) == 0)
Packit Service 37472d
    return 1;
Packit Service 37472d
Packit Service 37472d
  count = (USED(mp) - 1) * sizeof(mw_mp_digit);
Packit Service 37472d
  topdig = DIGIT(mp, USED(mp) - 1);
Packit Service 37472d
Packit Service 37472d
  while(topdig != 0) {
Packit Service 37472d
    ++count;
Packit Service 37472d
    topdig >>= CHAR_BIT;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return count;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_unsigned_bin_size() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_to_unsigned_bin(mp, str) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_to_unsigned_bin(mw_mp_int *mp, unsigned char *str)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_digit      *dp, *end, d;
Packit Service 37472d
  unsigned char *spos;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  dp = DIGITS(mp);
Packit Service 37472d
  end = dp + USED(mp) - 1;
Packit Service 37472d
  spos = str;
Packit Service 37472d
Packit Service 37472d
  /* Special case for zero, quick test */
Packit Service 37472d
  if(dp == end && *dp == 0) {
Packit Service 37472d
    *str = '\0';
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Generate digits in reverse order */
Packit Service 37472d
  while(dp < end) {
Packit Service 37472d
    int      ix;
Packit Service 37472d
Packit Service 37472d
    d = *dp;
Packit Service 37472d
    for(ix = 0; ix < sizeof(mw_mp_digit); ++ix) {
Packit Service 37472d
      *spos = d & UCHAR_MAX;
Packit Service 37472d
      d >>= CHAR_BIT;
Packit Service 37472d
      ++spos;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    ++dp;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Now handle last digit specially, high order zeroes are not written */
Packit Service 37472d
  d = *end;
Packit Service 37472d
  while(d != 0) {
Packit Service 37472d
    *spos = d & UCHAR_MAX;
Packit Service 37472d
    d >>= CHAR_BIT;
Packit Service 37472d
    ++spos;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Reverse everything to get digits in the correct order */
Packit Service 37472d
  while(--spos > str) {
Packit Service 37472d
    unsigned char t = *str;
Packit Service 37472d
    *str = *spos;
Packit Service 37472d
    *spos = t;
Packit Service 37472d
Packit Service 37472d
    ++str;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_to_unsigned_bin() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_count_bits(mp) */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_count_bits(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  int      len;
Packit Service 37472d
  mw_mp_digit d;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL, MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  len = DIGIT_BIT * (USED(mp) - 1);
Packit Service 37472d
  d = DIGIT(mp, USED(mp) - 1);
Packit Service 37472d
Packit Service 37472d
  while(d != 0) {
Packit Service 37472d
    ++len;
Packit Service 37472d
    d >>= 1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return len;
Packit Service 37472d
  
Packit Service 37472d
} /* end mw_mp_count_bits() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_read_radix(mp, str, radix) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_read_radix(mp, str, radix)
Packit Service 37472d
Packit Service 37472d
  Read an integer from the given string, and set mp to the resulting
Packit Service 37472d
  value.  The input is presumed to be in base 10.  Leading non-digit
Packit Service 37472d
  characters are ignored, and the function reads until a non-digit
Packit Service 37472d
  character or the end of the string.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err  mw_mp_read_radix(mw_mp_int *mp, unsigned char *str, int radix)
Packit Service 37472d
{
Packit Service 37472d
  int     ix = 0, val = 0;
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
  mw_mp_sign sig = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, 
Packit Service 37472d
	 MP_BADARG);
Packit Service 37472d
Packit Service 37472d
  mw_mp_zero(mp);
Packit Service 37472d
Packit Service 37472d
  /* Skip leading non-digit characters until a digit or '-' or '+' */
Packit Service 37472d
  while(str[ix] && 
Packit Service 37472d
	(s_mw_mp_tovalue(str[ix], radix) < 0) && 
Packit Service 37472d
	str[ix] != '-' &&
Packit Service 37472d
	str[ix] != '+') {
Packit Service 37472d
    ++ix;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(str[ix] == '-') {
Packit Service 37472d
    sig = MP_NEG;
Packit Service 37472d
    ++ix;
Packit Service 37472d
  } else if(str[ix] == '+') {
Packit Service 37472d
    sig = MP_ZPOS; /* this is the default anyway... */
Packit Service 37472d
    ++ix;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  while((val = s_mw_mp_tovalue(str[ix], radix)) >= 0) {
Packit Service 37472d
    if((res = s_mw_mp_mul_d(mp, radix)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
    if((res = s_mw_mp_add_d(mp, val)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
    ++ix;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(s_mw_mp_cmw_mp_d(mp, 0) == MP_EQ)
Packit Service 37472d
    SIGN(mp) = MP_ZPOS;
Packit Service 37472d
  else
Packit Service 37472d
    SIGN(mp) = sig;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_read_radix() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_radix_size(mp, radix) */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_radix_size(mw_mp_int *mp, int radix)
Packit Service 37472d
{
Packit Service 37472d
  int  len;
Packit Service 37472d
  ARGCHK(mp != NULL, 0);
Packit Service 37472d
Packit Service 37472d
  len = s_mw_mp_outlen(mw_mp_count_bits(mp), radix) + 1; /* for NUL terminator */
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(mp) < 0)
Packit Service 37472d
    ++len; /* for sign */
Packit Service 37472d
Packit Service 37472d
  return len;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_radix_size() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_value_radix_size(num, qty, radix) */
Packit Service 37472d
Packit Service 37472d
/* num = number of digits
Packit Service 37472d
   qty = number of bits per digit
Packit Service 37472d
   radix = target base
Packit Service 37472d
   
Packit Service 37472d
   Return the number of digits in the specified radix that would be
Packit Service 37472d
   needed to express 'num' digits of 'qty' bits each.
Packit Service 37472d
 */
Packit Service 37472d
int    mw_mp_value_radix_size(int num, int qty, int radix)
Packit Service 37472d
{
Packit Service 37472d
  ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0);
Packit Service 37472d
Packit Service 37472d
  return s_mw_mp_outlen(num * qty, radix);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_value_radix_size() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_toradix(mp, str, radix) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err mw_mp_toradix(mw_mp_int *mp, unsigned char *str, int radix)
Packit Service 37472d
{
Packit Service 37472d
  int  ix, pos = 0;
Packit Service 37472d
Packit Service 37472d
  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
Packit Service 37472d
  ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(mp) == MP_EQ) {
Packit Service 37472d
    str[0] = '0';
Packit Service 37472d
    str[1] = '\0';
Packit Service 37472d
  } else {
Packit Service 37472d
    mw_mp_err   res;
Packit Service 37472d
    mw_mp_int   tmp;
Packit Service 37472d
    mw_mp_sign  sgn;
Packit Service 37472d
    mw_mp_digit rem, rdx = (mw_mp_digit)radix;
Packit Service 37472d
    char     ch;
Packit Service 37472d
Packit Service 37472d
    if((res = mw_mp_init_copy(&tmp, mp)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    /* Save sign for later, and take absolute value */
Packit Service 37472d
    sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
    /* Generate output digits in reverse order      */
Packit Service 37472d
    while(mw_mp_cmw_mp_z(&tmp) != 0) {
Packit Service 37472d
      if((res = s_mw_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) {
Packit Service 37472d
	mw_mp_clear(&tmp);
Packit Service 37472d
	return res;
Packit Service 37472d
      }
Packit Service 37472d
Packit Service 37472d
      /* Generate digits, use capital letters */
Packit Service 37472d
      ch = s_mw_mp_todigit(rem, radix, 0);
Packit Service 37472d
Packit Service 37472d
      str[pos++] = ch;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    /* Add - sign if original value was negative */
Packit Service 37472d
    if(sgn == MP_NEG)
Packit Service 37472d
      str[pos++] = '-';
Packit Service 37472d
Packit Service 37472d
    /* Add trailing NUL to end the string        */
Packit Service 37472d
    str[pos--] = '\0';
Packit Service 37472d
Packit Service 37472d
    /* Reverse the digits and sign indicator     */
Packit Service 37472d
    ix = 0;
Packit Service 37472d
    while(ix < pos) {
Packit Service 37472d
      char tmp = str[ix];
Packit Service 37472d
Packit Service 37472d
      str[ix] = str[pos];
Packit Service 37472d
      str[pos] = tmp;
Packit Service 37472d
      ++ix;
Packit Service 37472d
      --pos;
Packit Service 37472d
    }
Packit Service 37472d
    
Packit Service 37472d
    mw_mp_clear(&tmp);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_toradix() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_char2value(ch, r) */
Packit Service 37472d
Packit Service 37472d
int    mw_mp_char2value(char ch, int r)
Packit Service 37472d
{
Packit Service 37472d
  return s_mw_mp_tovalue(ch, r);
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_tovalue() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ mw_mp_strerror(ec) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  mw_mp_strerror(ec)
Packit Service 37472d
Packit Service 37472d
  Return a string describing the meaning of error code 'ec'.  The
Packit Service 37472d
  string returned is allocated in static memory, so the caller should
Packit Service 37472d
  not attempt to modify or free the memory associated with this
Packit Service 37472d
  string.
Packit Service 37472d
 */
Packit Service 37472d
const char  *mw_mp_strerror(mw_mp_err ec)
Packit Service 37472d
{
Packit Service 37472d
  int   aec = (ec < 0) ? -ec : ec;
Packit Service 37472d
Packit Service 37472d
  /* Code values are negative, so the senses of these comparisons
Packit Service 37472d
     are accurate */
Packit Service 37472d
  if(ec < MP_LAST_CODE || ec > MP_OKAY) {
Packit Service 37472d
    return mw_mp_err_string[0];  /* unknown error code */
Packit Service 37472d
  } else {
Packit Service 37472d
    return mw_mp_err_string[aec + 1];
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
} /* end mw_mp_strerror() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*========================================================================*/
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* Static function definitions (internal use only)                        */
Packit Service 37472d
Packit Service 37472d
/* {{{ Memory management */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_grow(mp, min) */
Packit Service 37472d
Packit Service 37472d
/* Make sure there are at least 'min' digits allocated to mp              */
Packit Service 37472d
mw_mp_err   s_mw_mp_grow(mw_mp_int *mp, mw_mp_size min)
Packit Service 37472d
{
Packit Service 37472d
  if(min > ALLOC(mp)) {
Packit Service 37472d
    mw_mp_digit   *tmp;
Packit Service 37472d
Packit Service 37472d
    /* Set min to next nearest default precision block size */
Packit Service 37472d
    min = ((min + (s_mw_mp_defprec - 1)) / s_mw_mp_defprec) * s_mw_mp_defprec;
Packit Service 37472d
Packit Service 37472d
    if((tmp = s_mw_mp_alloc(min, sizeof(mw_mp_digit))) == NULL)
Packit Service 37472d
      return MP_MEM;
Packit Service 37472d
Packit Service 37472d
    s_mw_mp_copy(DIGITS(mp), tmp, USED(mp));
Packit Service 37472d
Packit Service 37472d
#if MP_CRYPTO
Packit Service 37472d
    s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
Packit Service 37472d
#endif
Packit Service 37472d
    s_mw_mp_free(DIGITS(mp));
Packit Service 37472d
    DIGITS(mp) = tmp;
Packit Service 37472d
    ALLOC(mp) = min;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_grow() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_pad(mp, min) */
Packit Service 37472d
Packit Service 37472d
/* Make sure the used size of mp is at least 'min', growing if needed     */
Packit Service 37472d
mw_mp_err   s_mw_mp_pad(mw_mp_int *mp, mw_mp_size min)
Packit Service 37472d
{
Packit Service 37472d
  if(min > USED(mp)) {
Packit Service 37472d
    mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
    /* Make sure there is room to increase precision  */
Packit Service 37472d
    if(min > ALLOC(mp) && (res = s_mw_mp_grow(mp, min)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    /* Increase precision; should already be 0-filled */
Packit Service 37472d
    USED(mp) = min;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_pad() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_setz(dp, count) */
Packit Service 37472d
Packit Service 37472d
#if MP_MACRO == 0
Packit Service 37472d
/* Set 'count' digits pointed to by dp to be zeroes                       */
Packit Service 37472d
void s_mw_mp_setz(mw_mp_digit *dp, mw_mp_size count)
Packit Service 37472d
{
Packit Service 37472d
#if MP_MEMSET == 0
Packit Service 37472d
  int  ix;
Packit Service 37472d
Packit Service 37472d
  for(ix = 0; ix < count; ix++)
Packit Service 37472d
    dp[ix] = 0;
Packit Service 37472d
#else
Packit Service 37472d
  memset(dp, 0, count * sizeof(mw_mp_digit));
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_setz() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_copy(sp, dp, count) */
Packit Service 37472d
Packit Service 37472d
#if MP_MACRO == 0
Packit Service 37472d
/* Copy 'count' digits from sp to dp                                      */
Packit Service 37472d
void s_mw_mp_copy(mw_mp_digit *sp, mw_mp_digit *dp, mw_mp_size count)
Packit Service 37472d
{
Packit Service 37472d
#if MP_MEMCPY == 0
Packit Service 37472d
  int  ix;
Packit Service 37472d
Packit Service 37472d
  for(ix = 0; ix < count; ix++)
Packit Service 37472d
    dp[ix] = sp[ix];
Packit Service 37472d
#else
Packit Service 37472d
  memcpy(dp, sp, count * sizeof(mw_mp_digit));
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_copy() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_alloc(nb, ni) */
Packit Service 37472d
Packit Service 37472d
#if MP_MACRO == 0
Packit Service 37472d
/* Allocate ni records of nb bytes each, and return a pointer to that     */
Packit Service 37472d
void    *s_mw_mp_alloc(size_t nb, size_t ni)
Packit Service 37472d
{
Packit Service 37472d
  return calloc(nb, ni);
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_alloc() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_free(ptr) */
Packit Service 37472d
Packit Service 37472d
#if MP_MACRO == 0
Packit Service 37472d
/* Free the memory pointed to by ptr                                      */
Packit Service 37472d
void     s_mw_mp_free(void *ptr)
Packit Service 37472d
{
Packit Service 37472d
  if(ptr)
Packit Service 37472d
    free(ptr);
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_free() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_clamp(mp) */
Packit Service 37472d
Packit Service 37472d
/* Remove leading zeroes from the given value                             */
Packit Service 37472d
void     s_mw_mp_clamp(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_size   du = USED(mp);
Packit Service 37472d
  mw_mp_digit *zp = DIGITS(mp) + du - 1;
Packit Service 37472d
Packit Service 37472d
  while(du > 1 && !*zp--)
Packit Service 37472d
    --du;
Packit Service 37472d
Packit Service 37472d
  if(du == 1 && *zp == 0)
Packit Service 37472d
    SIGN(mp) = MP_ZPOS;
Packit Service 37472d
Packit Service 37472d
  USED(mp) = du;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_clamp() */
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_exch(a, b) */
Packit Service 37472d
Packit Service 37472d
/* Exchange the data for a and b; (b, a) = (a, b)                         */
Packit Service 37472d
void     s_mw_mp_exch(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   tmp;
Packit Service 37472d
Packit Service 37472d
  tmp = *a;
Packit Service 37472d
  *a = *b;
Packit Service 37472d
  *b = tmp;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_exch() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Arithmetic helpers */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_lshd(mp, p) */
Packit Service 37472d
Packit Service 37472d
/* 
Packit Service 37472d
   Shift mp leftward by p digits, growing if needed, and zero-filling
Packit Service 37472d
   the in-shifted digits at the right end.  This is a convenient
Packit Service 37472d
   alternative to multiplication by powers of the radix
Packit Service 37472d
 */   
Packit Service 37472d
Packit Service 37472d
mw_mp_err   s_mw_mp_lshd(mw_mp_int *mp, mw_mp_size p)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_size  pos;
Packit Service 37472d
  mw_mp_digit *dp;
Packit Service 37472d
  int     ix;
Packit Service 37472d
Packit Service 37472d
  if(p == 0)
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
  if((res = s_mw_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  pos = USED(mp) - 1;
Packit Service 37472d
  dp = DIGITS(mp);
Packit Service 37472d
Packit Service 37472d
  /* Shift all the significant figures over as needed */
Packit Service 37472d
  for(ix = pos - p; ix >= 0; ix--) 
Packit Service 37472d
    dp[ix + p] = dp[ix];
Packit Service 37472d
Packit Service 37472d
  /* Fill the bottom digits with zeroes */
Packit Service 37472d
  for(ix = 0; ix < p; ix++)
Packit Service 37472d
    dp[ix] = 0;
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_lshd() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_rshd(mp, p) */
Packit Service 37472d
Packit Service 37472d
/* 
Packit Service 37472d
   Shift mp rightward by p digits.  Maintains the invariant that
Packit Service 37472d
   digits above the precision are all zero.  Digits shifted off the
Packit Service 37472d
   end are lost.  Cannot fail.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
void     s_mw_mp_rshd(mw_mp_int *mp, mw_mp_size p)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_size  ix;
Packit Service 37472d
  mw_mp_digit *dp;
Packit Service 37472d
Packit Service 37472d
  if(p == 0)
Packit Service 37472d
    return;
Packit Service 37472d
Packit Service 37472d
  /* Shortcut when all digits are to be shifted off */
Packit Service 37472d
  if(p >= USED(mp)) {
Packit Service 37472d
    s_mw_mp_setz(DIGITS(mp), ALLOC(mp));
Packit Service 37472d
    USED(mp) = 1;
Packit Service 37472d
    SIGN(mp) = MP_ZPOS;
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Shift all the significant figures over as needed */
Packit Service 37472d
  dp = DIGITS(mp);
Packit Service 37472d
  for(ix = p; ix < USED(mp); ix++)
Packit Service 37472d
    dp[ix - p] = dp[ix];
Packit Service 37472d
Packit Service 37472d
  /* Fill the top digits with zeroes */
Packit Service 37472d
  ix -= p;
Packit Service 37472d
  while(ix < USED(mp))
Packit Service 37472d
    dp[ix++] = 0;
Packit Service 37472d
Packit Service 37472d
  /* Strip off any leading zeroes    */
Packit Service 37472d
  s_mw_mp_clamp(mp);
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_rshd() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_div_2(mp) */
Packit Service 37472d
Packit Service 37472d
/* Divide by two -- take advantage of radix properties to do it fast      */
Packit Service 37472d
void     s_mw_mp_div_2(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  s_mw_mp_div_2d(mp, 1);
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_div_2() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_mul_2(mp) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err s_mw_mp_mul_2(mw_mp_int *mp)
Packit Service 37472d
{
Packit Service 37472d
  int      ix;
Packit Service 37472d
  mw_mp_digit kin = 0, kout, *dp = DIGITS(mp);
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
Packit Service 37472d
  /* Shift digits leftward by 1 bit */
Packit Service 37472d
  for(ix = 0; ix < USED(mp); ix++) {
Packit Service 37472d
    kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1;
Packit Service 37472d
    dp[ix] = (dp[ix] << 1) | kin;
Packit Service 37472d
Packit Service 37472d
    kin = kout;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Deal with rollover from last digit */
Packit Service 37472d
  if(kin) {
Packit Service 37472d
    if(ix >= ALLOC(mp)) {
Packit Service 37472d
      if((res = s_mw_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
Packit Service 37472d
	return res;
Packit Service 37472d
      dp = DIGITS(mp);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    dp[ix] = kin;
Packit Service 37472d
    USED(mp) += 1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_mul_2() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_mod_2d(mp, d) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Remainder the integer by 2^d, where d is a number of bits.  This
Packit Service 37472d
  amounts to a bitwise AND of the value, and does not require the full
Packit Service 37472d
  division code
Packit Service 37472d
 */
Packit Service 37472d
void     s_mw_mp_mod_2d(mw_mp_int *mp, mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  unsigned int  ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
Packit Service 37472d
  unsigned int  ix;
Packit Service 37472d
  mw_mp_digit      dmask, *dp = DIGITS(mp);
Packit Service 37472d
Packit Service 37472d
  if(ndig >= USED(mp))
Packit Service 37472d
    return;
Packit Service 37472d
Packit Service 37472d
  /* Flush all the bits above 2^d in its digit */
Packit Service 37472d
  dmask = (1 << nbit) - 1;
Packit Service 37472d
  dp[ndig] &= dmask;
Packit Service 37472d
Packit Service 37472d
  /* Flush all digits above the one with 2^d in it */
Packit Service 37472d
  for(ix = ndig + 1; ix < USED(mp); ix++)
Packit Service 37472d
    dp[ix] = 0;
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(mp);
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_mod_2d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_mul_2d(mp, d) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Multiply by the integer 2^d, where d is a number of bits.  This
Packit Service 37472d
  amounts to a bitwise shift of the value, and does not require the
Packit Service 37472d
  full multiplication code.
Packit Service 37472d
 */
Packit Service 37472d
mw_mp_err    s_mw_mp_mul_2d(mw_mp_int *mp, mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_digit save, next, mask, *dp;
Packit Service 37472d
  mw_mp_size  used;
Packit Service 37472d
  int      ix;
Packit Service 37472d
Packit Service 37472d
  if((res = s_mw_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  dp = DIGITS(mp); used = USED(mp);
Packit Service 37472d
  d %= DIGIT_BIT;
Packit Service 37472d
Packit Service 37472d
  mask = (1 << d) - 1;
Packit Service 37472d
Packit Service 37472d
  /* If the shift requires another digit, make sure we've got one to
Packit Service 37472d
     work with */
Packit Service 37472d
  if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) {
Packit Service 37472d
    if((res = s_mw_mp_grow(mp, used + 1)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
    dp = DIGITS(mp);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Do the shifting... */
Packit Service 37472d
  save = 0;
Packit Service 37472d
  for(ix = 0; ix < used; ix++) {
Packit Service 37472d
    next = (dp[ix] >> (DIGIT_BIT - d)) & mask;
Packit Service 37472d
    dp[ix] = (dp[ix] << d) | save;
Packit Service 37472d
    save = next;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* If, at this point, we have a nonzero carryout into the next
Packit Service 37472d
     digit, we'll increase the size by one digit, and store it...
Packit Service 37472d
   */
Packit Service 37472d
  if(save) {
Packit Service 37472d
    dp[used] = save;
Packit Service 37472d
    USED(mp) += 1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(mp);
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_mul_2d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_div_2d(mp, d) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Divide the integer by 2^d, where d is a number of bits.  This
Packit Service 37472d
  amounts to a bitwise shift of the value, and does not require the
Packit Service 37472d
  full division code (used in Barrett reduction, see below)
Packit Service 37472d
 */
Packit Service 37472d
void     s_mw_mp_div_2d(mw_mp_int *mp, mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  int       ix;
Packit Service 37472d
  mw_mp_digit  save, next, mask, *dp = DIGITS(mp);
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_rshd(mp, d / DIGIT_BIT);
Packit Service 37472d
  d %= DIGIT_BIT;
Packit Service 37472d
Packit Service 37472d
  mask = (1 << d) - 1;
Packit Service 37472d
Packit Service 37472d
  save = 0;
Packit Service 37472d
  for(ix = USED(mp) - 1; ix >= 0; ix--) {
Packit Service 37472d
    next = dp[ix] & mask;
Packit Service 37472d
    dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d));
Packit Service 37472d
    save = next;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(mp);
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_div_2d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_norm(a, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  s_mw_mp_norm(a, b)
Packit Service 37472d
Packit Service 37472d
  Normalize a and b for division, where b is the divisor.  In order
Packit Service 37472d
  that we might make good guesses for quotient digits, we want the
Packit Service 37472d
  leading digit of b to be at least half the radix, which we
Packit Service 37472d
  accomplish by multiplying a and b by a constant.  This constant is
Packit Service 37472d
  returned (so that it can be divided back out of the remainder at the
Packit Service 37472d
  end of the division process).
Packit Service 37472d
Packit Service 37472d
  We multiply by the smallest power of 2 that gives us a leading digit
Packit Service 37472d
  at least half the radix.  By choosing a power of 2, we simplify the 
Packit Service 37472d
  multiplication and division steps to simple shifts.
Packit Service 37472d
 */
Packit Service 37472d
mw_mp_digit s_mw_mp_norm(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_digit  t, d = 0;
Packit Service 37472d
Packit Service 37472d
  t = DIGIT(b, USED(b) - 1);
Packit Service 37472d
  while(t < (RADIX / 2)) {
Packit Service 37472d
    t <<= 1;
Packit Service 37472d
    ++d;
Packit Service 37472d
  }
Packit Service 37472d
    
Packit Service 37472d
  if(d != 0) {
Packit Service 37472d
    s_mw_mp_mul_2d(a, d);
Packit Service 37472d
    s_mw_mp_mul_2d(b, d);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return d;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_norm() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Primitive digit arithmetic */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_add_d(mp, d) */
Packit Service 37472d
Packit Service 37472d
/* Add d to |mp| in place                                                 */
Packit Service 37472d
mw_mp_err   s_mw_mp_add_d(mw_mp_int *mp, mw_mp_digit d)    /* unsigned digit addition */
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word   w, k = 0;
Packit Service 37472d
  mw_mp_size   ix = 1, used = USED(mp);
Packit Service 37472d
  mw_mp_digit *dp = DIGITS(mp);
Packit Service 37472d
Packit Service 37472d
  w = dp[0] + d;
Packit Service 37472d
  dp[0] = ACCUM(w);
Packit Service 37472d
  k = CARRYOUT(w);
Packit Service 37472d
Packit Service 37472d
  while(ix < used && k) {
Packit Service 37472d
    w = dp[ix] + k;
Packit Service 37472d
    dp[ix] = ACCUM(w);
Packit Service 37472d
    k = CARRYOUT(w);
Packit Service 37472d
    ++ix;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(k != 0) {
Packit Service 37472d
    mw_mp_err  res;
Packit Service 37472d
Packit Service 37472d
    if((res = s_mw_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    DIGIT(mp, ix) = k;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_add_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_sub_d(mp, d) */
Packit Service 37472d
Packit Service 37472d
/* Subtract d from |mp| in place, assumes |mp| > d                        */
Packit Service 37472d
mw_mp_err   s_mw_mp_sub_d(mw_mp_int *mp, mw_mp_digit d)    /* unsigned digit subtract */
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word   w, b = 0;
Packit Service 37472d
  mw_mp_size   ix = 1, used = USED(mp);
Packit Service 37472d
  mw_mp_digit *dp = DIGITS(mp);
Packit Service 37472d
Packit Service 37472d
  /* Compute initial subtraction    */
Packit Service 37472d
  w = (RADIX + dp[0]) - d;
Packit Service 37472d
  b = CARRYOUT(w) ? 0 : 1;
Packit Service 37472d
  dp[0] = ACCUM(w);
Packit Service 37472d
Packit Service 37472d
  /* Propagate borrows leftward     */
Packit Service 37472d
  while(b && ix < used) {
Packit Service 37472d
    w = (RADIX + dp[ix]) - b;
Packit Service 37472d
    b = CARRYOUT(w) ? 0 : 1;
Packit Service 37472d
    dp[ix] = ACCUM(w);
Packit Service 37472d
    ++ix;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Remove leading zeroes          */
Packit Service 37472d
  s_mw_mp_clamp(mp);
Packit Service 37472d
Packit Service 37472d
  /* If we have a borrow out, it's a violation of the input invariant */
Packit Service 37472d
  if(b)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
  else
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_sub_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_mul_d(a, d) */
Packit Service 37472d
Packit Service 37472d
/* Compute a = a * d, single digit multiplication                         */
Packit Service 37472d
mw_mp_err   s_mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word w, k = 0;
Packit Service 37472d
  mw_mp_size ix, max;
Packit Service 37472d
  mw_mp_err  res;
Packit Service 37472d
  mw_mp_digit *dp = DIGITS(a);
Packit Service 37472d
Packit Service 37472d
  /*
Packit Service 37472d
    Single-digit multiplication will increase the precision of the
Packit Service 37472d
    output by at most one digit.  However, we can detect when this
Packit Service 37472d
    will happen -- if the high-order digit of a, times d, gives a
Packit Service 37472d
    two-digit result, then the precision of the result will increase;
Packit Service 37472d
    otherwise it won't.  We use this fact to avoid calling s_mw_mp_pad()
Packit Service 37472d
    unless absolutely necessary.
Packit Service 37472d
   */
Packit Service 37472d
  max = USED(a);
Packit Service 37472d
  w = dp[max - 1] * d;
Packit Service 37472d
  if(CARRYOUT(w) != 0) {
Packit Service 37472d
    if((res = s_mw_mp_pad(a, max + 1)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
    dp = DIGITS(a);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  for(ix = 0; ix < max; ix++) {
Packit Service 37472d
    w = (dp[ix] * d) + k;
Packit Service 37472d
    dp[ix] = ACCUM(w);
Packit Service 37472d
    k = CARRYOUT(w);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* If there is a precision increase, take care of it here; the above
Packit Service 37472d
     test guarantees we have enough storage to do this safely.
Packit Service 37472d
   */
Packit Service 37472d
  if(k) {
Packit Service 37472d
    dp[max] = k; 
Packit Service 37472d
    USED(a) = max + 1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(a);
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
  
Packit Service 37472d
} /* end s_mw_mp_mul_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_div_d(mp, d, r) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  s_mw_mp_div_d(mp, d, r)
Packit Service 37472d
Packit Service 37472d
  Compute the quotient mp = mp / d and remainder r = mp mod d, for a
Packit Service 37472d
  single digit d.  If r is null, the remainder will be discarded.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err   s_mw_mp_div_d(mw_mp_int *mp, mw_mp_digit d, mw_mp_digit *r)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word   w = 0, t;
Packit Service 37472d
  mw_mp_int    quot;
Packit Service 37472d
  mw_mp_err    res;
Packit Service 37472d
  mw_mp_digit *dp = DIGITS(mp), *qp;
Packit Service 37472d
  int       ix;
Packit Service 37472d
Packit Service 37472d
  if(d == 0)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  /* Make room for the quotient */
Packit Service 37472d
  if((res = mw_mp_init_size(&quot, USED(mp))) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  USED(&quot) = USED(mp); /* so clamping will work below */
Packit Service 37472d
  qp = DIGITS(");
Packit Service 37472d
Packit Service 37472d
  /* Divide without subtraction */
Packit Service 37472d
  for(ix = USED(mp) - 1; ix >= 0; ix--) {
Packit Service 37472d
    w = (w << DIGIT_BIT) | dp[ix];
Packit Service 37472d
Packit Service 37472d
    if(w >= d) {
Packit Service 37472d
      t = w / d;
Packit Service 37472d
      w = w % d;
Packit Service 37472d
    } else {
Packit Service 37472d
      t = 0;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    qp[ix] = t;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Deliver the remainder, if desired */
Packit Service 37472d
  if(r)
Packit Service 37472d
    *r = w;
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(");
Packit Service 37472d
  mw_mp_exch(&quot, mp);
Packit Service 37472d
  mw_mp_clear(");
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_div_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Primitive full arithmetic */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_add(a, b) */
Packit Service 37472d
Packit Service 37472d
/* Compute a = |a| + |b|                                                  */
Packit Service 37472d
mw_mp_err   s_mw_mp_add(mw_mp_int *a, mw_mp_int *b)        /* magnitude addition      */
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word   w = 0;
Packit Service 37472d
  mw_mp_digit *pa, *pb;
Packit Service 37472d
  mw_mp_size   ix, used = USED(b);
Packit Service 37472d
  mw_mp_err    res;
Packit Service 37472d
Packit Service 37472d
  /* Make sure a has enough precision for the output value */
Packit Service 37472d
  if((used > USED(a)) && (res = s_mw_mp_pad(a, used)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  /*
Packit Service 37472d
    Add up all digits up to the precision of b.  If b had initially
Packit Service 37472d
    the same precision as a, or greater, we took care of it by the
Packit Service 37472d
    padding step above, so there is no problem.  If b had initially
Packit Service 37472d
    less precision, we'll have to make sure the carry out is duly
Packit Service 37472d
    propagated upward among the higher-order digits of the sum.
Packit Service 37472d
   */
Packit Service 37472d
  pa = DIGITS(a);
Packit Service 37472d
  pb = DIGITS(b);
Packit Service 37472d
  for(ix = 0; ix < used; ++ix) {
Packit Service 37472d
    w += *pa + *pb++;
Packit Service 37472d
    *pa++ = ACCUM(w);
Packit Service 37472d
    w = CARRYOUT(w);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* If we run out of 'b' digits before we're actually done, make
Packit Service 37472d
     sure the carries get propagated upward...  
Packit Service 37472d
   */
Packit Service 37472d
  used = USED(a);
Packit Service 37472d
  while(w && ix < used) {
Packit Service 37472d
    w += *pa;
Packit Service 37472d
    *pa++ = ACCUM(w);
Packit Service 37472d
    w = CARRYOUT(w);
Packit Service 37472d
    ++ix;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* If there's an overall carry out, increase precision and include
Packit Service 37472d
     it.  We could have done this initially, but why touch the memory
Packit Service 37472d
     allocator unless we're sure we have to?
Packit Service 37472d
   */
Packit Service 37472d
  if(w) {
Packit Service 37472d
    if((res = s_mw_mp_pad(a, used + 1)) != MP_OKAY)
Packit Service 37472d
      return res;
Packit Service 37472d
Packit Service 37472d
    DIGIT(a, ix) = w;  /* pa may not be valid after s_mw_mp_pad() call */
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_add() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_sub(a, b) */
Packit Service 37472d
Packit Service 37472d
/* Compute a = |a| - |b|, assumes |a| >= |b|                              */
Packit Service 37472d
mw_mp_err   s_mw_mp_sub(mw_mp_int *a, mw_mp_int *b)        /* magnitude subtract      */
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word   w = 0;
Packit Service 37472d
  mw_mp_digit *pa, *pb;
Packit Service 37472d
  mw_mp_size   ix, used = USED(b);
Packit Service 37472d
Packit Service 37472d
  /*
Packit Service 37472d
    Subtract and propagate borrow.  Up to the precision of b, this
Packit Service 37472d
    accounts for the digits of b; after that, we just make sure the
Packit Service 37472d
    carries get to the right place.  This saves having to pad b out to
Packit Service 37472d
    the precision of a just to make the loops work right...
Packit Service 37472d
   */
Packit Service 37472d
  pa = DIGITS(a);
Packit Service 37472d
  pb = DIGITS(b);
Packit Service 37472d
Packit Service 37472d
  for(ix = 0; ix < used; ++ix) {
Packit Service 37472d
    w = (RADIX + *pa) - w - *pb++;
Packit Service 37472d
    *pa++ = ACCUM(w);
Packit Service 37472d
    w = CARRYOUT(w) ? 0 : 1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  used = USED(a);
Packit Service 37472d
  while(ix < used) {
Packit Service 37472d
    w = RADIX + *pa - w;
Packit Service 37472d
    *pa++ = ACCUM(w);
Packit Service 37472d
    w = CARRYOUT(w) ? 0 : 1;
Packit Service 37472d
    ++ix;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Clobber any leading zeroes we created    */
Packit Service 37472d
  s_mw_mp_clamp(a);
Packit Service 37472d
Packit Service 37472d
  /* 
Packit Service 37472d
     If there was a borrow out, then |b| > |a| in violation
Packit Service 37472d
     of our input invariant.  We've already done the work,
Packit Service 37472d
     but we'll at least complain about it...
Packit Service 37472d
   */
Packit Service 37472d
  if(w)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
  else
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_sub() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_mul(a, b) */
Packit Service 37472d
Packit Service 37472d
/* Compute a = |a| * |b|                                                  */
Packit Service 37472d
mw_mp_err   s_mw_mp_mul(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word   w, k = 0;
Packit Service 37472d
  mw_mp_int    tmp;
Packit Service 37472d
  mw_mp_err    res;
Packit Service 37472d
  mw_mp_size   ix, jx, ua = USED(a), ub = USED(b);
Packit Service 37472d
  mw_mp_digit *pa, *pb, *pt, *pbt;
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init_size(&tmp, ua + ub)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  /* This has the effect of left-padding with zeroes... */
Packit Service 37472d
  USED(&tmp) = ua + ub;
Packit Service 37472d
Packit Service 37472d
  /* We're going to need the base value each iteration */
Packit Service 37472d
  pbt = DIGITS(&tmp);
Packit Service 37472d
Packit Service 37472d
  /* Outer loop:  Digits of b */
Packit Service 37472d
Packit Service 37472d
  pb = DIGITS(b);
Packit Service 37472d
  for(ix = 0; ix < ub; ++ix, ++pb) {
Packit Service 37472d
    if(*pb == 0) 
Packit Service 37472d
      continue;
Packit Service 37472d
Packit Service 37472d
    /* Inner product:  Digits of a */
Packit Service 37472d
    pa = DIGITS(a);
Packit Service 37472d
    for(jx = 0; jx < ua; ++jx, ++pa) {
Packit Service 37472d
      pt = pbt + ix + jx;
Packit Service 37472d
      w = *pb * *pa + k + *pt;
Packit Service 37472d
      *pt = ACCUM(w);
Packit Service 37472d
      k = CARRYOUT(w);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    pbt[ix + jx] = k;
Packit Service 37472d
    k = 0;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(&tmp);
Packit Service 37472d
  s_mw_mp_exch(&tmp, a);
Packit Service 37472d
Packit Service 37472d
  mw_mp_clear(&tmp);
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_mul() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_kmul(a, b, out, len) */
Packit Service 37472d
Packit Service 37472d
#if 0
Packit Service 37472d
void   s_mw_mp_kmul(mw_mp_digit *a, mw_mp_digit *b, mw_mp_digit *out, mw_mp_size len)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word   w, k = 0;
Packit Service 37472d
  mw_mp_size   ix, jx;
Packit Service 37472d
  mw_mp_digit *pa, *pt;
Packit Service 37472d
Packit Service 37472d
  for(ix = 0; ix < len; ++ix, ++b) {
Packit Service 37472d
    if(*b == 0)
Packit Service 37472d
      continue;
Packit Service 37472d
    
Packit Service 37472d
    pa = a;
Packit Service 37472d
    for(jx = 0; jx < len; ++jx, ++pa) {
Packit Service 37472d
      pt = out + ix + jx;
Packit Service 37472d
      w = *b * *pa + k + *pt;
Packit Service 37472d
      *pt = ACCUM(w);
Packit Service 37472d
      k = CARRYOUT(w);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    out[ix + jx] = k;
Packit Service 37472d
    k = 0;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_kmul() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_sqr(a) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Computes the square of a, in place.  This can be done more
Packit Service 37472d
  efficiently than a general multiplication, because many of the
Packit Service 37472d
  computation steps are redundant when squaring.  The inner product
Packit Service 37472d
  step is a bit more complicated, but we save a fair number of
Packit Service 37472d
  iterations of the multiplication loop.
Packit Service 37472d
 */
Packit Service 37472d
#if MP_SQUARE
Packit Service 37472d
mw_mp_err   s_mw_mp_sqr(mw_mp_int *a)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_word  w, k = 0;
Packit Service 37472d
  mw_mp_int   tmp;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_size  ix, jx, kx, used = USED(a);
Packit Service 37472d
  mw_mp_digit *pa1, *pa2, *pt, *pbt;
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init_size(&tmp, 2 * used)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  /* Left-pad with zeroes */
Packit Service 37472d
  USED(&tmp) = 2 * used;
Packit Service 37472d
Packit Service 37472d
  /* We need the base value each time through the loop */
Packit Service 37472d
  pbt = DIGITS(&tmp);
Packit Service 37472d
Packit Service 37472d
  pa1 = DIGITS(a);
Packit Service 37472d
  for(ix = 0; ix < used; ++ix, ++pa1) {
Packit Service 37472d
    if(*pa1 == 0)
Packit Service 37472d
      continue;
Packit Service 37472d
Packit Service 37472d
    w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1);
Packit Service 37472d
Packit Service 37472d
    pbt[ix + ix] = ACCUM(w);
Packit Service 37472d
    k = CARRYOUT(w);
Packit Service 37472d
Packit Service 37472d
    /*
Packit Service 37472d
      The inner product is computed as:
Packit Service 37472d
Packit Service 37472d
         (C, S) = t[i,j] + 2 a[i] a[j] + C
Packit Service 37472d
Packit Service 37472d
      This can overflow what can be represented in an mw_mp_word, and
Packit Service 37472d
      since C arithmetic does not provide any way to check for
Packit Service 37472d
      overflow, we have to check explicitly for overflow conditions
Packit Service 37472d
      before they happen.
Packit Service 37472d
     */
Packit Service 37472d
    for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) {
Packit Service 37472d
      mw_mp_word  u = 0, v;
Packit Service 37472d
      
Packit Service 37472d
      /* Store this in a temporary to avoid indirections later */
Packit Service 37472d
      pt = pbt + ix + jx;
Packit Service 37472d
Packit Service 37472d
      /* Compute the multiplicative step */
Packit Service 37472d
      w = *pa1 * *pa2;
Packit Service 37472d
Packit Service 37472d
      /* If w is more than half MP_WORD_MAX, the doubling will
Packit Service 37472d
	 overflow, and we need to record a carry out into the next
Packit Service 37472d
	 word */
Packit Service 37472d
      u = (w >> (MP_WORD_BIT - 1)) & 1;
Packit Service 37472d
Packit Service 37472d
      /* Double what we've got, overflow will be ignored as defined
Packit Service 37472d
	 for C arithmetic (we've already noted if it is to occur)
Packit Service 37472d
       */
Packit Service 37472d
      w *= 2;
Packit Service 37472d
Packit Service 37472d
      /* Compute the additive step */
Packit Service 37472d
      v = *pt + k;
Packit Service 37472d
Packit Service 37472d
      /* If we do not already have an overflow carry, check to see
Packit Service 37472d
	 if the addition will cause one, and set the carry out if so 
Packit Service 37472d
       */
Packit Service 37472d
      u |= ((MP_WORD_MAX - v) < w);
Packit Service 37472d
Packit Service 37472d
      /* Add in the rest, again ignoring overflow */
Packit Service 37472d
      w += v;
Packit Service 37472d
Packit Service 37472d
      /* Set the i,j digit of the output */
Packit Service 37472d
      *pt = ACCUM(w);
Packit Service 37472d
Packit Service 37472d
      /* Save carry information for the next iteration of the loop.
Packit Service 37472d
	 This is why k must be an mw_mp_word, instead of an mw_mp_digit */
Packit Service 37472d
      k = CARRYOUT(w) | (u << DIGIT_BIT);
Packit Service 37472d
Packit Service 37472d
    } /* for(jx ...) */
Packit Service 37472d
Packit Service 37472d
    /* Set the last digit in the cycle and reset the carry */
Packit Service 37472d
    k = DIGIT(&tmp, ix + jx) + k;
Packit Service 37472d
    pbt[ix + jx] = ACCUM(k);
Packit Service 37472d
    k = CARRYOUT(k);
Packit Service 37472d
Packit Service 37472d
    /* If we are carrying out, propagate the carry to the next digit
Packit Service 37472d
       in the output.  This may cascade, so we have to be somewhat
Packit Service 37472d
       circumspect -- but we will have enough precision in the output
Packit Service 37472d
       that we won't overflow 
Packit Service 37472d
     */
Packit Service 37472d
    kx = 1;
Packit Service 37472d
    while(k) {
Packit Service 37472d
      k = pbt[ix + jx + kx] + 1;
Packit Service 37472d
      pbt[ix + jx + kx] = ACCUM(k);
Packit Service 37472d
      k = CARRYOUT(k);
Packit Service 37472d
      ++kx;
Packit Service 37472d
    }
Packit Service 37472d
  } /* for(ix ...) */
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(&tmp);
Packit Service 37472d
  s_mw_mp_exch(&tmp, a);
Packit Service 37472d
Packit Service 37472d
  mw_mp_clear(&tmp);
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_sqr() */
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_div(a, b) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  s_mw_mp_div(a, b)
Packit Service 37472d
Packit Service 37472d
  Compute a = a / b and b = a mod b.  Assumes b > a.
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err   s_mw_mp_div(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   quot, rem, t;
Packit Service 37472d
  mw_mp_word  q;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_digit d;
Packit Service 37472d
  int      ix;
Packit Service 37472d
Packit Service 37472d
  if(mw_mp_cmw_mp_z(b) == 0)
Packit Service 37472d
    return MP_RANGE;
Packit Service 37472d
Packit Service 37472d
  /* Shortcut if b is power of two */
Packit Service 37472d
  if((ix = s_mw_mp_ispow2(b)) >= 0) {
Packit Service 37472d
    mw_mp_copy(a, b);  /* need this for remainder */
Packit Service 37472d
    s_mw_mp_div_2d(a, (mw_mp_digit)ix);
Packit Service 37472d
    s_mw_mp_mod_2d(b, (mw_mp_digit)ix);
Packit Service 37472d
Packit Service 37472d
    return MP_OKAY;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Allocate space to store the quotient */
Packit Service 37472d
  if((res = mw_mp_init_size(&quot, USED(a))) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  /* A working temporary for division     */
Packit Service 37472d
  if((res = mw_mp_init_size(&t, USED(a))) != MP_OKAY)
Packit Service 37472d
    goto T;
Packit Service 37472d
Packit Service 37472d
  /* Allocate space for the remainder     */
Packit Service 37472d
  if((res = mw_mp_init_size(&rem, USED(a))) != MP_OKAY)
Packit Service 37472d
    goto REM;
Packit Service 37472d
Packit Service 37472d
  /* Normalize to optimize guessing       */
Packit Service 37472d
  d = s_mw_mp_norm(a, b);
Packit Service 37472d
Packit Service 37472d
  /* Perform the division itself...woo!   */
Packit Service 37472d
  ix = USED(a) - 1;
Packit Service 37472d
Packit Service 37472d
  while(ix >= 0) {
Packit Service 37472d
    /* Find a partial substring of a which is at least b */
Packit Service 37472d
    while(s_mw_mp_cmp(&rem, b) < 0 && ix >= 0) {
Packit Service 37472d
      if((res = s_mw_mp_lshd(&rem, 1)) != MP_OKAY) 
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
      if((res = s_mw_mp_lshd(&quot, 1)) != MP_OKAY)
Packit Service 37472d
	goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
      DIGIT(&rem, 0) = DIGIT(a, ix);
Packit Service 37472d
      s_mw_mp_clamp(&rem;;
Packit Service 37472d
      --ix;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    /* If we didn't find one, we're finished dividing    */
Packit Service 37472d
    if(s_mw_mp_cmp(&rem, b) < 0) 
Packit Service 37472d
      break;    
Packit Service 37472d
Packit Service 37472d
    /* Compute a guess for the next quotient digit       */
Packit Service 37472d
    q = DIGIT(&rem, USED(&rem) - 1);
Packit Service 37472d
    if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1)
Packit Service 37472d
      q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2);
Packit Service 37472d
Packit Service 37472d
    q /= DIGIT(b, USED(b) - 1);
Packit Service 37472d
Packit Service 37472d
    /* The guess can be as much as RADIX + 1 */
Packit Service 37472d
    if(q >= RADIX)
Packit Service 37472d
      q = RADIX - 1;
Packit Service 37472d
Packit Service 37472d
    /* See what that multiplies out to                   */
Packit Service 37472d
    mw_mp_copy(b, &t);
Packit Service 37472d
    if((res = s_mw_mp_mul_d(&t, q)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
    /* 
Packit Service 37472d
       If it's too big, back it off.  We should not have to do this
Packit Service 37472d
       more than once, or, in rare cases, twice.  Knuth describes a
Packit Service 37472d
       method by which this could be reduced to a maximum of once, but
Packit Service 37472d
       I didn't implement that here.
Packit Service 37472d
     */
Packit Service 37472d
    while(s_mw_mp_cmp(&t, &rem) > 0) {
Packit Service 37472d
      --q;
Packit Service 37472d
      s_mw_mp_sub(&t, b);
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    /* At this point, q should be the right next digit   */
Packit Service 37472d
    if((res = s_mw_mp_sub(&rem, &t)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
    /*
Packit Service 37472d
      Include the digit in the quotient.  We allocated enough memory
Packit Service 37472d
      for any quotient we could ever possibly get, so we should not
Packit Service 37472d
      have to check for failures here
Packit Service 37472d
     */
Packit Service 37472d
    DIGIT(&quot, 0) = q;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Denormalize remainder                */
Packit Service 37472d
  if(d != 0) 
Packit Service 37472d
    s_mw_mp_div_2d(&rem, d);
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_clamp(");
Packit Service 37472d
  s_mw_mp_clamp(&rem;;
Packit Service 37472d
Packit Service 37472d
  /* Copy quotient back to output         */
Packit Service 37472d
  s_mw_mp_exch(&quot, a);
Packit Service 37472d
  
Packit Service 37472d
  /* Copy remainder back to output        */
Packit Service 37472d
  s_mw_mp_exch(&rem, b);
Packit Service 37472d
Packit Service 37472d
CLEANUP:
Packit Service 37472d
  mw_mp_clear(&rem;;
Packit Service 37472d
REM:
Packit Service 37472d
  mw_mp_clear(&t);
Packit Service 37472d
T:
Packit Service 37472d
  mw_mp_clear(");
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_div() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_2expt(a, k) */
Packit Service 37472d
Packit Service 37472d
mw_mp_err   s_mw_mp_2expt(mw_mp_int *a, mw_mp_digit k)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_err    res;
Packit Service 37472d
  mw_mp_size   dig, bit;
Packit Service 37472d
Packit Service 37472d
  dig = k / DIGIT_BIT;
Packit Service 37472d
  bit = k % DIGIT_BIT;
Packit Service 37472d
Packit Service 37472d
  mw_mp_zero(a);
Packit Service 37472d
  if((res = s_mw_mp_pad(a, dig + 1)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
  
Packit Service 37472d
  DIGIT(a, dig) |= (1 << bit);
Packit Service 37472d
Packit Service 37472d
  return MP_OKAY;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_2expt() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_reduce(x, m, mu) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Compute Barrett reduction, x (mod m), given a precomputed value for
Packit Service 37472d
  mu = b^2k / m, where b = RADIX and k = #digits(m).  This should be
Packit Service 37472d
  faster than straight division, when many reductions by the same
Packit Service 37472d
  value of m are required (such as in modular exponentiation).  This
Packit Service 37472d
  can nearly halve the time required to do modular exponentiation,
Packit Service 37472d
  as compared to using the full integer divide to reduce.
Packit Service 37472d
Packit Service 37472d
  This algorithm was derived from the _Handbook of Applied
Packit Service 37472d
  Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
Packit Service 37472d
  pp. 603-604.  
Packit Service 37472d
 */
Packit Service 37472d
Packit Service 37472d
mw_mp_err   s_mw_mp_reduce(mw_mp_int *x, mw_mp_int *m, mw_mp_int *mu)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_int   q;
Packit Service 37472d
  mw_mp_err   res;
Packit Service 37472d
  mw_mp_size  um = USED(m);
Packit Service 37472d
Packit Service 37472d
  if((res = mw_mp_init_copy(&q, x)) != MP_OKAY)
Packit Service 37472d
    return res;
Packit Service 37472d
Packit Service 37472d
  s_mw_mp_rshd(&q, um - 1);       /* q1 = x / b^(k-1)  */
Packit Service 37472d
  s_mw_mp_mul(&q, mu);            /* q2 = q1 * mu      */
Packit Service 37472d
  s_mw_mp_rshd(&q, um + 1);       /* q3 = q2 / b^(k+1) */
Packit Service 37472d
Packit Service 37472d
  /* x = x mod b^(k+1), quick (no division) */
Packit Service 37472d
  s_mw_mp_mod_2d(x, DIGIT_BIT * (um + 1));
Packit Service 37472d
Packit Service 37472d
  /* q = q * m mod b^(k+1), quick (no division) */
Packit Service 37472d
  s_mw_mp_mul(&q, m);
Packit Service 37472d
  s_mw_mp_mod_2d(&q, DIGIT_BIT * (um + 1));
Packit Service 37472d
Packit Service 37472d
  /* x = x - q */
Packit Service 37472d
  if((res = mw_mp_sub(x, &q, x)) != MP_OKAY)
Packit Service 37472d
    goto CLEANUP;
Packit Service 37472d
Packit Service 37472d
  /* If x < 0, add b^(k+1) to it */
Packit Service 37472d
  if(mw_mp_cmw_mp_z(x) < 0) {
Packit Service 37472d
    mw_mp_set(&q, 1);
Packit Service 37472d
    if((res = s_mw_mp_lshd(&q, um + 1)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
    if((res = mw_mp_add(x, &q, x)) != MP_OKAY)
Packit Service 37472d
      goto CLEANUP;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* Back off if it's too big */
Packit Service 37472d
  while(mw_mp_cmp(x, m) >= 0) {
Packit Service 37472d
    if((res = s_mw_mp_sub(x, m)) != MP_OKAY)
Packit Service 37472d
      break;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
 CLEANUP:
Packit Service 37472d
  mw_mp_clear(&q);
Packit Service 37472d
Packit Service 37472d
  return res;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_reduce() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Primitive comparisons */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_cmp(a, b) */
Packit Service 37472d
Packit Service 37472d
/* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b           */
Packit Service 37472d
int      s_mw_mp_cmp(mw_mp_int *a, mw_mp_int *b)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_size   ua = USED(a), ub = USED(b);
Packit Service 37472d
Packit Service 37472d
  if(ua > ub)
Packit Service 37472d
    return MP_GT;
Packit Service 37472d
  else if(ua < ub)
Packit Service 37472d
    return MP_LT;
Packit Service 37472d
  else {
Packit Service 37472d
    int      ix = ua - 1;
Packit Service 37472d
    mw_mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix;
Packit Service 37472d
Packit Service 37472d
    while(ix >= 0) {
Packit Service 37472d
      if(*ap > *bp)
Packit Service 37472d
	return MP_GT;
Packit Service 37472d
      else if(*ap < *bp)
Packit Service 37472d
	return MP_LT;
Packit Service 37472d
Packit Service 37472d
      --ap; --bp; --ix;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    return MP_EQ;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_cmp() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_cmw_mp_d(a, d) */
Packit Service 37472d
Packit Service 37472d
/* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d             */
Packit Service 37472d
int      s_mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_size  ua = USED(a);
Packit Service 37472d
  mw_mp_digit *ap = DIGITS(a);
Packit Service 37472d
Packit Service 37472d
  if(ua > 1)
Packit Service 37472d
    return MP_GT;
Packit Service 37472d
Packit Service 37472d
  if(*ap < d) 
Packit Service 37472d
    return MP_LT;
Packit Service 37472d
  else if(*ap > d)
Packit Service 37472d
    return MP_GT;
Packit Service 37472d
  else
Packit Service 37472d
    return MP_EQ;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_cmw_mp_d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_ispow2(v) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Returns -1 if the value is not a power of two; otherwise, it returns
Packit Service 37472d
  k such that v = 2^k, i.e. lg(v).
Packit Service 37472d
 */
Packit Service 37472d
int      s_mw_mp_ispow2(mw_mp_int *v)
Packit Service 37472d
{
Packit Service 37472d
  mw_mp_digit d, *dp;
Packit Service 37472d
  mw_mp_size  uv = USED(v);
Packit Service 37472d
  int      extra = 0, ix;
Packit Service 37472d
Packit Service 37472d
  d = DIGIT(v, uv - 1); /* most significant digit of v */
Packit Service 37472d
Packit Service 37472d
  while(d && ((d & 1) == 0)) {
Packit Service 37472d
    d >>= 1;
Packit Service 37472d
    ++extra;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(d == 1) {
Packit Service 37472d
    ix = uv - 2;
Packit Service 37472d
    dp = DIGITS(v) + ix;
Packit Service 37472d
Packit Service 37472d
    while(ix >= 0) {
Packit Service 37472d
      if(*dp)
Packit Service 37472d
	return -1; /* not a power of two */
Packit Service 37472d
Packit Service 37472d
      --dp; --ix;
Packit Service 37472d
    }
Packit Service 37472d
Packit Service 37472d
    return ((uv - 1) * DIGIT_BIT) + extra;
Packit Service 37472d
  } 
Packit Service 37472d
Packit Service 37472d
  return -1;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_ispow2() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_ispow2d(d) */
Packit Service 37472d
Packit Service 37472d
int      s_mw_mp_ispow2d(mw_mp_digit d)
Packit Service 37472d
{
Packit Service 37472d
  int   pow = 0;
Packit Service 37472d
Packit Service 37472d
  while((d & 1) == 0) {
Packit Service 37472d
    ++pow; d >>= 1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(d == 1)
Packit Service 37472d
    return pow;
Packit Service 37472d
Packit Service 37472d
  return -1;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_ispow2d() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ Primitive I/O helpers */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_tovalue(ch, r) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Convert the given character to its digit value, in the given radix.
Packit Service 37472d
  If the given character is not understood in the given radix, -1 is
Packit Service 37472d
  returned.  Otherwise the digit's numeric value is returned.
Packit Service 37472d
Packit Service 37472d
  The results will be odd if you use a radix < 2 or > 62, you are
Packit Service 37472d
  expected to know what you're up to.
Packit Service 37472d
 */
Packit Service 37472d
int      s_mw_mp_tovalue(char ch, int r)
Packit Service 37472d
{
Packit Service 37472d
  int    val, xch;
Packit Service 37472d
  
Packit Service 37472d
  if(r > 36)
Packit Service 37472d
    xch = ch;
Packit Service 37472d
  else
Packit Service 37472d
    xch = toupper(ch);
Packit Service 37472d
Packit Service 37472d
  if(isdigit(xch))
Packit Service 37472d
    val = xch - '0';
Packit Service 37472d
  else if(isupper(xch))
Packit Service 37472d
    val = xch - 'A' + 10;
Packit Service 37472d
  else if(islower(xch))
Packit Service 37472d
    val = xch - 'a' + 36;
Packit Service 37472d
  else if(xch == '+')
Packit Service 37472d
    val = 62;
Packit Service 37472d
  else if(xch == '/')
Packit Service 37472d
    val = 63;
Packit Service 37472d
  else 
Packit Service 37472d
    return -1;
Packit Service 37472d
Packit Service 37472d
  if(val < 0 || val >= r)
Packit Service 37472d
    return -1;
Packit Service 37472d
Packit Service 37472d
  return val;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_tovalue() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_todigit(val, r, low) */
Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Convert val to a radix-r digit, if possible.  If val is out of range
Packit Service 37472d
  for r, returns zero.  Otherwise, returns an ASCII character denoting
Packit Service 37472d
  the value in the given radix.
Packit Service 37472d
Packit Service 37472d
  The results may be odd if you use a radix < 2 or > 64, you are
Packit Service 37472d
  expected to know what you're doing.
Packit Service 37472d
 */
Packit Service 37472d
  
Packit Service 37472d
char     s_mw_mp_todigit(int val, int r, int low)
Packit Service 37472d
{
Packit Service 37472d
  char   ch;
Packit Service 37472d
Packit Service 37472d
  if(val < 0 || val >= r)
Packit Service 37472d
    return 0;
Packit Service 37472d
Packit Service 37472d
  ch = s_dmap_1[val];
Packit Service 37472d
Packit Service 37472d
  if(r <= 36 && low)
Packit Service 37472d
    ch = tolower(ch);
Packit Service 37472d
Packit Service 37472d
  return ch;
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_todigit() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* {{{ s_mw_mp_outlen(bits, radix) */
Packit Service 37472d
Packit Service 37472d
/* 
Packit Service 37472d
   Return an estimate for how long a string is needed to hold a radix
Packit Service 37472d
   r representation of a number with 'bits' significant bits.
Packit Service 37472d
Packit Service 37472d
   Does not include space for a sign or a NUL terminator.
Packit Service 37472d
 */
Packit Service 37472d
int      s_mw_mp_outlen(int bits, int r)
Packit Service 37472d
{
Packit Service 37472d
  return (int)((double)bits * LOG_V_2(r) + 0.5);
Packit Service 37472d
Packit Service 37472d
} /* end s_mw_mp_outlen() */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/* }}} */
Packit Service 37472d
Packit Service 37472d
/*------------------------------------------------------------------------*/
Packit Service 37472d
/* HERE THERE BE DRAGONS                                                  */