Blame isl-0.14/imath/imath.c

Packit fb9d21
/*
Packit fb9d21
  Name:     imath.c
Packit fb9d21
  Purpose:  Arbitrary precision integer arithmetic routines.
Packit fb9d21
  Author:   M. J. Fromberger <http://spinning-yarns.org/michael/>
Packit fb9d21
Packit fb9d21
  Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
Packit fb9d21
Packit fb9d21
  Permission is hereby granted, free of charge, to any person obtaining a copy
Packit fb9d21
  of this software and associated documentation files (the "Software"), to deal
Packit fb9d21
  in the Software without restriction, including without limitation the rights
Packit fb9d21
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Packit fb9d21
  copies of the Software, and to permit persons to whom the Software is
Packit fb9d21
  furnished to do so, subject to the following conditions:
Packit fb9d21
Packit fb9d21
  The above copyright notice and this permission notice shall be included in
Packit fb9d21
  all copies or substantial portions of the Software.
Packit fb9d21
Packit fb9d21
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit fb9d21
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit fb9d21
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit fb9d21
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit fb9d21
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Packit fb9d21
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit fb9d21
  SOFTWARE.
Packit fb9d21
 */
Packit fb9d21
Packit fb9d21
#include "imath.h"
Packit fb9d21
Packit fb9d21
#if DEBUG
Packit fb9d21
#include <stdio.h>
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
#include <stdlib.h>
Packit fb9d21
#include <string.h>
Packit fb9d21
#include <ctype.h>
Packit fb9d21
Packit fb9d21
#include <assert.h>
Packit fb9d21
Packit fb9d21
#if DEBUG
Packit fb9d21
#define STATIC /* public */
Packit fb9d21
#else
Packit fb9d21
#define STATIC static
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
/* {{{ Constants */
Packit fb9d21
Packit fb9d21
const mp_result MP_OK     = 0;  /* no error, all is well  */
Packit fb9d21
const mp_result MP_FALSE  = 0;  /* boolean false          */
Packit fb9d21
const mp_result MP_TRUE   = -1; /* boolean true           */
Packit fb9d21
const mp_result MP_MEMORY = -2; /* out of memory          */
Packit fb9d21
const mp_result MP_RANGE  = -3; /* argument out of range  */
Packit fb9d21
const mp_result MP_UNDEF  = -4; /* result undefined       */
Packit fb9d21
const mp_result MP_TRUNC  = -5; /* output truncated       */
Packit fb9d21
const mp_result MP_BADARG = -6; /* invalid null argument  */
Packit fb9d21
const mp_result MP_MINERR = -6;
Packit fb9d21
Packit fb9d21
const mp_sign   MP_NEG  = 1;    /* value is strictly negative */
Packit fb9d21
const mp_sign   MP_ZPOS = 0;    /* value is non-negative      */
Packit fb9d21
Packit fb9d21
STATIC const char *s_unknown_err = "unknown result code";
Packit fb9d21
STATIC const char *s_error_msg[] = {
Packit fb9d21
  "error code 0",
Packit fb9d21
  "boolean true",
Packit fb9d21
  "out of memory",
Packit fb9d21
  "argument out of range",
Packit fb9d21
  "result undefined",
Packit fb9d21
  "output truncated",
Packit fb9d21
  "invalid argument",
Packit fb9d21
  NULL
Packit fb9d21
};
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* Argument checking macros
Packit fb9d21
   Use CHECK() where a return value is required; NRCHECK() elsewhere */
Packit fb9d21
#define CHECK(TEST)   assert(TEST)
Packit fb9d21
#define NRCHECK(TEST) assert(TEST)
Packit fb9d21
Packit fb9d21
/* {{{ Logarithm table for computing output sizes */
Packit fb9d21
Packit fb9d21
/* The ith entry of this table gives the value of log_i(2).
Packit fb9d21
Packit fb9d21
   An integer value n requires ceil(log_i(n)) digits to be represented
Packit fb9d21
   in base i.  Since it is easy to compute lg(n), by counting bits, we
Packit fb9d21
   can compute log_i(n) = lg(n) * log_i(2).
Packit fb9d21
Packit fb9d21
   The use of this table eliminates a dependency upon linkage against
Packit fb9d21
   the standard math libraries.
Packit fb9d21
Packit fb9d21
   If MP_MAX_RADIX is increased, this table should be expanded too.
Packit fb9d21
 */
Packit fb9d21
STATIC const double s_log2[] = {
Packit fb9d21
   0.000000000, 0.000000000, 1.000000000, 0.630929754, 	/* (D)(D) 2  3 */
Packit fb9d21
   0.500000000, 0.430676558, 0.386852807, 0.356207187, 	/*  4  5  6  7 */
Packit fb9d21
   0.333333333, 0.315464877, 0.301029996, 0.289064826, 	/*  8  9 10 11 */
Packit fb9d21
   0.278942946, 0.270238154, 0.262649535, 0.255958025, 	/* 12 13 14 15 */
Packit fb9d21
   0.250000000, 0.244650542, 0.239812467, 0.235408913, 	/* 16 17 18 19 */
Packit fb9d21
   0.231378213, 0.227670249, 0.224243824, 0.221064729, 	/* 20 21 22 23 */
Packit fb9d21
   0.218104292, 0.215338279, 0.212746054, 0.210309918, 	/* 24 25 26 27 */
Packit fb9d21
   0.208014598, 0.205846832, 0.203795047, 0.201849087, 	/* 28 29 30 31 */
Packit fb9d21
   0.200000000, 0.198239863, 0.196561632, 0.194959022, 	/* 32 33 34 35 */
Packit fb9d21
   0.193426404,                                         /* 36          */
Packit fb9d21
};
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
/* {{{ Various macros */
Packit fb9d21
Packit fb9d21
/* Return the number of digits needed to represent a static value */
Packit fb9d21
#define MP_VALUE_DIGITS(V) \
Packit fb9d21
((sizeof(V)+(sizeof(mp_digit)-1))/sizeof(mp_digit))
Packit fb9d21
Packit fb9d21
/* Round precision P to nearest word boundary */
Packit fb9d21
#define ROUND_PREC(P) ((mp_size)(2*(((P)+1)/2)))
Packit fb9d21
Packit fb9d21
/* Set array P of S digits to zero */
Packit fb9d21
#define ZERO(P, S) \
Packit fb9d21
do{ \
Packit fb9d21
  mp_size i__ = (S) * sizeof(mp_digit); \
Packit fb9d21
  mp_digit *p__ = (P); \
Packit fb9d21
  memset(p__, 0, i__); \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
/* Copy S digits from array P to array Q */
Packit fb9d21
#define COPY(P, Q, S) \
Packit fb9d21
do{ \
Packit fb9d21
  mp_size i__ = (S) * sizeof(mp_digit); \
Packit fb9d21
  mp_digit *p__ = (P), *q__ = (Q); \
Packit fb9d21
  memcpy(q__, p__, i__); \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
/* Reverse N elements of type T in array A */
Packit fb9d21
#define REV(T, A, N) \
Packit fb9d21
do{ \
Packit fb9d21
  T *u_ = (A), *v_ = u_ + (N) - 1; \
Packit fb9d21
  while (u_ < v_) { \
Packit fb9d21
    T xch = *u_; \
Packit fb9d21
    *u_++ = *v_; \
Packit fb9d21
    *v_-- = xch; \
Packit fb9d21
  } \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
#define CLAMP(Z) \
Packit fb9d21
do{ \
Packit fb9d21
  mp_int z_ = (Z); \
Packit fb9d21
  mp_size uz_ = MP_USED(z_); \
Packit fb9d21
  mp_digit *dz_ = MP_DIGITS(z_) + uz_ -1; \
Packit fb9d21
  while (uz_ > 1 && (*dz_-- == 0)) \
Packit fb9d21
    --uz_; \
Packit fb9d21
  MP_USED(z_) = uz_; \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
/* Select min/max.  Do not provide expressions for which multiple
Packit fb9d21
   evaluation would be problematic, e.g. x++ */
Packit fb9d21
#define MIN(A, B) ((B)<(A)?(B):(A))
Packit fb9d21
#define MAX(A, B) ((B)>(A)?(B):(A))
Packit fb9d21
Packit fb9d21
/* Exchange lvalues A and B of type T, e.g.
Packit fb9d21
   SWAP(int, x, y) where x and y are variables of type int. */
Packit fb9d21
#define SWAP(T, A, B) \
Packit fb9d21
do{ \
Packit fb9d21
  T t_ = (A); \
Packit fb9d21
  A = (B); \
Packit fb9d21
  B = t_; \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
/* Used to set up and access simple temp stacks within functions. */
Packit fb9d21
#define DECLARE_TEMP(N) \
Packit fb9d21
  mpz_t temp[(N)]; \
Packit fb9d21
  int last__ = 0
Packit fb9d21
#define CLEANUP_TEMP() \
Packit fb9d21
 CLEANUP: \
Packit fb9d21
  while (--last__ >= 0) \
Packit fb9d21
    mp_int_clear(TEMP(last__))
Packit fb9d21
#define TEMP(K) (temp + (K))
Packit fb9d21
#define LAST_TEMP() TEMP(last__)
Packit fb9d21
#define SETUP(E) \
Packit fb9d21
do{ \
Packit fb9d21
  if ((res = (E)) != MP_OK) \
Packit fb9d21
    goto CLEANUP; \
Packit fb9d21
  ++(last__); \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
/* Compare value to zero. */
Packit fb9d21
#define CMPZ(Z) \
Packit fb9d21
(((Z)->used==1&&(Z)->digits[0]==0)?0:((Z)->sign==MP_NEG)?-1:1)
Packit fb9d21
Packit fb9d21
/* Multiply X by Y into Z, ignoring signs.  Requires that Z have
Packit fb9d21
   enough storage preallocated to hold the result. */
Packit fb9d21
#define UMUL(X, Y, Z) \
Packit fb9d21
do{ \
Packit fb9d21
  mp_size ua_ = MP_USED(X), ub_ = MP_USED(Y); \
Packit fb9d21
  mp_size o_ = ua_ + ub_; \
Packit fb9d21
  ZERO(MP_DIGITS(Z), o_); \
Packit fb9d21
  (void) s_kmul(MP_DIGITS(X), MP_DIGITS(Y), MP_DIGITS(Z), ua_, ub_); \
Packit fb9d21
  MP_USED(Z) = o_; \
Packit fb9d21
  CLAMP(Z); \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
/* Square X into Z.  Requires that Z have enough storage to hold the
Packit fb9d21
   result. */
Packit fb9d21
#define USQR(X, Z) \
Packit fb9d21
do{ \
Packit fb9d21
  mp_size ua_ = MP_USED(X), o_ = ua_ + ua_; \
Packit fb9d21
  ZERO(MP_DIGITS(Z), o_); \
Packit fb9d21
  (void) s_ksqr(MP_DIGITS(X), MP_DIGITS(Z), ua_); \
Packit fb9d21
  MP_USED(Z) = o_; \
Packit fb9d21
  CLAMP(Z); \
Packit fb9d21
} while(0)
Packit fb9d21
Packit fb9d21
#define UPPER_HALF(W)           ((mp_word)((W) >> MP_DIGIT_BIT))
Packit fb9d21
#define LOWER_HALF(W)           ((mp_digit)(W))
Packit fb9d21
#define HIGH_BIT_SET(W)         ((W) >> (MP_WORD_BIT - 1))
Packit fb9d21
#define ADD_WILL_OVERFLOW(W, V) ((MP_WORD_MAX - (V)) < (W))
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
/* {{{ Default configuration settings */
Packit fb9d21
Packit fb9d21
/* Default number of digits allocated to a new mp_int */
Packit fb9d21
#if IMATH_TEST
Packit fb9d21
mp_size default_precision = MP_DEFAULT_PREC;
Packit fb9d21
#else
Packit fb9d21
STATIC const mp_size default_precision = MP_DEFAULT_PREC;
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
/* Minimum number of digits to invoke recursive multiply */
Packit fb9d21
#if IMATH_TEST
Packit fb9d21
mp_size multiply_threshold = MP_MULT_THRESH;
Packit fb9d21
#else
Packit fb9d21
STATIC const mp_size multiply_threshold = MP_MULT_THRESH;
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* Allocate a buffer of (at least) num digits, or return
Packit fb9d21
   NULL if that couldn't be done.  */
Packit fb9d21
STATIC mp_digit *s_alloc(mp_size num);
Packit fb9d21
Packit fb9d21
/* Release a buffer of digits allocated by s_alloc(). */
Packit fb9d21
STATIC void s_free(void *ptr);
Packit fb9d21
Packit fb9d21
/* Insure that z has at least min digits allocated, resizing if
Packit fb9d21
   necessary.  Returns true if successful, false if out of memory. */
Packit fb9d21
STATIC int  s_pad(mp_int z, mp_size min);
Packit fb9d21
Packit fb9d21
/* Fill in a "fake" mp_int on the stack with a given value */
Packit fb9d21
STATIC void      s_fake(mp_int z, mp_small value, mp_digit vbuf[]);
Packit fb9d21
STATIC void      s_ufake(mp_int z, mp_usmall value, mp_digit vbuf[]);
Packit fb9d21
Packit fb9d21
/* Compare two runs of digits of given length, returns <0, 0, >0 */
Packit fb9d21
STATIC int       s_cdig(mp_digit *da, mp_digit *db, mp_size len);
Packit fb9d21
Packit fb9d21
/* Pack the unsigned digits of v into array t */
Packit fb9d21
STATIC int       s_uvpack(mp_usmall v, mp_digit t[]);
Packit fb9d21
Packit fb9d21
/* Compare magnitudes of a and b, returns <0, 0, >0 */
Packit fb9d21
STATIC int       s_ucmp(mp_int a, mp_int b);
Packit fb9d21
Packit fb9d21
/* Compare magnitudes of a and v, returns <0, 0, >0 */
Packit fb9d21
STATIC int       s_vcmp(mp_int a, mp_small v);
Packit fb9d21
STATIC int       s_uvcmp(mp_int a, mp_usmall uv);
Packit fb9d21
Packit fb9d21
/* Unsigned magnitude addition; assumes dc is big enough.
Packit fb9d21
   Carry out is returned (no memory allocated). */
Packit fb9d21
STATIC mp_digit  s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
		        mp_size size_a, mp_size size_b);
Packit fb9d21
Packit fb9d21
/* Unsigned magnitude subtraction.  Assumes dc is big enough. */
Packit fb9d21
STATIC void      s_usub(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
		        mp_size size_a, mp_size size_b);
Packit fb9d21
Packit fb9d21
/* Unsigned recursive multiplication.  Assumes dc is big enough. */
Packit fb9d21
STATIC int       s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
			mp_size size_a, mp_size size_b);
Packit fb9d21
Packit fb9d21
/* Unsigned magnitude multiplication.  Assumes dc is big enough. */
Packit fb9d21
STATIC void      s_umul(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
			mp_size size_a, mp_size size_b);
Packit fb9d21
Packit fb9d21
/* Unsigned recursive squaring.  Assumes dc is big enough. */
Packit fb9d21
STATIC int       s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a);
Packit fb9d21
Packit fb9d21
/* Unsigned magnitude squaring.  Assumes dc is big enough. */
Packit fb9d21
STATIC void      s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a);
Packit fb9d21
Packit fb9d21
/* Single digit addition.  Assumes a is big enough. */
Packit fb9d21
STATIC void      s_dadd(mp_int a, mp_digit b);
Packit fb9d21
Packit fb9d21
/* Single digit multiplication.  Assumes a is big enough. */
Packit fb9d21
STATIC void      s_dmul(mp_int a, mp_digit b);
Packit fb9d21
Packit fb9d21
/* Single digit multiplication on buffers; assumes dc is big enough. */
Packit fb9d21
STATIC void      s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc,
Packit fb9d21
			 mp_size size_a);
Packit fb9d21
Packit fb9d21
/* Single digit division.  Replaces a with the quotient,
Packit fb9d21
   returns the remainder.  */
Packit fb9d21
STATIC mp_digit  s_ddiv(mp_int a, mp_digit b);
Packit fb9d21
Packit fb9d21
/* Quick division by a power of 2, replaces z (no allocation) */
Packit fb9d21
STATIC void      s_qdiv(mp_int z, mp_size p2);
Packit fb9d21
Packit fb9d21
/* Quick remainder by a power of 2, replaces z (no allocation) */
Packit fb9d21
STATIC void      s_qmod(mp_int z, mp_size p2);
Packit fb9d21
Packit fb9d21
/* Quick multiplication by a power of 2, replaces z.
Packit fb9d21
   Allocates if necessary; returns false in case this fails. */
Packit fb9d21
STATIC int       s_qmul(mp_int z, mp_size p2);
Packit fb9d21
Packit fb9d21
/* Quick subtraction from a power of 2, replaces z.
Packit fb9d21
   Allocates if necessary; returns false in case this fails. */
Packit fb9d21
STATIC int       s_qsub(mp_int z, mp_size p2);
Packit fb9d21
Packit fb9d21
/* Return maximum k such that 2^k divides z. */
Packit fb9d21
STATIC int       s_dp2k(mp_int z);
Packit fb9d21
Packit fb9d21
/* Return k >= 0 such that z = 2^k, or -1 if there is no such k. */
Packit fb9d21
STATIC int       s_isp2(mp_int z);
Packit fb9d21
Packit fb9d21
/* Set z to 2^k.  May allocate; returns false in case this fails. */
Packit fb9d21
STATIC int       s_2expt(mp_int z, mp_small k);
Packit fb9d21
Packit fb9d21
/* Normalize a and b for division, returns normalization constant */
Packit fb9d21
STATIC int       s_norm(mp_int a, mp_int b);
Packit fb9d21
Packit fb9d21
/* Compute constant mu for Barrett reduction, given modulus m, result
Packit fb9d21
   replaces z, m is untouched. */
Packit fb9d21
STATIC mp_result s_brmu(mp_int z, mp_int m);
Packit fb9d21
Packit fb9d21
/* Reduce a modulo m, using Barrett's algorithm. */
Packit fb9d21
STATIC int       s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2);
Packit fb9d21
Packit fb9d21
/* Modular exponentiation, using Barrett reduction */
Packit fb9d21
STATIC mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c);
Packit fb9d21
Packit fb9d21
/* Unsigned magnitude division.  Assumes |a| > |b|.  Allocates temporaries;
Packit fb9d21
   overwrites a with quotient, b with remainder. */
Packit fb9d21
STATIC mp_result s_udiv_knuth(mp_int a, mp_int b);
Packit fb9d21
Packit fb9d21
/* Compute the number of digits in radix r required to represent the given
Packit fb9d21
   value.  Does not account for sign flags, terminators, etc. */
Packit fb9d21
STATIC int       s_outlen(mp_int z, mp_size r);
Packit fb9d21
Packit fb9d21
/* Guess how many digits of precision will be needed to represent a radix r
Packit fb9d21
   value of the specified number of digits.  Returns a value guaranteed to be
Packit fb9d21
   no smaller than the actual number required. */
Packit fb9d21
STATIC mp_size   s_inlen(int len, mp_size r);
Packit fb9d21
Packit fb9d21
/* Convert a character to a digit value in radix r, or
Packit fb9d21
   -1 if out of range */
Packit fb9d21
STATIC int       s_ch2val(char c, int r);
Packit fb9d21
Packit fb9d21
/* Convert a digit value to a character */
Packit fb9d21
STATIC char      s_val2ch(int v, int caps);
Packit fb9d21
Packit fb9d21
/* Take 2's complement of a buffer in place */
Packit fb9d21
STATIC void      s_2comp(unsigned char *buf, int len);
Packit fb9d21
Packit fb9d21
/* Convert a value to binary, ignoring sign.  On input, *limpos is the bound on
Packit fb9d21
   how many bytes should be written to buf; on output, *limpos is set to the
Packit fb9d21
   number of bytes actually written. */
Packit fb9d21
STATIC mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad);
Packit fb9d21
Packit fb9d21
#if DEBUG
Packit fb9d21
/* Dump a representation of the mp_int to standard output */
Packit fb9d21
void      s_print(char *tag, mp_int z);
Packit fb9d21
void      s_print_buf(char *tag, mp_digit *buf, mp_size num);
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_init(z) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_init(mp_int z)
Packit fb9d21
{
Packit fb9d21
  if (z == NULL)
Packit fb9d21
    return MP_BADARG;
Packit fb9d21
Packit fb9d21
  z->single = 0;
Packit fb9d21
  z->digits = &(z->single);
Packit fb9d21
  z->alloc  = 1;
Packit fb9d21
  z->used   = 1;
Packit fb9d21
  z->sign   = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_alloc() */
Packit fb9d21
Packit fb9d21
mp_int    mp_int_alloc(void)
Packit fb9d21
{
Packit fb9d21
  mp_int out = malloc(sizeof(mpz_t));
Packit fb9d21
Packit fb9d21
  if (out != NULL)
Packit fb9d21
    mp_int_init(out);
Packit fb9d21
Packit fb9d21
  return out;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_init_size(z, prec) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_init_size(mp_int z, mp_size prec)
Packit fb9d21
{
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  if (prec == 0)
Packit fb9d21
    prec = default_precision;
Packit fb9d21
  else if (prec == 1)
Packit fb9d21
    return mp_int_init(z);
Packit fb9d21
  else
Packit fb9d21
    prec = (mp_size) ROUND_PREC(prec);
Packit fb9d21
Packit fb9d21
  if ((MP_DIGITS(z) = s_alloc(prec)) == NULL)
Packit fb9d21
    return MP_MEMORY;
Packit fb9d21
Packit fb9d21
  z->digits[0] = 0;
Packit fb9d21
  MP_USED(z) = 1;
Packit fb9d21
  MP_ALLOC(z) = prec;
Packit fb9d21
  MP_SIGN(z) = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_init_copy(z, old) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_init_copy(mp_int z, mp_int old)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
  mp_size uold;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL && old != NULL);
Packit fb9d21
Packit fb9d21
  uold = MP_USED(old);
Packit fb9d21
  if (uold == 1) {
Packit fb9d21
    mp_int_init(z);
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    mp_size target = MAX(uold, default_precision);
Packit fb9d21
Packit fb9d21
    if ((res = mp_int_init_size(z, target)) != MP_OK)
Packit fb9d21
      return res;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  MP_USED(z) = uold;
Packit fb9d21
  MP_SIGN(z) = MP_SIGN(old);
Packit fb9d21
  COPY(MP_DIGITS(old), MP_DIGITS(z), uold);
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_init_value(z, value) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_init_value(mp_int z, mp_small value)
Packit fb9d21
{
Packit fb9d21
  mpz_t    vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
  return mp_int_init_copy(z, &vtmp);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_init_uvalue(z, uvalue) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_init_uvalue(mp_int z, mp_usmall uvalue)
Packit fb9d21
{
Packit fb9d21
  mpz_t    vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(uvalue)];
Packit fb9d21
Packit fb9d21
  s_ufake(&vtmp, uvalue, vbuf);
Packit fb9d21
  return mp_int_init_copy(z, &vtmp);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_set_value(z, value) */
Packit fb9d21
Packit fb9d21
mp_result  mp_int_set_value(mp_int z, mp_small value)
Packit fb9d21
{
Packit fb9d21
  mpz_t    vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
  return mp_int_copy(&vtmp, z);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_set_uvalue(z, value) */
Packit fb9d21
Packit fb9d21
mp_result  mp_int_set_uvalue(mp_int z, mp_usmall uvalue)
Packit fb9d21
{
Packit fb9d21
  mpz_t    vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(uvalue)];
Packit fb9d21
Packit fb9d21
  s_ufake(&vtmp, uvalue, vbuf);
Packit fb9d21
  return mp_int_copy(&vtmp, z);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_clear(z) */
Packit fb9d21
Packit fb9d21
void      mp_int_clear(mp_int z)
Packit fb9d21
{
Packit fb9d21
  if (z == NULL)
Packit fb9d21
    return;
Packit fb9d21
Packit fb9d21
  if (MP_DIGITS(z) != NULL) {
Packit fb9d21
    if (MP_DIGITS(z) != &(z->single))
Packit fb9d21
      s_free(MP_DIGITS(z));
Packit fb9d21
Packit fb9d21
    MP_DIGITS(z) = NULL;
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_free(z) */
Packit fb9d21
Packit fb9d21
void      mp_int_free(mp_int z)
Packit fb9d21
{
Packit fb9d21
  NRCHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  mp_int_clear(z);
Packit fb9d21
  free(z); /* note: NOT s_free() */
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_copy(a, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_copy(mp_int a, mp_int c)
Packit fb9d21
{
Packit fb9d21
  CHECK(a != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  if (a != c) {
Packit fb9d21
    mp_size ua = MP_USED(a);
Packit fb9d21
    mp_digit *da, *dc;
Packit fb9d21
Packit fb9d21
    if (!s_pad(c, ua))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
Packit fb9d21
    da = MP_DIGITS(a); dc = MP_DIGITS(c);
Packit fb9d21
    COPY(da, dc, ua);
Packit fb9d21
Packit fb9d21
    MP_USED(c) = ua;
Packit fb9d21
    MP_SIGN(c) = MP_SIGN(a);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_swap(a, c) */
Packit fb9d21
Packit fb9d21
void      mp_int_swap(mp_int a, mp_int c)
Packit fb9d21
{
Packit fb9d21
  if (a != c) {
Packit fb9d21
    mpz_t tmp = *a;
Packit fb9d21
Packit fb9d21
    *a = *c;
Packit fb9d21
    *c = tmp;
Packit fb9d21
Packit fb9d21
    if (MP_DIGITS(a) == &(c->single))
Packit fb9d21
      MP_DIGITS(a) = &(a->single);
Packit fb9d21
    if (MP_DIGITS(c) == &(a->single))
Packit fb9d21
      MP_DIGITS(c) = &(c->single);
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_zero(z) */
Packit fb9d21
Packit fb9d21
void      mp_int_zero(mp_int z)
Packit fb9d21
{
Packit fb9d21
  NRCHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  z->digits[0] = 0;
Packit fb9d21
  MP_USED(z) = 1;
Packit fb9d21
  MP_SIGN(z) = MP_ZPOS;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_abs(a, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_abs(mp_int a, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_copy(a, c)) != MP_OK)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  MP_SIGN(c) = MP_ZPOS;
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_neg(a, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_neg(mp_int a, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_copy(a, c)) != MP_OK)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  if (CMPZ(c) != 0)
Packit fb9d21
    MP_SIGN(c) = 1 - MP_SIGN(a);
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_add(a, b, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_add(mp_int a, mp_int b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_size ua, ub, uc, max;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c);
Packit fb9d21
  max = MAX(ua, ub);
Packit fb9d21
Packit fb9d21
  if (MP_SIGN(a) == MP_SIGN(b)) {
Packit fb9d21
    /* Same sign -- add magnitudes, preserve sign of addends */
Packit fb9d21
    mp_digit carry;
Packit fb9d21
Packit fb9d21
    if (!s_pad(c, max))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
Packit fb9d21
    carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub);
Packit fb9d21
    uc = max;
Packit fb9d21
Packit fb9d21
    if (carry) {
Packit fb9d21
      if (!s_pad(c, max + 1))
Packit fb9d21
	return MP_MEMORY;
Packit fb9d21
Packit fb9d21
      c->digits[max] = carry;
Packit fb9d21
      ++uc;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    MP_USED(c) = uc;
Packit fb9d21
    MP_SIGN(c) = MP_SIGN(a);
Packit fb9d21
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    /* Different signs -- subtract magnitudes, preserve sign of greater */
Packit fb9d21
    mp_int  x, y;
Packit fb9d21
    int     cmp = s_ucmp(a, b); /* magnitude comparision, sign ignored */
Packit fb9d21
Packit fb9d21
    /* Set x to max(a, b), y to min(a, b) to simplify later code.
Packit fb9d21
       A special case yields zero for equal magnitudes.
Packit fb9d21
    */
Packit fb9d21
    if (cmp == 0) {
Packit fb9d21
      mp_int_zero(c);
Packit fb9d21
      return MP_OK;
Packit fb9d21
    }
Packit fb9d21
    else if (cmp < 0) {
Packit fb9d21
      x = b; y = a;
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      x = a; y = b;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    if (!s_pad(c, MP_USED(x)))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
Packit fb9d21
    /* Subtract smaller from larger */
Packit fb9d21
    s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y));
Packit fb9d21
    MP_USED(c) = MP_USED(x);
Packit fb9d21
    CLAMP(c);
Packit fb9d21
Packit fb9d21
    /* Give result the sign of the larger */
Packit fb9d21
    MP_SIGN(c) = MP_SIGN(x);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_add_value(a, value, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_add_value(mp_int a, mp_small value, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t    vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
Packit fb9d21
  return mp_int_add(a, &vtmp, c);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_sub(a, b, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_sub(mp_int a, mp_int b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_size ua, ub, uc, max;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c);
Packit fb9d21
  max = MAX(ua, ub);
Packit fb9d21
Packit fb9d21
  if (MP_SIGN(a) != MP_SIGN(b)) {
Packit fb9d21
    /* Different signs -- add magnitudes and keep sign of a */
Packit fb9d21
    mp_digit carry;
Packit fb9d21
Packit fb9d21
    if (!s_pad(c, max))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
Packit fb9d21
    carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub);
Packit fb9d21
    uc = max;
Packit fb9d21
Packit fb9d21
    if (carry) {
Packit fb9d21
      if (!s_pad(c, max + 1))
Packit fb9d21
	return MP_MEMORY;
Packit fb9d21
Packit fb9d21
      c->digits[max] = carry;
Packit fb9d21
      ++uc;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    MP_USED(c) = uc;
Packit fb9d21
    MP_SIGN(c) = MP_SIGN(a);
Packit fb9d21
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    /* Same signs -- subtract magnitudes */
Packit fb9d21
    mp_int  x, y;
Packit fb9d21
    mp_sign osign;
Packit fb9d21
    int     cmp = s_ucmp(a, b);
Packit fb9d21
Packit fb9d21
    if (!s_pad(c, max))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
Packit fb9d21
    if (cmp >= 0) {
Packit fb9d21
      x = a; y = b; osign = MP_ZPOS;
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      x = b; y = a; osign = MP_NEG;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    if (MP_SIGN(a) == MP_NEG && cmp != 0)
Packit fb9d21
      osign = 1 - osign;
Packit fb9d21
Packit fb9d21
    s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y));
Packit fb9d21
    MP_USED(c) = MP_USED(x);
Packit fb9d21
    CLAMP(c);
Packit fb9d21
Packit fb9d21
    MP_SIGN(c) = osign;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_sub_value(a, value, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_sub_value(mp_int a, mp_small value, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t    vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
Packit fb9d21
  return mp_int_sub(a, &vtmp, c);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_mul(a, b, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_mul(mp_int a, mp_int b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_digit *out;
Packit fb9d21
  mp_size   osize, ua, ub, p = 0;
Packit fb9d21
  mp_sign   osign;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  /* If either input is zero, we can shortcut multiplication */
Packit fb9d21
  if (mp_int_compare_zero(a) == 0 || mp_int_compare_zero(b) == 0) {
Packit fb9d21
    mp_int_zero(c);
Packit fb9d21
    return MP_OK;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Output is positive if inputs have same sign, otherwise negative */
Packit fb9d21
  osign = (MP_SIGN(a) == MP_SIGN(b)) ? MP_ZPOS : MP_NEG;
Packit fb9d21
Packit fb9d21
  /* If the output is not identical to any of the inputs, we'll write the
Packit fb9d21
     results directly; otherwise, allocate a temporary space. */
Packit fb9d21
  ua = MP_USED(a); ub = MP_USED(b);
Packit fb9d21
  osize = MAX(ua, ub);
Packit fb9d21
  osize = 4 * ((osize + 1) / 2);
Packit fb9d21
Packit fb9d21
  if (c == a || c == b) {
Packit fb9d21
    p = ROUND_PREC(osize);
Packit fb9d21
    p = MAX(p, default_precision);
Packit fb9d21
Packit fb9d21
    if ((out = s_alloc(p)) == NULL)
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    if (!s_pad(c, osize))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
Packit fb9d21
    out = MP_DIGITS(c);
Packit fb9d21
  }
Packit fb9d21
  ZERO(out, osize);
Packit fb9d21
Packit fb9d21
  if (!s_kmul(MP_DIGITS(a), MP_DIGITS(b), out, ua, ub))
Packit fb9d21
    return MP_MEMORY;
Packit fb9d21
Packit fb9d21
  /* If we allocated a new buffer, get rid of whatever memory c was already
Packit fb9d21
     using, and fix up its fields to reflect that.
Packit fb9d21
   */
Packit fb9d21
  if (out != MP_DIGITS(c)) {
Packit fb9d21
    if ((void *) MP_DIGITS(c) != (void *) c)
Packit fb9d21
      s_free(MP_DIGITS(c));
Packit fb9d21
    MP_DIGITS(c) = out;
Packit fb9d21
    MP_ALLOC(c) = p;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  MP_USED(c) = osize; /* might not be true, but we'll fix it ... */
Packit fb9d21
  CLAMP(c);           /* ... right here */
Packit fb9d21
  MP_SIGN(c) = osign;
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_mul_value(a, value, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_mul_value(mp_int a, mp_small value, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t    vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
Packit fb9d21
  return mp_int_mul(a, &vtmp, c);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_mul_pow2(a, p2, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_mul_pow2(mp_int a, mp_small p2, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
  CHECK(a != NULL && c != NULL && p2 >= 0);
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_copy(a, c)) != MP_OK)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  if (s_qmul(c, (mp_size) p2))
Packit fb9d21
    return MP_OK;
Packit fb9d21
  else
Packit fb9d21
    return MP_MEMORY;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_sqr(a, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_sqr(mp_int a, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_digit *out;
Packit fb9d21
  mp_size   osize, p = 0;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  /* Get a temporary buffer big enough to hold the result */
Packit fb9d21
  osize = (mp_size) 4 * ((MP_USED(a) + 1) / 2);
Packit fb9d21
  if (a == c) {
Packit fb9d21
    p = ROUND_PREC(osize);
Packit fb9d21
    p = MAX(p, default_precision);
Packit fb9d21
Packit fb9d21
    if ((out = s_alloc(p)) == NULL)
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    if (!s_pad(c, osize))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
Packit fb9d21
    out = MP_DIGITS(c);
Packit fb9d21
  }
Packit fb9d21
  ZERO(out, osize);
Packit fb9d21
Packit fb9d21
  s_ksqr(MP_DIGITS(a), out, MP_USED(a));
Packit fb9d21
Packit fb9d21
  /* Get rid of whatever memory c was already using, and fix up its fields to
Packit fb9d21
     reflect the new digit array it's using
Packit fb9d21
   */
Packit fb9d21
  if (out != MP_DIGITS(c)) {
Packit fb9d21
    if ((void *) MP_DIGITS(c) != (void *) c)
Packit fb9d21
      s_free(MP_DIGITS(c));
Packit fb9d21
    MP_DIGITS(c) = out;
Packit fb9d21
    MP_ALLOC(c) = p;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  MP_USED(c) = osize; /* might not be true, but we'll fix it ... */
Packit fb9d21
  CLAMP(c);           /* ... right here */
Packit fb9d21
  MP_SIGN(c) = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_div(a, b, q, r) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_div(mp_int a, mp_int b, mp_int q, mp_int r)
Packit fb9d21
{
Packit fb9d21
  int cmp, lg;
Packit fb9d21
  mp_result res = MP_OK;
Packit fb9d21
  mp_int qout, rout;
Packit fb9d21
  mp_sign sa = MP_SIGN(a), sb = MP_SIGN(b);
Packit fb9d21
  DECLARE_TEMP(2);
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && q != r);
Packit fb9d21
Packit fb9d21
  if (CMPZ(b) == 0)
Packit fb9d21
    return MP_UNDEF;
Packit fb9d21
  else if ((cmp = s_ucmp(a, b)) < 0) {
Packit fb9d21
    /* If |a| < |b|, no division is required:
Packit fb9d21
       q = 0, r = a
Packit fb9d21
     */
Packit fb9d21
    if (r && (res = mp_int_copy(a, r)) != MP_OK)
Packit fb9d21
      return res;
Packit fb9d21
Packit fb9d21
    if (q)
Packit fb9d21
      mp_int_zero(q);
Packit fb9d21
Packit fb9d21
    return MP_OK;
Packit fb9d21
  }
Packit fb9d21
  else if (cmp == 0) {
Packit fb9d21
    /* If |a| = |b|, no division is required:
Packit fb9d21
       q = 1 or -1, r = 0
Packit fb9d21
     */
Packit fb9d21
    if (r)
Packit fb9d21
      mp_int_zero(r);
Packit fb9d21
Packit fb9d21
    if (q) {
Packit fb9d21
      mp_int_zero(q);
Packit fb9d21
      q->digits[0] = 1;
Packit fb9d21
Packit fb9d21
      if (sa != sb)
Packit fb9d21
	MP_SIGN(q) = MP_NEG;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    return MP_OK;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* When |a| > |b|, real division is required.  We need someplace to store
Packit fb9d21
     quotient and remainder, but q and r are allowed to be NULL or to overlap
Packit fb9d21
     with the inputs.
Packit fb9d21
   */
Packit fb9d21
  if ((lg = s_isp2(b)) < 0) {
Packit fb9d21
    if (q && b != q) {
Packit fb9d21
      if ((res = mp_int_copy(a, q)) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
      else
Packit fb9d21
	qout = q;
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      qout = LAST_TEMP();
Packit fb9d21
      SETUP(mp_int_init_copy(LAST_TEMP(), a));
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    if (r && a != r) {
Packit fb9d21
      if ((res = mp_int_copy(b, r)) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
      else
Packit fb9d21
	rout = r;
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      rout = LAST_TEMP();
Packit fb9d21
      SETUP(mp_int_init_copy(LAST_TEMP(), b));
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    if ((res = s_udiv_knuth(qout, rout)) != MP_OK) goto CLEANUP;
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    if (q && (res = mp_int_copy(a, q)) != MP_OK) goto CLEANUP;
Packit fb9d21
    if (r && (res = mp_int_copy(a, r)) != MP_OK) goto CLEANUP;
Packit fb9d21
Packit fb9d21
    if (q) s_qdiv(q, (mp_size) lg); qout = q;
Packit fb9d21
    if (r) s_qmod(r, (mp_size) lg); rout = r;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Recompute signs for output */
Packit fb9d21
  if (rout) {
Packit fb9d21
    MP_SIGN(rout) = sa;
Packit fb9d21
    if (CMPZ(rout) == 0)
Packit fb9d21
      MP_SIGN(rout) = MP_ZPOS;
Packit fb9d21
  }
Packit fb9d21
  if (qout) {
Packit fb9d21
    MP_SIGN(qout) = (sa == sb) ? MP_ZPOS : MP_NEG;
Packit fb9d21
    if (CMPZ(qout) == 0)
Packit fb9d21
      MP_SIGN(qout) = MP_ZPOS;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (q && (res = mp_int_copy(qout, q)) != MP_OK) goto CLEANUP;
Packit fb9d21
  if (r && (res = mp_int_copy(rout, r)) != MP_OK) goto CLEANUP;
Packit fb9d21
Packit fb9d21
  CLEANUP_TEMP();
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_mod(a, m, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_mod(mp_int a, mp_int m, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
  mpz_t     tmp;
Packit fb9d21
  mp_int    out;
Packit fb9d21
Packit fb9d21
  if (m == c) {
Packit fb9d21
    mp_int_init(&tmp);
Packit fb9d21
    out = &tm;;
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    out = c;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_div(a, m, NULL, out)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  if (CMPZ(out) < 0)
Packit fb9d21
    res = mp_int_add(out, m, c);
Packit fb9d21
  else
Packit fb9d21
    res = mp_int_copy(out, c);
Packit fb9d21
Packit fb9d21
 CLEANUP:
Packit fb9d21
  if (out != c)
Packit fb9d21
    mp_int_clear(&tmp);
Packit fb9d21
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_div_value(a, value, q, r) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_div_value(mp_int a, mp_small value, mp_int q, mp_small *r)
Packit fb9d21
{
Packit fb9d21
  mpz_t     vtmp, rtmp;
Packit fb9d21
  mp_digit  vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
  mp_result res;
Packit fb9d21
Packit fb9d21
  mp_int_init(&rtmp);
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_div(a, &vtmp, q, &rtmp)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  if (r)
Packit fb9d21
    (void) mp_int_to_int(&rtmp, r); /* can't fail */
Packit fb9d21
Packit fb9d21
 CLEANUP:
Packit fb9d21
  mp_int_clear(&rtmp);
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_div_pow2(a, p2, q, r) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_div_pow2(mp_int a, mp_small p2, mp_int q, mp_int r)
Packit fb9d21
{
Packit fb9d21
  mp_result res = MP_OK;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && p2 >= 0 && q != r);
Packit fb9d21
Packit fb9d21
  if (q != NULL && (res = mp_int_copy(a, q)) == MP_OK)
Packit fb9d21
    s_qdiv(q, (mp_size) p2);
Packit fb9d21
Packit fb9d21
  if (res == MP_OK && r != NULL && (res = mp_int_copy(a, r)) == MP_OK)
Packit fb9d21
    s_qmod(r, (mp_size) p2);
Packit fb9d21
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_expt(a, b, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_expt(mp_int a, mp_small b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t t;
Packit fb9d21
  mp_result res;
Packit fb9d21
  unsigned int v = abs(b);
Packit fb9d21
Packit fb9d21
  CHECK(c != NULL);
Packit fb9d21
  if (b < 0)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_init_copy(&t, a)) != MP_OK)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  (void) mp_int_set_value(c, 1);
Packit fb9d21
  while (v != 0) {
Packit fb9d21
    if (v & 1) {
Packit fb9d21
      if ((res = mp_int_mul(c, &t, c)) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    v >>= 1;
Packit fb9d21
    if (v == 0) break;
Packit fb9d21
Packit fb9d21
    if ((res = mp_int_sqr(&t, &t)) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
 CLEANUP:
Packit fb9d21
  mp_int_clear(&t);
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_expt_value(a, b, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_expt_value(mp_small a, mp_small b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t     t;
Packit fb9d21
  mp_result res;
Packit fb9d21
  unsigned int v = abs(b);
Packit fb9d21
Packit fb9d21
  CHECK(c != NULL);
Packit fb9d21
  if (b < 0)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_init_value(&t, a)) != MP_OK)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  (void) mp_int_set_value(c, 1);
Packit fb9d21
  while (v != 0) {
Packit fb9d21
    if (v & 1) {
Packit fb9d21
      if ((res = mp_int_mul(c, &t, c)) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    v >>= 1;
Packit fb9d21
    if (v == 0) break;
Packit fb9d21
Packit fb9d21
    if ((res = mp_int_sqr(&t, &t)) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
 CLEANUP:
Packit fb9d21
  mp_int_clear(&t);
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_expt_full(a, b, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_expt_full(mp_int a, mp_int b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t t;
Packit fb9d21
  mp_result res;
Packit fb9d21
  unsigned ix, jx;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL);
Packit fb9d21
  if (MP_SIGN(b) == MP_NEG)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_init_copy(&t, a)) != MP_OK)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  (void) mp_int_set_value(c, 1);
Packit fb9d21
  for (ix = 0; ix < MP_USED(b); ++ix) {
Packit fb9d21
    mp_digit d = b->digits[ix];
Packit fb9d21
Packit fb9d21
    for (jx = 0; jx < MP_DIGIT_BIT; ++jx) {
Packit fb9d21
      if (d & 1) {
Packit fb9d21
	if ((res = mp_int_mul(c, &t, c)) != MP_OK)
Packit fb9d21
	  goto CLEANUP;
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
      d >>= 1;
Packit fb9d21
      if (d == 0 && ix + 1 == MP_USED(b))
Packit fb9d21
	break;
Packit fb9d21
      if ((res = mp_int_sqr(&t, &t)) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
 CLEANUP:
Packit fb9d21
  mp_int_clear(&t);
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_compare(a, b) */
Packit fb9d21
Packit fb9d21
int       mp_int_compare(mp_int a, mp_int b)
Packit fb9d21
{
Packit fb9d21
  mp_sign sa;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL);
Packit fb9d21
Packit fb9d21
  sa = MP_SIGN(a);
Packit fb9d21
  if (sa == MP_SIGN(b)) {
Packit fb9d21
    int cmp = s_ucmp(a, b);
Packit fb9d21
Packit fb9d21
    /* If they're both zero or positive, the normal comparison applies; if both
Packit fb9d21
       negative, the sense is reversed. */
Packit fb9d21
    if (sa == MP_ZPOS)
Packit fb9d21
      return cmp;
Packit fb9d21
    else
Packit fb9d21
      return -cmp;
Packit fb9d21
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    if (sa == MP_ZPOS)
Packit fb9d21
      return 1;
Packit fb9d21
    else
Packit fb9d21
      return -1;
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_compare_unsigned(a, b) */
Packit fb9d21
Packit fb9d21
int       mp_int_compare_unsigned(mp_int a, mp_int b)
Packit fb9d21
{
Packit fb9d21
  NRCHECK(a != NULL && b != NULL);
Packit fb9d21
Packit fb9d21
  return s_ucmp(a, b);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_compare_zero(z) */
Packit fb9d21
Packit fb9d21
int       mp_int_compare_zero(mp_int z)
Packit fb9d21
{
Packit fb9d21
  NRCHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  if (MP_USED(z) == 1 && z->digits[0] == 0)
Packit fb9d21
    return 0;
Packit fb9d21
  else if (MP_SIGN(z) == MP_ZPOS)
Packit fb9d21
    return 1;
Packit fb9d21
  else
Packit fb9d21
    return -1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_compare_value(z, value) */
Packit fb9d21
Packit fb9d21
int       mp_int_compare_value(mp_int z, mp_small value)
Packit fb9d21
{
Packit fb9d21
  mp_sign vsign = (value < 0) ? MP_NEG : MP_ZPOS;
Packit fb9d21
  int cmp;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  if (vsign == MP_SIGN(z)) {
Packit fb9d21
    cmp = s_vcmp(z, value);
Packit fb9d21
Packit fb9d21
    return (vsign == MP_ZPOS) ? cmp : -cmp;
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    return (value < 0) ? 1 : -1;
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_compare_uvalue(z, uv) */
Packit fb9d21
Packit fb9d21
int       mp_int_compare_uvalue(mp_int z, mp_usmall uv)
Packit fb9d21
{
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  if (MP_SIGN(z) == MP_NEG)
Packit fb9d21
    return -1;
Packit fb9d21
  else
Packit fb9d21
    return s_uvcmp(z, uv);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_exptmod(a, b, m, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
  mp_size um;
Packit fb9d21
  mp_int s;
Packit fb9d21
  DECLARE_TEMP(3);
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL && m != NULL);
Packit fb9d21
Packit fb9d21
  /* Zero moduli and negative exponents are not considered. */
Packit fb9d21
  if (CMPZ(m) == 0)
Packit fb9d21
    return MP_UNDEF;
Packit fb9d21
  if (CMPZ(b) < 0)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  um = MP_USED(m);
Packit fb9d21
  SETUP(mp_int_init_size(TEMP(0), 2 * um));
Packit fb9d21
  SETUP(mp_int_init_size(TEMP(1), 2 * um));
Packit fb9d21
Packit fb9d21
  if (c == b || c == m) {
Packit fb9d21
    SETUP(mp_int_init_size(TEMP(2), 2 * um));
Packit fb9d21
    s = TEMP(2);
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    s = c;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP;
Packit fb9d21
Packit fb9d21
  if ((res = s_brmu(TEMP(1), m)) != MP_OK) goto CLEANUP;
Packit fb9d21
Packit fb9d21
  if ((res = s_embar(TEMP(0), b, m, TEMP(1), s)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  res = mp_int_copy(s, c);
Packit fb9d21
Packit fb9d21
  CLEANUP_TEMP();
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_exptmod_evalue(a, value, m, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_exptmod_evalue(mp_int a, mp_small value, mp_int m, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
Packit fb9d21
  return mp_int_exptmod(a, &vtmp, m, c);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_exptmod_bvalue(v, b, m, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_exptmod_bvalue(mp_small value, mp_int b,
Packit fb9d21
				mp_int m, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t vtmp;
Packit fb9d21
  mp_digit vbuf[MP_VALUE_DIGITS(value)];
Packit fb9d21
Packit fb9d21
  s_fake(&vtmp, value, vbuf);
Packit fb9d21
Packit fb9d21
  return mp_int_exptmod(&vtmp, b, m, c);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_exptmod_known(a, b, m, mu, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_exptmod_known(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
  mp_size um;
Packit fb9d21
  mp_int s;
Packit fb9d21
  DECLARE_TEMP(2);
Packit fb9d21
Packit fb9d21
  CHECK(a && b && m && c);
Packit fb9d21
Packit fb9d21
  /* Zero moduli and negative exponents are not considered. */
Packit fb9d21
  if (CMPZ(m) == 0)
Packit fb9d21
    return MP_UNDEF;
Packit fb9d21
  if (CMPZ(b) < 0)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  um = MP_USED(m);
Packit fb9d21
  SETUP(mp_int_init_size(TEMP(0), 2 * um));
Packit fb9d21
Packit fb9d21
  if (c == b || c == m) {
Packit fb9d21
    SETUP(mp_int_init_size(TEMP(1), 2 * um));
Packit fb9d21
    s = TEMP(1);
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    s = c;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP;
Packit fb9d21
Packit fb9d21
  if ((res = s_embar(TEMP(0), b, m, mu, s)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  res = mp_int_copy(s, c);
Packit fb9d21
Packit fb9d21
  CLEANUP_TEMP();
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_redux_const(m, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_redux_const(mp_int m, mp_int c)
Packit fb9d21
{
Packit fb9d21
  CHECK(m != NULL && c != NULL && m != c);
Packit fb9d21
Packit fb9d21
  return s_brmu(c, m);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_invmod(a, m, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
  mp_sign sa;
Packit fb9d21
  DECLARE_TEMP(2);
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && m != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  if (CMPZ(a) == 0 || CMPZ(m) <= 0)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  sa = MP_SIGN(a); /* need this for the result later */
Packit fb9d21
Packit fb9d21
  for (last__ = 0; last__ < 2; ++last__)
Packit fb9d21
    mp_int_init(LAST_TEMP());
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_egcd(a, m, TEMP(0), TEMP(1), NULL)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  if (mp_int_compare_value(TEMP(0), 1) != 0) {
Packit fb9d21
    res = MP_UNDEF;
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* It is first necessary to constrain the value to the proper range */
Packit fb9d21
  if ((res = mp_int_mod(TEMP(1), m, TEMP(1))) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  /* Now, if 'a' was originally negative, the value we have is actually the
Packit fb9d21
     magnitude of the negative representative; to get the positive value we
Packit fb9d21
     have to subtract from the modulus.  Otherwise, the value is okay as it
Packit fb9d21
     stands.
Packit fb9d21
   */
Packit fb9d21
  if (sa == MP_NEG)
Packit fb9d21
    res = mp_int_sub(m, TEMP(1), c);
Packit fb9d21
  else
Packit fb9d21
    res = mp_int_copy(TEMP(1), c);
Packit fb9d21
Packit fb9d21
  CLEANUP_TEMP();
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_gcd(a, b, c) */
Packit fb9d21
Packit fb9d21
/* Binary GCD algorithm due to Josef Stein, 1961 */
Packit fb9d21
mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  int ca, cb, k = 0;
Packit fb9d21
  mpz_t u, v, t;
Packit fb9d21
  mp_result res;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  ca = CMPZ(a);
Packit fb9d21
  cb = CMPZ(b);
Packit fb9d21
  if (ca == 0 && cb == 0)
Packit fb9d21
    return MP_UNDEF;
Packit fb9d21
  else if (ca == 0)
Packit fb9d21
    return mp_int_abs(b, c);
Packit fb9d21
  else if (cb == 0)
Packit fb9d21
    return mp_int_abs(a, c);
Packit fb9d21
Packit fb9d21
  mp_int_init(&t);
Packit fb9d21
  if ((res = mp_int_init_copy(&u, a)) != MP_OK)
Packit fb9d21
    goto U;
Packit fb9d21
  if ((res = mp_int_init_copy(&v, b)) != MP_OK)
Packit fb9d21
    goto V;
Packit fb9d21
Packit fb9d21
  MP_SIGN(&u) = MP_ZPOS; MP_SIGN(&v) = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  { /* Divide out common factors of 2 from u and v */
Packit fb9d21
    int div2_u = s_dp2k(&u), div2_v = s_dp2k(&v);
Packit fb9d21
Packit fb9d21
    k = MIN(div2_u, div2_v);
Packit fb9d21
    s_qdiv(&u, (mp_size) k);
Packit fb9d21
    s_qdiv(&v, (mp_size) k);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (mp_int_is_odd(&u)) {
Packit fb9d21
    if ((res = mp_int_neg(&v, &t)) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    if ((res = mp_int_copy(&u, &t)) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  for (;;) {
Packit fb9d21
    s_qdiv(&t, s_dp2k(&t);;
Packit fb9d21
Packit fb9d21
    if (CMPZ(&t) > 0) {
Packit fb9d21
      if ((res = mp_int_copy(&t, &u)) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      if ((res = mp_int_neg(&t, &v)) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    if ((res = mp_int_sub(&u, &v, &t)) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
Packit fb9d21
    if (CMPZ(&t) == 0)
Packit fb9d21
      break;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_abs(&u, c)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
  if (!s_qmul(c, (mp_size) k))
Packit fb9d21
    res = MP_MEMORY;
Packit fb9d21
Packit fb9d21
 CLEANUP:
Packit fb9d21
  mp_int_clear(&v);
Packit fb9d21
 V: mp_int_clear(&u);
Packit fb9d21
 U: mp_int_clear(&t);
Packit fb9d21
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_egcd(a, b, c, x, y) */
Packit fb9d21
Packit fb9d21
/* This is the binary GCD algorithm again, but this time we keep track of the
Packit fb9d21
   elementary matrix operations as we go, so we can get values x and y
Packit fb9d21
   satisfying c = ax + by.
Packit fb9d21
 */
Packit fb9d21
mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c,
Packit fb9d21
		      mp_int x, mp_int y)
Packit fb9d21
{
Packit fb9d21
  int k, ca, cb;
Packit fb9d21
  mp_result res;
Packit fb9d21
  DECLARE_TEMP(8);
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL &&
Packit fb9d21
	(x != NULL || y != NULL));
Packit fb9d21
Packit fb9d21
  ca = CMPZ(a);
Packit fb9d21
  cb = CMPZ(b);
Packit fb9d21
  if (ca == 0 && cb == 0)
Packit fb9d21
    return MP_UNDEF;
Packit fb9d21
  else if (ca == 0) {
Packit fb9d21
    if ((res = mp_int_abs(b, c)) != MP_OK) return res;
Packit fb9d21
    mp_int_zero(x); (void) mp_int_set_value(y, 1); return MP_OK;
Packit fb9d21
  }
Packit fb9d21
  else if (cb == 0) {
Packit fb9d21
    if ((res = mp_int_abs(a, c)) != MP_OK) return res;
Packit fb9d21
    (void) mp_int_set_value(x, 1); mp_int_zero(y); return MP_OK;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Initialize temporaries:
Packit fb9d21
     A:0, B:1, C:2, D:3, u:4, v:5, ou:6, ov:7 */
Packit fb9d21
  for (last__ = 0; last__ < 4; ++last__)
Packit fb9d21
    mp_int_init(LAST_TEMP());
Packit fb9d21
  TEMP(0)->digits[0] = 1;
Packit fb9d21
  TEMP(3)->digits[0] = 1;
Packit fb9d21
Packit fb9d21
  SETUP(mp_int_init_copy(TEMP(4), a));
Packit fb9d21
  SETUP(mp_int_init_copy(TEMP(5), b));
Packit fb9d21
Packit fb9d21
  /* We will work with absolute values here */
Packit fb9d21
  MP_SIGN(TEMP(4)) = MP_ZPOS;
Packit fb9d21
  MP_SIGN(TEMP(5)) = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  { /* Divide out common factors of 2 from u and v */
Packit fb9d21
    int  div2_u = s_dp2k(TEMP(4)), div2_v = s_dp2k(TEMP(5));
Packit fb9d21
Packit fb9d21
    k = MIN(div2_u, div2_v);
Packit fb9d21
    s_qdiv(TEMP(4), k);
Packit fb9d21
    s_qdiv(TEMP(5), k);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  SETUP(mp_int_init_copy(TEMP(6), TEMP(4)));
Packit fb9d21
  SETUP(mp_int_init_copy(TEMP(7), TEMP(5)));
Packit fb9d21
Packit fb9d21
  for (;;) {
Packit fb9d21
    while (mp_int_is_even(TEMP(4))) {
Packit fb9d21
      s_qdiv(TEMP(4), 1);
Packit fb9d21
Packit fb9d21
      if (mp_int_is_odd(TEMP(0)) || mp_int_is_odd(TEMP(1))) {
Packit fb9d21
	if ((res = mp_int_add(TEMP(0), TEMP(7), TEMP(0))) != MP_OK)
Packit fb9d21
	  goto CLEANUP;
Packit fb9d21
	if ((res = mp_int_sub(TEMP(1), TEMP(6), TEMP(1))) != MP_OK)
Packit fb9d21
	  goto CLEANUP;
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
      s_qdiv(TEMP(0), 1);
Packit fb9d21
      s_qdiv(TEMP(1), 1);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    while (mp_int_is_even(TEMP(5))) {
Packit fb9d21
      s_qdiv(TEMP(5), 1);
Packit fb9d21
Packit fb9d21
      if (mp_int_is_odd(TEMP(2)) || mp_int_is_odd(TEMP(3))) {
Packit fb9d21
	if ((res = mp_int_add(TEMP(2), TEMP(7), TEMP(2))) != MP_OK)
Packit fb9d21
	  goto CLEANUP;
Packit fb9d21
	if ((res = mp_int_sub(TEMP(3), TEMP(6), TEMP(3))) != MP_OK)
Packit fb9d21
	  goto CLEANUP;
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
      s_qdiv(TEMP(2), 1);
Packit fb9d21
      s_qdiv(TEMP(3), 1);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    if (mp_int_compare(TEMP(4), TEMP(5)) >= 0) {
Packit fb9d21
      if ((res = mp_int_sub(TEMP(4), TEMP(5), TEMP(4))) != MP_OK) goto CLEANUP;
Packit fb9d21
      if ((res = mp_int_sub(TEMP(0), TEMP(2), TEMP(0))) != MP_OK) goto CLEANUP;
Packit fb9d21
      if ((res = mp_int_sub(TEMP(1), TEMP(3), TEMP(1))) != MP_OK) goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      if ((res = mp_int_sub(TEMP(5), TEMP(4), TEMP(5))) != MP_OK) goto CLEANUP;
Packit fb9d21
      if ((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK) goto CLEANUP;
Packit fb9d21
      if ((res = mp_int_sub(TEMP(3), TEMP(1), TEMP(3))) != MP_OK) goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    if (CMPZ(TEMP(4)) == 0) {
Packit fb9d21
      if (x && (res = mp_int_copy(TEMP(2), x)) != MP_OK) goto CLEANUP;
Packit fb9d21
      if (y && (res = mp_int_copy(TEMP(3), y)) != MP_OK) goto CLEANUP;
Packit fb9d21
      if (c) {
Packit fb9d21
	if (!s_qmul(TEMP(5), k)) {
Packit fb9d21
	  res = MP_MEMORY;
Packit fb9d21
	  goto CLEANUP;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	res = mp_int_copy(TEMP(5), c);
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
      break;
Packit fb9d21
    }
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  CLEANUP_TEMP();
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_lcm(a, b, c) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_lcm(mp_int a, mp_int b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mpz_t lcm;
Packit fb9d21
  mp_result res;
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && b != NULL && c != NULL);
Packit fb9d21
Packit fb9d21
  /* Since a * b = gcd(a, b) * lcm(a, b), we can compute
Packit fb9d21
     lcm(a, b) = (a / gcd(a, b)) * b.
Packit fb9d21
Packit fb9d21
     This formulation insures everything works even if the input
Packit fb9d21
     variables share space.
Packit fb9d21
   */
Packit fb9d21
  if ((res = mp_int_init(&lcm)) != MP_OK)
Packit fb9d21
    return res;
Packit fb9d21
  if ((res = mp_int_gcd(a, b, &lcm)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
  if ((res = mp_int_div(a, &lcm, &lcm, NULL)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
  if ((res = mp_int_mul(&lcm, b, &lcm)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  res = mp_int_copy(&lcm, c);
Packit fb9d21
Packit fb9d21
  CLEANUP:
Packit fb9d21
    mp_int_clear(&lcm;;
Packit fb9d21
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_divisible_value(a, v) */
Packit fb9d21
Packit fb9d21
int       mp_int_divisible_value(mp_int a, mp_small v)
Packit fb9d21
{
Packit fb9d21
  mp_small rem = 0;
Packit fb9d21
Packit fb9d21
  if (mp_int_div_value(a, v, NULL, &rem) != MP_OK)
Packit fb9d21
    return 0;
Packit fb9d21
Packit fb9d21
  return rem == 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_is_pow2(z) */
Packit fb9d21
Packit fb9d21
int       mp_int_is_pow2(mp_int z)
Packit fb9d21
{
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  return s_isp2(z);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_root(a, b, c) */
Packit fb9d21
Packit fb9d21
/* Implementation of Newton's root finding method, based loosely on a patch
Packit fb9d21
   contributed by Hal Finkel <half@halssoftware.com>
Packit fb9d21
   modified by M. J. Fromberger.
Packit fb9d21
 */
Packit fb9d21
mp_result mp_int_root(mp_int a, mp_small b, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_result res = MP_OK;
Packit fb9d21
  int flips = 0;
Packit fb9d21
  DECLARE_TEMP(5);
Packit fb9d21
Packit fb9d21
  CHECK(a != NULL && c != NULL && b > 0);
Packit fb9d21
Packit fb9d21
  if (b == 1) {
Packit fb9d21
    return mp_int_copy(a, c);
Packit fb9d21
  }
Packit fb9d21
  if (MP_SIGN(a) == MP_NEG) {
Packit fb9d21
    if (b % 2 == 0)
Packit fb9d21
      return MP_UNDEF; /* root does not exist for negative a with even b */
Packit fb9d21
    else
Packit fb9d21
      flips = 1;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  SETUP(mp_int_init_copy(LAST_TEMP(), a));
Packit fb9d21
  SETUP(mp_int_init_copy(LAST_TEMP(), a));
Packit fb9d21
  SETUP(mp_int_init(LAST_TEMP()));
Packit fb9d21
  SETUP(mp_int_init(LAST_TEMP()));
Packit fb9d21
  SETUP(mp_int_init(LAST_TEMP()));
Packit fb9d21
Packit fb9d21
  (void) mp_int_abs(TEMP(0), TEMP(0));
Packit fb9d21
  (void) mp_int_abs(TEMP(1), TEMP(1));
Packit fb9d21
Packit fb9d21
  for (;;) {
Packit fb9d21
    if ((res = mp_int_expt(TEMP(1), b, TEMP(2))) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
Packit fb9d21
    if (mp_int_compare_unsigned(TEMP(2), TEMP(0)) <= 0)
Packit fb9d21
      break;
Packit fb9d21
Packit fb9d21
    if ((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
    if ((res = mp_int_expt(TEMP(1), b - 1, TEMP(3))) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
    if ((res = mp_int_mul_value(TEMP(3), b, TEMP(3))) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
    if ((res = mp_int_div(TEMP(2), TEMP(3), TEMP(4), NULL)) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
    if ((res = mp_int_sub(TEMP(1), TEMP(4), TEMP(4))) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
Packit fb9d21
    if (mp_int_compare_unsigned(TEMP(1), TEMP(4)) == 0) {
Packit fb9d21
      if ((res = mp_int_sub_value(TEMP(4), 1, TEMP(4))) != MP_OK)
Packit fb9d21
	goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
    if ((res = mp_int_copy(TEMP(4), TEMP(1))) != MP_OK)
Packit fb9d21
      goto CLEANUP;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if ((res = mp_int_copy(TEMP(1), c)) != MP_OK)
Packit fb9d21
    goto CLEANUP;
Packit fb9d21
Packit fb9d21
  /* If the original value of a was negative, flip the output sign. */
Packit fb9d21
  if (flips)
Packit fb9d21
    (void) mp_int_neg(c, c); /* cannot fail */
Packit fb9d21
Packit fb9d21
  CLEANUP_TEMP();
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_to_int(z, *out) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_to_int(mp_int z, mp_small *out)
Packit fb9d21
{
Packit fb9d21
  mp_usmall uv = 0;
Packit fb9d21
  mp_size   uz;
Packit fb9d21
  mp_digit *dz;
Packit fb9d21
  mp_sign   sz;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  /* Make sure the value is representable as a small integer */
Packit fb9d21
  sz = MP_SIGN(z);
Packit fb9d21
  if ((sz == MP_ZPOS && mp_int_compare_value(z, MP_SMALL_MAX) > 0) ||
Packit fb9d21
      mp_int_compare_value(z, MP_SMALL_MIN) < 0)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  uz = MP_USED(z);
Packit fb9d21
  dz = MP_DIGITS(z) + uz - 1;
Packit fb9d21
Packit fb9d21
  while (uz > 0) {
Packit fb9d21
    uv <<= MP_DIGIT_BIT/2;
Packit fb9d21
    uv = (uv << (MP_DIGIT_BIT/2)) | *dz--;
Packit fb9d21
    --uz;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (out)
Packit fb9d21
    *out = (sz == MP_NEG) ? -(mp_small)uv : (mp_small)uv;
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_to_uint(z, *out) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_to_uint(mp_int z, mp_usmall *out)
Packit fb9d21
{
Packit fb9d21
  mp_usmall uv = 0;
Packit fb9d21
  mp_size   uz;
Packit fb9d21
  mp_digit *dz;
Packit fb9d21
  mp_sign   sz;
Packit fb9d21
  
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  /* Make sure the value is representable as an unsigned small integer */
Packit fb9d21
  sz = MP_SIGN(z);
Packit fb9d21
  if (sz == MP_NEG || mp_int_compare_uvalue(z, MP_USMALL_MAX) > 0)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
     
Packit fb9d21
  uz = MP_USED(z);
Packit fb9d21
  dz = MP_DIGITS(z) + uz - 1;
Packit fb9d21
  
Packit fb9d21
  while (uz > 0) {
Packit fb9d21
    uv <<= MP_DIGIT_BIT/2;
Packit fb9d21
    uv = (uv << (MP_DIGIT_BIT/2)) | *dz--;
Packit fb9d21
    --uz;
Packit fb9d21
  }
Packit fb9d21
  
Packit fb9d21
  if (out)
Packit fb9d21
    *out = uv;
Packit fb9d21
  
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_to_string(z, radix, str, limit) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_to_string(mp_int z, mp_size radix,
Packit fb9d21
			   char *str, int limit)
Packit fb9d21
{
Packit fb9d21
  mp_result res;
Packit fb9d21
  int       cmp = 0;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL && str != NULL && limit >= 2);
Packit fb9d21
Packit fb9d21
  if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  if (CMPZ(z) == 0) {
Packit fb9d21
    *str++ = s_val2ch(0, 1);
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    mpz_t tmp;
Packit fb9d21
    char  *h, *t;
Packit fb9d21
Packit fb9d21
    if ((res = mp_int_init_copy(&tmp, z)) != MP_OK)
Packit fb9d21
      return res;
Packit fb9d21
Packit fb9d21
    if (MP_SIGN(z) == MP_NEG) {
Packit fb9d21
      *str++ = '-';
Packit fb9d21
      --limit;
Packit fb9d21
    }
Packit fb9d21
    h = str;
Packit fb9d21
Packit fb9d21
    /* Generate digits in reverse order until finished or limit reached */
Packit fb9d21
    for (/* */; limit > 0; --limit) {
Packit fb9d21
      mp_digit d;
Packit fb9d21
Packit fb9d21
      if ((cmp = CMPZ(&tmp)) == 0)
Packit fb9d21
	break;
Packit fb9d21
Packit fb9d21
      d = s_ddiv(&tmp, (mp_digit)radix);
Packit fb9d21
      *str++ = s_val2ch(d, 1);
Packit fb9d21
    }
Packit fb9d21
    t = str - 1;
Packit fb9d21
Packit fb9d21
    /* Put digits back in correct output order */
Packit fb9d21
    while (h < t) {
Packit fb9d21
      char tc = *h;
Packit fb9d21
      *h++ = *t;
Packit fb9d21
      *t-- = tc;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    mp_int_clear(&tmp);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  *str = '\0';
Packit fb9d21
  if (cmp == 0)
Packit fb9d21
    return MP_OK;
Packit fb9d21
  else
Packit fb9d21
    return MP_TRUNC;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_string_len(z, radix) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_string_len(mp_int z, mp_size radix)
Packit fb9d21
{
Packit fb9d21
  int  len;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  len = s_outlen(z, radix) + 1; /* for terminator */
Packit fb9d21
Packit fb9d21
  /* Allow for sign marker on negatives */
Packit fb9d21
  if (MP_SIGN(z) == MP_NEG)
Packit fb9d21
    len += 1;
Packit fb9d21
Packit fb9d21
  return len;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_read_string(z, radix, *str) */
Packit fb9d21
Packit fb9d21
/* Read zero-terminated string into z */
Packit fb9d21
mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str)
Packit fb9d21
{
Packit fb9d21
  return mp_int_read_cstring(z, radix, str, NULL);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_read_cstring(z, radix, *str, **end) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, char **end)
Packit fb9d21
{
Packit fb9d21
  int ch;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL && str != NULL);
Packit fb9d21
Packit fb9d21
  if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
Packit fb9d21
    return MP_RANGE;
Packit fb9d21
Packit fb9d21
  /* Skip leading whitespace */
Packit fb9d21
  while (isspace((int)*str))
Packit fb9d21
    ++str;
Packit fb9d21
Packit fb9d21
  /* Handle leading sign tag (+/-, positive default) */
Packit fb9d21
  switch (*str) {
Packit fb9d21
  case '-':
Packit fb9d21
    MP_SIGN(z) = MP_NEG;
Packit fb9d21
    ++str;
Packit fb9d21
    break;
Packit fb9d21
  case '+':
Packit fb9d21
    ++str; /* fallthrough */
Packit fb9d21
  default:
Packit fb9d21
    MP_SIGN(z) = MP_ZPOS;
Packit fb9d21
    break;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Skip leading zeroes */
Packit fb9d21
  while ((ch = s_ch2val(*str, radix)) == 0)
Packit fb9d21
    ++str;
Packit fb9d21
Packit fb9d21
  /* Make sure there is enough space for the value */
Packit fb9d21
  if (!s_pad(z, s_inlen(strlen(str), radix)))
Packit fb9d21
    return MP_MEMORY;
Packit fb9d21
Packit fb9d21
  MP_USED(z) = 1; z->digits[0] = 0;
Packit fb9d21
Packit fb9d21
  while (*str != '\0' && ((ch = s_ch2val(*str, radix)) >= 0)) {
Packit fb9d21
    s_dmul(z, (mp_digit)radix);
Packit fb9d21
    s_dadd(z, (mp_digit)ch);
Packit fb9d21
    ++str;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  CLAMP(z);
Packit fb9d21
Packit fb9d21
  /* Override sign for zero, even if negative specified. */
Packit fb9d21
  if (CMPZ(z) == 0)
Packit fb9d21
    MP_SIGN(z) = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  if (end != NULL)
Packit fb9d21
    *end = (char *)str;
Packit fb9d21
Packit fb9d21
  /* Return a truncation error if the string has unprocessed characters
Packit fb9d21
     remaining, so the caller can tell if the whole string was done */
Packit fb9d21
  if (*str != '\0')
Packit fb9d21
    return MP_TRUNC;
Packit fb9d21
  else
Packit fb9d21
    return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_count_bits(z) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_count_bits(mp_int z)
Packit fb9d21
{
Packit fb9d21
  mp_size  nbits = 0, uz;
Packit fb9d21
  mp_digit d;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL);
Packit fb9d21
Packit fb9d21
  uz = MP_USED(z);
Packit fb9d21
  if (uz == 1 && z->digits[0] == 0)
Packit fb9d21
    return 1;
Packit fb9d21
Packit fb9d21
  --uz;
Packit fb9d21
  nbits = uz * MP_DIGIT_BIT;
Packit fb9d21
  d = z->digits[uz];
Packit fb9d21
Packit fb9d21
  while (d != 0) {
Packit fb9d21
    d >>= 1;
Packit fb9d21
    ++nbits;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return nbits;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_to_binary(z, buf, limit) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit)
Packit fb9d21
{
Packit fb9d21
  static const int PAD_FOR_2C = 1;
Packit fb9d21
Packit fb9d21
  mp_result res;
Packit fb9d21
  int limpos = limit;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL && buf != NULL);
Packit fb9d21
Packit fb9d21
  res = s_tobin(z, buf, &limpos, PAD_FOR_2C);
Packit fb9d21
Packit fb9d21
  if (MP_SIGN(z) == MP_NEG)
Packit fb9d21
    s_2comp(buf, limpos);
Packit fb9d21
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_read_binary(z, buf, len) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len)
Packit fb9d21
{
Packit fb9d21
  mp_size need, i;
Packit fb9d21
  unsigned char *tmp;
Packit fb9d21
  mp_digit *dz;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL && buf != NULL && len > 0);
Packit fb9d21
Packit fb9d21
  /* Figure out how many digits are needed to represent this value */
Packit fb9d21
  need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT;
Packit fb9d21
  if (!s_pad(z, need))
Packit fb9d21
    return MP_MEMORY;
Packit fb9d21
Packit fb9d21
  mp_int_zero(z);
Packit fb9d21
Packit fb9d21
  /* If the high-order bit is set, take the 2's complement before reading the
Packit fb9d21
     value (it will be restored afterward) */
Packit fb9d21
  if (buf[0] >> (CHAR_BIT - 1)) {
Packit fb9d21
    MP_SIGN(z) = MP_NEG;
Packit fb9d21
    s_2comp(buf, len);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  dz = MP_DIGITS(z);
Packit fb9d21
  for (tmp = buf, i = len; i > 0; --i, ++tmp) {
Packit fb9d21
    s_qmul(z, (mp_size) CHAR_BIT);
Packit fb9d21
    *dz |= *tmp;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Restore 2's complement if we took it before */
Packit fb9d21
  if (MP_SIGN(z) == MP_NEG)
Packit fb9d21
    s_2comp(buf, len);
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_binary_len(z) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_binary_len(mp_int z)
Packit fb9d21
{
Packit fb9d21
  mp_result  res = mp_int_count_bits(z);
Packit fb9d21
  int        bytes = mp_int_unsigned_len(z);
Packit fb9d21
Packit fb9d21
  if (res <= 0)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT;
Packit fb9d21
Packit fb9d21
  /* If the highest-order bit falls exactly on a byte boundary, we need to pad
Packit fb9d21
     with an extra byte so that the sign will be read correctly when reading it
Packit fb9d21
     back in. */
Packit fb9d21
  if (bytes * CHAR_BIT == res)
Packit fb9d21
    ++bytes;
Packit fb9d21
Packit fb9d21
  return bytes;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_to_unsigned(z, buf, limit) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit)
Packit fb9d21
{
Packit fb9d21
  static const int NO_PADDING = 0;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL && buf != NULL);
Packit fb9d21
Packit fb9d21
  return s_tobin(z, buf, &limit, NO_PADDING);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_read_unsigned(z, buf, len) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len)
Packit fb9d21
{
Packit fb9d21
  mp_size need, i;
Packit fb9d21
  unsigned char *tmp;
Packit fb9d21
Packit fb9d21
  CHECK(z != NULL && buf != NULL && len > 0);
Packit fb9d21
Packit fb9d21
  /* Figure out how many digits are needed to represent this value */
Packit fb9d21
  need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT;
Packit fb9d21
  if (!s_pad(z, need))
Packit fb9d21
    return MP_MEMORY;
Packit fb9d21
Packit fb9d21
  mp_int_zero(z);
Packit fb9d21
Packit fb9d21
  for (tmp = buf, i = len; i > 0; --i, ++tmp) {
Packit fb9d21
    (void) s_qmul(z, CHAR_BIT);
Packit fb9d21
    *MP_DIGITS(z) |= *tmp;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return MP_OK;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_int_unsigned_len(z) */
Packit fb9d21
Packit fb9d21
mp_result mp_int_unsigned_len(mp_int z)
Packit fb9d21
{
Packit fb9d21
  mp_result  res = mp_int_count_bits(z);
Packit fb9d21
  int        bytes;
Packit fb9d21
Packit fb9d21
  if (res <= 0)
Packit fb9d21
    return res;
Packit fb9d21
Packit fb9d21
  bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT;
Packit fb9d21
Packit fb9d21
  return bytes;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ mp_error_string(res) */
Packit fb9d21
Packit fb9d21
const char *mp_error_string(mp_result res)
Packit fb9d21
{
Packit fb9d21
  int ix;
Packit fb9d21
  if (res > 0)
Packit fb9d21
    return s_unknown_err;
Packit fb9d21
Packit fb9d21
  res = -res;
Packit fb9d21
  for (ix = 0; ix < res && s_error_msg[ix] != NULL; ++ix)
Packit fb9d21
    ;
Packit fb9d21
Packit fb9d21
  if (s_error_msg[ix] != NULL)
Packit fb9d21
    return s_error_msg[ix];
Packit fb9d21
  else
Packit fb9d21
    return s_unknown_err;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/*------------------------------------------------------------------------*/
Packit fb9d21
/* Private functions for internal use.  These make assumptions.           */
Packit fb9d21
Packit fb9d21
/* {{{ s_alloc(num) */
Packit fb9d21
Packit fb9d21
STATIC mp_digit *s_alloc(mp_size num)
Packit fb9d21
{
Packit fb9d21
  mp_digit *out = malloc(num * sizeof(mp_digit));
Packit fb9d21
Packit fb9d21
  assert(out != NULL); /* for debugging */
Packit fb9d21
#if DEBUG > 1
Packit fb9d21
  {
Packit fb9d21
    mp_digit v = (mp_digit) 0xdeadbeef;
Packit fb9d21
    int      ix;
Packit fb9d21
Packit fb9d21
    for (ix = 0; ix < num; ++ix)
Packit fb9d21
      out[ix] = v;
Packit fb9d21
  }
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
  return out;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_realloc(old, osize, nsize) */
Packit fb9d21
Packit fb9d21
STATIC mp_digit *s_realloc(mp_digit *old, mp_size osize, mp_size nsize)
Packit fb9d21
{
Packit fb9d21
#if DEBUG > 1
Packit fb9d21
  mp_digit *new = s_alloc(nsize);
Packit fb9d21
  int       ix;
Packit fb9d21
Packit fb9d21
  for (ix = 0; ix < nsize; ++ix)
Packit fb9d21
    new[ix] = (mp_digit) 0xdeadbeef;
Packit fb9d21
Packit fb9d21
  memcpy(new, old, osize * sizeof(mp_digit));
Packit fb9d21
#else
Packit fb9d21
  mp_digit *new = realloc(old, nsize * sizeof(mp_digit));
Packit fb9d21
Packit fb9d21
  assert(new != NULL); /* for debugging */
Packit fb9d21
#endif
Packit fb9d21
  return new;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_free(ptr) */
Packit fb9d21
Packit fb9d21
STATIC void s_free(void *ptr)
Packit fb9d21
{
Packit fb9d21
  free(ptr);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_pad(z, min) */
Packit fb9d21
Packit fb9d21
STATIC int      s_pad(mp_int z, mp_size min)
Packit fb9d21
{
Packit fb9d21
  if (MP_ALLOC(z) < min) {
Packit fb9d21
    mp_size nsize = ROUND_PREC(min);
Packit fb9d21
    mp_digit *tmp;
Packit fb9d21
Packit fb9d21
    if ((void *)z->digits == (void *)z) {
Packit fb9d21
      if ((tmp = s_alloc(nsize)) == NULL)
Packit fb9d21
        return 0;
Packit fb9d21
Packit fb9d21
      COPY(MP_DIGITS(z), tmp, MP_USED(z));
Packit fb9d21
    }
Packit fb9d21
    else if ((tmp = s_realloc(MP_DIGITS(z), MP_ALLOC(z), nsize)) == NULL)
Packit fb9d21
      return 0;
Packit fb9d21
Packit fb9d21
    MP_DIGITS(z) = tmp;
Packit fb9d21
    MP_ALLOC(z) = nsize;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_fake(z, value, vbuf[]) */
Packit fb9d21
Packit fb9d21
/* Note: This will not work correctly when value == MP_SMALL_MIN */
Packit fb9d21
STATIC void      s_fake(mp_int z, mp_small value, mp_digit vbuf[])
Packit fb9d21
{
Packit fb9d21
  mp_usmall uv = (mp_usmall) (value < 0) ? -value : value;
Packit fb9d21
  s_ufake(z, uv, vbuf);
Packit fb9d21
  if (value < 0)
Packit fb9d21
    z->sign = MP_NEG;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_ufake(z, value, vbuf[]) */
Packit fb9d21
Packit fb9d21
STATIC void      s_ufake(mp_int z, mp_usmall value, mp_digit vbuf[])
Packit fb9d21
{
Packit fb9d21
  mp_size ndig = (mp_size) s_uvpack(value, vbuf);
Packit fb9d21
Packit fb9d21
  z->used = ndig;
Packit fb9d21
  z->alloc = MP_VALUE_DIGITS(value);
Packit fb9d21
  z->sign = MP_ZPOS;
Packit fb9d21
  z->digits = vbuf;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_cdig(da, db, len) */
Packit fb9d21
Packit fb9d21
STATIC int      s_cdig(mp_digit *da, mp_digit *db, mp_size len)
Packit fb9d21
{
Packit fb9d21
  mp_digit *dat = da + len - 1, *dbt = db + len - 1;
Packit fb9d21
Packit fb9d21
  for (/* */; len != 0; --len, --dat, --dbt) {
Packit fb9d21
    if (*dat > *dbt)
Packit fb9d21
      return 1;
Packit fb9d21
    else if (*dat < *dbt)
Packit fb9d21
      return -1;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_uvpack(uv, t[]) */
Packit fb9d21
Packit fb9d21
STATIC int       s_uvpack(mp_usmall uv, mp_digit t[])
Packit fb9d21
{
Packit fb9d21
  int ndig = 0;
Packit fb9d21
Packit fb9d21
  if (uv == 0)
Packit fb9d21
    t[ndig++] = 0;
Packit fb9d21
  else {
Packit fb9d21
    while (uv != 0) {
Packit fb9d21
      t[ndig++] = (mp_digit) uv;
Packit fb9d21
      uv >>= MP_DIGIT_BIT/2;
Packit fb9d21
      uv >>= MP_DIGIT_BIT/2;
Packit fb9d21
    }
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return ndig;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_ucmp(a, b) */
Packit fb9d21
Packit fb9d21
STATIC int      s_ucmp(mp_int a, mp_int b)
Packit fb9d21
{
Packit fb9d21
  mp_size  ua = MP_USED(a), ub = MP_USED(b);
Packit fb9d21
Packit fb9d21
  if (ua > ub)
Packit fb9d21
    return 1;
Packit fb9d21
  else if (ub > ua)
Packit fb9d21
    return -1;
Packit fb9d21
  else
Packit fb9d21
    return s_cdig(MP_DIGITS(a), MP_DIGITS(b), ua);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_vcmp(a, v) */
Packit fb9d21
Packit fb9d21
STATIC int      s_vcmp(mp_int a, mp_small v)
Packit fb9d21
{
Packit fb9d21
  mp_usmall uv = (mp_usmall) (v < 0) ? -v : v;
Packit fb9d21
  return s_uvcmp(a, uv);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_uvcmp(a, v) */
Packit fb9d21
Packit fb9d21
STATIC int      s_uvcmp(mp_int a, mp_usmall uv)
Packit fb9d21
{
Packit fb9d21
  mpz_t vtmp;
Packit fb9d21
  mp_digit vdig[MP_VALUE_DIGITS(uv)];
Packit fb9d21
Packit fb9d21
  s_ufake(&vtmp, uv, vdig);
Packit fb9d21
  return s_ucmp(a, &vtmp);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_uadd(da, db, dc, size_a, size_b) */
Packit fb9d21
Packit fb9d21
STATIC mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
		       mp_size size_a, mp_size size_b)
Packit fb9d21
{
Packit fb9d21
  mp_size pos;
Packit fb9d21
  mp_word w = 0;
Packit fb9d21
Packit fb9d21
  /* Insure that da is the longer of the two to simplify later code */
Packit fb9d21
  if (size_b > size_a) {
Packit fb9d21
    SWAP(mp_digit *, da, db);
Packit fb9d21
    SWAP(mp_size, size_a, size_b);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Add corresponding digits until the shorter number runs out */
Packit fb9d21
  for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) {
Packit fb9d21
    w = w + (mp_word) *da + (mp_word) *db;
Packit fb9d21
    *dc = LOWER_HALF(w);
Packit fb9d21
    w = UPPER_HALF(w);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Propagate carries as far as necessary */
Packit fb9d21
  for (/* */; pos < size_a; ++pos, ++da, ++dc) {
Packit fb9d21
    w = w + *da;
Packit fb9d21
Packit fb9d21
    *dc = LOWER_HALF(w);
Packit fb9d21
    w = UPPER_HALF(w);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Return carry out */
Packit fb9d21
  return (mp_digit)w;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_usub(da, db, dc, size_a, size_b) */
Packit fb9d21
Packit fb9d21
STATIC void     s_usub(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
		       mp_size size_a, mp_size size_b)
Packit fb9d21
{
Packit fb9d21
  mp_size pos;
Packit fb9d21
  mp_word w = 0;
Packit fb9d21
Packit fb9d21
  /* We assume that |a| >= |b| so this should definitely hold */
Packit fb9d21
  assert(size_a >= size_b);
Packit fb9d21
Packit fb9d21
  /* Subtract corresponding digits and propagate borrow */
Packit fb9d21
  for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) {
Packit fb9d21
    w = ((mp_word)MP_DIGIT_MAX + 1 +  /* MP_RADIX */
Packit fb9d21
	 (mp_word)*da) - w - (mp_word)*db;
Packit fb9d21
Packit fb9d21
    *dc = LOWER_HALF(w);
Packit fb9d21
    w = (UPPER_HALF(w) == 0);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Finish the subtraction for remaining upper digits of da */
Packit fb9d21
  for (/* */; pos < size_a; ++pos, ++da, ++dc) {
Packit fb9d21
    w = ((mp_word)MP_DIGIT_MAX + 1 +  /* MP_RADIX */
Packit fb9d21
	 (mp_word)*da) - w;
Packit fb9d21
Packit fb9d21
    *dc = LOWER_HALF(w);
Packit fb9d21
    w = (UPPER_HALF(w) == 0);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* If there is a borrow out at the end, it violates the precondition */
Packit fb9d21
  assert(w == 0);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_kmul(da, db, dc, size_a, size_b) */
Packit fb9d21
Packit fb9d21
STATIC int       s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
			mp_size size_a, mp_size size_b)
Packit fb9d21
{
Packit fb9d21
  mp_size  bot_size;
Packit fb9d21
Packit fb9d21
  /* Make sure b is the smaller of the two input values */
Packit fb9d21
  if (size_b > size_a) {
Packit fb9d21
    SWAP(mp_digit *, da, db);
Packit fb9d21
    SWAP(mp_size, size_a, size_b);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Insure that the bottom is the larger half in an odd-length split; the code
Packit fb9d21
     below relies on this being true.
Packit fb9d21
   */
Packit fb9d21
  bot_size = (size_a + 1) / 2;
Packit fb9d21
Packit fb9d21
  /* If the values are big enough to bother with recursion, use the Karatsuba
Packit fb9d21
     algorithm to compute the product; otherwise use the normal multiplication
Packit fb9d21
     algorithm
Packit fb9d21
   */
Packit fb9d21
  if (multiply_threshold &&
Packit fb9d21
      size_a >= multiply_threshold &&
Packit fb9d21
      size_b > bot_size) {
Packit fb9d21
Packit fb9d21
    mp_digit *t1, *t2, *t3, carry;
Packit fb9d21
Packit fb9d21
    mp_digit *a_top = da + bot_size;
Packit fb9d21
    mp_digit *b_top = db + bot_size;
Packit fb9d21
Packit fb9d21
    mp_size  at_size = size_a - bot_size;
Packit fb9d21
    mp_size  bt_size = size_b - bot_size;
Packit fb9d21
    mp_size  buf_size = 2 * bot_size;
Packit fb9d21
Packit fb9d21
    /* Do a single allocation for all three temporary buffers needed; each
Packit fb9d21
       buffer must be big enough to hold the product of two bottom halves, and
Packit fb9d21
       one buffer needs space for the completed product; twice the space is
Packit fb9d21
       plenty.
Packit fb9d21
     */
Packit fb9d21
    if ((t1 = s_alloc(4 * buf_size)) == NULL) return 0;
Packit fb9d21
    t2 = t1 + buf_size;
Packit fb9d21
    t3 = t2 + buf_size;
Packit fb9d21
    ZERO(t1, 4 * buf_size);
Packit fb9d21
Packit fb9d21
    /* t1 and t2 are initially used as temporaries to compute the inner product
Packit fb9d21
       (a1 + a0)(b1 + b0) = a1b1 + a1b0 + a0b1 + a0b0
Packit fb9d21
     */
Packit fb9d21
    carry = s_uadd(da, a_top, t1, bot_size, at_size);      /* t1 = a1 + a0 */
Packit fb9d21
    t1[bot_size] = carry;
Packit fb9d21
Packit fb9d21
    carry = s_uadd(db, b_top, t2, bot_size, bt_size);      /* t2 = b1 + b0 */
Packit fb9d21
    t2[bot_size] = carry;
Packit fb9d21
Packit fb9d21
    (void) s_kmul(t1, t2, t3, bot_size + 1, bot_size + 1); /* t3 = t1 * t2 */
Packit fb9d21
Packit fb9d21
    /* Now we'll get t1 = a0b0 and t2 = a1b1, and subtract them out so that
Packit fb9d21
       we're left with only the pieces we want:  t3 = a1b0 + a0b1
Packit fb9d21
     */
Packit fb9d21
    ZERO(t1, buf_size);
Packit fb9d21
    ZERO(t2, buf_size);
Packit fb9d21
    (void) s_kmul(da, db, t1, bot_size, bot_size);     /* t1 = a0 * b0 */
Packit fb9d21
    (void) s_kmul(a_top, b_top, t2, at_size, bt_size); /* t2 = a1 * b1 */
Packit fb9d21
Packit fb9d21
    /* Subtract out t1 and t2 to get the inner product */
Packit fb9d21
    s_usub(t3, t1, t3, buf_size + 2, buf_size);
Packit fb9d21
    s_usub(t3, t2, t3, buf_size + 2, buf_size);
Packit fb9d21
Packit fb9d21
    /* Assemble the output value */
Packit fb9d21
    COPY(t1, dc, buf_size);
Packit fb9d21
    carry = s_uadd(t3, dc + bot_size, dc + bot_size,
Packit fb9d21
		   buf_size + 1, buf_size);
Packit fb9d21
    assert(carry == 0);
Packit fb9d21
Packit fb9d21
    carry = s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size,
Packit fb9d21
		   buf_size, buf_size);
Packit fb9d21
    assert(carry == 0);
Packit fb9d21
Packit fb9d21
    s_free(t1); /* note t2 and t3 are just internal pointers to t1 */
Packit fb9d21
  }
Packit fb9d21
  else {
Packit fb9d21
    s_umul(da, db, dc, size_a, size_b);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_umul(da, db, dc, size_a, size_b) */
Packit fb9d21
Packit fb9d21
STATIC void     s_umul(mp_digit *da, mp_digit *db, mp_digit *dc,
Packit fb9d21
		       mp_size size_a, mp_size size_b)
Packit fb9d21
{
Packit fb9d21
  mp_size a, b;
Packit fb9d21
  mp_word w;
Packit fb9d21
Packit fb9d21
  for (a = 0; a < size_a; ++a, ++dc, ++da) {
Packit fb9d21
    mp_digit *dct = dc;
Packit fb9d21
    mp_digit *dbt = db;
Packit fb9d21
Packit fb9d21
    if (*da == 0)
Packit fb9d21
      continue;
Packit fb9d21
Packit fb9d21
    w = 0;
Packit fb9d21
    for (b = 0; b < size_b; ++b, ++dbt, ++dct) {
Packit fb9d21
      w = (mp_word)*da * (mp_word)*dbt + w + (mp_word)*dct;
Packit fb9d21
Packit fb9d21
      *dct = LOWER_HALF(w);
Packit fb9d21
      w = UPPER_HALF(w);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    *dct = (mp_digit)w;
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_ksqr(da, dc, size_a) */
Packit fb9d21
Packit fb9d21
STATIC int       s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a)
Packit fb9d21
{
Packit fb9d21
  if (multiply_threshold && size_a > multiply_threshold) {
Packit fb9d21
    mp_size  bot_size = (size_a + 1) / 2;
Packit fb9d21
    mp_digit *a_top = da + bot_size;
Packit fb9d21
    mp_digit *t1, *t2, *t3, carry;
Packit fb9d21
    mp_size  at_size = size_a - bot_size;
Packit fb9d21
    mp_size  buf_size = 2 * bot_size;
Packit fb9d21
Packit fb9d21
    if ((t1 = s_alloc(4 * buf_size)) == NULL) return 0;
Packit fb9d21
    t2 = t1 + buf_size;
Packit fb9d21
    t3 = t2 + buf_size;
Packit fb9d21
    ZERO(t1, 4 * buf_size);
Packit fb9d21
Packit fb9d21
    (void) s_ksqr(da, t1, bot_size);    /* t1 = a0 ^ 2 */
Packit fb9d21
    (void) s_ksqr(a_top, t2, at_size);  /* t2 = a1 ^ 2 */
Packit fb9d21
Packit fb9d21
    (void) s_kmul(da, a_top, t3, bot_size, at_size);  /* t3 = a0 * a1 */
Packit fb9d21
Packit fb9d21
    /* Quick multiply t3 by 2, shifting left (can't overflow) */
Packit fb9d21
    {
Packit fb9d21
      int i, top = bot_size + at_size;
Packit fb9d21
      mp_word w, save = 0;
Packit fb9d21
Packit fb9d21
      for (i = 0; i < top; ++i) {
Packit fb9d21
	w = t3[i];
Packit fb9d21
	w = (w << 1) | save;
Packit fb9d21
	t3[i] = LOWER_HALF(w);
Packit fb9d21
	save = UPPER_HALF(w);
Packit fb9d21
      }
Packit fb9d21
      t3[i] = LOWER_HALF(save);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    /* Assemble the output value */
Packit fb9d21
    COPY(t1, dc, 2 * bot_size);
Packit fb9d21
    carry = s_uadd(t3, dc + bot_size, dc + bot_size,
Packit fb9d21
		   buf_size + 1, buf_size);
Packit fb9d21
    assert(carry == 0);
Packit fb9d21
Packit fb9d21
    carry = s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size,
Packit fb9d21
		   buf_size, buf_size);
Packit fb9d21
    assert(carry == 0);
Packit fb9d21
Packit fb9d21
    s_free(t1); /* note that t2 and t2 are internal pointers only */
Packit fb9d21
Packit fb9d21
  } 
Packit fb9d21
  else {
Packit fb9d21
    s_usqr(da, dc, size_a);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_usqr(da, dc, size_a) */
Packit fb9d21
Packit fb9d21
STATIC void      s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a)
Packit fb9d21
{
Packit fb9d21
  mp_size i, j;
Packit fb9d21
  mp_word w;
Packit fb9d21
Packit fb9d21
  for (i = 0; i < size_a; ++i, dc += 2, ++da) {
Packit fb9d21
    mp_digit  *dct = dc, *dat = da;
Packit fb9d21
Packit fb9d21
    if (*da == 0)
Packit fb9d21
      continue;
Packit fb9d21
Packit fb9d21
    /* Take care of the first digit, no rollover */
Packit fb9d21
    w = (mp_word)*dat * (mp_word)*dat + (mp_word)*dct;
Packit fb9d21
    *dct = LOWER_HALF(w);
Packit fb9d21
    w = UPPER_HALF(w);
Packit fb9d21
    ++dat; ++dct;
Packit fb9d21
Packit fb9d21
    for (j = i + 1; j < size_a; ++j, ++dat, ++dct) {
Packit fb9d21
      mp_word  t = (mp_word)*da * (mp_word)*dat;
Packit fb9d21
      mp_word  u = w + (mp_word)*dct, ov = 0;
Packit fb9d21
Packit fb9d21
      /* Check if doubling t will overflow a word */
Packit fb9d21
      if (HIGH_BIT_SET(t))
Packit fb9d21
	ov = 1;
Packit fb9d21
Packit fb9d21
      w = t + t;
Packit fb9d21
Packit fb9d21
      /* Check if adding u to w will overflow a word */
Packit fb9d21
      if (ADD_WILL_OVERFLOW(w, u))
Packit fb9d21
	ov = 1;
Packit fb9d21
Packit fb9d21
      w += u;
Packit fb9d21
Packit fb9d21
      *dct = LOWER_HALF(w);
Packit fb9d21
      w = UPPER_HALF(w);
Packit fb9d21
      if (ov) {
Packit fb9d21
	w += MP_DIGIT_MAX; /* MP_RADIX */
Packit fb9d21
	++w;
Packit fb9d21
      }
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    w = w + *dct;
Packit fb9d21
    *dct = (mp_digit)w;
Packit fb9d21
    while ((w = UPPER_HALF(w)) != 0) {
Packit fb9d21
      ++dct; w = w + *dct;
Packit fb9d21
      *dct = LOWER_HALF(w);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    assert(w == 0);
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_dadd(a, b) */
Packit fb9d21
Packit fb9d21
STATIC void      s_dadd(mp_int a, mp_digit b)
Packit fb9d21
{
Packit fb9d21
  mp_word w = 0;
Packit fb9d21
  mp_digit *da = MP_DIGITS(a);
Packit fb9d21
  mp_size ua = MP_USED(a);
Packit fb9d21
Packit fb9d21
  w = (mp_word)*da + b;
Packit fb9d21
  *da++ = LOWER_HALF(w);
Packit fb9d21
  w = UPPER_HALF(w);
Packit fb9d21
Packit fb9d21
  for (ua -= 1; ua > 0; --ua, ++da) {
Packit fb9d21
    w = (mp_word)*da + w;
Packit fb9d21
Packit fb9d21
    *da = LOWER_HALF(w);
Packit fb9d21
    w = UPPER_HALF(w);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (w) {
Packit fb9d21
    *da = (mp_digit)w;
Packit fb9d21
    MP_USED(a) += 1;
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_dmul(a, b) */
Packit fb9d21
Packit fb9d21
STATIC void      s_dmul(mp_int a, mp_digit b)
Packit fb9d21
{
Packit fb9d21
  mp_word w = 0;
Packit fb9d21
  mp_digit *da = MP_DIGITS(a);
Packit fb9d21
  mp_size ua = MP_USED(a);
Packit fb9d21
Packit fb9d21
  while (ua > 0) {
Packit fb9d21
    w = (mp_word)*da * b + w;
Packit fb9d21
    *da++ = LOWER_HALF(w);
Packit fb9d21
    w = UPPER_HALF(w);
Packit fb9d21
    --ua;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (w) {
Packit fb9d21
    *da = (mp_digit)w;
Packit fb9d21
    MP_USED(a) += 1;
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_dbmul(da, b, dc, size_a) */
Packit fb9d21
Packit fb9d21
STATIC void      s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc, mp_size size_a)
Packit fb9d21
{
Packit fb9d21
  mp_word  w = 0;
Packit fb9d21
Packit fb9d21
  while (size_a > 0) {
Packit fb9d21
    w = (mp_word)*da++ * (mp_word)b + w;
Packit fb9d21
Packit fb9d21
    *dc++ = LOWER_HALF(w);
Packit fb9d21
    w = UPPER_HALF(w);
Packit fb9d21
    --size_a;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (w)
Packit fb9d21
    *dc = LOWER_HALF(w);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_ddiv(da, d, dc, size_a) */
Packit fb9d21
Packit fb9d21
STATIC mp_digit  s_ddiv(mp_int a, mp_digit b)
Packit fb9d21
{
Packit fb9d21
  mp_word w = 0, qdigit;
Packit fb9d21
  mp_size ua = MP_USED(a);
Packit fb9d21
  mp_digit *da = MP_DIGITS(a) + ua - 1;
Packit fb9d21
Packit fb9d21
  for (/* */; ua > 0; --ua, --da) {
Packit fb9d21
    w = (w << MP_DIGIT_BIT) | *da;
Packit fb9d21
Packit fb9d21
    if (w >= b) {
Packit fb9d21
      qdigit = w / b;
Packit fb9d21
      w = w % b;
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      qdigit = 0;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    *da = (mp_digit)qdigit;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  CLAMP(a);
Packit fb9d21
  return (mp_digit)w;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_qdiv(z, p2) */
Packit fb9d21
Packit fb9d21
STATIC void     s_qdiv(mp_int z, mp_size p2)
Packit fb9d21
{
Packit fb9d21
  mp_size ndig = p2 / MP_DIGIT_BIT, nbits = p2 % MP_DIGIT_BIT;
Packit fb9d21
  mp_size uz = MP_USED(z);
Packit fb9d21
Packit fb9d21
  if (ndig) {
Packit fb9d21
    mp_size  mark;
Packit fb9d21
    mp_digit *to, *from;
Packit fb9d21
Packit fb9d21
    if (ndig >= uz) {
Packit fb9d21
      mp_int_zero(z);
Packit fb9d21
      return;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    to = MP_DIGITS(z); from = to + ndig;
Packit fb9d21
Packit fb9d21
    for (mark = ndig; mark < uz; ++mark)
Packit fb9d21
      *to++ = *from++;
Packit fb9d21
Packit fb9d21
    MP_USED(z) = uz - ndig;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (nbits) {
Packit fb9d21
    mp_digit d = 0, *dz, save;
Packit fb9d21
    mp_size  up = MP_DIGIT_BIT - nbits;
Packit fb9d21
Packit fb9d21
    uz = MP_USED(z);
Packit fb9d21
    dz = MP_DIGITS(z) + uz - 1;
Packit fb9d21
Packit fb9d21
    for (/* */; uz > 0; --uz, --dz) {
Packit fb9d21
      save = *dz;
Packit fb9d21
Packit fb9d21
      *dz = (*dz >> nbits) | (d << up);
Packit fb9d21
      d = save;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    CLAMP(z);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (MP_USED(z) == 1 && z->digits[0] == 0)
Packit fb9d21
    MP_SIGN(z) = MP_ZPOS;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_qmod(z, p2) */
Packit fb9d21
Packit fb9d21
STATIC void     s_qmod(mp_int z, mp_size p2)
Packit fb9d21
{
Packit fb9d21
  mp_size start = p2 / MP_DIGIT_BIT + 1, rest = p2 % MP_DIGIT_BIT;
Packit fb9d21
  mp_size uz = MP_USED(z);
Packit fb9d21
  mp_digit mask = (1 << rest) - 1;
Packit fb9d21
Packit fb9d21
  if (start <= uz) {
Packit fb9d21
    MP_USED(z) = start;
Packit fb9d21
    z->digits[start - 1] &= mask;
Packit fb9d21
    CLAMP(z);
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_qmul(z, p2) */
Packit fb9d21
Packit fb9d21
STATIC int      s_qmul(mp_int z, mp_size p2)
Packit fb9d21
{
Packit fb9d21
  mp_size   uz, need, rest, extra, i;
Packit fb9d21
  mp_digit *from, *to, d;
Packit fb9d21
Packit fb9d21
  if (p2 == 0)
Packit fb9d21
    return 1;
Packit fb9d21
Packit fb9d21
  uz = MP_USED(z); 
Packit fb9d21
  need = p2 / MP_DIGIT_BIT; rest = p2 % MP_DIGIT_BIT;
Packit fb9d21
Packit fb9d21
  /* Figure out if we need an extra digit at the top end; this occurs if the
Packit fb9d21
     topmost `rest' bits of the high-order digit of z are not zero, meaning
Packit fb9d21
     they will be shifted off the end if not preserved */
Packit fb9d21
  extra = 0;
Packit fb9d21
  if (rest != 0) {
Packit fb9d21
    mp_digit *dz = MP_DIGITS(z) + uz - 1;
Packit fb9d21
Packit fb9d21
    if ((*dz >> (MP_DIGIT_BIT - rest)) != 0)
Packit fb9d21
      extra = 1;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (!s_pad(z, uz + need + extra))
Packit fb9d21
    return 0;
Packit fb9d21
Packit fb9d21
  /* If we need to shift by whole digits, do that in one pass, then
Packit fb9d21
     to back and shift by partial digits.
Packit fb9d21
   */
Packit fb9d21
  if (need > 0) {
Packit fb9d21
    from = MP_DIGITS(z) + uz - 1;
Packit fb9d21
    to = from + need;
Packit fb9d21
Packit fb9d21
    for (i = 0; i < uz; ++i)
Packit fb9d21
      *to-- = *from--;
Packit fb9d21
Packit fb9d21
    ZERO(MP_DIGITS(z), need);
Packit fb9d21
    uz += need;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (rest) {
Packit fb9d21
    d = 0;
Packit fb9d21
    for (i = need, from = MP_DIGITS(z) + need; i < uz; ++i, ++from) {
Packit fb9d21
      mp_digit save = *from;
Packit fb9d21
      
Packit fb9d21
      *from = (*from << rest) | (d >> (MP_DIGIT_BIT - rest));
Packit fb9d21
      d = save;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    d >>= (MP_DIGIT_BIT - rest);
Packit fb9d21
    if (d != 0) {
Packit fb9d21
      *from = d;
Packit fb9d21
      uz += extra;
Packit fb9d21
    }
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  MP_USED(z) = uz;
Packit fb9d21
  CLAMP(z);
Packit fb9d21
Packit fb9d21
  return 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_qsub(z, p2) */
Packit fb9d21
Packit fb9d21
/* Compute z = 2^p2 - |z|; requires that 2^p2 >= |z|
Packit fb9d21
   The sign of the result is always zero/positive.
Packit fb9d21
 */
Packit fb9d21
STATIC int       s_qsub(mp_int z, mp_size p2)
Packit fb9d21
{
Packit fb9d21
  mp_digit hi = (1 << (p2 % MP_DIGIT_BIT)), *zp;
Packit fb9d21
  mp_size  tdig = (p2 / MP_DIGIT_BIT), pos;
Packit fb9d21
  mp_word  w = 0;
Packit fb9d21
Packit fb9d21
  if (!s_pad(z, tdig + 1))
Packit fb9d21
    return 0;
Packit fb9d21
Packit fb9d21
  for (pos = 0, zp = MP_DIGITS(z); pos < tdig; ++pos, ++zp) {
Packit fb9d21
    w = ((mp_word) MP_DIGIT_MAX + 1) - w - (mp_word)*zp;
Packit fb9d21
Packit fb9d21
    *zp = LOWER_HALF(w);
Packit fb9d21
    w = UPPER_HALF(w) ? 0 : 1;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  w = ((mp_word) MP_DIGIT_MAX + 1 + hi) - w - (mp_word)*zp;
Packit fb9d21
  *zp = LOWER_HALF(w);
Packit fb9d21
Packit fb9d21
  assert(UPPER_HALF(w) != 0); /* no borrow out should be possible */
Packit fb9d21
Packit fb9d21
  MP_SIGN(z) = MP_ZPOS;
Packit fb9d21
  CLAMP(z);
Packit fb9d21
Packit fb9d21
  return 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_dp2k(z) */
Packit fb9d21
Packit fb9d21
STATIC int      s_dp2k(mp_int z)
Packit fb9d21
{
Packit fb9d21
  int       k = 0;
Packit fb9d21
  mp_digit *dp = MP_DIGITS(z), d;
Packit fb9d21
Packit fb9d21
  if (MP_USED(z) == 1 && *dp == 0)
Packit fb9d21
    return 1;
Packit fb9d21
Packit fb9d21
  while (*dp == 0) {
Packit fb9d21
    k += MP_DIGIT_BIT;
Packit fb9d21
    ++dp;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  d = *dp;
Packit fb9d21
  while ((d & 1) == 0) {
Packit fb9d21
    d >>= 1;
Packit fb9d21
    ++k;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return k;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_isp2(z) */
Packit fb9d21
Packit fb9d21
STATIC int       s_isp2(mp_int z)
Packit fb9d21
{
Packit fb9d21
  mp_size uz = MP_USED(z), k = 0;
Packit fb9d21
  mp_digit *dz = MP_DIGITS(z), d;
Packit fb9d21
Packit fb9d21
  while (uz > 1) {
Packit fb9d21
    if (*dz++ != 0)
Packit fb9d21
      return -1;
Packit fb9d21
    k += MP_DIGIT_BIT;
Packit fb9d21
    --uz;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  d = *dz;
Packit fb9d21
  while (d > 1) {
Packit fb9d21
    if (d & 1)
Packit fb9d21
      return -1;
Packit fb9d21
    ++k; d >>= 1;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return (int) k;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_2expt(z, k) */
Packit fb9d21
Packit fb9d21
STATIC int       s_2expt(mp_int z, mp_small k)
Packit fb9d21
{
Packit fb9d21
  mp_size  ndig, rest;
Packit fb9d21
  mp_digit *dz;
Packit fb9d21
Packit fb9d21
  ndig = (k + MP_DIGIT_BIT) / MP_DIGIT_BIT;
Packit fb9d21
  rest = k % MP_DIGIT_BIT;
Packit fb9d21
Packit fb9d21
  if (!s_pad(z, ndig))
Packit fb9d21
    return 0;
Packit fb9d21
Packit fb9d21
  dz = MP_DIGITS(z);
Packit fb9d21
  ZERO(dz, ndig);
Packit fb9d21
  *(dz + ndig - 1) = (1 << rest);
Packit fb9d21
  MP_USED(z) = ndig;
Packit fb9d21
Packit fb9d21
  return 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_norm(a, b) */
Packit fb9d21
Packit fb9d21
STATIC int      s_norm(mp_int a, mp_int b)
Packit fb9d21
{
Packit fb9d21
  mp_digit d = b->digits[MP_USED(b) - 1];
Packit fb9d21
  int k = 0;
Packit fb9d21
Packit fb9d21
  while (d < (mp_digit) (1 << (MP_DIGIT_BIT - 1))) { /* d < (MP_RADIX / 2) */
Packit fb9d21
    d <<= 1;
Packit fb9d21
    ++k;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* These multiplications can't fail */
Packit fb9d21
  if (k != 0) {
Packit fb9d21
    (void) s_qmul(a, (mp_size) k);
Packit fb9d21
    (void) s_qmul(b, (mp_size) k);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  return k;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_brmu(z, m) */
Packit fb9d21
Packit fb9d21
STATIC mp_result s_brmu(mp_int z, mp_int m)
Packit fb9d21
{
Packit fb9d21
  mp_size um = MP_USED(m) * 2;
Packit fb9d21
Packit fb9d21
  if (!s_pad(z, um))
Packit fb9d21
    return MP_MEMORY;
Packit fb9d21
Packit fb9d21
  s_2expt(z, MP_DIGIT_BIT * um);
Packit fb9d21
  return mp_int_div(z, m, z, NULL);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_reduce(x, m, mu, q1, q2) */
Packit fb9d21
Packit fb9d21
STATIC int       s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2)
Packit fb9d21
{
Packit fb9d21
  mp_size   um = MP_USED(m), umb_p1, umb_m1;
Packit fb9d21
Packit fb9d21
  umb_p1 = (um + 1) * MP_DIGIT_BIT;
Packit fb9d21
  umb_m1 = (um - 1) * MP_DIGIT_BIT;
Packit fb9d21
Packit fb9d21
  if (mp_int_copy(x, q1) != MP_OK)
Packit fb9d21
    return 0;
Packit fb9d21
Packit fb9d21
  /* Compute q2 = floor((floor(x / b^(k-1)) * mu) / b^(k+1)) */
Packit fb9d21
  s_qdiv(q1, umb_m1);
Packit fb9d21
  UMUL(q1, mu, q2);
Packit fb9d21
  s_qdiv(q2, umb_p1);
Packit fb9d21
Packit fb9d21
  /* Set x = x mod b^(k+1) */
Packit fb9d21
  s_qmod(x, umb_p1);
Packit fb9d21
Packit fb9d21
  /* Now, q is a guess for the quotient a / m.
Packit fb9d21
     Compute x - q * m mod b^(k+1), replacing x.  This may be off
Packit fb9d21
     by a factor of 2m, but no more than that.
Packit fb9d21
   */
Packit fb9d21
  UMUL(q2, m, q1);
Packit fb9d21
  s_qmod(q1, umb_p1);
Packit fb9d21
  (void) mp_int_sub(x, q1, x); /* can't fail */
Packit fb9d21
Packit fb9d21
  /* The result may be < 0; if it is, add b^(k+1) to pin it in the proper
Packit fb9d21
     range. */
Packit fb9d21
  if ((CMPZ(x) < 0) && !s_qsub(x, umb_p1))
Packit fb9d21
    return 0;
Packit fb9d21
Packit fb9d21
  /* If x > m, we need to back it off until it is in range.  This will be
Packit fb9d21
     required at most twice.  */
Packit fb9d21
  if (mp_int_compare(x, m) >= 0) {
Packit fb9d21
    (void) mp_int_sub(x, m, x);
Packit fb9d21
    if (mp_int_compare(x, m) >= 0)
Packit fb9d21
      (void) mp_int_sub(x, m, x);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* At this point, x has been properly reduced. */
Packit fb9d21
  return 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_embar(a, b, m, mu, c) */
Packit fb9d21
Packit fb9d21
/* Perform modular exponentiation using Barrett's method, where mu is the
Packit fb9d21
   reduction constant for m.  Assumes a < m, b > 0. */
Packit fb9d21
STATIC mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c)
Packit fb9d21
{
Packit fb9d21
  mp_digit  *db, *dbt, umu, d;
Packit fb9d21
  mp_result res;
Packit fb9d21
  DECLARE_TEMP(3);
Packit fb9d21
Packit fb9d21
  umu = MP_USED(mu); db = MP_DIGITS(b); dbt = db + MP_USED(b) - 1;
Packit fb9d21
Packit fb9d21
  while (last__ < 3) {
Packit fb9d21
    SETUP(mp_int_init_size(LAST_TEMP(), 4 * umu));
Packit fb9d21
    ZERO(MP_DIGITS(TEMP(last__ - 1)), MP_ALLOC(TEMP(last__ - 1)));
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  (void) mp_int_set_value(c, 1);
Packit fb9d21
Packit fb9d21
  /* Take care of low-order digits */
Packit fb9d21
  while (db < dbt) {
Packit fb9d21
    int      i;
Packit fb9d21
Packit fb9d21
    for (d = *db, i = MP_DIGIT_BIT; i > 0; --i, d >>= 1) {
Packit fb9d21
      if (d & 1) {
Packit fb9d21
	/* The use of a second temporary avoids allocation */
Packit fb9d21
	UMUL(c, a, TEMP(0));
Packit fb9d21
	if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
Packit fb9d21
	  res = MP_MEMORY; goto CLEANUP;
Packit fb9d21
	}
Packit fb9d21
	mp_int_copy(TEMP(0), c);
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
Packit fb9d21
      USQR(a, TEMP(0));
Packit fb9d21
      assert(MP_SIGN(TEMP(0)) == MP_ZPOS);
Packit fb9d21
      if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
Packit fb9d21
	res = MP_MEMORY; goto CLEANUP;
Packit fb9d21
      }
Packit fb9d21
      assert(MP_SIGN(TEMP(0)) == MP_ZPOS);
Packit fb9d21
      mp_int_copy(TEMP(0), a);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    ++db;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Take care of highest-order digit */
Packit fb9d21
  d = *dbt;
Packit fb9d21
  for (;;) {
Packit fb9d21
    if (d & 1) {
Packit fb9d21
      UMUL(c, a, TEMP(0));
Packit fb9d21
      if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
Packit fb9d21
	res = MP_MEMORY; goto CLEANUP;
Packit fb9d21
      }
Packit fb9d21
      mp_int_copy(TEMP(0), c);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    d >>= 1;
Packit fb9d21
    if (!d) break;
Packit fb9d21
Packit fb9d21
    USQR(a, TEMP(0));
Packit fb9d21
    if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
Packit fb9d21
      res = MP_MEMORY; goto CLEANUP;
Packit fb9d21
    }
Packit fb9d21
    (void) mp_int_copy(TEMP(0), a);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  CLEANUP_TEMP();
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
#if 0
Packit fb9d21
/* {{{ s_udiv(a, b) */
Packit fb9d21
/* The s_udiv function produces incorrect results. For example, with test
Packit fb9d21
     div:11141460315522012760862883825:48318382095:0,230584300062375935
Packit fb9d21
   commenting out the function for now and using s_udiv_knuth instead.
Packit fb9d21
   STATIC mp_result s_udiv(mp_int a, mp_int b);
Packit fb9d21
*/
Packit fb9d21
Packit fb9d21
/* Precondition:  a >= b and b > 0
Packit fb9d21
   Postcondition: a' = a / b, b' = a % b
Packit fb9d21
 */
Packit fb9d21
STATIC mp_result s_udiv(mp_int a, mp_int b)
Packit fb9d21
{
Packit fb9d21
  mpz_t q, r, t;
Packit fb9d21
  mp_size ua, ub, qpos = 0;
Packit fb9d21
  mp_digit *da, btop;
Packit fb9d21
  mp_result res = MP_OK;
Packit fb9d21
  int k, skip = 0;
Packit fb9d21
Packit fb9d21
  /* Force signs to positive */
Packit fb9d21
  MP_SIGN(a) = MP_ZPOS;
Packit fb9d21
  MP_SIGN(b) = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  /* Normalize, per Knuth */
Packit fb9d21
  k = s_norm(a, b);
Packit fb9d21
Packit fb9d21
  ua = MP_USED(a); ub = MP_USED(b); btop = b->digits[ub - 1];
Packit fb9d21
  if ((res = mp_int_init_size(&q, ua)) != MP_OK) return res;
Packit fb9d21
  if ((res = mp_int_init_size(&t, ua + 1)) != MP_OK) goto CLEANUP;
Packit fb9d21
Packit fb9d21
  da = MP_DIGITS(a);
Packit fb9d21
  r.digits = da + ua - 1;  /* The contents of r are shared with a */
Packit fb9d21
  r.used   = 1;
Packit fb9d21
  r.sign   = MP_ZPOS;
Packit fb9d21
  r.alloc  = MP_ALLOC(a);
Packit fb9d21
  ZERO(t.digits, t.alloc);
Packit fb9d21
Packit fb9d21
  /* Solve for quotient digits, store in q.digits in reverse order */
Packit fb9d21
  while (r.digits >= da) {
Packit fb9d21
    assert(qpos <= q.alloc);
Packit fb9d21
Packit fb9d21
    if (s_ucmp(b, &r) > 0) {
Packit fb9d21
      r.digits -= 1;
Packit fb9d21
      r.used += 1;
Packit fb9d21
Packit fb9d21
      if (++skip > 1 && qpos > 0)
Packit fb9d21
	q.digits[qpos++] = 0;
Packit fb9d21
Packit fb9d21
      CLAMP(&r);
Packit fb9d21
    }
Packit fb9d21
    else {
Packit fb9d21
      mp_word  pfx = r.digits[r.used - 1];
Packit fb9d21
      mp_word  qdigit;
Packit fb9d21
Packit fb9d21
      if (r.used > 1 && pfx < btop) {
Packit fb9d21
	pfx <<= MP_DIGIT_BIT / 2;
Packit fb9d21
	pfx <<= MP_DIGIT_BIT / 2;
Packit fb9d21
	pfx |= r.digits[r.used - 2];
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
      qdigit = pfx / btop;
Packit fb9d21
      if (qdigit > MP_DIGIT_MAX) {
Packit fb9d21
	qdigit = MP_DIGIT_MAX;
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
      s_dbmul(MP_DIGITS(b), (mp_digit) qdigit, t.digits, ub);
Packit fb9d21
      t.used = ub + 1; CLAMP(&t);
Packit fb9d21
      while (s_ucmp(&t, &r) > 0) {
Packit fb9d21
	--qdigit;
Packit fb9d21
	(void) mp_int_sub(&t, b, &t); /* cannot fail */
Packit fb9d21
      }
Packit fb9d21
Packit fb9d21
      s_usub(r.digits, t.digits, r.digits, r.used, t.used);
Packit fb9d21
      CLAMP(&r);
Packit fb9d21
Packit fb9d21
      q.digits[qpos++] = (mp_digit) qdigit;
Packit fb9d21
      ZERO(t.digits, t.used);
Packit fb9d21
      skip = 0;
Packit fb9d21
    }
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Put quotient digits in the correct order, and discard extra zeroes */
Packit fb9d21
  q.used = qpos;
Packit fb9d21
  REV(mp_digit, q.digits, qpos);
Packit fb9d21
  CLAMP(&q);
Packit fb9d21
Packit fb9d21
  /* Denormalize the remainder */
Packit fb9d21
  CLAMP(a);
Packit fb9d21
  if (k != 0)
Packit fb9d21
    s_qdiv(a, k);
Packit fb9d21
Packit fb9d21
  mp_int_copy(a, b);  /* ok:  0 <= r < b */
Packit fb9d21
  mp_int_copy(&q, a); /* ok:  q <= a     */
Packit fb9d21
Packit fb9d21
  mp_int_clear(&t);
Packit fb9d21
 CLEANUP:
Packit fb9d21
  mp_int_clear(&q);
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
/* Division of nonnegative integers
Packit fb9d21
Packit fb9d21
   This function implements division algorithm for unsigned multi-precision
Packit fb9d21
   integers. The algorithm is based on Algorithm D from Knuth's "The Art of
Packit fb9d21
   Computer Programming", 3rd ed. 1998, pg 272-273.
Packit fb9d21
Packit fb9d21
   We diverge from Knuth's algorithm in that we do not perform the subtraction
Packit fb9d21
   from the remainder until we have determined that we have the correct
Packit fb9d21
   quotient digit. This makes our algorithm less efficient that Knuth because
Packit fb9d21
   we might have to perform multiple multiplication and comparison steps before
Packit fb9d21
   the subtraction. The advantage is that it is easy to implement and ensure
Packit fb9d21
   correctness without worrying about underflow from the subtraction.
Packit fb9d21
Packit fb9d21
   inputs: u   a n+m digit integer in base b (b is 2^MP_DIGIT_BIT)
Packit fb9d21
           v   a n   digit integer in base b (b is 2^MP_DIGIT_BIT)
Packit fb9d21
           n >= 1
Packit fb9d21
           m >= 0
Packit fb9d21
  outputs: u / v stored in u
Packit fb9d21
           u % v stored in v
Packit fb9d21
 */
Packit fb9d21
STATIC mp_result s_udiv_knuth(mp_int u, mp_int v) {
Packit fb9d21
  mpz_t q, r, t;
Packit fb9d21
  mp_result
Packit fb9d21
  res = MP_OK;
Packit fb9d21
  int k,j;
Packit fb9d21
  mp_size m,n;
Packit fb9d21
Packit fb9d21
  /* Force signs to positive */
Packit fb9d21
  MP_SIGN(u) = MP_ZPOS;
Packit fb9d21
  MP_SIGN(v) = MP_ZPOS;
Packit fb9d21
Packit fb9d21
  /* Use simple division algorithm when v is only one digit long */
Packit fb9d21
  if (MP_USED(v) == 1) {
Packit fb9d21
    mp_digit d, rem;
Packit fb9d21
    d   = v->digits[0];
Packit fb9d21
    rem = s_ddiv(u, d);
Packit fb9d21
    mp_int_set_value(v, rem);
Packit fb9d21
    return MP_OK;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /************************************************************/
Packit fb9d21
  /* Algorithm D */
Packit fb9d21
  /************************************************************/
Packit fb9d21
  /* The n and m variables are defined as used by Knuth.
Packit fb9d21
     u is an n digit number with digits u_{n-1}..u_0.
Packit fb9d21
     v is an n+m digit number with digits from v_{m+n-1}..v_0.
Packit fb9d21
     We require that n > 1 and m >= 0 */
Packit fb9d21
  n = MP_USED(v);
Packit fb9d21
  m = MP_USED(u) - n;
Packit fb9d21
  assert(n >  1);
Packit fb9d21
  assert(m >= 0);
Packit fb9d21
Packit fb9d21
  /************************************************************/
Packit fb9d21
  /* D1: Normalize.
Packit fb9d21
     The normalization step provides the necessary condition for Theorem B,
Packit fb9d21
     which states that the quotient estimate for q_j, call it qhat
Packit fb9d21
Packit fb9d21
       qhat = u_{j+n}u_{j+n-1} / v_{n-1}
Packit fb9d21
Packit fb9d21
     is bounded by
Packit fb9d21
Packit fb9d21
      qhat - 2 <= q_j <= qhat.
Packit fb9d21
Packit fb9d21
     That is, qhat is always greater than the actual quotient digit q,
Packit fb9d21
     and it is never more than two larger than the actual quotient digit.  */
Packit fb9d21
  k = s_norm(u, v);
Packit fb9d21
Packit fb9d21
  /* Extend size of u by one if needed.
Packit fb9d21
Packit fb9d21
     The algorithm begins with a value of u that has one more digit of input.
Packit fb9d21
     The normalization step sets u_{m+n}..u_0 = 2^k * u_{m+n-1}..u_0. If the
Packit fb9d21
     multiplication did not increase the number of digits of u, we need to add
Packit fb9d21
     a leading zero here.
Packit fb9d21
   */
Packit fb9d21
  if (k == 0 || MP_USED(u) != m + n + 1) {
Packit fb9d21
    if (!s_pad(u, m+n+1))
Packit fb9d21
      return MP_MEMORY;
Packit fb9d21
    u->digits[m+n] = 0;
Packit fb9d21
    u->used = m+n+1;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Add a leading 0 to v.
Packit fb9d21
Packit fb9d21
     The multiplication in step D4 multiplies qhat * 0v_{n-1}..v_0.  We need to
Packit fb9d21
     add the leading zero to v here to ensure that the multiplication will
Packit fb9d21
     produce the full n+1 digit result.  */
Packit fb9d21
  if (!s_pad(v, n+1)) return MP_MEMORY; v->digits[n] = 0;
Packit fb9d21
Packit fb9d21
  /* Initialize temporary variables q and t.
Packit fb9d21
     q allocates space for m+1 digits to store the quotient digits
Packit fb9d21
     t allocates space for n+1 digits to hold the result of q_j*v */
Packit fb9d21
  if ((res = mp_int_init_size(&q, m + 1)) != MP_OK) return res;
Packit fb9d21
  if ((res = mp_int_init_size(&t, n + 1)) != MP_OK) goto CLEANUP;
Packit fb9d21
Packit fb9d21
  /************************************************************/
Packit fb9d21
  /* D2: Initialize j */
Packit fb9d21
  j = m;
Packit fb9d21
  r.digits = MP_DIGITS(u) + j;  /* The contents of r are shared with u */
Packit fb9d21
  r.used   = n + 1;
Packit fb9d21
  r.sign   = MP_ZPOS;
Packit fb9d21
  r.alloc  = MP_ALLOC(u);
Packit fb9d21
  ZERO(t.digits, t.alloc);
Packit fb9d21
Packit fb9d21
  /* Calculate the m+1 digits of the quotient result */
Packit fb9d21
  for (; j >= 0; j--) {
Packit fb9d21
    /************************************************************/
Packit fb9d21
    /* D3: Calculate q' */
Packit fb9d21
    /* r->digits is aligned to position j of the number u */
Packit fb9d21
    mp_word pfx, qhat;
Packit fb9d21
    pfx   = r.digits[n];
Packit fb9d21
    pfx <<= MP_DIGIT_BIT / 2;
Packit fb9d21
    pfx <<= MP_DIGIT_BIT / 2;
Packit fb9d21
    pfx |= r.digits[n-1]; /* pfx = u_{j+n}{j+n-1} */
Packit fb9d21
Packit fb9d21
    qhat = pfx / v->digits[n-1];
Packit fb9d21
    /* Check to see if qhat > b, and decrease qhat if so.
Packit fb9d21
       Theorem B guarantess that qhat is at most 2 larger than the
Packit fb9d21
       actual value, so it is possible that qhat is greater than
Packit fb9d21
       the maximum value that will fit in a digit */
Packit fb9d21
    if (qhat > MP_DIGIT_MAX)
Packit fb9d21
      qhat = MP_DIGIT_MAX;
Packit fb9d21
Packit fb9d21
    /************************************************************/
Packit fb9d21
    /* D4,D5,D6: Multiply qhat * v and test for a correct value of q
Packit fb9d21
Packit fb9d21
       We proceed a bit different than the way described by Knuth. This way is
Packit fb9d21
       simpler but less efficent. Instead of doing the multiply and subtract
Packit fb9d21
       then checking for underflow, we first do the multiply of qhat * v and
Packit fb9d21
       see if it is larger than the current remainder r. If it is larger, we
Packit fb9d21
       decrease qhat by one and try again. We may need to decrease qhat one
Packit fb9d21
       more time before we get a value that is smaller than r.
Packit fb9d21
Packit fb9d21
       This way is less efficent than Knuth becuase we do more multiplies, but
Packit fb9d21
       we do not need to worry about underflow this way.  */
Packit fb9d21
    /* t = qhat * v */
Packit fb9d21
    s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1); t.used = n + 1;
Packit fb9d21
    CLAMP(&t);
Packit fb9d21
Packit fb9d21
    /* Clamp r for the comparison. Comparisons do not like leading zeros. */
Packit fb9d21
    CLAMP(&r);
Packit fb9d21
    if (s_ucmp(&t, &r) > 0) {   /* would the remainder be negative? */
Packit fb9d21
      qhat -= 1;   /* try a smaller q */
Packit fb9d21
      s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1);
Packit fb9d21
      t.used = n + 1; CLAMP(&t);
Packit fb9d21
      if (s_ucmp(&t, &r) > 0) { /* would the remainder be negative? */
Packit fb9d21
        assert(qhat > 0);
Packit fb9d21
        qhat -= 1; /* try a smaller q */
Packit fb9d21
        s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1);
Packit fb9d21
        t.used = n + 1; CLAMP(&t);
Packit fb9d21
      }
Packit fb9d21
      assert(s_ucmp(&t, &r) <=  0 && "The mathematics failed us.");
Packit fb9d21
    }
Packit fb9d21
    /* Unclamp r. The D algorithm expects r = u_{j+n}..u_j to always be n+1
Packit fb9d21
       digits long. */
Packit fb9d21
    r.used = n + 1;
Packit fb9d21
Packit fb9d21
    /************************************************************/
Packit fb9d21
    /* D4: Multiply and subtract */
Packit fb9d21
    /* note: The multiply was completed above so we only need to subtract here.
Packit fb9d21
     **/
Packit fb9d21
    s_usub(r.digits, t.digits, r.digits, r.used, t.used);
Packit fb9d21
Packit fb9d21
    /************************************************************/
Packit fb9d21
    /* D5: Test remainder */
Packit fb9d21
    /* note: Not needed because we always check that qhat is the correct value
Packit fb9d21
     *       before performing the subtract. */
Packit fb9d21
    q.digits[j] = qhat;
Packit fb9d21
Packit fb9d21
    /************************************************************/
Packit fb9d21
    /* D6: Add back */
Packit fb9d21
    /* note: Not needed because we always check that qhat is the correct value
Packit fb9d21
     *       before performing the subtract. */
Packit fb9d21
Packit fb9d21
    /************************************************************/
Packit fb9d21
    /* D7: Loop on j */
Packit fb9d21
    r.digits--;
Packit fb9d21
    ZERO(t.digits, t.alloc);
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Get rid of leading zeros in q */
Packit fb9d21
  q.used = m + 1;
Packit fb9d21
  CLAMP(&q);
Packit fb9d21
Packit fb9d21
  /* Denormalize the remainder */
Packit fb9d21
  CLAMP(u); /* use u here because the r.digits pointer is off-by-one */
Packit fb9d21
  if (k != 0)
Packit fb9d21
    s_qdiv(u, k);
Packit fb9d21
Packit fb9d21
  mp_int_copy(u, v);  /* ok:  0 <= r < v */
Packit fb9d21
  mp_int_copy(&q, u); /* ok:  q <= u     */
Packit fb9d21
Packit fb9d21
  mp_int_clear(&t);
Packit fb9d21
 CLEANUP:
Packit fb9d21
  mp_int_clear(&q);
Packit fb9d21
  return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* {{{ s_outlen(z, r) */
Packit fb9d21
Packit fb9d21
STATIC int       s_outlen(mp_int z, mp_size r)
Packit fb9d21
{
Packit fb9d21
  mp_result bits;
Packit fb9d21
  double raw;
Packit fb9d21
Packit fb9d21
  assert(r >= MP_MIN_RADIX && r <= MP_MAX_RADIX);
Packit fb9d21
Packit fb9d21
  bits = mp_int_count_bits(z);
Packit fb9d21
  raw = (double)bits * s_log2[r];
Packit fb9d21
Packit fb9d21
  return (int)(raw + 0.999999);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_inlen(len, r) */
Packit fb9d21
Packit fb9d21
STATIC mp_size   s_inlen(int len, mp_size r)
Packit fb9d21
{
Packit fb9d21
  double  raw = (double)len / s_log2[r];
Packit fb9d21
  mp_size bits = (mp_size)(raw + 0.5);
Packit fb9d21
Packit fb9d21
  return (mp_size)((bits + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT) + 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_ch2val(c, r) */
Packit fb9d21
Packit fb9d21
STATIC int       s_ch2val(char c, int r)
Packit fb9d21
{
Packit fb9d21
  int out;
Packit fb9d21
Packit fb9d21
  if (isdigit((unsigned char) c))
Packit fb9d21
    out = c - '0';
Packit fb9d21
  else if (r > 10 && isalpha((unsigned char) c))
Packit fb9d21
    out = toupper(c) - 'A' + 10;
Packit fb9d21
  else
Packit fb9d21
    return -1;
Packit fb9d21
Packit fb9d21
  return (out >= r) ? -1 : out;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_val2ch(v, caps) */
Packit fb9d21
Packit fb9d21
STATIC char      s_val2ch(int v, int caps)
Packit fb9d21
{
Packit fb9d21
  assert(v >= 0);
Packit fb9d21
Packit fb9d21
  if (v < 10)
Packit fb9d21
    return v + '0';
Packit fb9d21
  else {
Packit fb9d21
    char out = (v - 10) + 'a';
Packit fb9d21
Packit fb9d21
    if (caps)
Packit fb9d21
      return toupper(out);
Packit fb9d21
    else
Packit fb9d21
      return out;
Packit fb9d21
  }
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_2comp(buf, len) */
Packit fb9d21
Packit fb9d21
STATIC void      s_2comp(unsigned char *buf, int len)
Packit fb9d21
{
Packit fb9d21
  int i;
Packit fb9d21
  unsigned short s = 1;
Packit fb9d21
Packit fb9d21
  for (i = len - 1; i >= 0; --i) {
Packit fb9d21
    unsigned char c = ~buf[i];
Packit fb9d21
Packit fb9d21
    s = c + s;
Packit fb9d21
    c = s & UCHAR_MAX;
Packit fb9d21
    s >>= CHAR_BIT;
Packit fb9d21
Packit fb9d21
    buf[i] = c;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* last carry out is ignored */
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_tobin(z, buf, *limpos) */
Packit fb9d21
Packit fb9d21
STATIC mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad)
Packit fb9d21
{
Packit fb9d21
  mp_size uz;
Packit fb9d21
  mp_digit *dz;
Packit fb9d21
  int pos = 0, limit = *limpos;
Packit fb9d21
Packit fb9d21
  uz = MP_USED(z); dz = MP_DIGITS(z);
Packit fb9d21
  while (uz > 0 && pos < limit) {
Packit fb9d21
    mp_digit d = *dz++;
Packit fb9d21
    int i;
Packit fb9d21
Packit fb9d21
    for (i = sizeof(mp_digit); i > 0 && pos < limit; --i) {
Packit fb9d21
      buf[pos++] = (unsigned char)d;
Packit fb9d21
      d >>= CHAR_BIT;
Packit fb9d21
Packit fb9d21
      /* Don't write leading zeroes */
Packit fb9d21
      if (d == 0 && uz == 1)
Packit fb9d21
	i = 0; /* exit loop without signaling truncation */
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    /* Detect truncation (loop exited with pos >= limit) */
Packit fb9d21
    if (i > 0) break;
Packit fb9d21
Packit fb9d21
    --uz;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  if (pad != 0 && (buf[pos - 1] >> (CHAR_BIT - 1))) {
Packit fb9d21
    if (pos < limit)
Packit fb9d21
      buf[pos++] = 0;
Packit fb9d21
    else
Packit fb9d21
      uz = 1;
Packit fb9d21
  }
Packit fb9d21
Packit fb9d21
  /* Digits are in reverse order, fix that */
Packit fb9d21
  REV(unsigned char, buf, pos);
Packit fb9d21
Packit fb9d21
  /* Return the number of bytes actually written */
Packit fb9d21
  *limpos = pos;
Packit fb9d21
Packit fb9d21
  return (uz == 0) ? MP_OK : MP_TRUNC;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* {{{ s_print(tag, z) */
Packit fb9d21
Packit fb9d21
#if DEBUG
Packit fb9d21
void      s_print(char *tag, mp_int z)
Packit fb9d21
{
Packit fb9d21
  int  i;
Packit fb9d21
Packit fb9d21
  fprintf(stderr, "%s: %c ", tag,
Packit fb9d21
	  (MP_SIGN(z) == MP_NEG) ? '-' : '+');
Packit fb9d21
Packit fb9d21
  for (i = MP_USED(z) - 1; i >= 0; --i)
Packit fb9d21
    fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), z->digits[i]);
Packit fb9d21
Packit fb9d21
  fputc('\n', stderr);
Packit fb9d21
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
void      s_print_buf(char *tag, mp_digit *buf, mp_size num)
Packit fb9d21
{
Packit fb9d21
  int i;
Packit fb9d21
Packit fb9d21
  fprintf(stderr, "%s: ", tag);
Packit fb9d21
Packit fb9d21
  for (i = num - 1; i >= 0; --i)
Packit fb9d21
    fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), buf[i]);
Packit fb9d21
Packit fb9d21
  fputc('\n', stderr);
Packit fb9d21
}
Packit fb9d21
#endif
Packit fb9d21
Packit fb9d21
/* }}} */
Packit fb9d21
Packit fb9d21
/* Here there be dragons */