xref: /freebsd/contrib/wpa/src/tls/libtommath.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * Minimal code for RSA support from LibTomMath 0.41
339beb93cSSam Leffler  * http://libtom.org/
439beb93cSSam Leffler  * http://libtom.org/files/ltm-0.41.tar.bz2
539beb93cSSam Leffler  * This library was released in public domain by Tom St Denis.
639beb93cSSam Leffler  *
739beb93cSSam Leffler  * The combination in this file may not use all of the optimized algorithms
839beb93cSSam Leffler  * from LibTomMath and may be considerable slower than the LibTomMath with its
939beb93cSSam Leffler  * default settings. The main purpose of having this version here is to make it
1039beb93cSSam Leffler  * easier to build bignum.c wrapper without having to install and build an
1139beb93cSSam Leffler  * external library.
1239beb93cSSam Leffler  *
1339beb93cSSam Leffler  * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
1439beb93cSSam Leffler  * libtommath.c file instead of using the external LibTomMath library.
1539beb93cSSam Leffler  */
1639beb93cSSam Leffler 
1739beb93cSSam Leffler #ifndef CHAR_BIT
1839beb93cSSam Leffler #define CHAR_BIT 8
1939beb93cSSam Leffler #endif
2039beb93cSSam Leffler 
2139beb93cSSam Leffler #define BN_MP_INVMOD_C
2239beb93cSSam Leffler #define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
2339beb93cSSam Leffler 			   * require BN_MP_EXPTMOD_FAST_C instead */
2439beb93cSSam Leffler #define BN_S_MP_MUL_DIGS_C
2539beb93cSSam Leffler #define BN_MP_INVMOD_SLOW_C
2639beb93cSSam Leffler #define BN_S_MP_SQR_C
2739beb93cSSam Leffler #define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
2839beb93cSSam Leffler 				 * would require other than mp_reduce */
2939beb93cSSam Leffler 
3039beb93cSSam Leffler #ifdef LTM_FAST
3139beb93cSSam Leffler 
3239beb93cSSam Leffler /* Use faster div at the cost of about 1 kB */
3339beb93cSSam Leffler #define BN_MP_MUL_D_C
3439beb93cSSam Leffler 
3539beb93cSSam Leffler /* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
3639beb93cSSam Leffler #define BN_MP_EXPTMOD_FAST_C
3739beb93cSSam Leffler #define BN_MP_MONTGOMERY_SETUP_C
3839beb93cSSam Leffler #define BN_FAST_MP_MONTGOMERY_REDUCE_C
3939beb93cSSam Leffler #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
4039beb93cSSam Leffler #define BN_MP_MUL_2_C
4139beb93cSSam Leffler 
4239beb93cSSam Leffler /* Include faster sqr at the cost of about 0.5 kB in code */
4339beb93cSSam Leffler #define BN_FAST_S_MP_SQR_C
4439beb93cSSam Leffler 
455b9c547cSRui Paulo /* About 0.25 kB of code, but ~1.7kB of stack space! */
465b9c547cSRui Paulo #define BN_FAST_S_MP_MUL_DIGS_C
475b9c547cSRui Paulo 
4839beb93cSSam Leffler #else /* LTM_FAST */
4939beb93cSSam Leffler 
5039beb93cSSam Leffler #define BN_MP_DIV_SMALL
5139beb93cSSam Leffler #define BN_MP_INIT_MULTI_C
5239beb93cSSam Leffler #define BN_MP_CLEAR_MULTI_C
5339beb93cSSam Leffler #define BN_MP_ABS_C
5439beb93cSSam Leffler #endif /* LTM_FAST */
5539beb93cSSam Leffler 
5639beb93cSSam Leffler /* Current uses do not require support for negative exponent in exptmod, so we
5739beb93cSSam Leffler  * can save about 1.5 kB in leaving out invmod. */
5839beb93cSSam Leffler #define LTM_NO_NEG_EXP
5939beb93cSSam Leffler 
6039beb93cSSam Leffler /* from tommath.h */
6139beb93cSSam Leffler 
6239beb93cSSam Leffler #define  OPT_CAST(x)
6339beb93cSSam Leffler 
64f05cddf9SRui Paulo #ifdef __x86_64__
65f05cddf9SRui Paulo typedef unsigned long mp_digit;
66f05cddf9SRui Paulo typedef unsigned long mp_word __attribute__((mode(TI)));
67f05cddf9SRui Paulo 
68f05cddf9SRui Paulo #define DIGIT_BIT 60
69f05cddf9SRui Paulo #define MP_64BIT
70f05cddf9SRui Paulo #else
7139beb93cSSam Leffler typedef unsigned long mp_digit;
7239beb93cSSam Leffler typedef u64 mp_word;
7339beb93cSSam Leffler 
7439beb93cSSam Leffler #define DIGIT_BIT          28
7539beb93cSSam Leffler #define MP_28BIT
76f05cddf9SRui Paulo #endif
7739beb93cSSam Leffler 
7839beb93cSSam Leffler 
7939beb93cSSam Leffler #define XMALLOC  os_malloc
8039beb93cSSam Leffler #define XFREE    os_free
8139beb93cSSam Leffler #define XREALLOC os_realloc
8239beb93cSSam Leffler 
8339beb93cSSam Leffler 
8439beb93cSSam Leffler #define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
8539beb93cSSam Leffler 
8639beb93cSSam Leffler #define MP_LT        -1   /* less than */
8739beb93cSSam Leffler #define MP_EQ         0   /* equal to */
8839beb93cSSam Leffler #define MP_GT         1   /* greater than */
8939beb93cSSam Leffler 
9039beb93cSSam Leffler #define MP_ZPOS       0   /* positive integer */
9139beb93cSSam Leffler #define MP_NEG        1   /* negative */
9239beb93cSSam Leffler 
9339beb93cSSam Leffler #define MP_OKAY       0   /* ok result */
9439beb93cSSam Leffler #define MP_MEM        -2  /* out of mem */
9539beb93cSSam Leffler #define MP_VAL        -3  /* invalid input */
9639beb93cSSam Leffler 
9739beb93cSSam Leffler #define MP_YES        1   /* yes response */
9839beb93cSSam Leffler #define MP_NO         0   /* no response */
9939beb93cSSam Leffler 
10039beb93cSSam Leffler typedef int           mp_err;
10139beb93cSSam Leffler 
10239beb93cSSam Leffler /* define this to use lower memory usage routines (exptmods mostly) */
10339beb93cSSam Leffler #define MP_LOW_MEM
10439beb93cSSam Leffler 
10539beb93cSSam Leffler /* default precision */
10639beb93cSSam Leffler #ifndef MP_PREC
10739beb93cSSam Leffler    #ifndef MP_LOW_MEM
10839beb93cSSam Leffler       #define MP_PREC                 32     /* default digits of precision */
10939beb93cSSam Leffler    #else
11039beb93cSSam Leffler       #define MP_PREC                 8      /* default digits of precision */
11139beb93cSSam Leffler    #endif
11239beb93cSSam Leffler #endif
11339beb93cSSam Leffler 
11439beb93cSSam Leffler /* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
11539beb93cSSam Leffler #define MP_WARRAY               (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
11639beb93cSSam Leffler 
11739beb93cSSam Leffler /* the infamous mp_int structure */
11839beb93cSSam Leffler typedef struct  {
11939beb93cSSam Leffler     int used, alloc, sign;
12039beb93cSSam Leffler     mp_digit *dp;
12139beb93cSSam Leffler } mp_int;
12239beb93cSSam Leffler 
12339beb93cSSam Leffler 
12439beb93cSSam Leffler /* ---> Basic Manipulations <--- */
12539beb93cSSam Leffler #define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
12639beb93cSSam Leffler #define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
12739beb93cSSam Leffler #define mp_isodd(a)  (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
12839beb93cSSam Leffler 
12939beb93cSSam Leffler 
13039beb93cSSam Leffler /* prototypes for copied functions */
13139beb93cSSam Leffler #define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
13239beb93cSSam Leffler static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
13339beb93cSSam Leffler static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
13439beb93cSSam Leffler static int s_mp_sqr(mp_int * a, mp_int * b);
13539beb93cSSam Leffler static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
13639beb93cSSam Leffler 
1375b9c547cSRui Paulo #ifdef BN_FAST_S_MP_MUL_DIGS_C
13839beb93cSSam Leffler static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
1395b9c547cSRui Paulo #endif
14039beb93cSSam Leffler 
14139beb93cSSam Leffler #ifdef BN_MP_INIT_MULTI_C
14239beb93cSSam Leffler static int mp_init_multi(mp_int *mp, ...);
14339beb93cSSam Leffler #endif
14439beb93cSSam Leffler #ifdef BN_MP_CLEAR_MULTI_C
14539beb93cSSam Leffler static void mp_clear_multi(mp_int *mp, ...);
14639beb93cSSam Leffler #endif
14739beb93cSSam Leffler static int mp_lshd(mp_int * a, int b);
14839beb93cSSam Leffler static void mp_set(mp_int * a, mp_digit b);
14939beb93cSSam Leffler static void mp_clamp(mp_int * a);
15039beb93cSSam Leffler static void mp_exch(mp_int * a, mp_int * b);
15139beb93cSSam Leffler static void mp_rshd(mp_int * a, int b);
15239beb93cSSam Leffler static void mp_zero(mp_int * a);
15339beb93cSSam Leffler static int mp_mod_2d(mp_int * a, int b, mp_int * c);
15439beb93cSSam Leffler static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
15539beb93cSSam Leffler static int mp_init_copy(mp_int * a, mp_int * b);
15639beb93cSSam Leffler static int mp_mul_2d(mp_int * a, int b, mp_int * c);
15739beb93cSSam Leffler #ifndef LTM_NO_NEG_EXP
15839beb93cSSam Leffler static int mp_div_2(mp_int * a, mp_int * b);
15939beb93cSSam Leffler static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
16039beb93cSSam Leffler static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
16139beb93cSSam Leffler #endif /* LTM_NO_NEG_EXP */
16239beb93cSSam Leffler static int mp_copy(mp_int * a, mp_int * b);
16339beb93cSSam Leffler static int mp_count_bits(mp_int * a);
16439beb93cSSam Leffler static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
16539beb93cSSam Leffler static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
16639beb93cSSam Leffler static int mp_grow(mp_int * a, int size);
16739beb93cSSam Leffler static int mp_cmp_mag(mp_int * a, mp_int * b);
16839beb93cSSam Leffler #ifdef BN_MP_ABS_C
16939beb93cSSam Leffler static int mp_abs(mp_int * a, mp_int * b);
17039beb93cSSam Leffler #endif
17139beb93cSSam Leffler static int mp_sqr(mp_int * a, mp_int * b);
17239beb93cSSam Leffler static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
17339beb93cSSam Leffler static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
17439beb93cSSam Leffler static int mp_2expt(mp_int * a, int b);
17539beb93cSSam Leffler static int mp_reduce_setup(mp_int * a, mp_int * b);
17639beb93cSSam Leffler static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
17739beb93cSSam Leffler static int mp_init_size(mp_int * a, int size);
17839beb93cSSam Leffler #ifdef BN_MP_EXPTMOD_FAST_C
17939beb93cSSam Leffler static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
18039beb93cSSam Leffler #endif /* BN_MP_EXPTMOD_FAST_C */
18139beb93cSSam Leffler #ifdef BN_FAST_S_MP_SQR_C
18239beb93cSSam Leffler static int fast_s_mp_sqr (mp_int * a, mp_int * b);
18339beb93cSSam Leffler #endif /* BN_FAST_S_MP_SQR_C */
18439beb93cSSam Leffler #ifdef BN_MP_MUL_D_C
18539beb93cSSam Leffler static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
18639beb93cSSam Leffler #endif /* BN_MP_MUL_D_C */
18739beb93cSSam Leffler 
18839beb93cSSam Leffler 
18939beb93cSSam Leffler 
19039beb93cSSam Leffler /* functions from bn_<func name>.c */
19139beb93cSSam Leffler 
19239beb93cSSam Leffler 
19339beb93cSSam Leffler /* reverse an array, used for radix code */
bn_reverse(unsigned char * s,int len)19439beb93cSSam Leffler static void bn_reverse (unsigned char *s, int len)
19539beb93cSSam Leffler {
19639beb93cSSam Leffler   int     ix, iy;
19739beb93cSSam Leffler   unsigned char t;
19839beb93cSSam Leffler 
19939beb93cSSam Leffler   ix = 0;
20039beb93cSSam Leffler   iy = len - 1;
20139beb93cSSam Leffler   while (ix < iy) {
20239beb93cSSam Leffler     t     = s[ix];
20339beb93cSSam Leffler     s[ix] = s[iy];
20439beb93cSSam Leffler     s[iy] = t;
20539beb93cSSam Leffler     ++ix;
20639beb93cSSam Leffler     --iy;
20739beb93cSSam Leffler   }
20839beb93cSSam Leffler }
20939beb93cSSam Leffler 
21039beb93cSSam Leffler 
21139beb93cSSam Leffler /* low level addition, based on HAC pp.594, Algorithm 14.7 */
s_mp_add(mp_int * a,mp_int * b,mp_int * c)21239beb93cSSam Leffler static int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
21339beb93cSSam Leffler {
21439beb93cSSam Leffler   mp_int *x;
21539beb93cSSam Leffler   int     olduse, res, min, max;
21639beb93cSSam Leffler 
21739beb93cSSam Leffler   /* find sizes, we let |a| <= |b| which means we have to sort
21839beb93cSSam Leffler    * them.  "x" will point to the input with the most digits
21939beb93cSSam Leffler    */
22039beb93cSSam Leffler   if (a->used > b->used) {
22139beb93cSSam Leffler     min = b->used;
22239beb93cSSam Leffler     max = a->used;
22339beb93cSSam Leffler     x = a;
22439beb93cSSam Leffler   } else {
22539beb93cSSam Leffler     min = a->used;
22639beb93cSSam Leffler     max = b->used;
22739beb93cSSam Leffler     x = b;
22839beb93cSSam Leffler   }
22939beb93cSSam Leffler 
23039beb93cSSam Leffler   /* init result */
23139beb93cSSam Leffler   if (c->alloc < max + 1) {
23239beb93cSSam Leffler     if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
23339beb93cSSam Leffler       return res;
23439beb93cSSam Leffler     }
23539beb93cSSam Leffler   }
23639beb93cSSam Leffler 
23739beb93cSSam Leffler   /* get old used digit count and set new one */
23839beb93cSSam Leffler   olduse = c->used;
23939beb93cSSam Leffler   c->used = max + 1;
24039beb93cSSam Leffler 
24139beb93cSSam Leffler   {
24239beb93cSSam Leffler     register mp_digit u, *tmpa, *tmpb, *tmpc;
24339beb93cSSam Leffler     register int i;
24439beb93cSSam Leffler 
24539beb93cSSam Leffler     /* alias for digit pointers */
24639beb93cSSam Leffler 
24739beb93cSSam Leffler     /* first input */
24839beb93cSSam Leffler     tmpa = a->dp;
24939beb93cSSam Leffler 
25039beb93cSSam Leffler     /* second input */
25139beb93cSSam Leffler     tmpb = b->dp;
25239beb93cSSam Leffler 
25339beb93cSSam Leffler     /* destination */
25439beb93cSSam Leffler     tmpc = c->dp;
25539beb93cSSam Leffler 
25639beb93cSSam Leffler     /* zero the carry */
25739beb93cSSam Leffler     u = 0;
25839beb93cSSam Leffler     for (i = 0; i < min; i++) {
25939beb93cSSam Leffler       /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
26039beb93cSSam Leffler       *tmpc = *tmpa++ + *tmpb++ + u;
26139beb93cSSam Leffler 
26239beb93cSSam Leffler       /* U = carry bit of T[i] */
26339beb93cSSam Leffler       u = *tmpc >> ((mp_digit)DIGIT_BIT);
26439beb93cSSam Leffler 
26539beb93cSSam Leffler       /* take away carry bit from T[i] */
26639beb93cSSam Leffler       *tmpc++ &= MP_MASK;
26739beb93cSSam Leffler     }
26839beb93cSSam Leffler 
26939beb93cSSam Leffler     /* now copy higher words if any, that is in A+B
27039beb93cSSam Leffler      * if A or B has more digits add those in
27139beb93cSSam Leffler      */
27239beb93cSSam Leffler     if (min != max) {
27339beb93cSSam Leffler       for (; i < max; i++) {
27439beb93cSSam Leffler         /* T[i] = X[i] + U */
27539beb93cSSam Leffler         *tmpc = x->dp[i] + u;
27639beb93cSSam Leffler 
27739beb93cSSam Leffler         /* U = carry bit of T[i] */
27839beb93cSSam Leffler         u = *tmpc >> ((mp_digit)DIGIT_BIT);
27939beb93cSSam Leffler 
28039beb93cSSam Leffler         /* take away carry bit from T[i] */
28139beb93cSSam Leffler         *tmpc++ &= MP_MASK;
28239beb93cSSam Leffler       }
28339beb93cSSam Leffler     }
28439beb93cSSam Leffler 
28539beb93cSSam Leffler     /* add carry */
28639beb93cSSam Leffler     *tmpc++ = u;
28739beb93cSSam Leffler 
28839beb93cSSam Leffler     /* clear digits above oldused */
28939beb93cSSam Leffler     for (i = c->used; i < olduse; i++) {
29039beb93cSSam Leffler       *tmpc++ = 0;
29139beb93cSSam Leffler     }
29239beb93cSSam Leffler   }
29339beb93cSSam Leffler 
29439beb93cSSam Leffler   mp_clamp (c);
29539beb93cSSam Leffler   return MP_OKAY;
29639beb93cSSam Leffler }
29739beb93cSSam Leffler 
29839beb93cSSam Leffler 
29939beb93cSSam Leffler /* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
s_mp_sub(mp_int * a,mp_int * b,mp_int * c)30039beb93cSSam Leffler static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
30139beb93cSSam Leffler {
30239beb93cSSam Leffler   int     olduse, res, min, max;
30339beb93cSSam Leffler 
30439beb93cSSam Leffler   /* find sizes */
30539beb93cSSam Leffler   min = b->used;
30639beb93cSSam Leffler   max = a->used;
30739beb93cSSam Leffler 
30839beb93cSSam Leffler   /* init result */
30939beb93cSSam Leffler   if (c->alloc < max) {
31039beb93cSSam Leffler     if ((res = mp_grow (c, max)) != MP_OKAY) {
31139beb93cSSam Leffler       return res;
31239beb93cSSam Leffler     }
31339beb93cSSam Leffler   }
31439beb93cSSam Leffler   olduse = c->used;
31539beb93cSSam Leffler   c->used = max;
31639beb93cSSam Leffler 
31739beb93cSSam Leffler   {
31839beb93cSSam Leffler     register mp_digit u, *tmpa, *tmpb, *tmpc;
31939beb93cSSam Leffler     register int i;
32039beb93cSSam Leffler 
32139beb93cSSam Leffler     /* alias for digit pointers */
32239beb93cSSam Leffler     tmpa = a->dp;
32339beb93cSSam Leffler     tmpb = b->dp;
32439beb93cSSam Leffler     tmpc = c->dp;
32539beb93cSSam Leffler 
32639beb93cSSam Leffler     /* set carry to zero */
32739beb93cSSam Leffler     u = 0;
32839beb93cSSam Leffler     for (i = 0; i < min; i++) {
32939beb93cSSam Leffler       /* T[i] = A[i] - B[i] - U */
33039beb93cSSam Leffler       *tmpc = *tmpa++ - *tmpb++ - u;
33139beb93cSSam Leffler 
33239beb93cSSam Leffler       /* U = carry bit of T[i]
33339beb93cSSam Leffler        * Note this saves performing an AND operation since
33439beb93cSSam Leffler        * if a carry does occur it will propagate all the way to the
33539beb93cSSam Leffler        * MSB.  As a result a single shift is enough to get the carry
33639beb93cSSam Leffler        */
33739beb93cSSam Leffler       u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
33839beb93cSSam Leffler 
33939beb93cSSam Leffler       /* Clear carry from T[i] */
34039beb93cSSam Leffler       *tmpc++ &= MP_MASK;
34139beb93cSSam Leffler     }
34239beb93cSSam Leffler 
34339beb93cSSam Leffler     /* now copy higher words if any, e.g. if A has more digits than B  */
34439beb93cSSam Leffler     for (; i < max; i++) {
34539beb93cSSam Leffler       /* T[i] = A[i] - U */
34639beb93cSSam Leffler       *tmpc = *tmpa++ - u;
34739beb93cSSam Leffler 
34839beb93cSSam Leffler       /* U = carry bit of T[i] */
34939beb93cSSam Leffler       u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
35039beb93cSSam Leffler 
35139beb93cSSam Leffler       /* Clear carry from T[i] */
35239beb93cSSam Leffler       *tmpc++ &= MP_MASK;
35339beb93cSSam Leffler     }
35439beb93cSSam Leffler 
35539beb93cSSam Leffler     /* clear digits above used (since we may not have grown result above) */
35639beb93cSSam Leffler     for (i = c->used; i < olduse; i++) {
35739beb93cSSam Leffler       *tmpc++ = 0;
35839beb93cSSam Leffler     }
35939beb93cSSam Leffler   }
36039beb93cSSam Leffler 
36139beb93cSSam Leffler   mp_clamp (c);
36239beb93cSSam Leffler   return MP_OKAY;
36339beb93cSSam Leffler }
36439beb93cSSam Leffler 
36539beb93cSSam Leffler 
36639beb93cSSam Leffler /* init a new mp_int */
mp_init(mp_int * a)36739beb93cSSam Leffler static int mp_init (mp_int * a)
36839beb93cSSam Leffler {
36939beb93cSSam Leffler   int i;
37039beb93cSSam Leffler 
37139beb93cSSam Leffler   /* allocate memory required and clear it */
37239beb93cSSam Leffler   a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
37339beb93cSSam Leffler   if (a->dp == NULL) {
37439beb93cSSam Leffler     return MP_MEM;
37539beb93cSSam Leffler   }
37639beb93cSSam Leffler 
37739beb93cSSam Leffler   /* set the digits to zero */
37839beb93cSSam Leffler   for (i = 0; i < MP_PREC; i++) {
37939beb93cSSam Leffler       a->dp[i] = 0;
38039beb93cSSam Leffler   }
38139beb93cSSam Leffler 
38239beb93cSSam Leffler   /* set the used to zero, allocated digits to the default precision
38339beb93cSSam Leffler    * and sign to positive */
38439beb93cSSam Leffler   a->used  = 0;
38539beb93cSSam Leffler   a->alloc = MP_PREC;
38639beb93cSSam Leffler   a->sign  = MP_ZPOS;
38739beb93cSSam Leffler 
38839beb93cSSam Leffler   return MP_OKAY;
38939beb93cSSam Leffler }
39039beb93cSSam Leffler 
39139beb93cSSam Leffler 
39239beb93cSSam Leffler /* clear one (frees)  */
mp_clear(mp_int * a)39339beb93cSSam Leffler static void mp_clear (mp_int * a)
39439beb93cSSam Leffler {
39539beb93cSSam Leffler   int i;
39639beb93cSSam Leffler 
39739beb93cSSam Leffler   /* only do anything if a hasn't been freed previously */
39839beb93cSSam Leffler   if (a->dp != NULL) {
39939beb93cSSam Leffler     /* first zero the digits */
40039beb93cSSam Leffler     for (i = 0; i < a->used; i++) {
40139beb93cSSam Leffler         a->dp[i] = 0;
40239beb93cSSam Leffler     }
40339beb93cSSam Leffler 
40439beb93cSSam Leffler     /* free ram */
40539beb93cSSam Leffler     XFREE(a->dp);
40639beb93cSSam Leffler 
40739beb93cSSam Leffler     /* reset members to make debugging easier */
40839beb93cSSam Leffler     a->dp    = NULL;
40939beb93cSSam Leffler     a->alloc = a->used = 0;
41039beb93cSSam Leffler     a->sign  = MP_ZPOS;
41139beb93cSSam Leffler   }
41239beb93cSSam Leffler }
41339beb93cSSam Leffler 
41439beb93cSSam Leffler 
41539beb93cSSam Leffler /* high level addition (handles signs) */
mp_add(mp_int * a,mp_int * b,mp_int * c)41639beb93cSSam Leffler static int mp_add (mp_int * a, mp_int * b, mp_int * c)
41739beb93cSSam Leffler {
41839beb93cSSam Leffler   int     sa, sb, res;
41939beb93cSSam Leffler 
42039beb93cSSam Leffler   /* get sign of both inputs */
42139beb93cSSam Leffler   sa = a->sign;
42239beb93cSSam Leffler   sb = b->sign;
42339beb93cSSam Leffler 
42439beb93cSSam Leffler   /* handle two cases, not four */
42539beb93cSSam Leffler   if (sa == sb) {
42639beb93cSSam Leffler     /* both positive or both negative */
42739beb93cSSam Leffler     /* add their magnitudes, copy the sign */
42839beb93cSSam Leffler     c->sign = sa;
42939beb93cSSam Leffler     res = s_mp_add (a, b, c);
43039beb93cSSam Leffler   } else {
43139beb93cSSam Leffler     /* one positive, the other negative */
43239beb93cSSam Leffler     /* subtract the one with the greater magnitude from */
43339beb93cSSam Leffler     /* the one of the lesser magnitude.  The result gets */
43439beb93cSSam Leffler     /* the sign of the one with the greater magnitude. */
43539beb93cSSam Leffler     if (mp_cmp_mag (a, b) == MP_LT) {
43639beb93cSSam Leffler       c->sign = sb;
43739beb93cSSam Leffler       res = s_mp_sub (b, a, c);
43839beb93cSSam Leffler     } else {
43939beb93cSSam Leffler       c->sign = sa;
44039beb93cSSam Leffler       res = s_mp_sub (a, b, c);
44139beb93cSSam Leffler     }
44239beb93cSSam Leffler   }
44339beb93cSSam Leffler   return res;
44439beb93cSSam Leffler }
44539beb93cSSam Leffler 
44639beb93cSSam Leffler 
44739beb93cSSam Leffler /* high level subtraction (handles signs) */
mp_sub(mp_int * a,mp_int * b,mp_int * c)44839beb93cSSam Leffler static int mp_sub (mp_int * a, mp_int * b, mp_int * c)
44939beb93cSSam Leffler {
45039beb93cSSam Leffler   int     sa, sb, res;
45139beb93cSSam Leffler 
45239beb93cSSam Leffler   sa = a->sign;
45339beb93cSSam Leffler   sb = b->sign;
45439beb93cSSam Leffler 
45539beb93cSSam Leffler   if (sa != sb) {
45639beb93cSSam Leffler     /* subtract a negative from a positive, OR */
45739beb93cSSam Leffler     /* subtract a positive from a negative. */
45839beb93cSSam Leffler     /* In either case, ADD their magnitudes, */
45939beb93cSSam Leffler     /* and use the sign of the first number. */
46039beb93cSSam Leffler     c->sign = sa;
46139beb93cSSam Leffler     res = s_mp_add (a, b, c);
46239beb93cSSam Leffler   } else {
46339beb93cSSam Leffler     /* subtract a positive from a positive, OR */
46439beb93cSSam Leffler     /* subtract a negative from a negative. */
46539beb93cSSam Leffler     /* First, take the difference between their */
46639beb93cSSam Leffler     /* magnitudes, then... */
46739beb93cSSam Leffler     if (mp_cmp_mag (a, b) != MP_LT) {
46839beb93cSSam Leffler       /* Copy the sign from the first */
46939beb93cSSam Leffler       c->sign = sa;
47039beb93cSSam Leffler       /* The first has a larger or equal magnitude */
47139beb93cSSam Leffler       res = s_mp_sub (a, b, c);
47239beb93cSSam Leffler     } else {
47339beb93cSSam Leffler       /* The result has the *opposite* sign from */
47439beb93cSSam Leffler       /* the first number. */
47539beb93cSSam Leffler       c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
47639beb93cSSam Leffler       /* The second has a larger magnitude */
47739beb93cSSam Leffler       res = s_mp_sub (b, a, c);
47839beb93cSSam Leffler     }
47939beb93cSSam Leffler   }
48039beb93cSSam Leffler   return res;
48139beb93cSSam Leffler }
48239beb93cSSam Leffler 
48339beb93cSSam Leffler 
48439beb93cSSam Leffler /* high level multiplication (handles sign) */
mp_mul(mp_int * a,mp_int * b,mp_int * c)48539beb93cSSam Leffler static int mp_mul (mp_int * a, mp_int * b, mp_int * c)
48639beb93cSSam Leffler {
48739beb93cSSam Leffler   int     res, neg;
48839beb93cSSam Leffler   neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
48939beb93cSSam Leffler 
49039beb93cSSam Leffler   /* use Toom-Cook? */
49139beb93cSSam Leffler #ifdef BN_MP_TOOM_MUL_C
49239beb93cSSam Leffler   if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
49339beb93cSSam Leffler     res = mp_toom_mul(a, b, c);
49439beb93cSSam Leffler   } else
49539beb93cSSam Leffler #endif
49639beb93cSSam Leffler #ifdef BN_MP_KARATSUBA_MUL_C
49739beb93cSSam Leffler   /* use Karatsuba? */
49839beb93cSSam Leffler   if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
49939beb93cSSam Leffler     res = mp_karatsuba_mul (a, b, c);
50039beb93cSSam Leffler   } else
50139beb93cSSam Leffler #endif
50239beb93cSSam Leffler   {
50339beb93cSSam Leffler     /* can we use the fast multiplier?
50439beb93cSSam Leffler      *
50539beb93cSSam Leffler      * The fast multiplier can be used if the output will
50639beb93cSSam Leffler      * have less than MP_WARRAY digits and the number of
50739beb93cSSam Leffler      * digits won't affect carry propagation
50839beb93cSSam Leffler      */
50939beb93cSSam Leffler #ifdef BN_FAST_S_MP_MUL_DIGS_C
51039beb93cSSam Leffler     int     digs = a->used + b->used + 1;
51139beb93cSSam Leffler 
51239beb93cSSam Leffler     if ((digs < MP_WARRAY) &&
51339beb93cSSam Leffler         MIN(a->used, b->used) <=
51439beb93cSSam Leffler         (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
51539beb93cSSam Leffler       res = fast_s_mp_mul_digs (a, b, c, digs);
51639beb93cSSam Leffler     } else
51739beb93cSSam Leffler #endif
51839beb93cSSam Leffler #ifdef BN_S_MP_MUL_DIGS_C
51939beb93cSSam Leffler       res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
52039beb93cSSam Leffler #else
52139beb93cSSam Leffler #error mp_mul could fail
52239beb93cSSam Leffler       res = MP_VAL;
52339beb93cSSam Leffler #endif
52439beb93cSSam Leffler 
52539beb93cSSam Leffler   }
52639beb93cSSam Leffler   c->sign = (c->used > 0) ? neg : MP_ZPOS;
52739beb93cSSam Leffler   return res;
52839beb93cSSam Leffler }
52939beb93cSSam Leffler 
53039beb93cSSam Leffler 
53139beb93cSSam Leffler /* d = a * b (mod c) */
mp_mulmod(mp_int * a,mp_int * b,mp_int * c,mp_int * d)53239beb93cSSam Leffler static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
53339beb93cSSam Leffler {
53439beb93cSSam Leffler   int     res;
53539beb93cSSam Leffler   mp_int  t;
53639beb93cSSam Leffler 
53739beb93cSSam Leffler   if ((res = mp_init (&t)) != MP_OKAY) {
53839beb93cSSam Leffler     return res;
53939beb93cSSam Leffler   }
54039beb93cSSam Leffler 
54139beb93cSSam Leffler   if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
54239beb93cSSam Leffler     mp_clear (&t);
54339beb93cSSam Leffler     return res;
54439beb93cSSam Leffler   }
54539beb93cSSam Leffler   res = mp_mod (&t, c, d);
54639beb93cSSam Leffler   mp_clear (&t);
54739beb93cSSam Leffler   return res;
54839beb93cSSam Leffler }
54939beb93cSSam Leffler 
55039beb93cSSam Leffler 
55139beb93cSSam Leffler /* c = a mod b, 0 <= c < b */
mp_mod(mp_int * a,mp_int * b,mp_int * c)55239beb93cSSam Leffler static int mp_mod (mp_int * a, mp_int * b, mp_int * c)
55339beb93cSSam Leffler {
55439beb93cSSam Leffler   mp_int  t;
55539beb93cSSam Leffler   int     res;
55639beb93cSSam Leffler 
55739beb93cSSam Leffler   if ((res = mp_init (&t)) != MP_OKAY) {
55839beb93cSSam Leffler     return res;
55939beb93cSSam Leffler   }
56039beb93cSSam Leffler 
56139beb93cSSam Leffler   if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
56239beb93cSSam Leffler     mp_clear (&t);
56339beb93cSSam Leffler     return res;
56439beb93cSSam Leffler   }
56539beb93cSSam Leffler 
56639beb93cSSam Leffler   if (t.sign != b->sign) {
56739beb93cSSam Leffler     res = mp_add (b, &t, c);
56839beb93cSSam Leffler   } else {
56939beb93cSSam Leffler     res = MP_OKAY;
57039beb93cSSam Leffler     mp_exch (&t, c);
57139beb93cSSam Leffler   }
57239beb93cSSam Leffler 
57339beb93cSSam Leffler   mp_clear (&t);
57439beb93cSSam Leffler   return res;
57539beb93cSSam Leffler }
57639beb93cSSam Leffler 
57739beb93cSSam Leffler 
57839beb93cSSam Leffler /* this is a shell function that calls either the normal or Montgomery
57939beb93cSSam Leffler  * exptmod functions.  Originally the call to the montgomery code was
58039beb93cSSam Leffler  * embedded in the normal function but that wasted a lot of stack space
58139beb93cSSam Leffler  * for nothing (since 99% of the time the Montgomery code would be called)
58239beb93cSSam Leffler  */
mp_exptmod(mp_int * G,mp_int * X,mp_int * P,mp_int * Y)58339beb93cSSam Leffler static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
58439beb93cSSam Leffler {
58539beb93cSSam Leffler   int dr;
58639beb93cSSam Leffler 
58739beb93cSSam Leffler   /* modulus P must be positive */
58839beb93cSSam Leffler   if (P->sign == MP_NEG) {
58939beb93cSSam Leffler      return MP_VAL;
59039beb93cSSam Leffler   }
59139beb93cSSam Leffler 
59239beb93cSSam Leffler   /* if exponent X is negative we have to recurse */
59339beb93cSSam Leffler   if (X->sign == MP_NEG) {
59439beb93cSSam Leffler #ifdef LTM_NO_NEG_EXP
59539beb93cSSam Leffler         return MP_VAL;
59639beb93cSSam Leffler #else /* LTM_NO_NEG_EXP */
59739beb93cSSam Leffler #ifdef BN_MP_INVMOD_C
59839beb93cSSam Leffler      mp_int tmpG, tmpX;
59939beb93cSSam Leffler      int err;
60039beb93cSSam Leffler 
60139beb93cSSam Leffler      /* first compute 1/G mod P */
60239beb93cSSam Leffler      if ((err = mp_init(&tmpG)) != MP_OKAY) {
60339beb93cSSam Leffler         return err;
60439beb93cSSam Leffler      }
60539beb93cSSam Leffler      if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
60639beb93cSSam Leffler         mp_clear(&tmpG);
60739beb93cSSam Leffler         return err;
60839beb93cSSam Leffler      }
60939beb93cSSam Leffler 
61039beb93cSSam Leffler      /* now get |X| */
61139beb93cSSam Leffler      if ((err = mp_init(&tmpX)) != MP_OKAY) {
61239beb93cSSam Leffler         mp_clear(&tmpG);
61339beb93cSSam Leffler         return err;
61439beb93cSSam Leffler      }
61539beb93cSSam Leffler      if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
61639beb93cSSam Leffler         mp_clear_multi(&tmpG, &tmpX, NULL);
61739beb93cSSam Leffler         return err;
61839beb93cSSam Leffler      }
61939beb93cSSam Leffler 
62039beb93cSSam Leffler      /* and now compute (1/G)**|X| instead of G**X [X < 0] */
62139beb93cSSam Leffler      err = mp_exptmod(&tmpG, &tmpX, P, Y);
62239beb93cSSam Leffler      mp_clear_multi(&tmpG, &tmpX, NULL);
62339beb93cSSam Leffler      return err;
62439beb93cSSam Leffler #else
62539beb93cSSam Leffler #error mp_exptmod would always fail
62639beb93cSSam Leffler      /* no invmod */
62739beb93cSSam Leffler      return MP_VAL;
62839beb93cSSam Leffler #endif
62939beb93cSSam Leffler #endif /* LTM_NO_NEG_EXP */
63039beb93cSSam Leffler   }
63139beb93cSSam Leffler 
63239beb93cSSam Leffler /* modified diminished radix reduction */
63339beb93cSSam Leffler #if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
63439beb93cSSam Leffler   if (mp_reduce_is_2k_l(P) == MP_YES) {
63539beb93cSSam Leffler      return s_mp_exptmod(G, X, P, Y, 1);
63639beb93cSSam Leffler   }
63739beb93cSSam Leffler #endif
63839beb93cSSam Leffler 
63939beb93cSSam Leffler #ifdef BN_MP_DR_IS_MODULUS_C
64039beb93cSSam Leffler   /* is it a DR modulus? */
64139beb93cSSam Leffler   dr = mp_dr_is_modulus(P);
64239beb93cSSam Leffler #else
64339beb93cSSam Leffler   /* default to no */
64439beb93cSSam Leffler   dr = 0;
64539beb93cSSam Leffler #endif
64639beb93cSSam Leffler 
64739beb93cSSam Leffler #ifdef BN_MP_REDUCE_IS_2K_C
64839beb93cSSam Leffler   /* if not, is it a unrestricted DR modulus? */
64939beb93cSSam Leffler   if (dr == 0) {
65039beb93cSSam Leffler      dr = mp_reduce_is_2k(P) << 1;
65139beb93cSSam Leffler   }
65239beb93cSSam Leffler #endif
65339beb93cSSam Leffler 
65439beb93cSSam Leffler   /* if the modulus is odd or dr != 0 use the montgomery method */
65539beb93cSSam Leffler #ifdef BN_MP_EXPTMOD_FAST_C
65639beb93cSSam Leffler   if (mp_isodd (P) == 1 || dr !=  0) {
65739beb93cSSam Leffler     return mp_exptmod_fast (G, X, P, Y, dr);
65839beb93cSSam Leffler   } else {
65939beb93cSSam Leffler #endif
66039beb93cSSam Leffler #ifdef BN_S_MP_EXPTMOD_C
66139beb93cSSam Leffler     /* otherwise use the generic Barrett reduction technique */
66239beb93cSSam Leffler     return s_mp_exptmod (G, X, P, Y, 0);
66339beb93cSSam Leffler #else
66439beb93cSSam Leffler #error mp_exptmod could fail
66539beb93cSSam Leffler     /* no exptmod for evens */
66639beb93cSSam Leffler     return MP_VAL;
66739beb93cSSam Leffler #endif
66839beb93cSSam Leffler #ifdef BN_MP_EXPTMOD_FAST_C
66939beb93cSSam Leffler   }
67039beb93cSSam Leffler #endif
6715b9c547cSRui Paulo   if (dr == 0) {
6725b9c547cSRui Paulo     /* avoid compiler warnings about possibly unused variable */
6735b9c547cSRui Paulo   }
67439beb93cSSam Leffler }
67539beb93cSSam Leffler 
67639beb93cSSam Leffler 
67739beb93cSSam Leffler /* compare two ints (signed)*/
mp_cmp(mp_int * a,mp_int * b)67839beb93cSSam Leffler static int mp_cmp (mp_int * a, mp_int * b)
67939beb93cSSam Leffler {
68039beb93cSSam Leffler   /* compare based on sign */
68139beb93cSSam Leffler   if (a->sign != b->sign) {
68239beb93cSSam Leffler      if (a->sign == MP_NEG) {
68339beb93cSSam Leffler         return MP_LT;
68439beb93cSSam Leffler      } else {
68539beb93cSSam Leffler         return MP_GT;
68639beb93cSSam Leffler      }
68739beb93cSSam Leffler   }
68839beb93cSSam Leffler 
68939beb93cSSam Leffler   /* compare digits */
69039beb93cSSam Leffler   if (a->sign == MP_NEG) {
69139beb93cSSam Leffler      /* if negative compare opposite direction */
69239beb93cSSam Leffler      return mp_cmp_mag(b, a);
69339beb93cSSam Leffler   } else {
69439beb93cSSam Leffler      return mp_cmp_mag(a, b);
69539beb93cSSam Leffler   }
69639beb93cSSam Leffler }
69739beb93cSSam Leffler 
69839beb93cSSam Leffler 
69939beb93cSSam Leffler /* compare a digit */
mp_cmp_d(mp_int * a,mp_digit b)70039beb93cSSam Leffler static int mp_cmp_d(mp_int * a, mp_digit b)
70139beb93cSSam Leffler {
70239beb93cSSam Leffler   /* compare based on sign */
70339beb93cSSam Leffler   if (a->sign == MP_NEG) {
70439beb93cSSam Leffler     return MP_LT;
70539beb93cSSam Leffler   }
70639beb93cSSam Leffler 
70739beb93cSSam Leffler   /* compare based on magnitude */
70839beb93cSSam Leffler   if (a->used > 1) {
70939beb93cSSam Leffler     return MP_GT;
71039beb93cSSam Leffler   }
71139beb93cSSam Leffler 
71239beb93cSSam Leffler   /* compare the only digit of a to b */
71339beb93cSSam Leffler   if (a->dp[0] > b) {
71439beb93cSSam Leffler     return MP_GT;
71539beb93cSSam Leffler   } else if (a->dp[0] < b) {
71639beb93cSSam Leffler     return MP_LT;
71739beb93cSSam Leffler   } else {
71839beb93cSSam Leffler     return MP_EQ;
71939beb93cSSam Leffler   }
72039beb93cSSam Leffler }
72139beb93cSSam Leffler 
72239beb93cSSam Leffler 
72339beb93cSSam Leffler #ifndef LTM_NO_NEG_EXP
72439beb93cSSam Leffler /* hac 14.61, pp608 */
mp_invmod(mp_int * a,mp_int * b,mp_int * c)72539beb93cSSam Leffler static int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
72639beb93cSSam Leffler {
72739beb93cSSam Leffler   /* b cannot be negative */
72839beb93cSSam Leffler   if (b->sign == MP_NEG || mp_iszero(b) == 1) {
72939beb93cSSam Leffler     return MP_VAL;
73039beb93cSSam Leffler   }
73139beb93cSSam Leffler 
73239beb93cSSam Leffler #ifdef BN_FAST_MP_INVMOD_C
73339beb93cSSam Leffler   /* if the modulus is odd we can use a faster routine instead */
73439beb93cSSam Leffler   if (mp_isodd (b) == 1) {
73539beb93cSSam Leffler     return fast_mp_invmod (a, b, c);
73639beb93cSSam Leffler   }
73739beb93cSSam Leffler #endif
73839beb93cSSam Leffler 
73939beb93cSSam Leffler #ifdef BN_MP_INVMOD_SLOW_C
74039beb93cSSam Leffler   return mp_invmod_slow(a, b, c);
74139beb93cSSam Leffler #endif
74239beb93cSSam Leffler 
74339beb93cSSam Leffler #ifndef BN_FAST_MP_INVMOD_C
74439beb93cSSam Leffler #ifndef BN_MP_INVMOD_SLOW_C
74539beb93cSSam Leffler #error mp_invmod would always fail
74639beb93cSSam Leffler #endif
74739beb93cSSam Leffler #endif
74839beb93cSSam Leffler   return MP_VAL;
74939beb93cSSam Leffler }
75039beb93cSSam Leffler #endif /* LTM_NO_NEG_EXP */
75139beb93cSSam Leffler 
75239beb93cSSam Leffler 
75339beb93cSSam Leffler /* get the size for an unsigned equivalent */
mp_unsigned_bin_size(mp_int * a)75439beb93cSSam Leffler static int mp_unsigned_bin_size (mp_int * a)
75539beb93cSSam Leffler {
75639beb93cSSam Leffler   int     size = mp_count_bits (a);
75739beb93cSSam Leffler   return (size / 8 + ((size & 7) != 0 ? 1 : 0));
75839beb93cSSam Leffler }
75939beb93cSSam Leffler 
76039beb93cSSam Leffler 
76139beb93cSSam Leffler #ifndef LTM_NO_NEG_EXP
76239beb93cSSam Leffler /* hac 14.61, pp608 */
mp_invmod_slow(mp_int * a,mp_int * b,mp_int * c)76339beb93cSSam Leffler static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
76439beb93cSSam Leffler {
76539beb93cSSam Leffler   mp_int  x, y, u, v, A, B, C, D;
76639beb93cSSam Leffler   int     res;
76739beb93cSSam Leffler 
76839beb93cSSam Leffler   /* b cannot be negative */
76939beb93cSSam Leffler   if (b->sign == MP_NEG || mp_iszero(b) == 1) {
77039beb93cSSam Leffler     return MP_VAL;
77139beb93cSSam Leffler   }
77239beb93cSSam Leffler 
77339beb93cSSam Leffler   /* init temps */
77439beb93cSSam Leffler   if ((res = mp_init_multi(&x, &y, &u, &v,
77539beb93cSSam Leffler                            &A, &B, &C, &D, NULL)) != MP_OKAY) {
77639beb93cSSam Leffler      return res;
77739beb93cSSam Leffler   }
77839beb93cSSam Leffler 
77939beb93cSSam Leffler   /* x = a, y = b */
78039beb93cSSam Leffler   if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
78139beb93cSSam Leffler       goto LBL_ERR;
78239beb93cSSam Leffler   }
78339beb93cSSam Leffler   if ((res = mp_copy (b, &y)) != MP_OKAY) {
78439beb93cSSam Leffler     goto LBL_ERR;
78539beb93cSSam Leffler   }
78639beb93cSSam Leffler 
78739beb93cSSam Leffler   /* 2. [modified] if x,y are both even then return an error! */
78839beb93cSSam Leffler   if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
78939beb93cSSam Leffler     res = MP_VAL;
79039beb93cSSam Leffler     goto LBL_ERR;
79139beb93cSSam Leffler   }
79239beb93cSSam Leffler 
79339beb93cSSam Leffler   /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
79439beb93cSSam Leffler   if ((res = mp_copy (&x, &u)) != MP_OKAY) {
79539beb93cSSam Leffler     goto LBL_ERR;
79639beb93cSSam Leffler   }
79739beb93cSSam Leffler   if ((res = mp_copy (&y, &v)) != MP_OKAY) {
79839beb93cSSam Leffler     goto LBL_ERR;
79939beb93cSSam Leffler   }
80039beb93cSSam Leffler   mp_set (&A, 1);
80139beb93cSSam Leffler   mp_set (&D, 1);
80239beb93cSSam Leffler 
80339beb93cSSam Leffler top:
80439beb93cSSam Leffler   /* 4.  while u is even do */
80539beb93cSSam Leffler   while (mp_iseven (&u) == 1) {
80639beb93cSSam Leffler     /* 4.1 u = u/2 */
80739beb93cSSam Leffler     if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
80839beb93cSSam Leffler       goto LBL_ERR;
80939beb93cSSam Leffler     }
81039beb93cSSam Leffler     /* 4.2 if A or B is odd then */
81139beb93cSSam Leffler     if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
81239beb93cSSam Leffler       /* A = (A+y)/2, B = (B-x)/2 */
81339beb93cSSam Leffler       if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
81439beb93cSSam Leffler          goto LBL_ERR;
81539beb93cSSam Leffler       }
81639beb93cSSam Leffler       if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
81739beb93cSSam Leffler          goto LBL_ERR;
81839beb93cSSam Leffler       }
81939beb93cSSam Leffler     }
82039beb93cSSam Leffler     /* A = A/2, B = B/2 */
82139beb93cSSam Leffler     if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
82239beb93cSSam Leffler       goto LBL_ERR;
82339beb93cSSam Leffler     }
82439beb93cSSam Leffler     if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
82539beb93cSSam Leffler       goto LBL_ERR;
82639beb93cSSam Leffler     }
82739beb93cSSam Leffler   }
82839beb93cSSam Leffler 
82939beb93cSSam Leffler   /* 5.  while v is even do */
83039beb93cSSam Leffler   while (mp_iseven (&v) == 1) {
83139beb93cSSam Leffler     /* 5.1 v = v/2 */
83239beb93cSSam Leffler     if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
83339beb93cSSam Leffler       goto LBL_ERR;
83439beb93cSSam Leffler     }
83539beb93cSSam Leffler     /* 5.2 if C or D is odd then */
83639beb93cSSam Leffler     if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
83739beb93cSSam Leffler       /* C = (C+y)/2, D = (D-x)/2 */
83839beb93cSSam Leffler       if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
83939beb93cSSam Leffler          goto LBL_ERR;
84039beb93cSSam Leffler       }
84139beb93cSSam Leffler       if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
84239beb93cSSam Leffler          goto LBL_ERR;
84339beb93cSSam Leffler       }
84439beb93cSSam Leffler     }
84539beb93cSSam Leffler     /* C = C/2, D = D/2 */
84639beb93cSSam Leffler     if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
84739beb93cSSam Leffler       goto LBL_ERR;
84839beb93cSSam Leffler     }
84939beb93cSSam Leffler     if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
85039beb93cSSam Leffler       goto LBL_ERR;
85139beb93cSSam Leffler     }
85239beb93cSSam Leffler   }
85339beb93cSSam Leffler 
85439beb93cSSam Leffler   /* 6.  if u >= v then */
85539beb93cSSam Leffler   if (mp_cmp (&u, &v) != MP_LT) {
85639beb93cSSam Leffler     /* u = u - v, A = A - C, B = B - D */
85739beb93cSSam Leffler     if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
85839beb93cSSam Leffler       goto LBL_ERR;
85939beb93cSSam Leffler     }
86039beb93cSSam Leffler 
86139beb93cSSam Leffler     if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
86239beb93cSSam Leffler       goto LBL_ERR;
86339beb93cSSam Leffler     }
86439beb93cSSam Leffler 
86539beb93cSSam Leffler     if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
86639beb93cSSam Leffler       goto LBL_ERR;
86739beb93cSSam Leffler     }
86839beb93cSSam Leffler   } else {
86939beb93cSSam Leffler     /* v - v - u, C = C - A, D = D - B */
87039beb93cSSam Leffler     if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
87139beb93cSSam Leffler       goto LBL_ERR;
87239beb93cSSam Leffler     }
87339beb93cSSam Leffler 
87439beb93cSSam Leffler     if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
87539beb93cSSam Leffler       goto LBL_ERR;
87639beb93cSSam Leffler     }
87739beb93cSSam Leffler 
87839beb93cSSam Leffler     if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
87939beb93cSSam Leffler       goto LBL_ERR;
88039beb93cSSam Leffler     }
88139beb93cSSam Leffler   }
88239beb93cSSam Leffler 
88339beb93cSSam Leffler   /* if not zero goto step 4 */
88439beb93cSSam Leffler   if (mp_iszero (&u) == 0)
88539beb93cSSam Leffler     goto top;
88639beb93cSSam Leffler 
88739beb93cSSam Leffler   /* now a = C, b = D, gcd == g*v */
88839beb93cSSam Leffler 
88939beb93cSSam Leffler   /* if v != 1 then there is no inverse */
89039beb93cSSam Leffler   if (mp_cmp_d (&v, 1) != MP_EQ) {
89139beb93cSSam Leffler     res = MP_VAL;
89239beb93cSSam Leffler     goto LBL_ERR;
89339beb93cSSam Leffler   }
89439beb93cSSam Leffler 
89539beb93cSSam Leffler   /* if its too low */
89639beb93cSSam Leffler   while (mp_cmp_d(&C, 0) == MP_LT) {
89739beb93cSSam Leffler       if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
89839beb93cSSam Leffler          goto LBL_ERR;
89939beb93cSSam Leffler       }
90039beb93cSSam Leffler   }
90139beb93cSSam Leffler 
90239beb93cSSam Leffler   /* too big */
90339beb93cSSam Leffler   while (mp_cmp_mag(&C, b) != MP_LT) {
90439beb93cSSam Leffler       if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
90539beb93cSSam Leffler          goto LBL_ERR;
90639beb93cSSam Leffler       }
90739beb93cSSam Leffler   }
90839beb93cSSam Leffler 
90939beb93cSSam Leffler   /* C is now the inverse */
91039beb93cSSam Leffler   mp_exch (&C, c);
91139beb93cSSam Leffler   res = MP_OKAY;
91239beb93cSSam Leffler LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
91339beb93cSSam Leffler   return res;
91439beb93cSSam Leffler }
91539beb93cSSam Leffler #endif /* LTM_NO_NEG_EXP */
91639beb93cSSam Leffler 
91739beb93cSSam Leffler 
91839beb93cSSam Leffler /* compare maginitude of two ints (unsigned) */
mp_cmp_mag(mp_int * a,mp_int * b)91939beb93cSSam Leffler static int mp_cmp_mag (mp_int * a, mp_int * b)
92039beb93cSSam Leffler {
92139beb93cSSam Leffler   int     n;
92239beb93cSSam Leffler   mp_digit *tmpa, *tmpb;
92339beb93cSSam Leffler 
92439beb93cSSam Leffler   /* compare based on # of non-zero digits */
92539beb93cSSam Leffler   if (a->used > b->used) {
92639beb93cSSam Leffler     return MP_GT;
92739beb93cSSam Leffler   }
92839beb93cSSam Leffler 
92939beb93cSSam Leffler   if (a->used < b->used) {
93039beb93cSSam Leffler     return MP_LT;
93139beb93cSSam Leffler   }
93239beb93cSSam Leffler 
93339beb93cSSam Leffler   /* alias for a */
93439beb93cSSam Leffler   tmpa = a->dp + (a->used - 1);
93539beb93cSSam Leffler 
93639beb93cSSam Leffler   /* alias for b */
93739beb93cSSam Leffler   tmpb = b->dp + (a->used - 1);
93839beb93cSSam Leffler 
93939beb93cSSam Leffler   /* compare based on digits  */
94039beb93cSSam Leffler   for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
94139beb93cSSam Leffler     if (*tmpa > *tmpb) {
94239beb93cSSam Leffler       return MP_GT;
94339beb93cSSam Leffler     }
94439beb93cSSam Leffler 
94539beb93cSSam Leffler     if (*tmpa < *tmpb) {
94639beb93cSSam Leffler       return MP_LT;
94739beb93cSSam Leffler     }
94839beb93cSSam Leffler   }
94939beb93cSSam Leffler   return MP_EQ;
95039beb93cSSam Leffler }
95139beb93cSSam Leffler 
95239beb93cSSam Leffler 
95339beb93cSSam Leffler /* reads a unsigned char array, assumes the msb is stored first [big endian] */
mp_read_unsigned_bin(mp_int * a,const unsigned char * b,int c)95439beb93cSSam Leffler static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
95539beb93cSSam Leffler {
95639beb93cSSam Leffler   int     res;
95739beb93cSSam Leffler 
95839beb93cSSam Leffler   /* make sure there are at least two digits */
95939beb93cSSam Leffler   if (a->alloc < 2) {
96039beb93cSSam Leffler      if ((res = mp_grow(a, 2)) != MP_OKAY) {
96139beb93cSSam Leffler         return res;
96239beb93cSSam Leffler      }
96339beb93cSSam Leffler   }
96439beb93cSSam Leffler 
96539beb93cSSam Leffler   /* zero the int */
96639beb93cSSam Leffler   mp_zero (a);
96739beb93cSSam Leffler 
96839beb93cSSam Leffler   /* read the bytes in */
96939beb93cSSam Leffler   while (c-- > 0) {
97039beb93cSSam Leffler     if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
97139beb93cSSam Leffler       return res;
97239beb93cSSam Leffler     }
97339beb93cSSam Leffler 
97439beb93cSSam Leffler #ifndef MP_8BIT
97539beb93cSSam Leffler       a->dp[0] |= *b++;
97639beb93cSSam Leffler       a->used += 1;
97739beb93cSSam Leffler #else
97839beb93cSSam Leffler       a->dp[0] = (*b & MP_MASK);
97939beb93cSSam Leffler       a->dp[1] |= ((*b++ >> 7U) & 1);
98039beb93cSSam Leffler       a->used += 2;
98139beb93cSSam Leffler #endif
98239beb93cSSam Leffler   }
98339beb93cSSam Leffler   mp_clamp (a);
98439beb93cSSam Leffler   return MP_OKAY;
98539beb93cSSam Leffler }
98639beb93cSSam Leffler 
98739beb93cSSam Leffler 
98839beb93cSSam Leffler /* store in unsigned [big endian] format */
mp_to_unsigned_bin(mp_int * a,unsigned char * b)98939beb93cSSam Leffler static int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
99039beb93cSSam Leffler {
99139beb93cSSam Leffler   int     x, res;
99239beb93cSSam Leffler   mp_int  t;
99339beb93cSSam Leffler 
99439beb93cSSam Leffler   if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
99539beb93cSSam Leffler     return res;
99639beb93cSSam Leffler   }
99739beb93cSSam Leffler 
99839beb93cSSam Leffler   x = 0;
99939beb93cSSam Leffler   while (mp_iszero (&t) == 0) {
100039beb93cSSam Leffler #ifndef MP_8BIT
100139beb93cSSam Leffler       b[x++] = (unsigned char) (t.dp[0] & 255);
100239beb93cSSam Leffler #else
100339beb93cSSam Leffler       b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
100439beb93cSSam Leffler #endif
100539beb93cSSam Leffler     if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
100639beb93cSSam Leffler       mp_clear (&t);
100739beb93cSSam Leffler       return res;
100839beb93cSSam Leffler     }
100939beb93cSSam Leffler   }
101039beb93cSSam Leffler   bn_reverse (b, x);
101139beb93cSSam Leffler   mp_clear (&t);
101239beb93cSSam Leffler   return MP_OKAY;
101339beb93cSSam Leffler }
101439beb93cSSam Leffler 
101539beb93cSSam Leffler 
101639beb93cSSam Leffler /* shift right by a certain bit count (store quotient in c, optional remainder in d) */
mp_div_2d(mp_int * a,int b,mp_int * c,mp_int * d)101739beb93cSSam Leffler static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
101839beb93cSSam Leffler {
101939beb93cSSam Leffler   mp_digit D, r, rr;
102039beb93cSSam Leffler   int     x, res;
102139beb93cSSam Leffler   mp_int  t;
102239beb93cSSam Leffler 
102339beb93cSSam Leffler 
102439beb93cSSam Leffler   /* if the shift count is <= 0 then we do no work */
102539beb93cSSam Leffler   if (b <= 0) {
102639beb93cSSam Leffler     res = mp_copy (a, c);
102739beb93cSSam Leffler     if (d != NULL) {
102839beb93cSSam Leffler       mp_zero (d);
102939beb93cSSam Leffler     }
103039beb93cSSam Leffler     return res;
103139beb93cSSam Leffler   }
103239beb93cSSam Leffler 
103339beb93cSSam Leffler   if ((res = mp_init (&t)) != MP_OKAY) {
103439beb93cSSam Leffler     return res;
103539beb93cSSam Leffler   }
103639beb93cSSam Leffler 
103739beb93cSSam Leffler   /* get the remainder */
103839beb93cSSam Leffler   if (d != NULL) {
103939beb93cSSam Leffler     if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
104039beb93cSSam Leffler       mp_clear (&t);
104139beb93cSSam Leffler       return res;
104239beb93cSSam Leffler     }
104339beb93cSSam Leffler   }
104439beb93cSSam Leffler 
104539beb93cSSam Leffler   /* copy */
104639beb93cSSam Leffler   if ((res = mp_copy (a, c)) != MP_OKAY) {
104739beb93cSSam Leffler     mp_clear (&t);
104839beb93cSSam Leffler     return res;
104939beb93cSSam Leffler   }
105039beb93cSSam Leffler 
105139beb93cSSam Leffler   /* shift by as many digits in the bit count */
105239beb93cSSam Leffler   if (b >= (int)DIGIT_BIT) {
105339beb93cSSam Leffler     mp_rshd (c, b / DIGIT_BIT);
105439beb93cSSam Leffler   }
105539beb93cSSam Leffler 
105639beb93cSSam Leffler   /* shift any bit count < DIGIT_BIT */
105739beb93cSSam Leffler   D = (mp_digit) (b % DIGIT_BIT);
105839beb93cSSam Leffler   if (D != 0) {
105939beb93cSSam Leffler     register mp_digit *tmpc, mask, shift;
106039beb93cSSam Leffler 
106139beb93cSSam Leffler     /* mask */
106239beb93cSSam Leffler     mask = (((mp_digit)1) << D) - 1;
106339beb93cSSam Leffler 
106439beb93cSSam Leffler     /* shift for lsb */
106539beb93cSSam Leffler     shift = DIGIT_BIT - D;
106639beb93cSSam Leffler 
106739beb93cSSam Leffler     /* alias */
106839beb93cSSam Leffler     tmpc = c->dp + (c->used - 1);
106939beb93cSSam Leffler 
107039beb93cSSam Leffler     /* carry */
107139beb93cSSam Leffler     r = 0;
107239beb93cSSam Leffler     for (x = c->used - 1; x >= 0; x--) {
107339beb93cSSam Leffler       /* get the lower  bits of this word in a temp */
107439beb93cSSam Leffler       rr = *tmpc & mask;
107539beb93cSSam Leffler 
107639beb93cSSam Leffler       /* shift the current word and mix in the carry bits from the previous word */
107739beb93cSSam Leffler       *tmpc = (*tmpc >> D) | (r << shift);
107839beb93cSSam Leffler       --tmpc;
107939beb93cSSam Leffler 
108039beb93cSSam Leffler       /* set the carry to the carry bits of the current word found above */
108139beb93cSSam Leffler       r = rr;
108239beb93cSSam Leffler     }
108339beb93cSSam Leffler   }
108439beb93cSSam Leffler   mp_clamp (c);
108539beb93cSSam Leffler   if (d != NULL) {
108639beb93cSSam Leffler     mp_exch (&t, d);
108739beb93cSSam Leffler   }
108839beb93cSSam Leffler   mp_clear (&t);
108939beb93cSSam Leffler   return MP_OKAY;
109039beb93cSSam Leffler }
109139beb93cSSam Leffler 
109239beb93cSSam Leffler 
mp_init_copy(mp_int * a,mp_int * b)109339beb93cSSam Leffler static int mp_init_copy (mp_int * a, mp_int * b)
109439beb93cSSam Leffler {
109539beb93cSSam Leffler   int     res;
109639beb93cSSam Leffler 
109739beb93cSSam Leffler   if ((res = mp_init (a)) != MP_OKAY) {
109839beb93cSSam Leffler     return res;
109939beb93cSSam Leffler   }
110039beb93cSSam Leffler   return mp_copy (b, a);
110139beb93cSSam Leffler }
110239beb93cSSam Leffler 
110339beb93cSSam Leffler 
110439beb93cSSam Leffler /* set to zero */
mp_zero(mp_int * a)110539beb93cSSam Leffler static void mp_zero (mp_int * a)
110639beb93cSSam Leffler {
110739beb93cSSam Leffler   int       n;
110839beb93cSSam Leffler   mp_digit *tmp;
110939beb93cSSam Leffler 
111039beb93cSSam Leffler   a->sign = MP_ZPOS;
111139beb93cSSam Leffler   a->used = 0;
111239beb93cSSam Leffler 
111339beb93cSSam Leffler   tmp = a->dp;
111439beb93cSSam Leffler   for (n = 0; n < a->alloc; n++) {
111539beb93cSSam Leffler      *tmp++ = 0;
111639beb93cSSam Leffler   }
111739beb93cSSam Leffler }
111839beb93cSSam Leffler 
111939beb93cSSam Leffler 
112039beb93cSSam Leffler /* copy, b = a */
mp_copy(mp_int * a,mp_int * b)112139beb93cSSam Leffler static int mp_copy (mp_int * a, mp_int * b)
112239beb93cSSam Leffler {
112339beb93cSSam Leffler   int     res, n;
112439beb93cSSam Leffler 
112539beb93cSSam Leffler   /* if dst == src do nothing */
112639beb93cSSam Leffler   if (a == b) {
112739beb93cSSam Leffler     return MP_OKAY;
112839beb93cSSam Leffler   }
112939beb93cSSam Leffler 
113039beb93cSSam Leffler   /* grow dest */
113139beb93cSSam Leffler   if (b->alloc < a->used) {
113239beb93cSSam Leffler      if ((res = mp_grow (b, a->used)) != MP_OKAY) {
113339beb93cSSam Leffler         return res;
113439beb93cSSam Leffler      }
113539beb93cSSam Leffler   }
113639beb93cSSam Leffler 
113739beb93cSSam Leffler   /* zero b and copy the parameters over */
113839beb93cSSam Leffler   {
113939beb93cSSam Leffler     register mp_digit *tmpa, *tmpb;
114039beb93cSSam Leffler 
114139beb93cSSam Leffler     /* pointer aliases */
114239beb93cSSam Leffler 
114339beb93cSSam Leffler     /* source */
114439beb93cSSam Leffler     tmpa = a->dp;
114539beb93cSSam Leffler 
114639beb93cSSam Leffler     /* destination */
114739beb93cSSam Leffler     tmpb = b->dp;
114839beb93cSSam Leffler 
114939beb93cSSam Leffler     /* copy all the digits */
115039beb93cSSam Leffler     for (n = 0; n < a->used; n++) {
115139beb93cSSam Leffler       *tmpb++ = *tmpa++;
115239beb93cSSam Leffler     }
115339beb93cSSam Leffler 
115439beb93cSSam Leffler     /* clear high digits */
115539beb93cSSam Leffler     for (; n < b->used; n++) {
115639beb93cSSam Leffler       *tmpb++ = 0;
115739beb93cSSam Leffler     }
115839beb93cSSam Leffler   }
115939beb93cSSam Leffler 
116039beb93cSSam Leffler   /* copy used count and sign */
116139beb93cSSam Leffler   b->used = a->used;
116239beb93cSSam Leffler   b->sign = a->sign;
116339beb93cSSam Leffler   return MP_OKAY;
116439beb93cSSam Leffler }
116539beb93cSSam Leffler 
116639beb93cSSam Leffler 
116739beb93cSSam Leffler /* shift right a certain amount of digits */
mp_rshd(mp_int * a,int b)116839beb93cSSam Leffler static void mp_rshd (mp_int * a, int b)
116939beb93cSSam Leffler {
117039beb93cSSam Leffler   int     x;
117139beb93cSSam Leffler 
117239beb93cSSam Leffler   /* if b <= 0 then ignore it */
117339beb93cSSam Leffler   if (b <= 0) {
117439beb93cSSam Leffler     return;
117539beb93cSSam Leffler   }
117639beb93cSSam Leffler 
117739beb93cSSam Leffler   /* if b > used then simply zero it and return */
117839beb93cSSam Leffler   if (a->used <= b) {
117939beb93cSSam Leffler     mp_zero (a);
118039beb93cSSam Leffler     return;
118139beb93cSSam Leffler   }
118239beb93cSSam Leffler 
118339beb93cSSam Leffler   {
118439beb93cSSam Leffler     register mp_digit *bottom, *top;
118539beb93cSSam Leffler 
118639beb93cSSam Leffler     /* shift the digits down */
118739beb93cSSam Leffler 
118839beb93cSSam Leffler     /* bottom */
118939beb93cSSam Leffler     bottom = a->dp;
119039beb93cSSam Leffler 
119139beb93cSSam Leffler     /* top [offset into digits] */
119239beb93cSSam Leffler     top = a->dp + b;
119339beb93cSSam Leffler 
119439beb93cSSam Leffler     /* this is implemented as a sliding window where
119539beb93cSSam Leffler      * the window is b-digits long and digits from
119639beb93cSSam Leffler      * the top of the window are copied to the bottom
119739beb93cSSam Leffler      *
119839beb93cSSam Leffler      * e.g.
119939beb93cSSam Leffler 
120039beb93cSSam Leffler      b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
120139beb93cSSam Leffler                  /\                   |      ---->
120239beb93cSSam Leffler                   \-------------------/      ---->
120339beb93cSSam Leffler      */
120439beb93cSSam Leffler     for (x = 0; x < (a->used - b); x++) {
120539beb93cSSam Leffler       *bottom++ = *top++;
120639beb93cSSam Leffler     }
120739beb93cSSam Leffler 
120839beb93cSSam Leffler     /* zero the top digits */
120939beb93cSSam Leffler     for (; x < a->used; x++) {
121039beb93cSSam Leffler       *bottom++ = 0;
121139beb93cSSam Leffler     }
121239beb93cSSam Leffler   }
121339beb93cSSam Leffler 
121439beb93cSSam Leffler   /* remove excess digits */
121539beb93cSSam Leffler   a->used -= b;
121639beb93cSSam Leffler }
121739beb93cSSam Leffler 
121839beb93cSSam Leffler 
121939beb93cSSam Leffler /* swap the elements of two integers, for cases where you can't simply swap the
122039beb93cSSam Leffler  * mp_int pointers around
122139beb93cSSam Leffler  */
mp_exch(mp_int * a,mp_int * b)122239beb93cSSam Leffler static void mp_exch (mp_int * a, mp_int * b)
122339beb93cSSam Leffler {
122439beb93cSSam Leffler   mp_int  t;
122539beb93cSSam Leffler 
122639beb93cSSam Leffler   t  = *a;
122739beb93cSSam Leffler   *a = *b;
122839beb93cSSam Leffler   *b = t;
122939beb93cSSam Leffler }
123039beb93cSSam Leffler 
123139beb93cSSam Leffler 
123239beb93cSSam Leffler /* trim unused digits
123339beb93cSSam Leffler  *
123439beb93cSSam Leffler  * This is used to ensure that leading zero digits are
123539beb93cSSam Leffler  * trimed and the leading "used" digit will be non-zero
123639beb93cSSam Leffler  * Typically very fast.  Also fixes the sign if there
123739beb93cSSam Leffler  * are no more leading digits
123839beb93cSSam Leffler  */
mp_clamp(mp_int * a)123939beb93cSSam Leffler static void mp_clamp (mp_int * a)
124039beb93cSSam Leffler {
124139beb93cSSam Leffler   /* decrease used while the most significant digit is
124239beb93cSSam Leffler    * zero.
124339beb93cSSam Leffler    */
124439beb93cSSam Leffler   while (a->used > 0 && a->dp[a->used - 1] == 0) {
124539beb93cSSam Leffler     --(a->used);
124639beb93cSSam Leffler   }
124739beb93cSSam Leffler 
124839beb93cSSam Leffler   /* reset the sign flag if used == 0 */
124939beb93cSSam Leffler   if (a->used == 0) {
125039beb93cSSam Leffler     a->sign = MP_ZPOS;
125139beb93cSSam Leffler   }
125239beb93cSSam Leffler }
125339beb93cSSam Leffler 
125439beb93cSSam Leffler 
125539beb93cSSam Leffler /* grow as required */
mp_grow(mp_int * a,int size)125639beb93cSSam Leffler static int mp_grow (mp_int * a, int size)
125739beb93cSSam Leffler {
125839beb93cSSam Leffler   int     i;
125939beb93cSSam Leffler   mp_digit *tmp;
126039beb93cSSam Leffler 
126139beb93cSSam Leffler   /* if the alloc size is smaller alloc more ram */
126239beb93cSSam Leffler   if (a->alloc < size) {
126339beb93cSSam Leffler     /* ensure there are always at least MP_PREC digits extra on top */
126439beb93cSSam Leffler     size += (MP_PREC * 2) - (size % MP_PREC);
126539beb93cSSam Leffler 
126639beb93cSSam Leffler     /* reallocate the array a->dp
126739beb93cSSam Leffler      *
126839beb93cSSam Leffler      * We store the return in a temporary variable
126939beb93cSSam Leffler      * in case the operation failed we don't want
127039beb93cSSam Leffler      * to overwrite the dp member of a.
127139beb93cSSam Leffler      */
127239beb93cSSam Leffler     tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
127339beb93cSSam Leffler     if (tmp == NULL) {
127439beb93cSSam Leffler       /* reallocation failed but "a" is still valid [can be freed] */
127539beb93cSSam Leffler       return MP_MEM;
127639beb93cSSam Leffler     }
127739beb93cSSam Leffler 
127839beb93cSSam Leffler     /* reallocation succeeded so set a->dp */
127939beb93cSSam Leffler     a->dp = tmp;
128039beb93cSSam Leffler 
128139beb93cSSam Leffler     /* zero excess digits */
128239beb93cSSam Leffler     i        = a->alloc;
128339beb93cSSam Leffler     a->alloc = size;
128439beb93cSSam Leffler     for (; i < a->alloc; i++) {
128539beb93cSSam Leffler       a->dp[i] = 0;
128639beb93cSSam Leffler     }
128739beb93cSSam Leffler   }
128839beb93cSSam Leffler   return MP_OKAY;
128939beb93cSSam Leffler }
129039beb93cSSam Leffler 
129139beb93cSSam Leffler 
129239beb93cSSam Leffler #ifdef BN_MP_ABS_C
129339beb93cSSam Leffler /* b = |a|
129439beb93cSSam Leffler  *
129539beb93cSSam Leffler  * Simple function copies the input and fixes the sign to positive
129639beb93cSSam Leffler  */
mp_abs(mp_int * a,mp_int * b)129739beb93cSSam Leffler static int mp_abs (mp_int * a, mp_int * b)
129839beb93cSSam Leffler {
129939beb93cSSam Leffler   int     res;
130039beb93cSSam Leffler 
130139beb93cSSam Leffler   /* copy a to b */
130239beb93cSSam Leffler   if (a != b) {
130339beb93cSSam Leffler      if ((res = mp_copy (a, b)) != MP_OKAY) {
130439beb93cSSam Leffler        return res;
130539beb93cSSam Leffler      }
130639beb93cSSam Leffler   }
130739beb93cSSam Leffler 
130839beb93cSSam Leffler   /* force the sign of b to positive */
130939beb93cSSam Leffler   b->sign = MP_ZPOS;
131039beb93cSSam Leffler 
131139beb93cSSam Leffler   return MP_OKAY;
131239beb93cSSam Leffler }
131339beb93cSSam Leffler #endif
131439beb93cSSam Leffler 
131539beb93cSSam Leffler 
131639beb93cSSam Leffler /* set to a digit */
mp_set(mp_int * a,mp_digit b)131739beb93cSSam Leffler static void mp_set (mp_int * a, mp_digit b)
131839beb93cSSam Leffler {
131939beb93cSSam Leffler   mp_zero (a);
132039beb93cSSam Leffler   a->dp[0] = b & MP_MASK;
132139beb93cSSam Leffler   a->used  = (a->dp[0] != 0) ? 1 : 0;
132239beb93cSSam Leffler }
132339beb93cSSam Leffler 
132439beb93cSSam Leffler 
132539beb93cSSam Leffler #ifndef LTM_NO_NEG_EXP
132639beb93cSSam Leffler /* b = a/2 */
mp_div_2(mp_int * a,mp_int * b)132739beb93cSSam Leffler static int mp_div_2(mp_int * a, mp_int * b)
132839beb93cSSam Leffler {
132939beb93cSSam Leffler   int     x, res, oldused;
133039beb93cSSam Leffler 
133139beb93cSSam Leffler   /* copy */
133239beb93cSSam Leffler   if (b->alloc < a->used) {
133339beb93cSSam Leffler     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
133439beb93cSSam Leffler       return res;
133539beb93cSSam Leffler     }
133639beb93cSSam Leffler   }
133739beb93cSSam Leffler 
133839beb93cSSam Leffler   oldused = b->used;
133939beb93cSSam Leffler   b->used = a->used;
134039beb93cSSam Leffler   {
134139beb93cSSam Leffler     register mp_digit r, rr, *tmpa, *tmpb;
134239beb93cSSam Leffler 
134339beb93cSSam Leffler     /* source alias */
134439beb93cSSam Leffler     tmpa = a->dp + b->used - 1;
134539beb93cSSam Leffler 
134639beb93cSSam Leffler     /* dest alias */
134739beb93cSSam Leffler     tmpb = b->dp + b->used - 1;
134839beb93cSSam Leffler 
134939beb93cSSam Leffler     /* carry */
135039beb93cSSam Leffler     r = 0;
135139beb93cSSam Leffler     for (x = b->used - 1; x >= 0; x--) {
135239beb93cSSam Leffler       /* get the carry for the next iteration */
135339beb93cSSam Leffler       rr = *tmpa & 1;
135439beb93cSSam Leffler 
135539beb93cSSam Leffler       /* shift the current digit, add in carry and store */
135639beb93cSSam Leffler       *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
135739beb93cSSam Leffler 
135839beb93cSSam Leffler       /* forward carry to next iteration */
135939beb93cSSam Leffler       r = rr;
136039beb93cSSam Leffler     }
136139beb93cSSam Leffler 
136239beb93cSSam Leffler     /* zero excess digits */
136339beb93cSSam Leffler     tmpb = b->dp + b->used;
136439beb93cSSam Leffler     for (x = b->used; x < oldused; x++) {
136539beb93cSSam Leffler       *tmpb++ = 0;
136639beb93cSSam Leffler     }
136739beb93cSSam Leffler   }
136839beb93cSSam Leffler   b->sign = a->sign;
136939beb93cSSam Leffler   mp_clamp (b);
137039beb93cSSam Leffler   return MP_OKAY;
137139beb93cSSam Leffler }
137239beb93cSSam Leffler #endif /* LTM_NO_NEG_EXP */
137339beb93cSSam Leffler 
137439beb93cSSam Leffler 
137539beb93cSSam Leffler /* shift left by a certain bit count */
mp_mul_2d(mp_int * a,int b,mp_int * c)137639beb93cSSam Leffler static int mp_mul_2d (mp_int * a, int b, mp_int * c)
137739beb93cSSam Leffler {
137839beb93cSSam Leffler   mp_digit d;
137939beb93cSSam Leffler   int      res;
138039beb93cSSam Leffler 
138139beb93cSSam Leffler   /* copy */
138239beb93cSSam Leffler   if (a != c) {
138339beb93cSSam Leffler      if ((res = mp_copy (a, c)) != MP_OKAY) {
138439beb93cSSam Leffler        return res;
138539beb93cSSam Leffler      }
138639beb93cSSam Leffler   }
138739beb93cSSam Leffler 
138839beb93cSSam Leffler   if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
138939beb93cSSam Leffler      if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
139039beb93cSSam Leffler        return res;
139139beb93cSSam Leffler      }
139239beb93cSSam Leffler   }
139339beb93cSSam Leffler 
139439beb93cSSam Leffler   /* shift by as many digits in the bit count */
139539beb93cSSam Leffler   if (b >= (int)DIGIT_BIT) {
139639beb93cSSam Leffler     if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
139739beb93cSSam Leffler       return res;
139839beb93cSSam Leffler     }
139939beb93cSSam Leffler   }
140039beb93cSSam Leffler 
140139beb93cSSam Leffler   /* shift any bit count < DIGIT_BIT */
140239beb93cSSam Leffler   d = (mp_digit) (b % DIGIT_BIT);
140339beb93cSSam Leffler   if (d != 0) {
140439beb93cSSam Leffler     register mp_digit *tmpc, shift, mask, r, rr;
140539beb93cSSam Leffler     register int x;
140639beb93cSSam Leffler 
140739beb93cSSam Leffler     /* bitmask for carries */
140839beb93cSSam Leffler     mask = (((mp_digit)1) << d) - 1;
140939beb93cSSam Leffler 
141039beb93cSSam Leffler     /* shift for msbs */
141139beb93cSSam Leffler     shift = DIGIT_BIT - d;
141239beb93cSSam Leffler 
141339beb93cSSam Leffler     /* alias */
141439beb93cSSam Leffler     tmpc = c->dp;
141539beb93cSSam Leffler 
141639beb93cSSam Leffler     /* carry */
141739beb93cSSam Leffler     r    = 0;
141839beb93cSSam Leffler     for (x = 0; x < c->used; x++) {
141939beb93cSSam Leffler       /* get the higher bits of the current word */
142039beb93cSSam Leffler       rr = (*tmpc >> shift) & mask;
142139beb93cSSam Leffler 
142239beb93cSSam Leffler       /* shift the current word and OR in the carry */
142339beb93cSSam Leffler       *tmpc = ((*tmpc << d) | r) & MP_MASK;
142439beb93cSSam Leffler       ++tmpc;
142539beb93cSSam Leffler 
142639beb93cSSam Leffler       /* set the carry to the carry bits of the current word */
142739beb93cSSam Leffler       r = rr;
142839beb93cSSam Leffler     }
142939beb93cSSam Leffler 
143039beb93cSSam Leffler     /* set final carry */
143139beb93cSSam Leffler     if (r != 0) {
143239beb93cSSam Leffler        c->dp[(c->used)++] = r;
143339beb93cSSam Leffler     }
143439beb93cSSam Leffler   }
143539beb93cSSam Leffler   mp_clamp (c);
143639beb93cSSam Leffler   return MP_OKAY;
143739beb93cSSam Leffler }
143839beb93cSSam Leffler 
143939beb93cSSam Leffler 
144039beb93cSSam Leffler #ifdef BN_MP_INIT_MULTI_C
mp_init_multi(mp_int * mp,...)144139beb93cSSam Leffler static int mp_init_multi(mp_int *mp, ...)
144239beb93cSSam Leffler {
144339beb93cSSam Leffler     mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
144439beb93cSSam Leffler     int n = 0;                 /* Number of ok inits */
144539beb93cSSam Leffler     mp_int* cur_arg = mp;
144639beb93cSSam Leffler     va_list args;
144739beb93cSSam Leffler 
144839beb93cSSam Leffler     va_start(args, mp);        /* init args to next argument from caller */
144939beb93cSSam Leffler     while (cur_arg != NULL) {
145039beb93cSSam Leffler         if (mp_init(cur_arg) != MP_OKAY) {
145139beb93cSSam Leffler             /* Oops - error! Back-track and mp_clear what we already
145239beb93cSSam Leffler                succeeded in init-ing, then return error.
145339beb93cSSam Leffler             */
145439beb93cSSam Leffler             va_list clean_args;
145539beb93cSSam Leffler 
145639beb93cSSam Leffler             /* end the current list */
145739beb93cSSam Leffler             va_end(args);
145839beb93cSSam Leffler 
145939beb93cSSam Leffler             /* now start cleaning up */
146039beb93cSSam Leffler             cur_arg = mp;
146139beb93cSSam Leffler             va_start(clean_args, mp);
146239beb93cSSam Leffler             while (n--) {
146339beb93cSSam Leffler                 mp_clear(cur_arg);
146439beb93cSSam Leffler                 cur_arg = va_arg(clean_args, mp_int*);
146539beb93cSSam Leffler             }
146639beb93cSSam Leffler             va_end(clean_args);
1467325151a3SRui Paulo             return MP_MEM;
146839beb93cSSam Leffler         }
146939beb93cSSam Leffler         n++;
147039beb93cSSam Leffler         cur_arg = va_arg(args, mp_int*);
147139beb93cSSam Leffler     }
147239beb93cSSam Leffler     va_end(args);
147339beb93cSSam Leffler     return res;                /* Assumed ok, if error flagged above. */
147439beb93cSSam Leffler }
147539beb93cSSam Leffler #endif
147639beb93cSSam Leffler 
147739beb93cSSam Leffler 
147839beb93cSSam Leffler #ifdef BN_MP_CLEAR_MULTI_C
mp_clear_multi(mp_int * mp,...)147939beb93cSSam Leffler static void mp_clear_multi(mp_int *mp, ...)
148039beb93cSSam Leffler {
148139beb93cSSam Leffler     mp_int* next_mp = mp;
148239beb93cSSam Leffler     va_list args;
148339beb93cSSam Leffler     va_start(args, mp);
148439beb93cSSam Leffler     while (next_mp != NULL) {
148539beb93cSSam Leffler         mp_clear(next_mp);
148639beb93cSSam Leffler         next_mp = va_arg(args, mp_int*);
148739beb93cSSam Leffler     }
148839beb93cSSam Leffler     va_end(args);
148939beb93cSSam Leffler }
149039beb93cSSam Leffler #endif
149139beb93cSSam Leffler 
149239beb93cSSam Leffler 
149339beb93cSSam Leffler /* shift left a certain amount of digits */
mp_lshd(mp_int * a,int b)149439beb93cSSam Leffler static int mp_lshd (mp_int * a, int b)
149539beb93cSSam Leffler {
149639beb93cSSam Leffler   int     x, res;
149739beb93cSSam Leffler 
149839beb93cSSam Leffler   /* if its less than zero return */
149939beb93cSSam Leffler   if (b <= 0) {
150039beb93cSSam Leffler     return MP_OKAY;
150139beb93cSSam Leffler   }
150239beb93cSSam Leffler 
150339beb93cSSam Leffler   /* grow to fit the new digits */
150439beb93cSSam Leffler   if (a->alloc < a->used + b) {
150539beb93cSSam Leffler      if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
150639beb93cSSam Leffler        return res;
150739beb93cSSam Leffler      }
150839beb93cSSam Leffler   }
150939beb93cSSam Leffler 
151039beb93cSSam Leffler   {
151139beb93cSSam Leffler     register mp_digit *top, *bottom;
151239beb93cSSam Leffler 
151339beb93cSSam Leffler     /* increment the used by the shift amount then copy upwards */
151439beb93cSSam Leffler     a->used += b;
151539beb93cSSam Leffler 
151639beb93cSSam Leffler     /* top */
151739beb93cSSam Leffler     top = a->dp + a->used - 1;
151839beb93cSSam Leffler 
151939beb93cSSam Leffler     /* base */
152039beb93cSSam Leffler     bottom = a->dp + a->used - 1 - b;
152139beb93cSSam Leffler 
152239beb93cSSam Leffler     /* much like mp_rshd this is implemented using a sliding window
152339beb93cSSam Leffler      * except the window goes the otherway around.  Copying from
152439beb93cSSam Leffler      * the bottom to the top.  see bn_mp_rshd.c for more info.
152539beb93cSSam Leffler      */
152639beb93cSSam Leffler     for (x = a->used - 1; x >= b; x--) {
152739beb93cSSam Leffler       *top-- = *bottom--;
152839beb93cSSam Leffler     }
152939beb93cSSam Leffler 
153039beb93cSSam Leffler     /* zero the lower digits */
153139beb93cSSam Leffler     top = a->dp;
153239beb93cSSam Leffler     for (x = 0; x < b; x++) {
153339beb93cSSam Leffler       *top++ = 0;
153439beb93cSSam Leffler     }
153539beb93cSSam Leffler   }
153639beb93cSSam Leffler   return MP_OKAY;
153739beb93cSSam Leffler }
153839beb93cSSam Leffler 
153939beb93cSSam Leffler 
154039beb93cSSam Leffler /* returns the number of bits in an int */
mp_count_bits(mp_int * a)154139beb93cSSam Leffler static int mp_count_bits (mp_int * a)
154239beb93cSSam Leffler {
154339beb93cSSam Leffler   int     r;
154439beb93cSSam Leffler   mp_digit q;
154539beb93cSSam Leffler 
154639beb93cSSam Leffler   /* shortcut */
154739beb93cSSam Leffler   if (a->used == 0) {
154839beb93cSSam Leffler     return 0;
154939beb93cSSam Leffler   }
155039beb93cSSam Leffler 
155139beb93cSSam Leffler   /* get number of digits and add that */
155239beb93cSSam Leffler   r = (a->used - 1) * DIGIT_BIT;
155339beb93cSSam Leffler 
155439beb93cSSam Leffler   /* take the last digit and count the bits in it */
155539beb93cSSam Leffler   q = a->dp[a->used - 1];
155639beb93cSSam Leffler   while (q > ((mp_digit) 0)) {
155739beb93cSSam Leffler     ++r;
155839beb93cSSam Leffler     q >>= ((mp_digit) 1);
155939beb93cSSam Leffler   }
156039beb93cSSam Leffler   return r;
156139beb93cSSam Leffler }
156239beb93cSSam Leffler 
156339beb93cSSam Leffler 
156439beb93cSSam Leffler /* calc a value mod 2**b */
mp_mod_2d(mp_int * a,int b,mp_int * c)156539beb93cSSam Leffler static int mp_mod_2d (mp_int * a, int b, mp_int * c)
156639beb93cSSam Leffler {
156739beb93cSSam Leffler   int     x, res;
156839beb93cSSam Leffler 
156939beb93cSSam Leffler   /* if b is <= 0 then zero the int */
157039beb93cSSam Leffler   if (b <= 0) {
157139beb93cSSam Leffler     mp_zero (c);
157239beb93cSSam Leffler     return MP_OKAY;
157339beb93cSSam Leffler   }
157439beb93cSSam Leffler 
157539beb93cSSam Leffler   /* if the modulus is larger than the value than return */
157639beb93cSSam Leffler   if (b >= (int) (a->used * DIGIT_BIT)) {
157739beb93cSSam Leffler     res = mp_copy (a, c);
157839beb93cSSam Leffler     return res;
157939beb93cSSam Leffler   }
158039beb93cSSam Leffler 
158139beb93cSSam Leffler   /* copy */
158239beb93cSSam Leffler   if ((res = mp_copy (a, c)) != MP_OKAY) {
158339beb93cSSam Leffler     return res;
158439beb93cSSam Leffler   }
158539beb93cSSam Leffler 
158639beb93cSSam Leffler   /* zero digits above the last digit of the modulus */
158739beb93cSSam Leffler   for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
158839beb93cSSam Leffler     c->dp[x] = 0;
158939beb93cSSam Leffler   }
159039beb93cSSam Leffler   /* clear the digit that is not completely outside/inside the modulus */
159139beb93cSSam Leffler   c->dp[b / DIGIT_BIT] &=
159239beb93cSSam Leffler     (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
159339beb93cSSam Leffler   mp_clamp (c);
159439beb93cSSam Leffler   return MP_OKAY;
159539beb93cSSam Leffler }
159639beb93cSSam Leffler 
159739beb93cSSam Leffler 
159839beb93cSSam Leffler #ifdef BN_MP_DIV_SMALL
159939beb93cSSam Leffler 
160039beb93cSSam Leffler /* slower bit-bang division... also smaller */
mp_div(mp_int * a,mp_int * b,mp_int * c,mp_int * d)160139beb93cSSam Leffler static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
160239beb93cSSam Leffler {
160339beb93cSSam Leffler    mp_int ta, tb, tq, q;
160439beb93cSSam Leffler    int    res, n, n2;
160539beb93cSSam Leffler 
160639beb93cSSam Leffler   /* is divisor zero ? */
160739beb93cSSam Leffler   if (mp_iszero (b) == 1) {
160839beb93cSSam Leffler     return MP_VAL;
160939beb93cSSam Leffler   }
161039beb93cSSam Leffler 
161139beb93cSSam Leffler   /* if a < b then q=0, r = a */
161239beb93cSSam Leffler   if (mp_cmp_mag (a, b) == MP_LT) {
161339beb93cSSam Leffler     if (d != NULL) {
161439beb93cSSam Leffler       res = mp_copy (a, d);
161539beb93cSSam Leffler     } else {
161639beb93cSSam Leffler       res = MP_OKAY;
161739beb93cSSam Leffler     }
161839beb93cSSam Leffler     if (c != NULL) {
161939beb93cSSam Leffler       mp_zero (c);
162039beb93cSSam Leffler     }
162139beb93cSSam Leffler     return res;
162239beb93cSSam Leffler   }
162339beb93cSSam Leffler 
162439beb93cSSam Leffler   /* init our temps */
1625325151a3SRui Paulo   if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
162639beb93cSSam Leffler      return res;
162739beb93cSSam Leffler   }
162839beb93cSSam Leffler 
162939beb93cSSam Leffler 
163039beb93cSSam Leffler   mp_set(&tq, 1);
163139beb93cSSam Leffler   n = mp_count_bits(a) - mp_count_bits(b);
163239beb93cSSam Leffler   if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
163339beb93cSSam Leffler       ((res = mp_abs(b, &tb)) != MP_OKAY) ||
163439beb93cSSam Leffler       ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
163539beb93cSSam Leffler       ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
163639beb93cSSam Leffler       goto LBL_ERR;
163739beb93cSSam Leffler   }
163839beb93cSSam Leffler 
163939beb93cSSam Leffler   while (n-- >= 0) {
164039beb93cSSam Leffler      if (mp_cmp(&tb, &ta) != MP_GT) {
164139beb93cSSam Leffler         if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
164239beb93cSSam Leffler             ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
164339beb93cSSam Leffler            goto LBL_ERR;
164439beb93cSSam Leffler         }
164539beb93cSSam Leffler      }
164639beb93cSSam Leffler      if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
164739beb93cSSam Leffler          ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
164839beb93cSSam Leffler            goto LBL_ERR;
164939beb93cSSam Leffler      }
165039beb93cSSam Leffler   }
165139beb93cSSam Leffler 
165239beb93cSSam Leffler   /* now q == quotient and ta == remainder */
165339beb93cSSam Leffler   n  = a->sign;
165439beb93cSSam Leffler   n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
165539beb93cSSam Leffler   if (c != NULL) {
165639beb93cSSam Leffler      mp_exch(c, &q);
165739beb93cSSam Leffler      c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
165839beb93cSSam Leffler   }
165939beb93cSSam Leffler   if (d != NULL) {
166039beb93cSSam Leffler      mp_exch(d, &ta);
166139beb93cSSam Leffler      d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
166239beb93cSSam Leffler   }
166339beb93cSSam Leffler LBL_ERR:
166439beb93cSSam Leffler    mp_clear_multi(&ta, &tb, &tq, &q, NULL);
166539beb93cSSam Leffler    return res;
166639beb93cSSam Leffler }
166739beb93cSSam Leffler 
166839beb93cSSam Leffler #else
166939beb93cSSam Leffler 
167039beb93cSSam Leffler /* integer signed division.
167139beb93cSSam Leffler  * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
167239beb93cSSam Leffler  * HAC pp.598 Algorithm 14.20
167339beb93cSSam Leffler  *
167439beb93cSSam Leffler  * Note that the description in HAC is horribly
167539beb93cSSam Leffler  * incomplete.  For example, it doesn't consider
167639beb93cSSam Leffler  * the case where digits are removed from 'x' in
167739beb93cSSam Leffler  * the inner loop.  It also doesn't consider the
167839beb93cSSam Leffler  * case that y has fewer than three digits, etc..
167939beb93cSSam Leffler  *
168039beb93cSSam Leffler  * The overall algorithm is as described as
168139beb93cSSam Leffler  * 14.20 from HAC but fixed to treat these cases.
168239beb93cSSam Leffler */
mp_div(mp_int * a,mp_int * b,mp_int * c,mp_int * d)168339beb93cSSam Leffler static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
168439beb93cSSam Leffler {
168539beb93cSSam Leffler   mp_int  q, x, y, t1, t2;
168639beb93cSSam Leffler   int     res, n, t, i, norm, neg;
168739beb93cSSam Leffler 
168839beb93cSSam Leffler   /* is divisor zero ? */
168939beb93cSSam Leffler   if (mp_iszero (b) == 1) {
169039beb93cSSam Leffler     return MP_VAL;
169139beb93cSSam Leffler   }
169239beb93cSSam Leffler 
169339beb93cSSam Leffler   /* if a < b then q=0, r = a */
169439beb93cSSam Leffler   if (mp_cmp_mag (a, b) == MP_LT) {
169539beb93cSSam Leffler     if (d != NULL) {
169639beb93cSSam Leffler       res = mp_copy (a, d);
169739beb93cSSam Leffler     } else {
169839beb93cSSam Leffler       res = MP_OKAY;
169939beb93cSSam Leffler     }
170039beb93cSSam Leffler     if (c != NULL) {
170139beb93cSSam Leffler       mp_zero (c);
170239beb93cSSam Leffler     }
170339beb93cSSam Leffler     return res;
170439beb93cSSam Leffler   }
170539beb93cSSam Leffler 
170639beb93cSSam Leffler   if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
170739beb93cSSam Leffler     return res;
170839beb93cSSam Leffler   }
170939beb93cSSam Leffler   q.used = a->used + 2;
171039beb93cSSam Leffler 
171139beb93cSSam Leffler   if ((res = mp_init (&t1)) != MP_OKAY) {
171239beb93cSSam Leffler     goto LBL_Q;
171339beb93cSSam Leffler   }
171439beb93cSSam Leffler 
171539beb93cSSam Leffler   if ((res = mp_init (&t2)) != MP_OKAY) {
171639beb93cSSam Leffler     goto LBL_T1;
171739beb93cSSam Leffler   }
171839beb93cSSam Leffler 
171939beb93cSSam Leffler   if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
172039beb93cSSam Leffler     goto LBL_T2;
172139beb93cSSam Leffler   }
172239beb93cSSam Leffler 
172339beb93cSSam Leffler   if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
172439beb93cSSam Leffler     goto LBL_X;
172539beb93cSSam Leffler   }
172639beb93cSSam Leffler 
172739beb93cSSam Leffler   /* fix the sign */
172839beb93cSSam Leffler   neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
172939beb93cSSam Leffler   x.sign = y.sign = MP_ZPOS;
173039beb93cSSam Leffler 
173139beb93cSSam Leffler   /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
173239beb93cSSam Leffler   norm = mp_count_bits(&y) % DIGIT_BIT;
173339beb93cSSam Leffler   if (norm < (int)(DIGIT_BIT-1)) {
173439beb93cSSam Leffler      norm = (DIGIT_BIT-1) - norm;
173539beb93cSSam Leffler      if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
173639beb93cSSam Leffler        goto LBL_Y;
173739beb93cSSam Leffler      }
173839beb93cSSam Leffler      if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
173939beb93cSSam Leffler        goto LBL_Y;
174039beb93cSSam Leffler      }
174139beb93cSSam Leffler   } else {
174239beb93cSSam Leffler      norm = 0;
174339beb93cSSam Leffler   }
174439beb93cSSam Leffler 
174539beb93cSSam Leffler   /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
174639beb93cSSam Leffler   n = x.used - 1;
174739beb93cSSam Leffler   t = y.used - 1;
174839beb93cSSam Leffler 
174939beb93cSSam Leffler   /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
175039beb93cSSam Leffler   if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
175139beb93cSSam Leffler     goto LBL_Y;
175239beb93cSSam Leffler   }
175339beb93cSSam Leffler 
175439beb93cSSam Leffler   while (mp_cmp (&x, &y) != MP_LT) {
175539beb93cSSam Leffler     ++(q.dp[n - t]);
175639beb93cSSam Leffler     if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
175739beb93cSSam Leffler       goto LBL_Y;
175839beb93cSSam Leffler     }
175939beb93cSSam Leffler   }
176039beb93cSSam Leffler 
176139beb93cSSam Leffler   /* reset y by shifting it back down */
176239beb93cSSam Leffler   mp_rshd (&y, n - t);
176339beb93cSSam Leffler 
176439beb93cSSam Leffler   /* step 3. for i from n down to (t + 1) */
176539beb93cSSam Leffler   for (i = n; i >= (t + 1); i--) {
176639beb93cSSam Leffler     if (i > x.used) {
176739beb93cSSam Leffler       continue;
176839beb93cSSam Leffler     }
176939beb93cSSam Leffler 
177039beb93cSSam Leffler     /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
177139beb93cSSam Leffler      * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
177239beb93cSSam Leffler     if (x.dp[i] == y.dp[t]) {
177339beb93cSSam Leffler       q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
177439beb93cSSam Leffler     } else {
177539beb93cSSam Leffler       mp_word tmp;
177639beb93cSSam Leffler       tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
177739beb93cSSam Leffler       tmp |= ((mp_word) x.dp[i - 1]);
177839beb93cSSam Leffler       tmp /= ((mp_word) y.dp[t]);
177939beb93cSSam Leffler       if (tmp > (mp_word) MP_MASK)
178039beb93cSSam Leffler         tmp = MP_MASK;
178139beb93cSSam Leffler       q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
178239beb93cSSam Leffler     }
178339beb93cSSam Leffler 
178439beb93cSSam Leffler     /* while (q{i-t-1} * (yt * b + y{t-1})) >
178539beb93cSSam Leffler              xi * b**2 + xi-1 * b + xi-2
178639beb93cSSam Leffler 
178739beb93cSSam Leffler        do q{i-t-1} -= 1;
178839beb93cSSam Leffler     */
178939beb93cSSam Leffler     q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
179039beb93cSSam Leffler     do {
179139beb93cSSam Leffler       q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
179239beb93cSSam Leffler 
179339beb93cSSam Leffler       /* find left hand */
179439beb93cSSam Leffler       mp_zero (&t1);
179539beb93cSSam Leffler       t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
179639beb93cSSam Leffler       t1.dp[1] = y.dp[t];
179739beb93cSSam Leffler       t1.used = 2;
179839beb93cSSam Leffler       if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
179939beb93cSSam Leffler         goto LBL_Y;
180039beb93cSSam Leffler       }
180139beb93cSSam Leffler 
180239beb93cSSam Leffler       /* find right hand */
180339beb93cSSam Leffler       t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
180439beb93cSSam Leffler       t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
180539beb93cSSam Leffler       t2.dp[2] = x.dp[i];
180639beb93cSSam Leffler       t2.used = 3;
180739beb93cSSam Leffler     } while (mp_cmp_mag(&t1, &t2) == MP_GT);
180839beb93cSSam Leffler 
180939beb93cSSam Leffler     /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
181039beb93cSSam Leffler     if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
181139beb93cSSam Leffler       goto LBL_Y;
181239beb93cSSam Leffler     }
181339beb93cSSam Leffler 
181439beb93cSSam Leffler     if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
181539beb93cSSam Leffler       goto LBL_Y;
181639beb93cSSam Leffler     }
181739beb93cSSam Leffler 
181839beb93cSSam Leffler     if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
181939beb93cSSam Leffler       goto LBL_Y;
182039beb93cSSam Leffler     }
182139beb93cSSam Leffler 
182239beb93cSSam Leffler     /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
182339beb93cSSam Leffler     if (x.sign == MP_NEG) {
182439beb93cSSam Leffler       if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
182539beb93cSSam Leffler         goto LBL_Y;
182639beb93cSSam Leffler       }
182739beb93cSSam Leffler       if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
182839beb93cSSam Leffler         goto LBL_Y;
182939beb93cSSam Leffler       }
183039beb93cSSam Leffler       if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
183139beb93cSSam Leffler         goto LBL_Y;
183239beb93cSSam Leffler       }
183339beb93cSSam Leffler 
183439beb93cSSam Leffler       q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
183539beb93cSSam Leffler     }
183639beb93cSSam Leffler   }
183739beb93cSSam Leffler 
183839beb93cSSam Leffler   /* now q is the quotient and x is the remainder
183939beb93cSSam Leffler    * [which we have to normalize]
184039beb93cSSam Leffler    */
184139beb93cSSam Leffler 
184239beb93cSSam Leffler   /* get sign before writing to c */
184339beb93cSSam Leffler   x.sign = x.used == 0 ? MP_ZPOS : a->sign;
184439beb93cSSam Leffler 
184539beb93cSSam Leffler   if (c != NULL) {
184639beb93cSSam Leffler     mp_clamp (&q);
184739beb93cSSam Leffler     mp_exch (&q, c);
184839beb93cSSam Leffler     c->sign = neg;
184939beb93cSSam Leffler   }
185039beb93cSSam Leffler 
185139beb93cSSam Leffler   if (d != NULL) {
185239beb93cSSam Leffler     mp_div_2d (&x, norm, &x, NULL);
185339beb93cSSam Leffler     mp_exch (&x, d);
185439beb93cSSam Leffler   }
185539beb93cSSam Leffler 
185639beb93cSSam Leffler   res = MP_OKAY;
185739beb93cSSam Leffler 
185839beb93cSSam Leffler LBL_Y:mp_clear (&y);
185939beb93cSSam Leffler LBL_X:mp_clear (&x);
186039beb93cSSam Leffler LBL_T2:mp_clear (&t2);
186139beb93cSSam Leffler LBL_T1:mp_clear (&t1);
186239beb93cSSam Leffler LBL_Q:mp_clear (&q);
186339beb93cSSam Leffler   return res;
186439beb93cSSam Leffler }
186539beb93cSSam Leffler 
186639beb93cSSam Leffler #endif
186739beb93cSSam Leffler 
186839beb93cSSam Leffler 
186939beb93cSSam Leffler #ifdef MP_LOW_MEM
187039beb93cSSam Leffler    #define TAB_SIZE 32
187139beb93cSSam Leffler #else
187239beb93cSSam Leffler    #define TAB_SIZE 256
187339beb93cSSam Leffler #endif
187439beb93cSSam Leffler 
s_mp_exptmod(mp_int * G,mp_int * X,mp_int * P,mp_int * Y,int redmode)187539beb93cSSam Leffler static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
187639beb93cSSam Leffler {
187739beb93cSSam Leffler   mp_int  M[TAB_SIZE], res, mu;
187839beb93cSSam Leffler   mp_digit buf;
187939beb93cSSam Leffler   int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
188039beb93cSSam Leffler   int (*redux)(mp_int*,mp_int*,mp_int*);
188139beb93cSSam Leffler 
188239beb93cSSam Leffler   /* find window size */
188339beb93cSSam Leffler   x = mp_count_bits (X);
188439beb93cSSam Leffler   if (x <= 7) {
188539beb93cSSam Leffler     winsize = 2;
188639beb93cSSam Leffler   } else if (x <= 36) {
188739beb93cSSam Leffler     winsize = 3;
188839beb93cSSam Leffler   } else if (x <= 140) {
188939beb93cSSam Leffler     winsize = 4;
189039beb93cSSam Leffler   } else if (x <= 450) {
189139beb93cSSam Leffler     winsize = 5;
189239beb93cSSam Leffler   } else if (x <= 1303) {
189339beb93cSSam Leffler     winsize = 6;
189439beb93cSSam Leffler   } else if (x <= 3529) {
189539beb93cSSam Leffler     winsize = 7;
189639beb93cSSam Leffler   } else {
189739beb93cSSam Leffler     winsize = 8;
189839beb93cSSam Leffler   }
189939beb93cSSam Leffler 
190039beb93cSSam Leffler #ifdef MP_LOW_MEM
190139beb93cSSam Leffler     if (winsize > 5) {
190239beb93cSSam Leffler        winsize = 5;
190339beb93cSSam Leffler     }
190439beb93cSSam Leffler #endif
190539beb93cSSam Leffler 
190639beb93cSSam Leffler   /* init M array */
190739beb93cSSam Leffler   /* init first cell */
190839beb93cSSam Leffler   if ((err = mp_init(&M[1])) != MP_OKAY) {
190939beb93cSSam Leffler      return err;
191039beb93cSSam Leffler   }
191139beb93cSSam Leffler 
191239beb93cSSam Leffler   /* now init the second half of the array */
191339beb93cSSam Leffler   for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
191439beb93cSSam Leffler     if ((err = mp_init(&M[x])) != MP_OKAY) {
191539beb93cSSam Leffler       for (y = 1<<(winsize-1); y < x; y++) {
191639beb93cSSam Leffler         mp_clear (&M[y]);
191739beb93cSSam Leffler       }
191839beb93cSSam Leffler       mp_clear(&M[1]);
191939beb93cSSam Leffler       return err;
192039beb93cSSam Leffler     }
192139beb93cSSam Leffler   }
192239beb93cSSam Leffler 
192339beb93cSSam Leffler   /* create mu, used for Barrett reduction */
192439beb93cSSam Leffler   if ((err = mp_init (&mu)) != MP_OKAY) {
192539beb93cSSam Leffler     goto LBL_M;
192639beb93cSSam Leffler   }
192739beb93cSSam Leffler 
192839beb93cSSam Leffler   if (redmode == 0) {
192939beb93cSSam Leffler      if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
193039beb93cSSam Leffler         goto LBL_MU;
193139beb93cSSam Leffler      }
193239beb93cSSam Leffler      redux = mp_reduce;
193339beb93cSSam Leffler   } else {
193439beb93cSSam Leffler      if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
193539beb93cSSam Leffler         goto LBL_MU;
193639beb93cSSam Leffler      }
193739beb93cSSam Leffler      redux = mp_reduce_2k_l;
193839beb93cSSam Leffler   }
193939beb93cSSam Leffler 
194039beb93cSSam Leffler   /* create M table
194139beb93cSSam Leffler    *
194239beb93cSSam Leffler    * The M table contains powers of the base,
194339beb93cSSam Leffler    * e.g. M[x] = G**x mod P
194439beb93cSSam Leffler    *
194539beb93cSSam Leffler    * The first half of the table is not
194639beb93cSSam Leffler    * computed though accept for M[0] and M[1]
194739beb93cSSam Leffler    */
194839beb93cSSam Leffler   if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
194939beb93cSSam Leffler     goto LBL_MU;
195039beb93cSSam Leffler   }
195139beb93cSSam Leffler 
195239beb93cSSam Leffler   /* compute the value at M[1<<(winsize-1)] by squaring
195339beb93cSSam Leffler    * M[1] (winsize-1) times
195439beb93cSSam Leffler    */
195539beb93cSSam Leffler   if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
195639beb93cSSam Leffler     goto LBL_MU;
195739beb93cSSam Leffler   }
195839beb93cSSam Leffler 
195939beb93cSSam Leffler   for (x = 0; x < (winsize - 1); x++) {
196039beb93cSSam Leffler     /* square it */
196139beb93cSSam Leffler     if ((err = mp_sqr (&M[1 << (winsize - 1)],
196239beb93cSSam Leffler                        &M[1 << (winsize - 1)])) != MP_OKAY) {
196339beb93cSSam Leffler       goto LBL_MU;
196439beb93cSSam Leffler     }
196539beb93cSSam Leffler 
196639beb93cSSam Leffler     /* reduce modulo P */
196739beb93cSSam Leffler     if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
196839beb93cSSam Leffler       goto LBL_MU;
196939beb93cSSam Leffler     }
197039beb93cSSam Leffler   }
197139beb93cSSam Leffler 
197239beb93cSSam Leffler   /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
197339beb93cSSam Leffler    * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
197439beb93cSSam Leffler    */
197539beb93cSSam Leffler   for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
197639beb93cSSam Leffler     if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
197739beb93cSSam Leffler       goto LBL_MU;
197839beb93cSSam Leffler     }
197939beb93cSSam Leffler     if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
198039beb93cSSam Leffler       goto LBL_MU;
198139beb93cSSam Leffler     }
198239beb93cSSam Leffler   }
198339beb93cSSam Leffler 
198439beb93cSSam Leffler   /* setup result */
198539beb93cSSam Leffler   if ((err = mp_init (&res)) != MP_OKAY) {
198639beb93cSSam Leffler     goto LBL_MU;
198739beb93cSSam Leffler   }
198839beb93cSSam Leffler   mp_set (&res, 1);
198939beb93cSSam Leffler 
199039beb93cSSam Leffler   /* set initial mode and bit cnt */
199139beb93cSSam Leffler   mode   = 0;
199239beb93cSSam Leffler   bitcnt = 1;
199339beb93cSSam Leffler   buf    = 0;
199439beb93cSSam Leffler   digidx = X->used - 1;
199539beb93cSSam Leffler   bitcpy = 0;
199639beb93cSSam Leffler   bitbuf = 0;
199739beb93cSSam Leffler 
199839beb93cSSam Leffler   for (;;) {
199939beb93cSSam Leffler     /* grab next digit as required */
200039beb93cSSam Leffler     if (--bitcnt == 0) {
200139beb93cSSam Leffler       /* if digidx == -1 we are out of digits */
200239beb93cSSam Leffler       if (digidx == -1) {
200339beb93cSSam Leffler         break;
200439beb93cSSam Leffler       }
200539beb93cSSam Leffler       /* read next digit and reset the bitcnt */
200639beb93cSSam Leffler       buf    = X->dp[digidx--];
200739beb93cSSam Leffler       bitcnt = (int) DIGIT_BIT;
200839beb93cSSam Leffler     }
200939beb93cSSam Leffler 
201039beb93cSSam Leffler     /* grab the next msb from the exponent */
201139beb93cSSam Leffler     y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
201239beb93cSSam Leffler     buf <<= (mp_digit)1;
201339beb93cSSam Leffler 
201439beb93cSSam Leffler     /* if the bit is zero and mode == 0 then we ignore it
201539beb93cSSam Leffler      * These represent the leading zero bits before the first 1 bit
201639beb93cSSam Leffler      * in the exponent.  Technically this opt is not required but it
201739beb93cSSam Leffler      * does lower the # of trivial squaring/reductions used
201839beb93cSSam Leffler      */
201939beb93cSSam Leffler     if (mode == 0 && y == 0) {
202039beb93cSSam Leffler       continue;
202139beb93cSSam Leffler     }
202239beb93cSSam Leffler 
202339beb93cSSam Leffler     /* if the bit is zero and mode == 1 then we square */
202439beb93cSSam Leffler     if (mode == 1 && y == 0) {
202539beb93cSSam Leffler       if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
202639beb93cSSam Leffler         goto LBL_RES;
202739beb93cSSam Leffler       }
202839beb93cSSam Leffler       if ((err = redux (&res, P, &mu)) != MP_OKAY) {
202939beb93cSSam Leffler         goto LBL_RES;
203039beb93cSSam Leffler       }
203139beb93cSSam Leffler       continue;
203239beb93cSSam Leffler     }
203339beb93cSSam Leffler 
203439beb93cSSam Leffler     /* else we add it to the window */
203539beb93cSSam Leffler     bitbuf |= (y << (winsize - ++bitcpy));
203639beb93cSSam Leffler     mode    = 2;
203739beb93cSSam Leffler 
203839beb93cSSam Leffler     if (bitcpy == winsize) {
203939beb93cSSam Leffler       /* ok window is filled so square as required and multiply  */
204039beb93cSSam Leffler       /* square first */
204139beb93cSSam Leffler       for (x = 0; x < winsize; x++) {
204239beb93cSSam Leffler         if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
204339beb93cSSam Leffler           goto LBL_RES;
204439beb93cSSam Leffler         }
204539beb93cSSam Leffler         if ((err = redux (&res, P, &mu)) != MP_OKAY) {
204639beb93cSSam Leffler           goto LBL_RES;
204739beb93cSSam Leffler         }
204839beb93cSSam Leffler       }
204939beb93cSSam Leffler 
205039beb93cSSam Leffler       /* then multiply */
205139beb93cSSam Leffler       if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
205239beb93cSSam Leffler         goto LBL_RES;
205339beb93cSSam Leffler       }
205439beb93cSSam Leffler       if ((err = redux (&res, P, &mu)) != MP_OKAY) {
205539beb93cSSam Leffler         goto LBL_RES;
205639beb93cSSam Leffler       }
205739beb93cSSam Leffler 
205839beb93cSSam Leffler       /* empty window and reset */
205939beb93cSSam Leffler       bitcpy = 0;
206039beb93cSSam Leffler       bitbuf = 0;
206139beb93cSSam Leffler       mode   = 1;
206239beb93cSSam Leffler     }
206339beb93cSSam Leffler   }
206439beb93cSSam Leffler 
206539beb93cSSam Leffler   /* if bits remain then square/multiply */
206639beb93cSSam Leffler   if (mode == 2 && bitcpy > 0) {
206739beb93cSSam Leffler     /* square then multiply if the bit is set */
206839beb93cSSam Leffler     for (x = 0; x < bitcpy; x++) {
206939beb93cSSam Leffler       if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
207039beb93cSSam Leffler         goto LBL_RES;
207139beb93cSSam Leffler       }
207239beb93cSSam Leffler       if ((err = redux (&res, P, &mu)) != MP_OKAY) {
207339beb93cSSam Leffler         goto LBL_RES;
207439beb93cSSam Leffler       }
207539beb93cSSam Leffler 
207639beb93cSSam Leffler       bitbuf <<= 1;
207739beb93cSSam Leffler       if ((bitbuf & (1 << winsize)) != 0) {
207839beb93cSSam Leffler         /* then multiply */
207939beb93cSSam Leffler         if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
208039beb93cSSam Leffler           goto LBL_RES;
208139beb93cSSam Leffler         }
208239beb93cSSam Leffler         if ((err = redux (&res, P, &mu)) != MP_OKAY) {
208339beb93cSSam Leffler           goto LBL_RES;
208439beb93cSSam Leffler         }
208539beb93cSSam Leffler       }
208639beb93cSSam Leffler     }
208739beb93cSSam Leffler   }
208839beb93cSSam Leffler 
208939beb93cSSam Leffler   mp_exch (&res, Y);
209039beb93cSSam Leffler   err = MP_OKAY;
209139beb93cSSam Leffler LBL_RES:mp_clear (&res);
209239beb93cSSam Leffler LBL_MU:mp_clear (&mu);
209339beb93cSSam Leffler LBL_M:
209439beb93cSSam Leffler   mp_clear(&M[1]);
209539beb93cSSam Leffler   for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
209639beb93cSSam Leffler     mp_clear (&M[x]);
209739beb93cSSam Leffler   }
209839beb93cSSam Leffler   return err;
209939beb93cSSam Leffler }
210039beb93cSSam Leffler 
210139beb93cSSam Leffler 
210239beb93cSSam Leffler /* computes b = a*a */
mp_sqr(mp_int * a,mp_int * b)210339beb93cSSam Leffler static int mp_sqr (mp_int * a, mp_int * b)
210439beb93cSSam Leffler {
210539beb93cSSam Leffler   int     res;
210639beb93cSSam Leffler 
210739beb93cSSam Leffler #ifdef BN_MP_TOOM_SQR_C
210839beb93cSSam Leffler   /* use Toom-Cook? */
210939beb93cSSam Leffler   if (a->used >= TOOM_SQR_CUTOFF) {
211039beb93cSSam Leffler     res = mp_toom_sqr(a, b);
211139beb93cSSam Leffler   /* Karatsuba? */
211239beb93cSSam Leffler   } else
211339beb93cSSam Leffler #endif
211439beb93cSSam Leffler #ifdef BN_MP_KARATSUBA_SQR_C
211539beb93cSSam Leffler if (a->used >= KARATSUBA_SQR_CUTOFF) {
211639beb93cSSam Leffler     res = mp_karatsuba_sqr (a, b);
211739beb93cSSam Leffler   } else
211839beb93cSSam Leffler #endif
211939beb93cSSam Leffler   {
212039beb93cSSam Leffler #ifdef BN_FAST_S_MP_SQR_C
212139beb93cSSam Leffler     /* can we use the fast comba multiplier? */
212239beb93cSSam Leffler     if ((a->used * 2 + 1) < MP_WARRAY &&
212339beb93cSSam Leffler          a->used <
212439beb93cSSam Leffler          (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
212539beb93cSSam Leffler       res = fast_s_mp_sqr (a, b);
212639beb93cSSam Leffler     } else
212739beb93cSSam Leffler #endif
212839beb93cSSam Leffler #ifdef BN_S_MP_SQR_C
212939beb93cSSam Leffler       res = s_mp_sqr (a, b);
213039beb93cSSam Leffler #else
213139beb93cSSam Leffler #error mp_sqr could fail
213239beb93cSSam Leffler       res = MP_VAL;
213339beb93cSSam Leffler #endif
213439beb93cSSam Leffler   }
213539beb93cSSam Leffler   b->sign = MP_ZPOS;
213639beb93cSSam Leffler   return res;
213739beb93cSSam Leffler }
213839beb93cSSam Leffler 
213939beb93cSSam Leffler 
214039beb93cSSam Leffler /* reduces a modulo n where n is of the form 2**p - d
214139beb93cSSam Leffler    This differs from reduce_2k since "d" can be larger
214239beb93cSSam Leffler    than a single digit.
214339beb93cSSam Leffler */
mp_reduce_2k_l(mp_int * a,mp_int * n,mp_int * d)214439beb93cSSam Leffler static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
214539beb93cSSam Leffler {
214639beb93cSSam Leffler    mp_int q;
214739beb93cSSam Leffler    int    p, res;
214839beb93cSSam Leffler 
214939beb93cSSam Leffler    if ((res = mp_init(&q)) != MP_OKAY) {
215039beb93cSSam Leffler       return res;
215139beb93cSSam Leffler    }
215239beb93cSSam Leffler 
215339beb93cSSam Leffler    p = mp_count_bits(n);
215439beb93cSSam Leffler top:
215539beb93cSSam Leffler    /* q = a/2**p, a = a mod 2**p */
215639beb93cSSam Leffler    if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
215739beb93cSSam Leffler       goto ERR;
215839beb93cSSam Leffler    }
215939beb93cSSam Leffler 
216039beb93cSSam Leffler    /* q = q * d */
216139beb93cSSam Leffler    if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
216239beb93cSSam Leffler       goto ERR;
216339beb93cSSam Leffler    }
216439beb93cSSam Leffler 
216539beb93cSSam Leffler    /* a = a + q */
216639beb93cSSam Leffler    if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
216739beb93cSSam Leffler       goto ERR;
216839beb93cSSam Leffler    }
216939beb93cSSam Leffler 
217039beb93cSSam Leffler    if (mp_cmp_mag(a, n) != MP_LT) {
217139beb93cSSam Leffler       s_mp_sub(a, n, a);
217239beb93cSSam Leffler       goto top;
217339beb93cSSam Leffler    }
217439beb93cSSam Leffler 
217539beb93cSSam Leffler ERR:
217639beb93cSSam Leffler    mp_clear(&q);
217739beb93cSSam Leffler    return res;
217839beb93cSSam Leffler }
217939beb93cSSam Leffler 
218039beb93cSSam Leffler 
218139beb93cSSam Leffler /* determines the setup value */
mp_reduce_2k_setup_l(mp_int * a,mp_int * d)218239beb93cSSam Leffler static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
218339beb93cSSam Leffler {
218439beb93cSSam Leffler    int    res;
218539beb93cSSam Leffler    mp_int tmp;
218639beb93cSSam Leffler 
218739beb93cSSam Leffler    if ((res = mp_init(&tmp)) != MP_OKAY) {
218839beb93cSSam Leffler       return res;
218939beb93cSSam Leffler    }
219039beb93cSSam Leffler 
219139beb93cSSam Leffler    if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
219239beb93cSSam Leffler       goto ERR;
219339beb93cSSam Leffler    }
219439beb93cSSam Leffler 
219539beb93cSSam Leffler    if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
219639beb93cSSam Leffler       goto ERR;
219739beb93cSSam Leffler    }
219839beb93cSSam Leffler 
219939beb93cSSam Leffler ERR:
220039beb93cSSam Leffler    mp_clear(&tmp);
220139beb93cSSam Leffler    return res;
220239beb93cSSam Leffler }
220339beb93cSSam Leffler 
220439beb93cSSam Leffler 
220539beb93cSSam Leffler /* computes a = 2**b
220639beb93cSSam Leffler  *
220739beb93cSSam Leffler  * Simple algorithm which zeroes the int, grows it then just sets one bit
220839beb93cSSam Leffler  * as required.
220939beb93cSSam Leffler  */
mp_2expt(mp_int * a,int b)221039beb93cSSam Leffler static int mp_2expt (mp_int * a, int b)
221139beb93cSSam Leffler {
221239beb93cSSam Leffler   int     res;
221339beb93cSSam Leffler 
221439beb93cSSam Leffler   /* zero a as per default */
221539beb93cSSam Leffler   mp_zero (a);
221639beb93cSSam Leffler 
2217f05cddf9SRui Paulo   /* grow a to accommodate the single bit */
221839beb93cSSam Leffler   if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
221939beb93cSSam Leffler     return res;
222039beb93cSSam Leffler   }
222139beb93cSSam Leffler 
222239beb93cSSam Leffler   /* set the used count of where the bit will go */
222339beb93cSSam Leffler   a->used = b / DIGIT_BIT + 1;
222439beb93cSSam Leffler 
222539beb93cSSam Leffler   /* put the single bit in its place */
222639beb93cSSam Leffler   a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
222739beb93cSSam Leffler 
222839beb93cSSam Leffler   return MP_OKAY;
222939beb93cSSam Leffler }
223039beb93cSSam Leffler 
223139beb93cSSam Leffler 
223239beb93cSSam Leffler /* pre-calculate the value required for Barrett reduction
223339beb93cSSam Leffler  * For a given modulus "b" it calulates the value required in "a"
223439beb93cSSam Leffler  */
mp_reduce_setup(mp_int * a,mp_int * b)223539beb93cSSam Leffler static int mp_reduce_setup (mp_int * a, mp_int * b)
223639beb93cSSam Leffler {
223739beb93cSSam Leffler   int     res;
223839beb93cSSam Leffler 
223939beb93cSSam Leffler   if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
224039beb93cSSam Leffler     return res;
224139beb93cSSam Leffler   }
224239beb93cSSam Leffler   return mp_div (a, b, a, NULL);
224339beb93cSSam Leffler }
224439beb93cSSam Leffler 
224539beb93cSSam Leffler 
224639beb93cSSam Leffler /* reduces x mod m, assumes 0 < x < m**2, mu is
224739beb93cSSam Leffler  * precomputed via mp_reduce_setup.
224839beb93cSSam Leffler  * From HAC pp.604 Algorithm 14.42
224939beb93cSSam Leffler  */
mp_reduce(mp_int * x,mp_int * m,mp_int * mu)225039beb93cSSam Leffler static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
225139beb93cSSam Leffler {
225239beb93cSSam Leffler   mp_int  q;
225339beb93cSSam Leffler   int     res, um = m->used;
225439beb93cSSam Leffler 
225539beb93cSSam Leffler   /* q = x */
225639beb93cSSam Leffler   if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
225739beb93cSSam Leffler     return res;
225839beb93cSSam Leffler   }
225939beb93cSSam Leffler 
226039beb93cSSam Leffler   /* q1 = x / b**(k-1)  */
226139beb93cSSam Leffler   mp_rshd (&q, um - 1);
226239beb93cSSam Leffler 
226339beb93cSSam Leffler   /* according to HAC this optimization is ok */
226439beb93cSSam Leffler   if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
226539beb93cSSam Leffler     if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
226639beb93cSSam Leffler       goto CLEANUP;
226739beb93cSSam Leffler     }
226839beb93cSSam Leffler   } else {
226939beb93cSSam Leffler #ifdef BN_S_MP_MUL_HIGH_DIGS_C
227039beb93cSSam Leffler     if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
227139beb93cSSam Leffler       goto CLEANUP;
227239beb93cSSam Leffler     }
227339beb93cSSam Leffler #elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
227439beb93cSSam Leffler     if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
227539beb93cSSam Leffler       goto CLEANUP;
227639beb93cSSam Leffler     }
227739beb93cSSam Leffler #else
227839beb93cSSam Leffler     {
227939beb93cSSam Leffler #error mp_reduce would always fail
228039beb93cSSam Leffler       res = MP_VAL;
228139beb93cSSam Leffler       goto CLEANUP;
228239beb93cSSam Leffler     }
228339beb93cSSam Leffler #endif
228439beb93cSSam Leffler   }
228539beb93cSSam Leffler 
228639beb93cSSam Leffler   /* q3 = q2 / b**(k+1) */
228739beb93cSSam Leffler   mp_rshd (&q, um + 1);
228839beb93cSSam Leffler 
228939beb93cSSam Leffler   /* x = x mod b**(k+1), quick (no division) */
229039beb93cSSam Leffler   if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
229139beb93cSSam Leffler     goto CLEANUP;
229239beb93cSSam Leffler   }
229339beb93cSSam Leffler 
229439beb93cSSam Leffler   /* q = q * m mod b**(k+1), quick (no division) */
229539beb93cSSam Leffler   if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
229639beb93cSSam Leffler     goto CLEANUP;
229739beb93cSSam Leffler   }
229839beb93cSSam Leffler 
229939beb93cSSam Leffler   /* x = x - q */
230039beb93cSSam Leffler   if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
230139beb93cSSam Leffler     goto CLEANUP;
230239beb93cSSam Leffler   }
230339beb93cSSam Leffler 
230439beb93cSSam Leffler   /* If x < 0, add b**(k+1) to it */
230539beb93cSSam Leffler   if (mp_cmp_d (x, 0) == MP_LT) {
230639beb93cSSam Leffler     mp_set (&q, 1);
230739beb93cSSam Leffler     if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
230839beb93cSSam Leffler       goto CLEANUP;
230939beb93cSSam Leffler     }
231039beb93cSSam Leffler     if ((res = mp_add (x, &q, x)) != MP_OKAY) {
231139beb93cSSam Leffler       goto CLEANUP;
231239beb93cSSam Leffler     }
231339beb93cSSam Leffler   }
231439beb93cSSam Leffler 
231539beb93cSSam Leffler   /* Back off if it's too big */
231639beb93cSSam Leffler   while (mp_cmp (x, m) != MP_LT) {
231739beb93cSSam Leffler     if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
231839beb93cSSam Leffler       goto CLEANUP;
231939beb93cSSam Leffler     }
232039beb93cSSam Leffler   }
232139beb93cSSam Leffler 
232239beb93cSSam Leffler CLEANUP:
232339beb93cSSam Leffler   mp_clear (&q);
232439beb93cSSam Leffler 
232539beb93cSSam Leffler   return res;
232639beb93cSSam Leffler }
232739beb93cSSam Leffler 
232839beb93cSSam Leffler 
232939beb93cSSam Leffler /* multiplies |a| * |b| and only computes up to digs digits of result
233039beb93cSSam Leffler  * HAC pp. 595, Algorithm 14.12  Modified so you can control how
233139beb93cSSam Leffler  * many digits of output are created.
233239beb93cSSam Leffler  */
s_mp_mul_digs(mp_int * a,mp_int * b,mp_int * c,int digs)233339beb93cSSam Leffler static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
233439beb93cSSam Leffler {
233539beb93cSSam Leffler   mp_int  t;
233639beb93cSSam Leffler   int     res, pa, pb, ix, iy;
233739beb93cSSam Leffler   mp_digit u;
233839beb93cSSam Leffler   mp_word r;
233939beb93cSSam Leffler   mp_digit tmpx, *tmpt, *tmpy;
234039beb93cSSam Leffler 
23415b9c547cSRui Paulo #ifdef BN_FAST_S_MP_MUL_DIGS_C
234239beb93cSSam Leffler   /* can we use the fast multiplier? */
234339beb93cSSam Leffler   if (((digs) < MP_WARRAY) &&
234439beb93cSSam Leffler       MIN (a->used, b->used) <
234539beb93cSSam Leffler           (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
234639beb93cSSam Leffler     return fast_s_mp_mul_digs (a, b, c, digs);
234739beb93cSSam Leffler   }
23485b9c547cSRui Paulo #endif
234939beb93cSSam Leffler 
235039beb93cSSam Leffler   if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
235139beb93cSSam Leffler     return res;
235239beb93cSSam Leffler   }
235339beb93cSSam Leffler   t.used = digs;
235439beb93cSSam Leffler 
235539beb93cSSam Leffler   /* compute the digits of the product directly */
235639beb93cSSam Leffler   pa = a->used;
235739beb93cSSam Leffler   for (ix = 0; ix < pa; ix++) {
235839beb93cSSam Leffler     /* set the carry to zero */
235939beb93cSSam Leffler     u = 0;
236039beb93cSSam Leffler 
236139beb93cSSam Leffler     /* limit ourselves to making digs digits of output */
236239beb93cSSam Leffler     pb = MIN (b->used, digs - ix);
236339beb93cSSam Leffler 
236439beb93cSSam Leffler     /* setup some aliases */
236539beb93cSSam Leffler     /* copy of the digit from a used within the nested loop */
236639beb93cSSam Leffler     tmpx = a->dp[ix];
236739beb93cSSam Leffler 
236839beb93cSSam Leffler     /* an alias for the destination shifted ix places */
236939beb93cSSam Leffler     tmpt = t.dp + ix;
237039beb93cSSam Leffler 
237139beb93cSSam Leffler     /* an alias for the digits of b */
237239beb93cSSam Leffler     tmpy = b->dp;
237339beb93cSSam Leffler 
237439beb93cSSam Leffler     /* compute the columns of the output and propagate the carry */
237539beb93cSSam Leffler     for (iy = 0; iy < pb; iy++) {
237639beb93cSSam Leffler       /* compute the column as a mp_word */
237739beb93cSSam Leffler       r       = ((mp_word)*tmpt) +
237839beb93cSSam Leffler                 ((mp_word)tmpx) * ((mp_word)*tmpy++) +
237939beb93cSSam Leffler                 ((mp_word) u);
238039beb93cSSam Leffler 
238139beb93cSSam Leffler       /* the new column is the lower part of the result */
238239beb93cSSam Leffler       *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
238339beb93cSSam Leffler 
238439beb93cSSam Leffler       /* get the carry word from the result */
238539beb93cSSam Leffler       u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
238639beb93cSSam Leffler     }
238739beb93cSSam Leffler     /* set carry if it is placed below digs */
238839beb93cSSam Leffler     if (ix + iy < digs) {
238939beb93cSSam Leffler       *tmpt = u;
239039beb93cSSam Leffler     }
239139beb93cSSam Leffler   }
239239beb93cSSam Leffler 
239339beb93cSSam Leffler   mp_clamp (&t);
239439beb93cSSam Leffler   mp_exch (&t, c);
239539beb93cSSam Leffler 
239639beb93cSSam Leffler   mp_clear (&t);
239739beb93cSSam Leffler   return MP_OKAY;
239839beb93cSSam Leffler }
239939beb93cSSam Leffler 
240039beb93cSSam Leffler 
24015b9c547cSRui Paulo #ifdef BN_FAST_S_MP_MUL_DIGS_C
240239beb93cSSam Leffler /* Fast (comba) multiplier
240339beb93cSSam Leffler  *
240439beb93cSSam Leffler  * This is the fast column-array [comba] multiplier.  It is
240539beb93cSSam Leffler  * designed to compute the columns of the product first
240639beb93cSSam Leffler  * then handle the carries afterwards.  This has the effect
240739beb93cSSam Leffler  * of making the nested loops that compute the columns very
240839beb93cSSam Leffler  * simple and schedulable on super-scalar processors.
240939beb93cSSam Leffler  *
241039beb93cSSam Leffler  * This has been modified to produce a variable number of
241139beb93cSSam Leffler  * digits of output so if say only a half-product is required
241239beb93cSSam Leffler  * you don't have to compute the upper half (a feature
241339beb93cSSam Leffler  * required for fast Barrett reduction).
241439beb93cSSam Leffler  *
241539beb93cSSam Leffler  * Based on Algorithm 14.12 on pp.595 of HAC.
241639beb93cSSam Leffler  *
241739beb93cSSam Leffler  */
fast_s_mp_mul_digs(mp_int * a,mp_int * b,mp_int * c,int digs)241839beb93cSSam Leffler static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
241939beb93cSSam Leffler {
242039beb93cSSam Leffler   int     olduse, res, pa, ix, iz;
242139beb93cSSam Leffler   mp_digit W[MP_WARRAY];
242239beb93cSSam Leffler   register mp_word  _W;
242339beb93cSSam Leffler 
242439beb93cSSam Leffler   /* grow the destination as required */
242539beb93cSSam Leffler   if (c->alloc < digs) {
242639beb93cSSam Leffler     if ((res = mp_grow (c, digs)) != MP_OKAY) {
242739beb93cSSam Leffler       return res;
242839beb93cSSam Leffler     }
242939beb93cSSam Leffler   }
243039beb93cSSam Leffler 
243139beb93cSSam Leffler   /* number of output digits to produce */
243239beb93cSSam Leffler   pa = MIN(digs, a->used + b->used);
243339beb93cSSam Leffler 
243439beb93cSSam Leffler   /* clear the carry */
243539beb93cSSam Leffler   _W = 0;
2436*206b73d0SCy Schubert   os_memset(W, 0, sizeof(W));
243739beb93cSSam Leffler   for (ix = 0; ix < pa; ix++) {
243839beb93cSSam Leffler       int      tx, ty;
243939beb93cSSam Leffler       int      iy;
244039beb93cSSam Leffler       mp_digit *tmpx, *tmpy;
244139beb93cSSam Leffler 
244239beb93cSSam Leffler       /* get offsets into the two bignums */
244339beb93cSSam Leffler       ty = MIN(b->used-1, ix);
244439beb93cSSam Leffler       tx = ix - ty;
244539beb93cSSam Leffler 
244639beb93cSSam Leffler       /* setup temp aliases */
244739beb93cSSam Leffler       tmpx = a->dp + tx;
244839beb93cSSam Leffler       tmpy = b->dp + ty;
244939beb93cSSam Leffler 
245039beb93cSSam Leffler       /* this is the number of times the loop will iterrate, essentially
245139beb93cSSam Leffler          while (tx++ < a->used && ty-- >= 0) { ... }
245239beb93cSSam Leffler        */
245339beb93cSSam Leffler       iy = MIN(a->used-tx, ty+1);
245439beb93cSSam Leffler 
245539beb93cSSam Leffler       /* execute loop */
245639beb93cSSam Leffler       for (iz = 0; iz < iy; ++iz) {
245739beb93cSSam Leffler          _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
245839beb93cSSam Leffler 
245939beb93cSSam Leffler       }
246039beb93cSSam Leffler 
246139beb93cSSam Leffler       /* store term */
246239beb93cSSam Leffler       W[ix] = ((mp_digit)_W) & MP_MASK;
246339beb93cSSam Leffler 
246439beb93cSSam Leffler       /* make next carry */
246539beb93cSSam Leffler       _W = _W >> ((mp_word)DIGIT_BIT);
246639beb93cSSam Leffler  }
246739beb93cSSam Leffler 
246839beb93cSSam Leffler   /* setup dest */
246939beb93cSSam Leffler   olduse  = c->used;
247039beb93cSSam Leffler   c->used = pa;
247139beb93cSSam Leffler 
247239beb93cSSam Leffler   {
247339beb93cSSam Leffler     register mp_digit *tmpc;
247439beb93cSSam Leffler     tmpc = c->dp;
247539beb93cSSam Leffler     for (ix = 0; ix < pa+1; ix++) {
247639beb93cSSam Leffler       /* now extract the previous digit [below the carry] */
247739beb93cSSam Leffler       *tmpc++ = W[ix];
247839beb93cSSam Leffler     }
247939beb93cSSam Leffler 
248039beb93cSSam Leffler     /* clear unused digits [that existed in the old copy of c] */
248139beb93cSSam Leffler     for (; ix < olduse; ix++) {
248239beb93cSSam Leffler       *tmpc++ = 0;
248339beb93cSSam Leffler     }
248439beb93cSSam Leffler   }
248539beb93cSSam Leffler   mp_clamp (c);
248639beb93cSSam Leffler   return MP_OKAY;
248739beb93cSSam Leffler }
24885b9c547cSRui Paulo #endif /* BN_FAST_S_MP_MUL_DIGS_C */
248939beb93cSSam Leffler 
249039beb93cSSam Leffler 
249139beb93cSSam Leffler /* init an mp_init for a given size */
mp_init_size(mp_int * a,int size)249239beb93cSSam Leffler static int mp_init_size (mp_int * a, int size)
249339beb93cSSam Leffler {
249439beb93cSSam Leffler   int x;
249539beb93cSSam Leffler 
249639beb93cSSam Leffler   /* pad size so there are always extra digits */
249739beb93cSSam Leffler   size += (MP_PREC * 2) - (size % MP_PREC);
249839beb93cSSam Leffler 
249939beb93cSSam Leffler   /* alloc mem */
250039beb93cSSam Leffler   a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
250139beb93cSSam Leffler   if (a->dp == NULL) {
250239beb93cSSam Leffler     return MP_MEM;
250339beb93cSSam Leffler   }
250439beb93cSSam Leffler 
250539beb93cSSam Leffler   /* set the members */
250639beb93cSSam Leffler   a->used  = 0;
250739beb93cSSam Leffler   a->alloc = size;
250839beb93cSSam Leffler   a->sign  = MP_ZPOS;
250939beb93cSSam Leffler 
251039beb93cSSam Leffler   /* zero the digits */
251139beb93cSSam Leffler   for (x = 0; x < size; x++) {
251239beb93cSSam Leffler       a->dp[x] = 0;
251339beb93cSSam Leffler   }
251439beb93cSSam Leffler 
251539beb93cSSam Leffler   return MP_OKAY;
251639beb93cSSam Leffler }
251739beb93cSSam Leffler 
251839beb93cSSam Leffler 
251939beb93cSSam Leffler /* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
s_mp_sqr(mp_int * a,mp_int * b)252039beb93cSSam Leffler static int s_mp_sqr (mp_int * a, mp_int * b)
252139beb93cSSam Leffler {
252239beb93cSSam Leffler   mp_int  t;
252339beb93cSSam Leffler   int     res, ix, iy, pa;
252439beb93cSSam Leffler   mp_word r;
252539beb93cSSam Leffler   mp_digit u, tmpx, *tmpt;
252639beb93cSSam Leffler 
252739beb93cSSam Leffler   pa = a->used;
252839beb93cSSam Leffler   if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
252939beb93cSSam Leffler     return res;
253039beb93cSSam Leffler   }
253139beb93cSSam Leffler 
253239beb93cSSam Leffler   /* default used is maximum possible size */
253339beb93cSSam Leffler   t.used = 2*pa + 1;
253439beb93cSSam Leffler 
253539beb93cSSam Leffler   for (ix = 0; ix < pa; ix++) {
253639beb93cSSam Leffler     /* first calculate the digit at 2*ix */
253739beb93cSSam Leffler     /* calculate double precision result */
253839beb93cSSam Leffler     r = ((mp_word) t.dp[2*ix]) +
253939beb93cSSam Leffler         ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
254039beb93cSSam Leffler 
254139beb93cSSam Leffler     /* store lower part in result */
254239beb93cSSam Leffler     t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
254339beb93cSSam Leffler 
254439beb93cSSam Leffler     /* get the carry */
254539beb93cSSam Leffler     u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
254639beb93cSSam Leffler 
254739beb93cSSam Leffler     /* left hand side of A[ix] * A[iy] */
254839beb93cSSam Leffler     tmpx        = a->dp[ix];
254939beb93cSSam Leffler 
255039beb93cSSam Leffler     /* alias for where to store the results */
255139beb93cSSam Leffler     tmpt        = t.dp + (2*ix + 1);
255239beb93cSSam Leffler 
255339beb93cSSam Leffler     for (iy = ix + 1; iy < pa; iy++) {
255439beb93cSSam Leffler       /* first calculate the product */
255539beb93cSSam Leffler       r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
255639beb93cSSam Leffler 
255739beb93cSSam Leffler       /* now calculate the double precision result, note we use
255839beb93cSSam Leffler        * addition instead of *2 since it's easier to optimize
255939beb93cSSam Leffler        */
256039beb93cSSam Leffler       r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
256139beb93cSSam Leffler 
256239beb93cSSam Leffler       /* store lower part */
256339beb93cSSam Leffler       *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
256439beb93cSSam Leffler 
256539beb93cSSam Leffler       /* get carry */
256639beb93cSSam Leffler       u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
256739beb93cSSam Leffler     }
256839beb93cSSam Leffler     /* propagate upwards */
256939beb93cSSam Leffler     while (u != ((mp_digit) 0)) {
257039beb93cSSam Leffler       r       = ((mp_word) *tmpt) + ((mp_word) u);
257139beb93cSSam Leffler       *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
257239beb93cSSam Leffler       u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
257339beb93cSSam Leffler     }
257439beb93cSSam Leffler   }
257539beb93cSSam Leffler 
257639beb93cSSam Leffler   mp_clamp (&t);
257739beb93cSSam Leffler   mp_exch (&t, b);
257839beb93cSSam Leffler   mp_clear (&t);
257939beb93cSSam Leffler   return MP_OKAY;
258039beb93cSSam Leffler }
258139beb93cSSam Leffler 
258239beb93cSSam Leffler 
258339beb93cSSam Leffler /* multiplies |a| * |b| and does not compute the lower digs digits
258439beb93cSSam Leffler  * [meant to get the higher part of the product]
258539beb93cSSam Leffler  */
s_mp_mul_high_digs(mp_int * a,mp_int * b,mp_int * c,int digs)258639beb93cSSam Leffler static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
258739beb93cSSam Leffler {
258839beb93cSSam Leffler   mp_int  t;
258939beb93cSSam Leffler   int     res, pa, pb, ix, iy;
259039beb93cSSam Leffler   mp_digit u;
259139beb93cSSam Leffler   mp_word r;
259239beb93cSSam Leffler   mp_digit tmpx, *tmpt, *tmpy;
259339beb93cSSam Leffler 
259439beb93cSSam Leffler   /* can we use the fast multiplier? */
259539beb93cSSam Leffler #ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
259639beb93cSSam Leffler   if (((a->used + b->used + 1) < MP_WARRAY)
259739beb93cSSam Leffler       && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
259839beb93cSSam Leffler     return fast_s_mp_mul_high_digs (a, b, c, digs);
259939beb93cSSam Leffler   }
260039beb93cSSam Leffler #endif
260139beb93cSSam Leffler 
260239beb93cSSam Leffler   if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
260339beb93cSSam Leffler     return res;
260439beb93cSSam Leffler   }
260539beb93cSSam Leffler   t.used = a->used + b->used + 1;
260639beb93cSSam Leffler 
260739beb93cSSam Leffler   pa = a->used;
260839beb93cSSam Leffler   pb = b->used;
260939beb93cSSam Leffler   for (ix = 0; ix < pa; ix++) {
261039beb93cSSam Leffler     /* clear the carry */
261139beb93cSSam Leffler     u = 0;
261239beb93cSSam Leffler 
261339beb93cSSam Leffler     /* left hand side of A[ix] * B[iy] */
261439beb93cSSam Leffler     tmpx = a->dp[ix];
261539beb93cSSam Leffler 
261639beb93cSSam Leffler     /* alias to the address of where the digits will be stored */
261739beb93cSSam Leffler     tmpt = &(t.dp[digs]);
261839beb93cSSam Leffler 
261939beb93cSSam Leffler     /* alias for where to read the right hand side from */
262039beb93cSSam Leffler     tmpy = b->dp + (digs - ix);
262139beb93cSSam Leffler 
262239beb93cSSam Leffler     for (iy = digs - ix; iy < pb; iy++) {
262339beb93cSSam Leffler       /* calculate the double precision result */
262439beb93cSSam Leffler       r       = ((mp_word)*tmpt) +
262539beb93cSSam Leffler                 ((mp_word)tmpx) * ((mp_word)*tmpy++) +
262639beb93cSSam Leffler                 ((mp_word) u);
262739beb93cSSam Leffler 
262839beb93cSSam Leffler       /* get the lower part */
262939beb93cSSam Leffler       *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
263039beb93cSSam Leffler 
263139beb93cSSam Leffler       /* carry the carry */
263239beb93cSSam Leffler       u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
263339beb93cSSam Leffler     }
263439beb93cSSam Leffler     *tmpt = u;
263539beb93cSSam Leffler   }
263639beb93cSSam Leffler   mp_clamp (&t);
263739beb93cSSam Leffler   mp_exch (&t, c);
263839beb93cSSam Leffler   mp_clear (&t);
263939beb93cSSam Leffler   return MP_OKAY;
264039beb93cSSam Leffler }
264139beb93cSSam Leffler 
264239beb93cSSam Leffler 
264339beb93cSSam Leffler #ifdef BN_MP_MONTGOMERY_SETUP_C
264439beb93cSSam Leffler /* setups the montgomery reduction stuff */
264539beb93cSSam Leffler static int
mp_montgomery_setup(mp_int * n,mp_digit * rho)264639beb93cSSam Leffler mp_montgomery_setup (mp_int * n, mp_digit * rho)
264739beb93cSSam Leffler {
264839beb93cSSam Leffler   mp_digit x, b;
264939beb93cSSam Leffler 
265039beb93cSSam Leffler /* fast inversion mod 2**k
265139beb93cSSam Leffler  *
265239beb93cSSam Leffler  * Based on the fact that
265339beb93cSSam Leffler  *
265439beb93cSSam Leffler  * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
265539beb93cSSam Leffler  *                    =>  2*X*A - X*X*A*A = 1
265639beb93cSSam Leffler  *                    =>  2*(1) - (1)     = 1
265739beb93cSSam Leffler  */
265839beb93cSSam Leffler   b = n->dp[0];
265939beb93cSSam Leffler 
266039beb93cSSam Leffler   if ((b & 1) == 0) {
266139beb93cSSam Leffler     return MP_VAL;
266239beb93cSSam Leffler   }
266339beb93cSSam Leffler 
266439beb93cSSam Leffler   x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
266539beb93cSSam Leffler   x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
266639beb93cSSam Leffler #if !defined(MP_8BIT)
266739beb93cSSam Leffler   x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
266839beb93cSSam Leffler #endif
266939beb93cSSam Leffler #if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
267039beb93cSSam Leffler   x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
267139beb93cSSam Leffler #endif
267239beb93cSSam Leffler #ifdef MP_64BIT
267339beb93cSSam Leffler   x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
267439beb93cSSam Leffler #endif
267539beb93cSSam Leffler 
267639beb93cSSam Leffler   /* rho = -1/m mod b */
267739beb93cSSam Leffler   *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
267839beb93cSSam Leffler 
267939beb93cSSam Leffler   return MP_OKAY;
268039beb93cSSam Leffler }
268139beb93cSSam Leffler #endif
268239beb93cSSam Leffler 
268339beb93cSSam Leffler 
268439beb93cSSam Leffler #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
268539beb93cSSam Leffler /* computes xR**-1 == x (mod N) via Montgomery Reduction
268639beb93cSSam Leffler  *
268739beb93cSSam Leffler  * This is an optimized implementation of montgomery_reduce
268839beb93cSSam Leffler  * which uses the comba method to quickly calculate the columns of the
268939beb93cSSam Leffler  * reduction.
269039beb93cSSam Leffler  *
269139beb93cSSam Leffler  * Based on Algorithm 14.32 on pp.601 of HAC.
269239beb93cSSam Leffler */
fast_mp_montgomery_reduce(mp_int * x,mp_int * n,mp_digit rho)2693f05cddf9SRui Paulo static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
269439beb93cSSam Leffler {
269539beb93cSSam Leffler   int     ix, res, olduse;
269639beb93cSSam Leffler   mp_word W[MP_WARRAY];
269739beb93cSSam Leffler 
269839beb93cSSam Leffler   /* get old used count */
269939beb93cSSam Leffler   olduse = x->used;
270039beb93cSSam Leffler 
270139beb93cSSam Leffler   /* grow a as required */
270239beb93cSSam Leffler   if (x->alloc < n->used + 1) {
270339beb93cSSam Leffler     if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
270439beb93cSSam Leffler       return res;
270539beb93cSSam Leffler     }
270639beb93cSSam Leffler   }
270739beb93cSSam Leffler 
270839beb93cSSam Leffler   /* first we have to get the digits of the input into
270939beb93cSSam Leffler    * an array of double precision words W[...]
271039beb93cSSam Leffler    */
271139beb93cSSam Leffler   {
271239beb93cSSam Leffler     register mp_word *_W;
271339beb93cSSam Leffler     register mp_digit *tmpx;
271439beb93cSSam Leffler 
271539beb93cSSam Leffler     /* alias for the W[] array */
271639beb93cSSam Leffler     _W   = W;
271739beb93cSSam Leffler 
271839beb93cSSam Leffler     /* alias for the digits of  x*/
271939beb93cSSam Leffler     tmpx = x->dp;
272039beb93cSSam Leffler 
272139beb93cSSam Leffler     /* copy the digits of a into W[0..a->used-1] */
272239beb93cSSam Leffler     for (ix = 0; ix < x->used; ix++) {
272339beb93cSSam Leffler       *_W++ = *tmpx++;
272439beb93cSSam Leffler     }
272539beb93cSSam Leffler 
272639beb93cSSam Leffler     /* zero the high words of W[a->used..m->used*2] */
272739beb93cSSam Leffler     for (; ix < n->used * 2 + 1; ix++) {
272839beb93cSSam Leffler       *_W++ = 0;
272939beb93cSSam Leffler     }
273039beb93cSSam Leffler   }
273139beb93cSSam Leffler 
273239beb93cSSam Leffler   /* now we proceed to zero successive digits
273339beb93cSSam Leffler    * from the least significant upwards
273439beb93cSSam Leffler    */
273539beb93cSSam Leffler   for (ix = 0; ix < n->used; ix++) {
273639beb93cSSam Leffler     /* mu = ai * m' mod b
273739beb93cSSam Leffler      *
273839beb93cSSam Leffler      * We avoid a double precision multiplication (which isn't required)
273939beb93cSSam Leffler      * by casting the value down to a mp_digit.  Note this requires
274039beb93cSSam Leffler      * that W[ix-1] have  the carry cleared (see after the inner loop)
274139beb93cSSam Leffler      */
274239beb93cSSam Leffler     register mp_digit mu;
274339beb93cSSam Leffler     mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
274439beb93cSSam Leffler 
274539beb93cSSam Leffler     /* a = a + mu * m * b**i
274639beb93cSSam Leffler      *
274739beb93cSSam Leffler      * This is computed in place and on the fly.  The multiplication
274839beb93cSSam Leffler      * by b**i is handled by offseting which columns the results
274939beb93cSSam Leffler      * are added to.
275039beb93cSSam Leffler      *
275139beb93cSSam Leffler      * Note the comba method normally doesn't handle carries in the
275239beb93cSSam Leffler      * inner loop In this case we fix the carry from the previous
275339beb93cSSam Leffler      * column since the Montgomery reduction requires digits of the
275439beb93cSSam Leffler      * result (so far) [see above] to work.  This is
275539beb93cSSam Leffler      * handled by fixing up one carry after the inner loop.  The
275639beb93cSSam Leffler      * carry fixups are done in order so after these loops the
275739beb93cSSam Leffler      * first m->used words of W[] have the carries fixed
275839beb93cSSam Leffler      */
275939beb93cSSam Leffler     {
276039beb93cSSam Leffler       register int iy;
276139beb93cSSam Leffler       register mp_digit *tmpn;
276239beb93cSSam Leffler       register mp_word *_W;
276339beb93cSSam Leffler 
276439beb93cSSam Leffler       /* alias for the digits of the modulus */
276539beb93cSSam Leffler       tmpn = n->dp;
276639beb93cSSam Leffler 
276739beb93cSSam Leffler       /* Alias for the columns set by an offset of ix */
276839beb93cSSam Leffler       _W = W + ix;
276939beb93cSSam Leffler 
277039beb93cSSam Leffler       /* inner loop */
277139beb93cSSam Leffler       for (iy = 0; iy < n->used; iy++) {
277239beb93cSSam Leffler           *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
277339beb93cSSam Leffler       }
277439beb93cSSam Leffler     }
277539beb93cSSam Leffler 
277639beb93cSSam Leffler     /* now fix carry for next digit, W[ix+1] */
277739beb93cSSam Leffler     W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
277839beb93cSSam Leffler   }
277939beb93cSSam Leffler 
278039beb93cSSam Leffler   /* now we have to propagate the carries and
278139beb93cSSam Leffler    * shift the words downward [all those least
278239beb93cSSam Leffler    * significant digits we zeroed].
278339beb93cSSam Leffler    */
278439beb93cSSam Leffler   {
278539beb93cSSam Leffler     register mp_digit *tmpx;
278639beb93cSSam Leffler     register mp_word *_W, *_W1;
278739beb93cSSam Leffler 
278839beb93cSSam Leffler     /* nox fix rest of carries */
278939beb93cSSam Leffler 
279039beb93cSSam Leffler     /* alias for current word */
279139beb93cSSam Leffler     _W1 = W + ix;
279239beb93cSSam Leffler 
279339beb93cSSam Leffler     /* alias for next word, where the carry goes */
279439beb93cSSam Leffler     _W = W + ++ix;
279539beb93cSSam Leffler 
279639beb93cSSam Leffler     for (; ix <= n->used * 2 + 1; ix++) {
279739beb93cSSam Leffler       *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
279839beb93cSSam Leffler     }
279939beb93cSSam Leffler 
280039beb93cSSam Leffler     /* copy out, A = A/b**n
280139beb93cSSam Leffler      *
280239beb93cSSam Leffler      * The result is A/b**n but instead of converting from an
280339beb93cSSam Leffler      * array of mp_word to mp_digit than calling mp_rshd
280439beb93cSSam Leffler      * we just copy them in the right order
280539beb93cSSam Leffler      */
280639beb93cSSam Leffler 
280739beb93cSSam Leffler     /* alias for destination word */
280839beb93cSSam Leffler     tmpx = x->dp;
280939beb93cSSam Leffler 
281039beb93cSSam Leffler     /* alias for shifted double precision result */
281139beb93cSSam Leffler     _W = W + n->used;
281239beb93cSSam Leffler 
281339beb93cSSam Leffler     for (ix = 0; ix < n->used + 1; ix++) {
281439beb93cSSam Leffler       *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
281539beb93cSSam Leffler     }
281639beb93cSSam Leffler 
281739beb93cSSam Leffler     /* zero oldused digits, if the input a was larger than
281839beb93cSSam Leffler      * m->used+1 we'll have to clear the digits
281939beb93cSSam Leffler      */
282039beb93cSSam Leffler     for (; ix < olduse; ix++) {
282139beb93cSSam Leffler       *tmpx++ = 0;
282239beb93cSSam Leffler     }
282339beb93cSSam Leffler   }
282439beb93cSSam Leffler 
282539beb93cSSam Leffler   /* set the max used and clamp */
282639beb93cSSam Leffler   x->used = n->used + 1;
282739beb93cSSam Leffler   mp_clamp (x);
282839beb93cSSam Leffler 
282939beb93cSSam Leffler   /* if A >= m then A = A - m */
283039beb93cSSam Leffler   if (mp_cmp_mag (x, n) != MP_LT) {
283139beb93cSSam Leffler     return s_mp_sub (x, n, x);
283239beb93cSSam Leffler   }
283339beb93cSSam Leffler   return MP_OKAY;
283439beb93cSSam Leffler }
283539beb93cSSam Leffler #endif
283639beb93cSSam Leffler 
283739beb93cSSam Leffler 
283839beb93cSSam Leffler #ifdef BN_MP_MUL_2_C
283939beb93cSSam Leffler /* b = a*2 */
mp_mul_2(mp_int * a,mp_int * b)284039beb93cSSam Leffler static int mp_mul_2(mp_int * a, mp_int * b)
284139beb93cSSam Leffler {
284239beb93cSSam Leffler   int     x, res, oldused;
284339beb93cSSam Leffler 
2844f05cddf9SRui Paulo   /* grow to accommodate result */
284539beb93cSSam Leffler   if (b->alloc < a->used + 1) {
284639beb93cSSam Leffler     if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
284739beb93cSSam Leffler       return res;
284839beb93cSSam Leffler     }
284939beb93cSSam Leffler   }
285039beb93cSSam Leffler 
285139beb93cSSam Leffler   oldused = b->used;
285239beb93cSSam Leffler   b->used = a->used;
285339beb93cSSam Leffler 
285439beb93cSSam Leffler   {
285539beb93cSSam Leffler     register mp_digit r, rr, *tmpa, *tmpb;
285639beb93cSSam Leffler 
285739beb93cSSam Leffler     /* alias for source */
285839beb93cSSam Leffler     tmpa = a->dp;
285939beb93cSSam Leffler 
286039beb93cSSam Leffler     /* alias for dest */
286139beb93cSSam Leffler     tmpb = b->dp;
286239beb93cSSam Leffler 
286339beb93cSSam Leffler     /* carry */
286439beb93cSSam Leffler     r = 0;
286539beb93cSSam Leffler     for (x = 0; x < a->used; x++) {
286639beb93cSSam Leffler 
286739beb93cSSam Leffler       /* get what will be the *next* carry bit from the
286839beb93cSSam Leffler        * MSB of the current digit
286939beb93cSSam Leffler        */
287039beb93cSSam Leffler       rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
287139beb93cSSam Leffler 
287239beb93cSSam Leffler       /* now shift up this digit, add in the carry [from the previous] */
287339beb93cSSam Leffler       *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
287439beb93cSSam Leffler 
287539beb93cSSam Leffler       /* copy the carry that would be from the source
287639beb93cSSam Leffler        * digit into the next iteration
287739beb93cSSam Leffler        */
287839beb93cSSam Leffler       r = rr;
287939beb93cSSam Leffler     }
288039beb93cSSam Leffler 
288139beb93cSSam Leffler     /* new leading digit? */
288239beb93cSSam Leffler     if (r != 0) {
288339beb93cSSam Leffler       /* add a MSB which is always 1 at this point */
288439beb93cSSam Leffler       *tmpb = 1;
288539beb93cSSam Leffler       ++(b->used);
288639beb93cSSam Leffler     }
288739beb93cSSam Leffler 
288839beb93cSSam Leffler     /* now zero any excess digits on the destination
288939beb93cSSam Leffler      * that we didn't write to
289039beb93cSSam Leffler      */
289139beb93cSSam Leffler     tmpb = b->dp + b->used;
289239beb93cSSam Leffler     for (x = b->used; x < oldused; x++) {
289339beb93cSSam Leffler       *tmpb++ = 0;
289439beb93cSSam Leffler     }
289539beb93cSSam Leffler   }
289639beb93cSSam Leffler   b->sign = a->sign;
289739beb93cSSam Leffler   return MP_OKAY;
289839beb93cSSam Leffler }
289939beb93cSSam Leffler #endif
290039beb93cSSam Leffler 
290139beb93cSSam Leffler 
290239beb93cSSam Leffler #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
290339beb93cSSam Leffler /*
290439beb93cSSam Leffler  * shifts with subtractions when the result is greater than b.
290539beb93cSSam Leffler  *
290639beb93cSSam Leffler  * The method is slightly modified to shift B unconditionally up to just under
290739beb93cSSam Leffler  * the leading bit of b.  This saves a lot of multiple precision shifting.
290839beb93cSSam Leffler  */
mp_montgomery_calc_normalization(mp_int * a,mp_int * b)290939beb93cSSam Leffler static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
291039beb93cSSam Leffler {
291139beb93cSSam Leffler   int     x, bits, res;
291239beb93cSSam Leffler 
291339beb93cSSam Leffler   /* how many bits of last digit does b use */
291439beb93cSSam Leffler   bits = mp_count_bits (b) % DIGIT_BIT;
291539beb93cSSam Leffler 
291639beb93cSSam Leffler   if (b->used > 1) {
291739beb93cSSam Leffler      if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
291839beb93cSSam Leffler         return res;
291939beb93cSSam Leffler      }
292039beb93cSSam Leffler   } else {
292139beb93cSSam Leffler      mp_set(a, 1);
292239beb93cSSam Leffler      bits = 1;
292339beb93cSSam Leffler   }
292439beb93cSSam Leffler 
292539beb93cSSam Leffler 
292639beb93cSSam Leffler   /* now compute C = A * B mod b */
292739beb93cSSam Leffler   for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
292839beb93cSSam Leffler     if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
292939beb93cSSam Leffler       return res;
293039beb93cSSam Leffler     }
293139beb93cSSam Leffler     if (mp_cmp_mag (a, b) != MP_LT) {
293239beb93cSSam Leffler       if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
293339beb93cSSam Leffler         return res;
293439beb93cSSam Leffler       }
293539beb93cSSam Leffler     }
293639beb93cSSam Leffler   }
293739beb93cSSam Leffler 
293839beb93cSSam Leffler   return MP_OKAY;
293939beb93cSSam Leffler }
294039beb93cSSam Leffler #endif
294139beb93cSSam Leffler 
294239beb93cSSam Leffler 
294339beb93cSSam Leffler #ifdef BN_MP_EXPTMOD_FAST_C
294439beb93cSSam Leffler /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
294539beb93cSSam Leffler  *
294639beb93cSSam Leffler  * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
294739beb93cSSam Leffler  * The value of k changes based on the size of the exponent.
294839beb93cSSam Leffler  *
294939beb93cSSam Leffler  * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
295039beb93cSSam Leffler  */
295139beb93cSSam Leffler 
mp_exptmod_fast(mp_int * G,mp_int * X,mp_int * P,mp_int * Y,int redmode)295239beb93cSSam Leffler static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
295339beb93cSSam Leffler {
295439beb93cSSam Leffler   mp_int  M[TAB_SIZE], res;
295539beb93cSSam Leffler   mp_digit buf, mp;
295639beb93cSSam Leffler   int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
295739beb93cSSam Leffler 
295839beb93cSSam Leffler   /* use a pointer to the reduction algorithm.  This allows us to use
295939beb93cSSam Leffler    * one of many reduction algorithms without modding the guts of
296039beb93cSSam Leffler    * the code with if statements everywhere.
296139beb93cSSam Leffler    */
296239beb93cSSam Leffler   int     (*redux)(mp_int*,mp_int*,mp_digit);
296339beb93cSSam Leffler 
296439beb93cSSam Leffler   /* find window size */
296539beb93cSSam Leffler   x = mp_count_bits (X);
296639beb93cSSam Leffler   if (x <= 7) {
296739beb93cSSam Leffler     winsize = 2;
296839beb93cSSam Leffler   } else if (x <= 36) {
296939beb93cSSam Leffler     winsize = 3;
297039beb93cSSam Leffler   } else if (x <= 140) {
297139beb93cSSam Leffler     winsize = 4;
297239beb93cSSam Leffler   } else if (x <= 450) {
297339beb93cSSam Leffler     winsize = 5;
297439beb93cSSam Leffler   } else if (x <= 1303) {
297539beb93cSSam Leffler     winsize = 6;
297639beb93cSSam Leffler   } else if (x <= 3529) {
297739beb93cSSam Leffler     winsize = 7;
297839beb93cSSam Leffler   } else {
297939beb93cSSam Leffler     winsize = 8;
298039beb93cSSam Leffler   }
298139beb93cSSam Leffler 
298239beb93cSSam Leffler #ifdef MP_LOW_MEM
298339beb93cSSam Leffler   if (winsize > 5) {
298439beb93cSSam Leffler      winsize = 5;
298539beb93cSSam Leffler   }
298639beb93cSSam Leffler #endif
298739beb93cSSam Leffler 
298839beb93cSSam Leffler   /* init M array */
298939beb93cSSam Leffler   /* init first cell */
299039beb93cSSam Leffler   if ((err = mp_init(&M[1])) != MP_OKAY) {
299139beb93cSSam Leffler      return err;
299239beb93cSSam Leffler   }
299339beb93cSSam Leffler 
299439beb93cSSam Leffler   /* now init the second half of the array */
299539beb93cSSam Leffler   for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
299639beb93cSSam Leffler     if ((err = mp_init(&M[x])) != MP_OKAY) {
299739beb93cSSam Leffler       for (y = 1<<(winsize-1); y < x; y++) {
299839beb93cSSam Leffler         mp_clear (&M[y]);
299939beb93cSSam Leffler       }
300039beb93cSSam Leffler       mp_clear(&M[1]);
300139beb93cSSam Leffler       return err;
300239beb93cSSam Leffler     }
300339beb93cSSam Leffler   }
300439beb93cSSam Leffler 
300539beb93cSSam Leffler   /* determine and setup reduction code */
300639beb93cSSam Leffler   if (redmode == 0) {
300739beb93cSSam Leffler #ifdef BN_MP_MONTGOMERY_SETUP_C
300839beb93cSSam Leffler      /* now setup montgomery  */
300939beb93cSSam Leffler      if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
301039beb93cSSam Leffler         goto LBL_M;
301139beb93cSSam Leffler      }
301239beb93cSSam Leffler #else
301339beb93cSSam Leffler      err = MP_VAL;
301439beb93cSSam Leffler      goto LBL_M;
301539beb93cSSam Leffler #endif
301639beb93cSSam Leffler 
301739beb93cSSam Leffler      /* automatically pick the comba one if available (saves quite a few calls/ifs) */
301839beb93cSSam Leffler #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
301939beb93cSSam Leffler      if (((P->used * 2 + 1) < MP_WARRAY) &&
302039beb93cSSam Leffler           P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
302139beb93cSSam Leffler         redux = fast_mp_montgomery_reduce;
302239beb93cSSam Leffler      } else
302339beb93cSSam Leffler #endif
302439beb93cSSam Leffler      {
302539beb93cSSam Leffler #ifdef BN_MP_MONTGOMERY_REDUCE_C
302639beb93cSSam Leffler         /* use slower baseline Montgomery method */
302739beb93cSSam Leffler         redux = mp_montgomery_reduce;
302839beb93cSSam Leffler #else
302939beb93cSSam Leffler         err = MP_VAL;
303039beb93cSSam Leffler         goto LBL_M;
303139beb93cSSam Leffler #endif
303239beb93cSSam Leffler      }
303339beb93cSSam Leffler   } else if (redmode == 1) {
303439beb93cSSam Leffler #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
303539beb93cSSam Leffler      /* setup DR reduction for moduli of the form B**k - b */
303639beb93cSSam Leffler      mp_dr_setup(P, &mp);
303739beb93cSSam Leffler      redux = mp_dr_reduce;
303839beb93cSSam Leffler #else
303939beb93cSSam Leffler      err = MP_VAL;
304039beb93cSSam Leffler      goto LBL_M;
304139beb93cSSam Leffler #endif
304239beb93cSSam Leffler   } else {
304339beb93cSSam Leffler #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
304439beb93cSSam Leffler      /* setup DR reduction for moduli of the form 2**k - b */
304539beb93cSSam Leffler      if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
304639beb93cSSam Leffler         goto LBL_M;
304739beb93cSSam Leffler      }
304839beb93cSSam Leffler      redux = mp_reduce_2k;
304939beb93cSSam Leffler #else
305039beb93cSSam Leffler      err = MP_VAL;
305139beb93cSSam Leffler      goto LBL_M;
305239beb93cSSam Leffler #endif
305339beb93cSSam Leffler   }
305439beb93cSSam Leffler 
305539beb93cSSam Leffler   /* setup result */
305639beb93cSSam Leffler   if ((err = mp_init (&res)) != MP_OKAY) {
305739beb93cSSam Leffler     goto LBL_M;
305839beb93cSSam Leffler   }
305939beb93cSSam Leffler 
306039beb93cSSam Leffler   /* create M table
306139beb93cSSam Leffler    *
306239beb93cSSam Leffler 
306339beb93cSSam Leffler    *
306439beb93cSSam Leffler    * The first half of the table is not computed though accept for M[0] and M[1]
306539beb93cSSam Leffler    */
306639beb93cSSam Leffler 
306739beb93cSSam Leffler   if (redmode == 0) {
306839beb93cSSam Leffler #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
306939beb93cSSam Leffler      /* now we need R mod m */
307039beb93cSSam Leffler      if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
307139beb93cSSam Leffler        goto LBL_RES;
307239beb93cSSam Leffler      }
307339beb93cSSam Leffler #else
307439beb93cSSam Leffler      err = MP_VAL;
307539beb93cSSam Leffler      goto LBL_RES;
307639beb93cSSam Leffler #endif
307739beb93cSSam Leffler 
307839beb93cSSam Leffler      /* now set M[1] to G * R mod m */
307939beb93cSSam Leffler      if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
308039beb93cSSam Leffler        goto LBL_RES;
308139beb93cSSam Leffler      }
308239beb93cSSam Leffler   } else {
308339beb93cSSam Leffler      mp_set(&res, 1);
308439beb93cSSam Leffler      if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
308539beb93cSSam Leffler         goto LBL_RES;
308639beb93cSSam Leffler      }
308739beb93cSSam Leffler   }
308839beb93cSSam Leffler 
308939beb93cSSam Leffler   /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
309039beb93cSSam Leffler   if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
309139beb93cSSam Leffler     goto LBL_RES;
309239beb93cSSam Leffler   }
309339beb93cSSam Leffler 
309439beb93cSSam Leffler   for (x = 0; x < (winsize - 1); x++) {
309539beb93cSSam Leffler     if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
309639beb93cSSam Leffler       goto LBL_RES;
309739beb93cSSam Leffler     }
309839beb93cSSam Leffler     if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
309939beb93cSSam Leffler       goto LBL_RES;
310039beb93cSSam Leffler     }
310139beb93cSSam Leffler   }
310239beb93cSSam Leffler 
310339beb93cSSam Leffler   /* create upper table */
310439beb93cSSam Leffler   for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
310539beb93cSSam Leffler     if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
310639beb93cSSam Leffler       goto LBL_RES;
310739beb93cSSam Leffler     }
310839beb93cSSam Leffler     if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
310939beb93cSSam Leffler       goto LBL_RES;
311039beb93cSSam Leffler     }
311139beb93cSSam Leffler   }
311239beb93cSSam Leffler 
311339beb93cSSam Leffler   /* set initial mode and bit cnt */
311439beb93cSSam Leffler   mode   = 0;
311539beb93cSSam Leffler   bitcnt = 1;
311639beb93cSSam Leffler   buf    = 0;
311739beb93cSSam Leffler   digidx = X->used - 1;
311839beb93cSSam Leffler   bitcpy = 0;
311939beb93cSSam Leffler   bitbuf = 0;
312039beb93cSSam Leffler 
312139beb93cSSam Leffler   for (;;) {
312239beb93cSSam Leffler     /* grab next digit as required */
312339beb93cSSam Leffler     if (--bitcnt == 0) {
312439beb93cSSam Leffler       /* if digidx == -1 we are out of digits so break */
312539beb93cSSam Leffler       if (digidx == -1) {
312639beb93cSSam Leffler         break;
312739beb93cSSam Leffler       }
312839beb93cSSam Leffler       /* read next digit and reset bitcnt */
312939beb93cSSam Leffler       buf    = X->dp[digidx--];
313039beb93cSSam Leffler       bitcnt = (int)DIGIT_BIT;
313139beb93cSSam Leffler     }
313239beb93cSSam Leffler 
313339beb93cSSam Leffler     /* grab the next msb from the exponent */
313439beb93cSSam Leffler     y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
313539beb93cSSam Leffler     buf <<= (mp_digit)1;
313639beb93cSSam Leffler 
313739beb93cSSam Leffler     /* if the bit is zero and mode == 0 then we ignore it
313839beb93cSSam Leffler      * These represent the leading zero bits before the first 1 bit
313939beb93cSSam Leffler      * in the exponent.  Technically this opt is not required but it
314039beb93cSSam Leffler      * does lower the # of trivial squaring/reductions used
314139beb93cSSam Leffler      */
314239beb93cSSam Leffler     if (mode == 0 && y == 0) {
314339beb93cSSam Leffler       continue;
314439beb93cSSam Leffler     }
314539beb93cSSam Leffler 
314639beb93cSSam Leffler     /* if the bit is zero and mode == 1 then we square */
314739beb93cSSam Leffler     if (mode == 1 && y == 0) {
314839beb93cSSam Leffler       if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
314939beb93cSSam Leffler         goto LBL_RES;
315039beb93cSSam Leffler       }
315139beb93cSSam Leffler       if ((err = redux (&res, P, mp)) != MP_OKAY) {
315239beb93cSSam Leffler         goto LBL_RES;
315339beb93cSSam Leffler       }
315439beb93cSSam Leffler       continue;
315539beb93cSSam Leffler     }
315639beb93cSSam Leffler 
315739beb93cSSam Leffler     /* else we add it to the window */
315839beb93cSSam Leffler     bitbuf |= (y << (winsize - ++bitcpy));
315939beb93cSSam Leffler     mode    = 2;
316039beb93cSSam Leffler 
316139beb93cSSam Leffler     if (bitcpy == winsize) {
316239beb93cSSam Leffler       /* ok window is filled so square as required and multiply  */
316339beb93cSSam Leffler       /* square first */
316439beb93cSSam Leffler       for (x = 0; x < winsize; x++) {
316539beb93cSSam Leffler         if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
316639beb93cSSam Leffler           goto LBL_RES;
316739beb93cSSam Leffler         }
316839beb93cSSam Leffler         if ((err = redux (&res, P, mp)) != MP_OKAY) {
316939beb93cSSam Leffler           goto LBL_RES;
317039beb93cSSam Leffler         }
317139beb93cSSam Leffler       }
317239beb93cSSam Leffler 
317339beb93cSSam Leffler       /* then multiply */
317439beb93cSSam Leffler       if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
317539beb93cSSam Leffler         goto LBL_RES;
317639beb93cSSam Leffler       }
317739beb93cSSam Leffler       if ((err = redux (&res, P, mp)) != MP_OKAY) {
317839beb93cSSam Leffler         goto LBL_RES;
317939beb93cSSam Leffler       }
318039beb93cSSam Leffler 
318139beb93cSSam Leffler       /* empty window and reset */
318239beb93cSSam Leffler       bitcpy = 0;
318339beb93cSSam Leffler       bitbuf = 0;
318439beb93cSSam Leffler       mode   = 1;
318539beb93cSSam Leffler     }
318639beb93cSSam Leffler   }
318739beb93cSSam Leffler 
318839beb93cSSam Leffler   /* if bits remain then square/multiply */
318939beb93cSSam Leffler   if (mode == 2 && bitcpy > 0) {
319039beb93cSSam Leffler     /* square then multiply if the bit is set */
319139beb93cSSam Leffler     for (x = 0; x < bitcpy; x++) {
319239beb93cSSam Leffler       if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
319339beb93cSSam Leffler         goto LBL_RES;
319439beb93cSSam Leffler       }
319539beb93cSSam Leffler       if ((err = redux (&res, P, mp)) != MP_OKAY) {
319639beb93cSSam Leffler         goto LBL_RES;
319739beb93cSSam Leffler       }
319839beb93cSSam Leffler 
319939beb93cSSam Leffler       /* get next bit of the window */
320039beb93cSSam Leffler       bitbuf <<= 1;
320139beb93cSSam Leffler       if ((bitbuf & (1 << winsize)) != 0) {
320239beb93cSSam Leffler         /* then multiply */
320339beb93cSSam Leffler         if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
320439beb93cSSam Leffler           goto LBL_RES;
320539beb93cSSam Leffler         }
320639beb93cSSam Leffler         if ((err = redux (&res, P, mp)) != MP_OKAY) {
320739beb93cSSam Leffler           goto LBL_RES;
320839beb93cSSam Leffler         }
320939beb93cSSam Leffler       }
321039beb93cSSam Leffler     }
321139beb93cSSam Leffler   }
321239beb93cSSam Leffler 
321339beb93cSSam Leffler   if (redmode == 0) {
321439beb93cSSam Leffler      /* fixup result if Montgomery reduction is used
321539beb93cSSam Leffler       * recall that any value in a Montgomery system is
321639beb93cSSam Leffler       * actually multiplied by R mod n.  So we have
321739beb93cSSam Leffler       * to reduce one more time to cancel out the factor
321839beb93cSSam Leffler       * of R.
321939beb93cSSam Leffler       */
322039beb93cSSam Leffler      if ((err = redux(&res, P, mp)) != MP_OKAY) {
322139beb93cSSam Leffler        goto LBL_RES;
322239beb93cSSam Leffler      }
322339beb93cSSam Leffler   }
322439beb93cSSam Leffler 
322539beb93cSSam Leffler   /* swap res with Y */
322639beb93cSSam Leffler   mp_exch (&res, Y);
322739beb93cSSam Leffler   err = MP_OKAY;
322839beb93cSSam Leffler LBL_RES:mp_clear (&res);
322939beb93cSSam Leffler LBL_M:
323039beb93cSSam Leffler   mp_clear(&M[1]);
323139beb93cSSam Leffler   for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
323239beb93cSSam Leffler     mp_clear (&M[x]);
323339beb93cSSam Leffler   }
323439beb93cSSam Leffler   return err;
323539beb93cSSam Leffler }
323639beb93cSSam Leffler #endif
323739beb93cSSam Leffler 
323839beb93cSSam Leffler 
323939beb93cSSam Leffler #ifdef BN_FAST_S_MP_SQR_C
324039beb93cSSam Leffler /* the jist of squaring...
324139beb93cSSam Leffler  * you do like mult except the offset of the tmpx [one that
324239beb93cSSam Leffler  * starts closer to zero] can't equal the offset of tmpy.
324339beb93cSSam Leffler  * So basically you set up iy like before then you min it with
324439beb93cSSam Leffler  * (ty-tx) so that it never happens.  You double all those
324539beb93cSSam Leffler  * you add in the inner loop
324639beb93cSSam Leffler 
324739beb93cSSam Leffler After that loop you do the squares and add them in.
324839beb93cSSam Leffler */
324939beb93cSSam Leffler 
fast_s_mp_sqr(mp_int * a,mp_int * b)325039beb93cSSam Leffler static int fast_s_mp_sqr (mp_int * a, mp_int * b)
325139beb93cSSam Leffler {
325239beb93cSSam Leffler   int       olduse, res, pa, ix, iz;
325339beb93cSSam Leffler   mp_digit   W[MP_WARRAY], *tmpx;
325439beb93cSSam Leffler   mp_word   W1;
325539beb93cSSam Leffler 
325639beb93cSSam Leffler   /* grow the destination as required */
325739beb93cSSam Leffler   pa = a->used + a->used;
325839beb93cSSam Leffler   if (b->alloc < pa) {
325939beb93cSSam Leffler     if ((res = mp_grow (b, pa)) != MP_OKAY) {
326039beb93cSSam Leffler       return res;
326139beb93cSSam Leffler     }
326239beb93cSSam Leffler   }
326339beb93cSSam Leffler 
326439beb93cSSam Leffler   /* number of output digits to produce */
326539beb93cSSam Leffler   W1 = 0;
326639beb93cSSam Leffler   for (ix = 0; ix < pa; ix++) {
326739beb93cSSam Leffler       int      tx, ty, iy;
326839beb93cSSam Leffler       mp_word  _W;
326939beb93cSSam Leffler       mp_digit *tmpy;
327039beb93cSSam Leffler 
327139beb93cSSam Leffler       /* clear counter */
327239beb93cSSam Leffler       _W = 0;
327339beb93cSSam Leffler 
327439beb93cSSam Leffler       /* get offsets into the two bignums */
327539beb93cSSam Leffler       ty = MIN(a->used-1, ix);
327639beb93cSSam Leffler       tx = ix - ty;
327739beb93cSSam Leffler 
327839beb93cSSam Leffler       /* setup temp aliases */
327939beb93cSSam Leffler       tmpx = a->dp + tx;
328039beb93cSSam Leffler       tmpy = a->dp + ty;
328139beb93cSSam Leffler 
328239beb93cSSam Leffler       /* this is the number of times the loop will iterrate, essentially
328339beb93cSSam Leffler          while (tx++ < a->used && ty-- >= 0) { ... }
328439beb93cSSam Leffler        */
328539beb93cSSam Leffler       iy = MIN(a->used-tx, ty+1);
328639beb93cSSam Leffler 
328739beb93cSSam Leffler       /* now for squaring tx can never equal ty
328839beb93cSSam Leffler        * we halve the distance since they approach at a rate of 2x
328939beb93cSSam Leffler        * and we have to round because odd cases need to be executed
329039beb93cSSam Leffler        */
329139beb93cSSam Leffler       iy = MIN(iy, (ty-tx+1)>>1);
329239beb93cSSam Leffler 
329339beb93cSSam Leffler       /* execute loop */
329439beb93cSSam Leffler       for (iz = 0; iz < iy; iz++) {
329539beb93cSSam Leffler          _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
329639beb93cSSam Leffler       }
329739beb93cSSam Leffler 
329839beb93cSSam Leffler       /* double the inner product and add carry */
329939beb93cSSam Leffler       _W = _W + _W + W1;
330039beb93cSSam Leffler 
330139beb93cSSam Leffler       /* even columns have the square term in them */
330239beb93cSSam Leffler       if ((ix&1) == 0) {
330339beb93cSSam Leffler          _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
330439beb93cSSam Leffler       }
330539beb93cSSam Leffler 
330639beb93cSSam Leffler       /* store it */
330739beb93cSSam Leffler       W[ix] = (mp_digit)(_W & MP_MASK);
330839beb93cSSam Leffler 
330939beb93cSSam Leffler       /* make next carry */
331039beb93cSSam Leffler       W1 = _W >> ((mp_word)DIGIT_BIT);
331139beb93cSSam Leffler   }
331239beb93cSSam Leffler 
331339beb93cSSam Leffler   /* setup dest */
331439beb93cSSam Leffler   olduse  = b->used;
331539beb93cSSam Leffler   b->used = a->used+a->used;
331639beb93cSSam Leffler 
331739beb93cSSam Leffler   {
331839beb93cSSam Leffler     mp_digit *tmpb;
331939beb93cSSam Leffler     tmpb = b->dp;
332039beb93cSSam Leffler     for (ix = 0; ix < pa; ix++) {
332139beb93cSSam Leffler       *tmpb++ = W[ix] & MP_MASK;
332239beb93cSSam Leffler     }
332339beb93cSSam Leffler 
332439beb93cSSam Leffler     /* clear unused digits [that existed in the old copy of c] */
332539beb93cSSam Leffler     for (; ix < olduse; ix++) {
332639beb93cSSam Leffler       *tmpb++ = 0;
332739beb93cSSam Leffler     }
332839beb93cSSam Leffler   }
332939beb93cSSam Leffler   mp_clamp (b);
333039beb93cSSam Leffler   return MP_OKAY;
333139beb93cSSam Leffler }
333239beb93cSSam Leffler #endif
333339beb93cSSam Leffler 
333439beb93cSSam Leffler 
333539beb93cSSam Leffler #ifdef BN_MP_MUL_D_C
333639beb93cSSam Leffler /* multiply by a digit */
333739beb93cSSam Leffler static int
mp_mul_d(mp_int * a,mp_digit b,mp_int * c)333839beb93cSSam Leffler mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
333939beb93cSSam Leffler {
334039beb93cSSam Leffler   mp_digit u, *tmpa, *tmpc;
334139beb93cSSam Leffler   mp_word  r;
334239beb93cSSam Leffler   int      ix, res, olduse;
334339beb93cSSam Leffler 
334439beb93cSSam Leffler   /* make sure c is big enough to hold a*b */
334539beb93cSSam Leffler   if (c->alloc < a->used + 1) {
334639beb93cSSam Leffler     if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
334739beb93cSSam Leffler       return res;
334839beb93cSSam Leffler     }
334939beb93cSSam Leffler   }
335039beb93cSSam Leffler 
335139beb93cSSam Leffler   /* get the original destinations used count */
335239beb93cSSam Leffler   olduse = c->used;
335339beb93cSSam Leffler 
335439beb93cSSam Leffler   /* set the sign */
335539beb93cSSam Leffler   c->sign = a->sign;
335639beb93cSSam Leffler 
335739beb93cSSam Leffler   /* alias for a->dp [source] */
335839beb93cSSam Leffler   tmpa = a->dp;
335939beb93cSSam Leffler 
336039beb93cSSam Leffler   /* alias for c->dp [dest] */
336139beb93cSSam Leffler   tmpc = c->dp;
336239beb93cSSam Leffler 
336339beb93cSSam Leffler   /* zero carry */
336439beb93cSSam Leffler   u = 0;
336539beb93cSSam Leffler 
336639beb93cSSam Leffler   /* compute columns */
336739beb93cSSam Leffler   for (ix = 0; ix < a->used; ix++) {
336839beb93cSSam Leffler     /* compute product and carry sum for this term */
336939beb93cSSam Leffler     r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
337039beb93cSSam Leffler 
337139beb93cSSam Leffler     /* mask off higher bits to get a single digit */
337239beb93cSSam Leffler     *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
337339beb93cSSam Leffler 
337439beb93cSSam Leffler     /* send carry into next iteration */
337539beb93cSSam Leffler     u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
337639beb93cSSam Leffler   }
337739beb93cSSam Leffler 
337839beb93cSSam Leffler   /* store final carry [if any] and increment ix offset  */
337939beb93cSSam Leffler   *tmpc++ = u;
338039beb93cSSam Leffler   ++ix;
338139beb93cSSam Leffler 
338239beb93cSSam Leffler   /* now zero digits above the top */
338339beb93cSSam Leffler   while (ix++ < olduse) {
338439beb93cSSam Leffler      *tmpc++ = 0;
338539beb93cSSam Leffler   }
338639beb93cSSam Leffler 
338739beb93cSSam Leffler   /* set used count */
338839beb93cSSam Leffler   c->used = a->used + 1;
338939beb93cSSam Leffler   mp_clamp(c);
339039beb93cSSam Leffler 
339139beb93cSSam Leffler   return MP_OKAY;
339239beb93cSSam Leffler }
339339beb93cSSam Leffler #endif
3394