1189251Ssam/*
2189251Ssam * Minimal code for RSA support from LibTomMath 0.41
3189251Ssam * http://libtom.org/
4189251Ssam * http://libtom.org/files/ltm-0.41.tar.bz2
5189251Ssam * This library was released in public domain by Tom St Denis.
6189251Ssam *
7189251Ssam * The combination in this file may not use all of the optimized algorithms
8189251Ssam * from LibTomMath and may be considerable slower than the LibTomMath with its
9189251Ssam * default settings. The main purpose of having this version here is to make it
10189251Ssam * easier to build bignum.c wrapper without having to install and build an
11189251Ssam * external library.
12189251Ssam *
13189251Ssam * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
14189251Ssam * libtommath.c file instead of using the external LibTomMath library.
15189251Ssam */
16189251Ssam
17189251Ssam#ifndef CHAR_BIT
18189251Ssam#define CHAR_BIT 8
19189251Ssam#endif
20189251Ssam
21189251Ssam#define BN_MP_INVMOD_C
22189251Ssam#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
23189251Ssam			   * require BN_MP_EXPTMOD_FAST_C instead */
24189251Ssam#define BN_S_MP_MUL_DIGS_C
25189251Ssam#define BN_MP_INVMOD_SLOW_C
26189251Ssam#define BN_S_MP_SQR_C
27189251Ssam#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
28189251Ssam				 * would require other than mp_reduce */
29189251Ssam
30189251Ssam#ifdef LTM_FAST
31189251Ssam
32189251Ssam/* Use faster div at the cost of about 1 kB */
33189251Ssam#define BN_MP_MUL_D_C
34189251Ssam
35189251Ssam/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
36189251Ssam#define BN_MP_EXPTMOD_FAST_C
37189251Ssam#define BN_MP_MONTGOMERY_SETUP_C
38189251Ssam#define BN_FAST_MP_MONTGOMERY_REDUCE_C
39189251Ssam#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
40189251Ssam#define BN_MP_MUL_2_C
41189251Ssam
42189251Ssam/* Include faster sqr at the cost of about 0.5 kB in code */
43189251Ssam#define BN_FAST_S_MP_SQR_C
44189251Ssam
45281806Srpaulo/* About 0.25 kB of code, but ~1.7kB of stack space! */
46281806Srpaulo#define BN_FAST_S_MP_MUL_DIGS_C
47281806Srpaulo
48189251Ssam#else /* LTM_FAST */
49189251Ssam
50189251Ssam#define BN_MP_DIV_SMALL
51189251Ssam#define BN_MP_INIT_MULTI_C
52189251Ssam#define BN_MP_CLEAR_MULTI_C
53189251Ssam#define BN_MP_ABS_C
54189251Ssam#endif /* LTM_FAST */
55189251Ssam
56189251Ssam/* Current uses do not require support for negative exponent in exptmod, so we
57189251Ssam * can save about 1.5 kB in leaving out invmod. */
58189251Ssam#define LTM_NO_NEG_EXP
59189251Ssam
60189251Ssam/* from tommath.h */
61189251Ssam
62189251Ssam#ifndef MIN
63189251Ssam   #define MIN(x,y) ((x)<(y)?(x):(y))
64189251Ssam#endif
65189251Ssam
66189251Ssam#ifndef MAX
67189251Ssam   #define MAX(x,y) ((x)>(y)?(x):(y))
68189251Ssam#endif
69189251Ssam
70189251Ssam#define  OPT_CAST(x)
71189251Ssam
72252726Srpaulo#ifdef __x86_64__
73189251Ssamtypedef unsigned long mp_digit;
74252726Srpaulotypedef unsigned long mp_word __attribute__((mode(TI)));
75252726Srpaulo
76252726Srpaulo#define DIGIT_BIT 60
77252726Srpaulo#define MP_64BIT
78252726Srpaulo#else
79252726Srpaulotypedef unsigned long mp_digit;
80189251Ssamtypedef u64 mp_word;
81189251Ssam
82189251Ssam#define DIGIT_BIT          28
83189251Ssam#define MP_28BIT
84252726Srpaulo#endif
85189251Ssam
86189251Ssam
87189251Ssam#define XMALLOC  os_malloc
88189251Ssam#define XFREE    os_free
89189251Ssam#define XREALLOC os_realloc
90189251Ssam
91189251Ssam
92189251Ssam#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
93189251Ssam
94189251Ssam#define MP_LT        -1   /* less than */
95189251Ssam#define MP_EQ         0   /* equal to */
96189251Ssam#define MP_GT         1   /* greater than */
97189251Ssam
98189251Ssam#define MP_ZPOS       0   /* positive integer */
99189251Ssam#define MP_NEG        1   /* negative */
100189251Ssam
101189251Ssam#define MP_OKAY       0   /* ok result */
102189251Ssam#define MP_MEM        -2  /* out of mem */
103189251Ssam#define MP_VAL        -3  /* invalid input */
104189251Ssam
105189251Ssam#define MP_YES        1   /* yes response */
106189251Ssam#define MP_NO         0   /* no response */
107189251Ssam
108189251Ssamtypedef int           mp_err;
109189251Ssam
110189251Ssam/* define this to use lower memory usage routines (exptmods mostly) */
111189251Ssam#define MP_LOW_MEM
112189251Ssam
113189251Ssam/* default precision */
114189251Ssam#ifndef MP_PREC
115189251Ssam   #ifndef MP_LOW_MEM
116189251Ssam      #define MP_PREC                 32     /* default digits of precision */
117189251Ssam   #else
118189251Ssam      #define MP_PREC                 8      /* default digits of precision */
119189251Ssam   #endif
120189251Ssam#endif
121189251Ssam
122189251Ssam/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
123189251Ssam#define MP_WARRAY               (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
124189251Ssam
125189251Ssam/* the infamous mp_int structure */
126189251Ssamtypedef struct  {
127189251Ssam    int used, alloc, sign;
128189251Ssam    mp_digit *dp;
129189251Ssam} mp_int;
130189251Ssam
131189251Ssam
132189251Ssam/* ---> Basic Manipulations <--- */
133189251Ssam#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
134189251Ssam#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
135189251Ssam#define mp_isodd(a)  (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
136189251Ssam
137189251Ssam
138189251Ssam/* prototypes for copied functions */
139189251Ssam#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
140189251Ssamstatic int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
141189251Ssamstatic int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
142189251Ssamstatic int s_mp_sqr(mp_int * a, mp_int * b);
143189251Ssamstatic int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
144189251Ssam
145281806Srpaulo#ifdef BN_FAST_S_MP_MUL_DIGS_C
146189251Ssamstatic int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
147281806Srpaulo#endif
148189251Ssam
149189251Ssam#ifdef BN_MP_INIT_MULTI_C
150189251Ssamstatic int mp_init_multi(mp_int *mp, ...);
151189251Ssam#endif
152189251Ssam#ifdef BN_MP_CLEAR_MULTI_C
153189251Ssamstatic void mp_clear_multi(mp_int *mp, ...);
154189251Ssam#endif
155189251Ssamstatic int mp_lshd(mp_int * a, int b);
156189251Ssamstatic void mp_set(mp_int * a, mp_digit b);
157189251Ssamstatic void mp_clamp(mp_int * a);
158189251Ssamstatic void mp_exch(mp_int * a, mp_int * b);
159189251Ssamstatic void mp_rshd(mp_int * a, int b);
160189251Ssamstatic void mp_zero(mp_int * a);
161189251Ssamstatic int mp_mod_2d(mp_int * a, int b, mp_int * c);
162189251Ssamstatic int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
163189251Ssamstatic int mp_init_copy(mp_int * a, mp_int * b);
164189251Ssamstatic int mp_mul_2d(mp_int * a, int b, mp_int * c);
165189251Ssam#ifndef LTM_NO_NEG_EXP
166189251Ssamstatic int mp_div_2(mp_int * a, mp_int * b);
167189251Ssamstatic int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
168189251Ssamstatic int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
169189251Ssam#endif /* LTM_NO_NEG_EXP */
170189251Ssamstatic int mp_copy(mp_int * a, mp_int * b);
171189251Ssamstatic int mp_count_bits(mp_int * a);
172189251Ssamstatic int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
173189251Ssamstatic int mp_mod(mp_int * a, mp_int * b, mp_int * c);
174189251Ssamstatic int mp_grow(mp_int * a, int size);
175189251Ssamstatic int mp_cmp_mag(mp_int * a, mp_int * b);
176189251Ssam#ifdef BN_MP_ABS_C
177189251Ssamstatic int mp_abs(mp_int * a, mp_int * b);
178189251Ssam#endif
179189251Ssamstatic int mp_sqr(mp_int * a, mp_int * b);
180189251Ssamstatic int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
181189251Ssamstatic int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
182189251Ssamstatic int mp_2expt(mp_int * a, int b);
183189251Ssamstatic int mp_reduce_setup(mp_int * a, mp_int * b);
184189251Ssamstatic int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
185189251Ssamstatic int mp_init_size(mp_int * a, int size);
186189251Ssam#ifdef BN_MP_EXPTMOD_FAST_C
187189251Ssamstatic int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
188189251Ssam#endif /* BN_MP_EXPTMOD_FAST_C */
189189251Ssam#ifdef BN_FAST_S_MP_SQR_C
190189251Ssamstatic int fast_s_mp_sqr (mp_int * a, mp_int * b);
191189251Ssam#endif /* BN_FAST_S_MP_SQR_C */
192189251Ssam#ifdef BN_MP_MUL_D_C
193189251Ssamstatic int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
194189251Ssam#endif /* BN_MP_MUL_D_C */
195189251Ssam
196189251Ssam
197189251Ssam
198189251Ssam/* functions from bn_<func name>.c */
199189251Ssam
200189251Ssam
201189251Ssam/* reverse an array, used for radix code */
202189251Ssamstatic void bn_reverse (unsigned char *s, int len)
203189251Ssam{
204189251Ssam  int     ix, iy;
205189251Ssam  unsigned char t;
206189251Ssam
207189251Ssam  ix = 0;
208189251Ssam  iy = len - 1;
209189251Ssam  while (ix < iy) {
210189251Ssam    t     = s[ix];
211189251Ssam    s[ix] = s[iy];
212189251Ssam    s[iy] = t;
213189251Ssam    ++ix;
214189251Ssam    --iy;
215189251Ssam  }
216189251Ssam}
217189251Ssam
218189251Ssam
219189251Ssam/* low level addition, based on HAC pp.594, Algorithm 14.7 */
220189251Ssamstatic int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
221189251Ssam{
222189251Ssam  mp_int *x;
223189251Ssam  int     olduse, res, min, max;
224189251Ssam
225189251Ssam  /* find sizes, we let |a| <= |b| which means we have to sort
226189251Ssam   * them.  "x" will point to the input with the most digits
227189251Ssam   */
228189251Ssam  if (a->used > b->used) {
229189251Ssam    min = b->used;
230189251Ssam    max = a->used;
231189251Ssam    x = a;
232189251Ssam  } else {
233189251Ssam    min = a->used;
234189251Ssam    max = b->used;
235189251Ssam    x = b;
236189251Ssam  }
237189251Ssam
238189251Ssam  /* init result */
239189251Ssam  if (c->alloc < max + 1) {
240189251Ssam    if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
241189251Ssam      return res;
242189251Ssam    }
243189251Ssam  }
244189251Ssam
245189251Ssam  /* get old used digit count and set new one */
246189251Ssam  olduse = c->used;
247189251Ssam  c->used = max + 1;
248189251Ssam
249189251Ssam  {
250189251Ssam    register mp_digit u, *tmpa, *tmpb, *tmpc;
251189251Ssam    register int i;
252189251Ssam
253189251Ssam    /* alias for digit pointers */
254189251Ssam
255189251Ssam    /* first input */
256189251Ssam    tmpa = a->dp;
257189251Ssam
258189251Ssam    /* second input */
259189251Ssam    tmpb = b->dp;
260189251Ssam
261189251Ssam    /* destination */
262189251Ssam    tmpc = c->dp;
263189251Ssam
264189251Ssam    /* zero the carry */
265189251Ssam    u = 0;
266189251Ssam    for (i = 0; i < min; i++) {
267189251Ssam      /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
268189251Ssam      *tmpc = *tmpa++ + *tmpb++ + u;
269189251Ssam
270189251Ssam      /* U = carry bit of T[i] */
271189251Ssam      u = *tmpc >> ((mp_digit)DIGIT_BIT);
272189251Ssam
273189251Ssam      /* take away carry bit from T[i] */
274189251Ssam      *tmpc++ &= MP_MASK;
275189251Ssam    }
276189251Ssam
277189251Ssam    /* now copy higher words if any, that is in A+B
278189251Ssam     * if A or B has more digits add those in
279189251Ssam     */
280189251Ssam    if (min != max) {
281189251Ssam      for (; i < max; i++) {
282189251Ssam        /* T[i] = X[i] + U */
283189251Ssam        *tmpc = x->dp[i] + u;
284189251Ssam
285189251Ssam        /* U = carry bit of T[i] */
286189251Ssam        u = *tmpc >> ((mp_digit)DIGIT_BIT);
287189251Ssam
288189251Ssam        /* take away carry bit from T[i] */
289189251Ssam        *tmpc++ &= MP_MASK;
290189251Ssam      }
291189251Ssam    }
292189251Ssam
293189251Ssam    /* add carry */
294189251Ssam    *tmpc++ = u;
295189251Ssam
296189251Ssam    /* clear digits above oldused */
297189251Ssam    for (i = c->used; i < olduse; i++) {
298189251Ssam      *tmpc++ = 0;
299189251Ssam    }
300189251Ssam  }
301189251Ssam
302189251Ssam  mp_clamp (c);
303189251Ssam  return MP_OKAY;
304189251Ssam}
305189251Ssam
306189251Ssam
307189251Ssam/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
308189251Ssamstatic int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
309189251Ssam{
310189251Ssam  int     olduse, res, min, max;
311189251Ssam
312189251Ssam  /* find sizes */
313189251Ssam  min = b->used;
314189251Ssam  max = a->used;
315189251Ssam
316189251Ssam  /* init result */
317189251Ssam  if (c->alloc < max) {
318189251Ssam    if ((res = mp_grow (c, max)) != MP_OKAY) {
319189251Ssam      return res;
320189251Ssam    }
321189251Ssam  }
322189251Ssam  olduse = c->used;
323189251Ssam  c->used = max;
324189251Ssam
325189251Ssam  {
326189251Ssam    register mp_digit u, *tmpa, *tmpb, *tmpc;
327189251Ssam    register int i;
328189251Ssam
329189251Ssam    /* alias for digit pointers */
330189251Ssam    tmpa = a->dp;
331189251Ssam    tmpb = b->dp;
332189251Ssam    tmpc = c->dp;
333189251Ssam
334189251Ssam    /* set carry to zero */
335189251Ssam    u = 0;
336189251Ssam    for (i = 0; i < min; i++) {
337189251Ssam      /* T[i] = A[i] - B[i] - U */
338189251Ssam      *tmpc = *tmpa++ - *tmpb++ - u;
339189251Ssam
340189251Ssam      /* U = carry bit of T[i]
341189251Ssam       * Note this saves performing an AND operation since
342189251Ssam       * if a carry does occur it will propagate all the way to the
343189251Ssam       * MSB.  As a result a single shift is enough to get the carry
344189251Ssam       */
345189251Ssam      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
346189251Ssam
347189251Ssam      /* Clear carry from T[i] */
348189251Ssam      *tmpc++ &= MP_MASK;
349189251Ssam    }
350189251Ssam
351189251Ssam    /* now copy higher words if any, e.g. if A has more digits than B  */
352189251Ssam    for (; i < max; i++) {
353189251Ssam      /* T[i] = A[i] - U */
354189251Ssam      *tmpc = *tmpa++ - u;
355189251Ssam
356189251Ssam      /* U = carry bit of T[i] */
357189251Ssam      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
358189251Ssam
359189251Ssam      /* Clear carry from T[i] */
360189251Ssam      *tmpc++ &= MP_MASK;
361189251Ssam    }
362189251Ssam
363189251Ssam    /* clear digits above used (since we may not have grown result above) */
364189251Ssam    for (i = c->used; i < olduse; i++) {
365189251Ssam      *tmpc++ = 0;
366189251Ssam    }
367189251Ssam  }
368189251Ssam
369189251Ssam  mp_clamp (c);
370189251Ssam  return MP_OKAY;
371189251Ssam}
372189251Ssam
373189251Ssam
374189251Ssam/* init a new mp_int */
375189251Ssamstatic int mp_init (mp_int * a)
376189251Ssam{
377189251Ssam  int i;
378189251Ssam
379189251Ssam  /* allocate memory required and clear it */
380189251Ssam  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
381189251Ssam  if (a->dp == NULL) {
382189251Ssam    return MP_MEM;
383189251Ssam  }
384189251Ssam
385189251Ssam  /* set the digits to zero */
386189251Ssam  for (i = 0; i < MP_PREC; i++) {
387189251Ssam      a->dp[i] = 0;
388189251Ssam  }
389189251Ssam
390189251Ssam  /* set the used to zero, allocated digits to the default precision
391189251Ssam   * and sign to positive */
392189251Ssam  a->used  = 0;
393189251Ssam  a->alloc = MP_PREC;
394189251Ssam  a->sign  = MP_ZPOS;
395189251Ssam
396189251Ssam  return MP_OKAY;
397189251Ssam}
398189251Ssam
399189251Ssam
400189251Ssam/* clear one (frees)  */
401189251Ssamstatic void mp_clear (mp_int * a)
402189251Ssam{
403189251Ssam  int i;
404189251Ssam
405189251Ssam  /* only do anything if a hasn't been freed previously */
406189251Ssam  if (a->dp != NULL) {
407189251Ssam    /* first zero the digits */
408189251Ssam    for (i = 0; i < a->used; i++) {
409189251Ssam        a->dp[i] = 0;
410189251Ssam    }
411189251Ssam
412189251Ssam    /* free ram */
413189251Ssam    XFREE(a->dp);
414189251Ssam
415189251Ssam    /* reset members to make debugging easier */
416189251Ssam    a->dp    = NULL;
417189251Ssam    a->alloc = a->used = 0;
418189251Ssam    a->sign  = MP_ZPOS;
419189251Ssam  }
420189251Ssam}
421189251Ssam
422189251Ssam
423189251Ssam/* high level addition (handles signs) */
424189251Ssamstatic int mp_add (mp_int * a, mp_int * b, mp_int * c)
425189251Ssam{
426189251Ssam  int     sa, sb, res;
427189251Ssam
428189251Ssam  /* get sign of both inputs */
429189251Ssam  sa = a->sign;
430189251Ssam  sb = b->sign;
431189251Ssam
432189251Ssam  /* handle two cases, not four */
433189251Ssam  if (sa == sb) {
434189251Ssam    /* both positive or both negative */
435189251Ssam    /* add their magnitudes, copy the sign */
436189251Ssam    c->sign = sa;
437189251Ssam    res = s_mp_add (a, b, c);
438189251Ssam  } else {
439189251Ssam    /* one positive, the other negative */
440189251Ssam    /* subtract the one with the greater magnitude from */
441189251Ssam    /* the one of the lesser magnitude.  The result gets */
442189251Ssam    /* the sign of the one with the greater magnitude. */
443189251Ssam    if (mp_cmp_mag (a, b) == MP_LT) {
444189251Ssam      c->sign = sb;
445189251Ssam      res = s_mp_sub (b, a, c);
446189251Ssam    } else {
447189251Ssam      c->sign = sa;
448189251Ssam      res = s_mp_sub (a, b, c);
449189251Ssam    }
450189251Ssam  }
451189251Ssam  return res;
452189251Ssam}
453189251Ssam
454189251Ssam
455189251Ssam/* high level subtraction (handles signs) */
456189251Ssamstatic int mp_sub (mp_int * a, mp_int * b, mp_int * c)
457189251Ssam{
458189251Ssam  int     sa, sb, res;
459189251Ssam
460189251Ssam  sa = a->sign;
461189251Ssam  sb = b->sign;
462189251Ssam
463189251Ssam  if (sa != sb) {
464189251Ssam    /* subtract a negative from a positive, OR */
465189251Ssam    /* subtract a positive from a negative. */
466189251Ssam    /* In either case, ADD their magnitudes, */
467189251Ssam    /* and use the sign of the first number. */
468189251Ssam    c->sign = sa;
469189251Ssam    res = s_mp_add (a, b, c);
470189251Ssam  } else {
471189251Ssam    /* subtract a positive from a positive, OR */
472189251Ssam    /* subtract a negative from a negative. */
473189251Ssam    /* First, take the difference between their */
474189251Ssam    /* magnitudes, then... */
475189251Ssam    if (mp_cmp_mag (a, b) != MP_LT) {
476189251Ssam      /* Copy the sign from the first */
477189251Ssam      c->sign = sa;
478189251Ssam      /* The first has a larger or equal magnitude */
479189251Ssam      res = s_mp_sub (a, b, c);
480189251Ssam    } else {
481189251Ssam      /* The result has the *opposite* sign from */
482189251Ssam      /* the first number. */
483189251Ssam      c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
484189251Ssam      /* The second has a larger magnitude */
485189251Ssam      res = s_mp_sub (b, a, c);
486189251Ssam    }
487189251Ssam  }
488189251Ssam  return res;
489189251Ssam}
490189251Ssam
491189251Ssam
492189251Ssam/* high level multiplication (handles sign) */
493189251Ssamstatic int mp_mul (mp_int * a, mp_int * b, mp_int * c)
494189251Ssam{
495189251Ssam  int     res, neg;
496189251Ssam  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
497189251Ssam
498189251Ssam  /* use Toom-Cook? */
499189251Ssam#ifdef BN_MP_TOOM_MUL_C
500189251Ssam  if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
501189251Ssam    res = mp_toom_mul(a, b, c);
502189251Ssam  } else
503189251Ssam#endif
504189251Ssam#ifdef BN_MP_KARATSUBA_MUL_C
505189251Ssam  /* use Karatsuba? */
506189251Ssam  if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
507189251Ssam    res = mp_karatsuba_mul (a, b, c);
508189251Ssam  } else
509189251Ssam#endif
510189251Ssam  {
511189251Ssam    /* can we use the fast multiplier?
512189251Ssam     *
513189251Ssam     * The fast multiplier can be used if the output will
514189251Ssam     * have less than MP_WARRAY digits and the number of
515189251Ssam     * digits won't affect carry propagation
516189251Ssam     */
517189251Ssam#ifdef BN_FAST_S_MP_MUL_DIGS_C
518189251Ssam    int     digs = a->used + b->used + 1;
519189251Ssam
520189251Ssam    if ((digs < MP_WARRAY) &&
521189251Ssam        MIN(a->used, b->used) <=
522189251Ssam        (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
523189251Ssam      res = fast_s_mp_mul_digs (a, b, c, digs);
524189251Ssam    } else
525189251Ssam#endif
526189251Ssam#ifdef BN_S_MP_MUL_DIGS_C
527189251Ssam      res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
528189251Ssam#else
529189251Ssam#error mp_mul could fail
530189251Ssam      res = MP_VAL;
531189251Ssam#endif
532189251Ssam
533189251Ssam  }
534189251Ssam  c->sign = (c->used > 0) ? neg : MP_ZPOS;
535189251Ssam  return res;
536189251Ssam}
537189251Ssam
538189251Ssam
539189251Ssam/* d = a * b (mod c) */
540189251Ssamstatic int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
541189251Ssam{
542189251Ssam  int     res;
543189251Ssam  mp_int  t;
544189251Ssam
545189251Ssam  if ((res = mp_init (&t)) != MP_OKAY) {
546189251Ssam    return res;
547189251Ssam  }
548189251Ssam
549189251Ssam  if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
550189251Ssam    mp_clear (&t);
551189251Ssam    return res;
552189251Ssam  }
553189251Ssam  res = mp_mod (&t, c, d);
554189251Ssam  mp_clear (&t);
555189251Ssam  return res;
556189251Ssam}
557189251Ssam
558189251Ssam
559189251Ssam/* c = a mod b, 0 <= c < b */
560189251Ssamstatic int mp_mod (mp_int * a, mp_int * b, mp_int * c)
561189251Ssam{
562189251Ssam  mp_int  t;
563189251Ssam  int     res;
564189251Ssam
565189251Ssam  if ((res = mp_init (&t)) != MP_OKAY) {
566189251Ssam    return res;
567189251Ssam  }
568189251Ssam
569189251Ssam  if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
570189251Ssam    mp_clear (&t);
571189251Ssam    return res;
572189251Ssam  }
573189251Ssam
574189251Ssam  if (t.sign != b->sign) {
575189251Ssam    res = mp_add (b, &t, c);
576189251Ssam  } else {
577189251Ssam    res = MP_OKAY;
578189251Ssam    mp_exch (&t, c);
579189251Ssam  }
580189251Ssam
581189251Ssam  mp_clear (&t);
582189251Ssam  return res;
583189251Ssam}
584189251Ssam
585189251Ssam
586189251Ssam/* this is a shell function that calls either the normal or Montgomery
587189251Ssam * exptmod functions.  Originally the call to the montgomery code was
588252726Srpaulo * embedded in the normal function but that wasted a lot of stack space
589189251Ssam * for nothing (since 99% of the time the Montgomery code would be called)
590189251Ssam */
591189251Ssamstatic int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
592189251Ssam{
593189251Ssam  int dr;
594189251Ssam
595189251Ssam  /* modulus P must be positive */
596189251Ssam  if (P->sign == MP_NEG) {
597189251Ssam     return MP_VAL;
598189251Ssam  }
599189251Ssam
600189251Ssam  /* if exponent X is negative we have to recurse */
601189251Ssam  if (X->sign == MP_NEG) {
602189251Ssam#ifdef LTM_NO_NEG_EXP
603189251Ssam        return MP_VAL;
604189251Ssam#else /* LTM_NO_NEG_EXP */
605189251Ssam#ifdef BN_MP_INVMOD_C
606189251Ssam     mp_int tmpG, tmpX;
607189251Ssam     int err;
608189251Ssam
609189251Ssam     /* first compute 1/G mod P */
610189251Ssam     if ((err = mp_init(&tmpG)) != MP_OKAY) {
611189251Ssam        return err;
612189251Ssam     }
613189251Ssam     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
614189251Ssam        mp_clear(&tmpG);
615189251Ssam        return err;
616189251Ssam     }
617189251Ssam
618189251Ssam     /* now get |X| */
619189251Ssam     if ((err = mp_init(&tmpX)) != MP_OKAY) {
620189251Ssam        mp_clear(&tmpG);
621189251Ssam        return err;
622189251Ssam     }
623189251Ssam     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
624189251Ssam        mp_clear_multi(&tmpG, &tmpX, NULL);
625189251Ssam        return err;
626189251Ssam     }
627189251Ssam
628189251Ssam     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
629189251Ssam     err = mp_exptmod(&tmpG, &tmpX, P, Y);
630189251Ssam     mp_clear_multi(&tmpG, &tmpX, NULL);
631189251Ssam     return err;
632189251Ssam#else
633189251Ssam#error mp_exptmod would always fail
634189251Ssam     /* no invmod */
635189251Ssam     return MP_VAL;
636189251Ssam#endif
637189251Ssam#endif /* LTM_NO_NEG_EXP */
638189251Ssam  }
639189251Ssam
640189251Ssam/* modified diminished radix reduction */
641189251Ssam#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
642189251Ssam  if (mp_reduce_is_2k_l(P) == MP_YES) {
643189251Ssam     return s_mp_exptmod(G, X, P, Y, 1);
644189251Ssam  }
645189251Ssam#endif
646189251Ssam
647189251Ssam#ifdef BN_MP_DR_IS_MODULUS_C
648189251Ssam  /* is it a DR modulus? */
649189251Ssam  dr = mp_dr_is_modulus(P);
650189251Ssam#else
651189251Ssam  /* default to no */
652189251Ssam  dr = 0;
653189251Ssam#endif
654189251Ssam
655189251Ssam#ifdef BN_MP_REDUCE_IS_2K_C
656189251Ssam  /* if not, is it a unrestricted DR modulus? */
657189251Ssam  if (dr == 0) {
658189251Ssam     dr = mp_reduce_is_2k(P) << 1;
659189251Ssam  }
660189251Ssam#endif
661189251Ssam
662189251Ssam  /* if the modulus is odd or dr != 0 use the montgomery method */
663189251Ssam#ifdef BN_MP_EXPTMOD_FAST_C
664189251Ssam  if (mp_isodd (P) == 1 || dr !=  0) {
665189251Ssam    return mp_exptmod_fast (G, X, P, Y, dr);
666189251Ssam  } else {
667189251Ssam#endif
668189251Ssam#ifdef BN_S_MP_EXPTMOD_C
669189251Ssam    /* otherwise use the generic Barrett reduction technique */
670189251Ssam    return s_mp_exptmod (G, X, P, Y, 0);
671189251Ssam#else
672189251Ssam#error mp_exptmod could fail
673189251Ssam    /* no exptmod for evens */
674189251Ssam    return MP_VAL;
675189251Ssam#endif
676189251Ssam#ifdef BN_MP_EXPTMOD_FAST_C
677189251Ssam  }
678189251Ssam#endif
679281806Srpaulo  if (dr == 0) {
680281806Srpaulo    /* avoid compiler warnings about possibly unused variable */
681281806Srpaulo  }
682189251Ssam}
683189251Ssam
684189251Ssam
685189251Ssam/* compare two ints (signed)*/
686189251Ssamstatic int mp_cmp (mp_int * a, mp_int * b)
687189251Ssam{
688189251Ssam  /* compare based on sign */
689189251Ssam  if (a->sign != b->sign) {
690189251Ssam     if (a->sign == MP_NEG) {
691189251Ssam        return MP_LT;
692189251Ssam     } else {
693189251Ssam        return MP_GT;
694189251Ssam     }
695189251Ssam  }
696189251Ssam
697189251Ssam  /* compare digits */
698189251Ssam  if (a->sign == MP_NEG) {
699189251Ssam     /* if negative compare opposite direction */
700189251Ssam     return mp_cmp_mag(b, a);
701189251Ssam  } else {
702189251Ssam     return mp_cmp_mag(a, b);
703189251Ssam  }
704189251Ssam}
705189251Ssam
706189251Ssam
707189251Ssam/* compare a digit */
708189251Ssamstatic int mp_cmp_d(mp_int * a, mp_digit b)
709189251Ssam{
710189251Ssam  /* compare based on sign */
711189251Ssam  if (a->sign == MP_NEG) {
712189251Ssam    return MP_LT;
713189251Ssam  }
714189251Ssam
715189251Ssam  /* compare based on magnitude */
716189251Ssam  if (a->used > 1) {
717189251Ssam    return MP_GT;
718189251Ssam  }
719189251Ssam
720189251Ssam  /* compare the only digit of a to b */
721189251Ssam  if (a->dp[0] > b) {
722189251Ssam    return MP_GT;
723189251Ssam  } else if (a->dp[0] < b) {
724189251Ssam    return MP_LT;
725189251Ssam  } else {
726189251Ssam    return MP_EQ;
727189251Ssam  }
728189251Ssam}
729189251Ssam
730189251Ssam
731189251Ssam#ifndef LTM_NO_NEG_EXP
732189251Ssam/* hac 14.61, pp608 */
733189251Ssamstatic int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
734189251Ssam{
735189251Ssam  /* b cannot be negative */
736189251Ssam  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
737189251Ssam    return MP_VAL;
738189251Ssam  }
739189251Ssam
740189251Ssam#ifdef BN_FAST_MP_INVMOD_C
741189251Ssam  /* if the modulus is odd we can use a faster routine instead */
742189251Ssam  if (mp_isodd (b) == 1) {
743189251Ssam    return fast_mp_invmod (a, b, c);
744189251Ssam  }
745189251Ssam#endif
746189251Ssam
747189251Ssam#ifdef BN_MP_INVMOD_SLOW_C
748189251Ssam  return mp_invmod_slow(a, b, c);
749189251Ssam#endif
750189251Ssam
751189251Ssam#ifndef BN_FAST_MP_INVMOD_C
752189251Ssam#ifndef BN_MP_INVMOD_SLOW_C
753189251Ssam#error mp_invmod would always fail
754189251Ssam#endif
755189251Ssam#endif
756189251Ssam  return MP_VAL;
757189251Ssam}
758189251Ssam#endif /* LTM_NO_NEG_EXP */
759189251Ssam
760189251Ssam
761189251Ssam/* get the size for an unsigned equivalent */
762189251Ssamstatic int mp_unsigned_bin_size (mp_int * a)
763189251Ssam{
764189251Ssam  int     size = mp_count_bits (a);
765189251Ssam  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
766189251Ssam}
767189251Ssam
768189251Ssam
769189251Ssam#ifndef LTM_NO_NEG_EXP
770189251Ssam/* hac 14.61, pp608 */
771189251Ssamstatic int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
772189251Ssam{
773189251Ssam  mp_int  x, y, u, v, A, B, C, D;
774189251Ssam  int     res;
775189251Ssam
776189251Ssam  /* b cannot be negative */
777189251Ssam  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
778189251Ssam    return MP_VAL;
779189251Ssam  }
780189251Ssam
781189251Ssam  /* init temps */
782189251Ssam  if ((res = mp_init_multi(&x, &y, &u, &v,
783189251Ssam                           &A, &B, &C, &D, NULL)) != MP_OKAY) {
784189251Ssam     return res;
785189251Ssam  }
786189251Ssam
787189251Ssam  /* x = a, y = b */
788189251Ssam  if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
789189251Ssam      goto LBL_ERR;
790189251Ssam  }
791189251Ssam  if ((res = mp_copy (b, &y)) != MP_OKAY) {
792189251Ssam    goto LBL_ERR;
793189251Ssam  }
794189251Ssam
795189251Ssam  /* 2. [modified] if x,y are both even then return an error! */
796189251Ssam  if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
797189251Ssam    res = MP_VAL;
798189251Ssam    goto LBL_ERR;
799189251Ssam  }
800189251Ssam
801189251Ssam  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
802189251Ssam  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
803189251Ssam    goto LBL_ERR;
804189251Ssam  }
805189251Ssam  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
806189251Ssam    goto LBL_ERR;
807189251Ssam  }
808189251Ssam  mp_set (&A, 1);
809189251Ssam  mp_set (&D, 1);
810189251Ssam
811189251Ssamtop:
812189251Ssam  /* 4.  while u is even do */
813189251Ssam  while (mp_iseven (&u) == 1) {
814189251Ssam    /* 4.1 u = u/2 */
815189251Ssam    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
816189251Ssam      goto LBL_ERR;
817189251Ssam    }
818189251Ssam    /* 4.2 if A or B is odd then */
819189251Ssam    if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
820189251Ssam      /* A = (A+y)/2, B = (B-x)/2 */
821189251Ssam      if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
822189251Ssam         goto LBL_ERR;
823189251Ssam      }
824189251Ssam      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
825189251Ssam         goto LBL_ERR;
826189251Ssam      }
827189251Ssam    }
828189251Ssam    /* A = A/2, B = B/2 */
829189251Ssam    if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
830189251Ssam      goto LBL_ERR;
831189251Ssam    }
832189251Ssam    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
833189251Ssam      goto LBL_ERR;
834189251Ssam    }
835189251Ssam  }
836189251Ssam
837189251Ssam  /* 5.  while v is even do */
838189251Ssam  while (mp_iseven (&v) == 1) {
839189251Ssam    /* 5.1 v = v/2 */
840189251Ssam    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
841189251Ssam      goto LBL_ERR;
842189251Ssam    }
843189251Ssam    /* 5.2 if C or D is odd then */
844189251Ssam    if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
845189251Ssam      /* C = (C+y)/2, D = (D-x)/2 */
846189251Ssam      if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
847189251Ssam         goto LBL_ERR;
848189251Ssam      }
849189251Ssam      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
850189251Ssam         goto LBL_ERR;
851189251Ssam      }
852189251Ssam    }
853189251Ssam    /* C = C/2, D = D/2 */
854189251Ssam    if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
855189251Ssam      goto LBL_ERR;
856189251Ssam    }
857189251Ssam    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
858189251Ssam      goto LBL_ERR;
859189251Ssam    }
860189251Ssam  }
861189251Ssam
862189251Ssam  /* 6.  if u >= v then */
863189251Ssam  if (mp_cmp (&u, &v) != MP_LT) {
864189251Ssam    /* u = u - v, A = A - C, B = B - D */
865189251Ssam    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
866189251Ssam      goto LBL_ERR;
867189251Ssam    }
868189251Ssam
869189251Ssam    if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
870189251Ssam      goto LBL_ERR;
871189251Ssam    }
872189251Ssam
873189251Ssam    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
874189251Ssam      goto LBL_ERR;
875189251Ssam    }
876189251Ssam  } else {
877189251Ssam    /* v - v - u, C = C - A, D = D - B */
878189251Ssam    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
879189251Ssam      goto LBL_ERR;
880189251Ssam    }
881189251Ssam
882189251Ssam    if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
883189251Ssam      goto LBL_ERR;
884189251Ssam    }
885189251Ssam
886189251Ssam    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
887189251Ssam      goto LBL_ERR;
888189251Ssam    }
889189251Ssam  }
890189251Ssam
891189251Ssam  /* if not zero goto step 4 */
892189251Ssam  if (mp_iszero (&u) == 0)
893189251Ssam    goto top;
894189251Ssam
895189251Ssam  /* now a = C, b = D, gcd == g*v */
896189251Ssam
897189251Ssam  /* if v != 1 then there is no inverse */
898189251Ssam  if (mp_cmp_d (&v, 1) != MP_EQ) {
899189251Ssam    res = MP_VAL;
900189251Ssam    goto LBL_ERR;
901189251Ssam  }
902189251Ssam
903189251Ssam  /* if its too low */
904189251Ssam  while (mp_cmp_d(&C, 0) == MP_LT) {
905189251Ssam      if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
906189251Ssam         goto LBL_ERR;
907189251Ssam      }
908189251Ssam  }
909189251Ssam
910189251Ssam  /* too big */
911189251Ssam  while (mp_cmp_mag(&C, b) != MP_LT) {
912189251Ssam      if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
913189251Ssam         goto LBL_ERR;
914189251Ssam      }
915189251Ssam  }
916189251Ssam
917189251Ssam  /* C is now the inverse */
918189251Ssam  mp_exch (&C, c);
919189251Ssam  res = MP_OKAY;
920189251SsamLBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
921189251Ssam  return res;
922189251Ssam}
923189251Ssam#endif /* LTM_NO_NEG_EXP */
924189251Ssam
925189251Ssam
926189251Ssam/* compare maginitude of two ints (unsigned) */
927189251Ssamstatic int mp_cmp_mag (mp_int * a, mp_int * b)
928189251Ssam{
929189251Ssam  int     n;
930189251Ssam  mp_digit *tmpa, *tmpb;
931189251Ssam
932189251Ssam  /* compare based on # of non-zero digits */
933189251Ssam  if (a->used > b->used) {
934189251Ssam    return MP_GT;
935189251Ssam  }
936189251Ssam
937189251Ssam  if (a->used < b->used) {
938189251Ssam    return MP_LT;
939189251Ssam  }
940189251Ssam
941189251Ssam  /* alias for a */
942189251Ssam  tmpa = a->dp + (a->used - 1);
943189251Ssam
944189251Ssam  /* alias for b */
945189251Ssam  tmpb = b->dp + (a->used - 1);
946189251Ssam
947189251Ssam  /* compare based on digits  */
948189251Ssam  for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
949189251Ssam    if (*tmpa > *tmpb) {
950189251Ssam      return MP_GT;
951189251Ssam    }
952189251Ssam
953189251Ssam    if (*tmpa < *tmpb) {
954189251Ssam      return MP_LT;
955189251Ssam    }
956189251Ssam  }
957189251Ssam  return MP_EQ;
958189251Ssam}
959189251Ssam
960189251Ssam
961189251Ssam/* reads a unsigned char array, assumes the msb is stored first [big endian] */
962189251Ssamstatic int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
963189251Ssam{
964189251Ssam  int     res;
965189251Ssam
966189251Ssam  /* make sure there are at least two digits */
967189251Ssam  if (a->alloc < 2) {
968189251Ssam     if ((res = mp_grow(a, 2)) != MP_OKAY) {
969189251Ssam        return res;
970189251Ssam     }
971189251Ssam  }
972189251Ssam
973189251Ssam  /* zero the int */
974189251Ssam  mp_zero (a);
975189251Ssam
976189251Ssam  /* read the bytes in */
977189251Ssam  while (c-- > 0) {
978189251Ssam    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
979189251Ssam      return res;
980189251Ssam    }
981189251Ssam
982189251Ssam#ifndef MP_8BIT
983189251Ssam      a->dp[0] |= *b++;
984189251Ssam      a->used += 1;
985189251Ssam#else
986189251Ssam      a->dp[0] = (*b & MP_MASK);
987189251Ssam      a->dp[1] |= ((*b++ >> 7U) & 1);
988189251Ssam      a->used += 2;
989189251Ssam#endif
990189251Ssam  }
991189251Ssam  mp_clamp (a);
992189251Ssam  return MP_OKAY;
993189251Ssam}
994189251Ssam
995189251Ssam
996189251Ssam/* store in unsigned [big endian] format */
997189251Ssamstatic int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
998189251Ssam{
999189251Ssam  int     x, res;
1000189251Ssam  mp_int  t;
1001189251Ssam
1002189251Ssam  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
1003189251Ssam    return res;
1004189251Ssam  }
1005189251Ssam
1006189251Ssam  x = 0;
1007189251Ssam  while (mp_iszero (&t) == 0) {
1008189251Ssam#ifndef MP_8BIT
1009189251Ssam      b[x++] = (unsigned char) (t.dp[0] & 255);
1010189251Ssam#else
1011189251Ssam      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
1012189251Ssam#endif
1013189251Ssam    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
1014189251Ssam      mp_clear (&t);
1015189251Ssam      return res;
1016189251Ssam    }
1017189251Ssam  }
1018189251Ssam  bn_reverse (b, x);
1019189251Ssam  mp_clear (&t);
1020189251Ssam  return MP_OKAY;
1021189251Ssam}
1022189251Ssam
1023189251Ssam
1024189251Ssam/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
1025189251Ssamstatic int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
1026189251Ssam{
1027189251Ssam  mp_digit D, r, rr;
1028189251Ssam  int     x, res;
1029189251Ssam  mp_int  t;
1030189251Ssam
1031189251Ssam
1032189251Ssam  /* if the shift count is <= 0 then we do no work */
1033189251Ssam  if (b <= 0) {
1034189251Ssam    res = mp_copy (a, c);
1035189251Ssam    if (d != NULL) {
1036189251Ssam      mp_zero (d);
1037189251Ssam    }
1038189251Ssam    return res;
1039189251Ssam  }
1040189251Ssam
1041189251Ssam  if ((res = mp_init (&t)) != MP_OKAY) {
1042189251Ssam    return res;
1043189251Ssam  }
1044189251Ssam
1045189251Ssam  /* get the remainder */
1046189251Ssam  if (d != NULL) {
1047189251Ssam    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
1048189251Ssam      mp_clear (&t);
1049189251Ssam      return res;
1050189251Ssam    }
1051189251Ssam  }
1052189251Ssam
1053189251Ssam  /* copy */
1054189251Ssam  if ((res = mp_copy (a, c)) != MP_OKAY) {
1055189251Ssam    mp_clear (&t);
1056189251Ssam    return res;
1057189251Ssam  }
1058189251Ssam
1059189251Ssam  /* shift by as many digits in the bit count */
1060189251Ssam  if (b >= (int)DIGIT_BIT) {
1061189251Ssam    mp_rshd (c, b / DIGIT_BIT);
1062189251Ssam  }
1063189251Ssam
1064189251Ssam  /* shift any bit count < DIGIT_BIT */
1065189251Ssam  D = (mp_digit) (b % DIGIT_BIT);
1066189251Ssam  if (D != 0) {
1067189251Ssam    register mp_digit *tmpc, mask, shift;
1068189251Ssam
1069189251Ssam    /* mask */
1070189251Ssam    mask = (((mp_digit)1) << D) - 1;
1071189251Ssam
1072189251Ssam    /* shift for lsb */
1073189251Ssam    shift = DIGIT_BIT - D;
1074189251Ssam
1075189251Ssam    /* alias */
1076189251Ssam    tmpc = c->dp + (c->used - 1);
1077189251Ssam
1078189251Ssam    /* carry */
1079189251Ssam    r = 0;
1080189251Ssam    for (x = c->used - 1; x >= 0; x--) {
1081189251Ssam      /* get the lower  bits of this word in a temp */
1082189251Ssam      rr = *tmpc & mask;
1083189251Ssam
1084189251Ssam      /* shift the current word and mix in the carry bits from the previous word */
1085189251Ssam      *tmpc = (*tmpc >> D) | (r << shift);
1086189251Ssam      --tmpc;
1087189251Ssam
1088189251Ssam      /* set the carry to the carry bits of the current word found above */
1089189251Ssam      r = rr;
1090189251Ssam    }
1091189251Ssam  }
1092189251Ssam  mp_clamp (c);
1093189251Ssam  if (d != NULL) {
1094189251Ssam    mp_exch (&t, d);
1095189251Ssam  }
1096189251Ssam  mp_clear (&t);
1097189251Ssam  return MP_OKAY;
1098189251Ssam}
1099189251Ssam
1100189251Ssam
1101189251Ssamstatic int mp_init_copy (mp_int * a, mp_int * b)
1102189251Ssam{
1103189251Ssam  int     res;
1104189251Ssam
1105189251Ssam  if ((res = mp_init (a)) != MP_OKAY) {
1106189251Ssam    return res;
1107189251Ssam  }
1108189251Ssam  return mp_copy (b, a);
1109189251Ssam}
1110189251Ssam
1111189251Ssam
1112189251Ssam/* set to zero */
1113189251Ssamstatic void mp_zero (mp_int * a)
1114189251Ssam{
1115189251Ssam  int       n;
1116189251Ssam  mp_digit *tmp;
1117189251Ssam
1118189251Ssam  a->sign = MP_ZPOS;
1119189251Ssam  a->used = 0;
1120189251Ssam
1121189251Ssam  tmp = a->dp;
1122189251Ssam  for (n = 0; n < a->alloc; n++) {
1123189251Ssam     *tmp++ = 0;
1124189251Ssam  }
1125189251Ssam}
1126189251Ssam
1127189251Ssam
1128189251Ssam/* copy, b = a */
1129189251Ssamstatic int mp_copy (mp_int * a, mp_int * b)
1130189251Ssam{
1131189251Ssam  int     res, n;
1132189251Ssam
1133189251Ssam  /* if dst == src do nothing */
1134189251Ssam  if (a == b) {
1135189251Ssam    return MP_OKAY;
1136189251Ssam  }
1137189251Ssam
1138189251Ssam  /* grow dest */
1139189251Ssam  if (b->alloc < a->used) {
1140189251Ssam     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
1141189251Ssam        return res;
1142189251Ssam     }
1143189251Ssam  }
1144189251Ssam
1145189251Ssam  /* zero b and copy the parameters over */
1146189251Ssam  {
1147189251Ssam    register mp_digit *tmpa, *tmpb;
1148189251Ssam
1149189251Ssam    /* pointer aliases */
1150189251Ssam
1151189251Ssam    /* source */
1152189251Ssam    tmpa = a->dp;
1153189251Ssam
1154189251Ssam    /* destination */
1155189251Ssam    tmpb = b->dp;
1156189251Ssam
1157189251Ssam    /* copy all the digits */
1158189251Ssam    for (n = 0; n < a->used; n++) {
1159189251Ssam      *tmpb++ = *tmpa++;
1160189251Ssam    }
1161189251Ssam
1162189251Ssam    /* clear high digits */
1163189251Ssam    for (; n < b->used; n++) {
1164189251Ssam      *tmpb++ = 0;
1165189251Ssam    }
1166189251Ssam  }
1167189251Ssam
1168189251Ssam  /* copy used count and sign */
1169189251Ssam  b->used = a->used;
1170189251Ssam  b->sign = a->sign;
1171189251Ssam  return MP_OKAY;
1172189251Ssam}
1173189251Ssam
1174189251Ssam
1175189251Ssam/* shift right a certain amount of digits */
1176189251Ssamstatic void mp_rshd (mp_int * a, int b)
1177189251Ssam{
1178189251Ssam  int     x;
1179189251Ssam
1180189251Ssam  /* if b <= 0 then ignore it */
1181189251Ssam  if (b <= 0) {
1182189251Ssam    return;
1183189251Ssam  }
1184189251Ssam
1185189251Ssam  /* if b > used then simply zero it and return */
1186189251Ssam  if (a->used <= b) {
1187189251Ssam    mp_zero (a);
1188189251Ssam    return;
1189189251Ssam  }
1190189251Ssam
1191189251Ssam  {
1192189251Ssam    register mp_digit *bottom, *top;
1193189251Ssam
1194189251Ssam    /* shift the digits down */
1195189251Ssam
1196189251Ssam    /* bottom */
1197189251Ssam    bottom = a->dp;
1198189251Ssam
1199189251Ssam    /* top [offset into digits] */
1200189251Ssam    top = a->dp + b;
1201189251Ssam
1202189251Ssam    /* this is implemented as a sliding window where
1203189251Ssam     * the window is b-digits long and digits from
1204189251Ssam     * the top of the window are copied to the bottom
1205189251Ssam     *
1206189251Ssam     * e.g.
1207189251Ssam
1208189251Ssam     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
1209189251Ssam                 /\                   |      ---->
1210189251Ssam                  \-------------------/      ---->
1211189251Ssam     */
1212189251Ssam    for (x = 0; x < (a->used - b); x++) {
1213189251Ssam      *bottom++ = *top++;
1214189251Ssam    }
1215189251Ssam
1216189251Ssam    /* zero the top digits */
1217189251Ssam    for (; x < a->used; x++) {
1218189251Ssam      *bottom++ = 0;
1219189251Ssam    }
1220189251Ssam  }
1221189251Ssam
1222189251Ssam  /* remove excess digits */
1223189251Ssam  a->used -= b;
1224189251Ssam}
1225189251Ssam
1226189251Ssam
1227189251Ssam/* swap the elements of two integers, for cases where you can't simply swap the
1228189251Ssam * mp_int pointers around
1229189251Ssam */
1230189251Ssamstatic void mp_exch (mp_int * a, mp_int * b)
1231189251Ssam{
1232189251Ssam  mp_int  t;
1233189251Ssam
1234189251Ssam  t  = *a;
1235189251Ssam  *a = *b;
1236189251Ssam  *b = t;
1237189251Ssam}
1238189251Ssam
1239189251Ssam
1240189251Ssam/* trim unused digits
1241189251Ssam *
1242189251Ssam * This is used to ensure that leading zero digits are
1243189251Ssam * trimed and the leading "used" digit will be non-zero
1244189251Ssam * Typically very fast.  Also fixes the sign if there
1245189251Ssam * are no more leading digits
1246189251Ssam */
1247189251Ssamstatic void mp_clamp (mp_int * a)
1248189251Ssam{
1249189251Ssam  /* decrease used while the most significant digit is
1250189251Ssam   * zero.
1251189251Ssam   */
1252189251Ssam  while (a->used > 0 && a->dp[a->used - 1] == 0) {
1253189251Ssam    --(a->used);
1254189251Ssam  }
1255189251Ssam
1256189251Ssam  /* reset the sign flag if used == 0 */
1257189251Ssam  if (a->used == 0) {
1258189251Ssam    a->sign = MP_ZPOS;
1259189251Ssam  }
1260189251Ssam}
1261189251Ssam
1262189251Ssam
1263189251Ssam/* grow as required */
1264189251Ssamstatic int mp_grow (mp_int * a, int size)
1265189251Ssam{
1266189251Ssam  int     i;
1267189251Ssam  mp_digit *tmp;
1268189251Ssam
1269189251Ssam  /* if the alloc size is smaller alloc more ram */
1270189251Ssam  if (a->alloc < size) {
1271189251Ssam    /* ensure there are always at least MP_PREC digits extra on top */
1272189251Ssam    size += (MP_PREC * 2) - (size % MP_PREC);
1273189251Ssam
1274189251Ssam    /* reallocate the array a->dp
1275189251Ssam     *
1276189251Ssam     * We store the return in a temporary variable
1277189251Ssam     * in case the operation failed we don't want
1278189251Ssam     * to overwrite the dp member of a.
1279189251Ssam     */
1280189251Ssam    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
1281189251Ssam    if (tmp == NULL) {
1282189251Ssam      /* reallocation failed but "a" is still valid [can be freed] */
1283189251Ssam      return MP_MEM;
1284189251Ssam    }
1285189251Ssam
1286189251Ssam    /* reallocation succeeded so set a->dp */
1287189251Ssam    a->dp = tmp;
1288189251Ssam
1289189251Ssam    /* zero excess digits */
1290189251Ssam    i        = a->alloc;
1291189251Ssam    a->alloc = size;
1292189251Ssam    for (; i < a->alloc; i++) {
1293189251Ssam      a->dp[i] = 0;
1294189251Ssam    }
1295189251Ssam  }
1296189251Ssam  return MP_OKAY;
1297189251Ssam}
1298189251Ssam
1299189251Ssam
1300189251Ssam#ifdef BN_MP_ABS_C
1301189251Ssam/* b = |a|
1302189251Ssam *
1303189251Ssam * Simple function copies the input and fixes the sign to positive
1304189251Ssam */
1305189251Ssamstatic int mp_abs (mp_int * a, mp_int * b)
1306189251Ssam{
1307189251Ssam  int     res;
1308189251Ssam
1309189251Ssam  /* copy a to b */
1310189251Ssam  if (a != b) {
1311189251Ssam     if ((res = mp_copy (a, b)) != MP_OKAY) {
1312189251Ssam       return res;
1313189251Ssam     }
1314189251Ssam  }
1315189251Ssam
1316189251Ssam  /* force the sign of b to positive */
1317189251Ssam  b->sign = MP_ZPOS;
1318189251Ssam
1319189251Ssam  return MP_OKAY;
1320189251Ssam}
1321189251Ssam#endif
1322189251Ssam
1323189251Ssam
1324189251Ssam/* set to a digit */
1325189251Ssamstatic void mp_set (mp_int * a, mp_digit b)
1326189251Ssam{
1327189251Ssam  mp_zero (a);
1328189251Ssam  a->dp[0] = b & MP_MASK;
1329189251Ssam  a->used  = (a->dp[0] != 0) ? 1 : 0;
1330189251Ssam}
1331189251Ssam
1332189251Ssam
1333189251Ssam#ifndef LTM_NO_NEG_EXP
1334189251Ssam/* b = a/2 */
1335189251Ssamstatic int mp_div_2(mp_int * a, mp_int * b)
1336189251Ssam{
1337189251Ssam  int     x, res, oldused;
1338189251Ssam
1339189251Ssam  /* copy */
1340189251Ssam  if (b->alloc < a->used) {
1341189251Ssam    if ((res = mp_grow (b, a->used)) != MP_OKAY) {
1342189251Ssam      return res;
1343189251Ssam    }
1344189251Ssam  }
1345189251Ssam
1346189251Ssam  oldused = b->used;
1347189251Ssam  b->used = a->used;
1348189251Ssam  {
1349189251Ssam    register mp_digit r, rr, *tmpa, *tmpb;
1350189251Ssam
1351189251Ssam    /* source alias */
1352189251Ssam    tmpa = a->dp + b->used - 1;
1353189251Ssam
1354189251Ssam    /* dest alias */
1355189251Ssam    tmpb = b->dp + b->used - 1;
1356189251Ssam
1357189251Ssam    /* carry */
1358189251Ssam    r = 0;
1359189251Ssam    for (x = b->used - 1; x >= 0; x--) {
1360189251Ssam      /* get the carry for the next iteration */
1361189251Ssam      rr = *tmpa & 1;
1362189251Ssam
1363189251Ssam      /* shift the current digit, add in carry and store */
1364189251Ssam      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
1365189251Ssam
1366189251Ssam      /* forward carry to next iteration */
1367189251Ssam      r = rr;
1368189251Ssam    }
1369189251Ssam
1370189251Ssam    /* zero excess digits */
1371189251Ssam    tmpb = b->dp + b->used;
1372189251Ssam    for (x = b->used; x < oldused; x++) {
1373189251Ssam      *tmpb++ = 0;
1374189251Ssam    }
1375189251Ssam  }
1376189251Ssam  b->sign = a->sign;
1377189251Ssam  mp_clamp (b);
1378189251Ssam  return MP_OKAY;
1379189251Ssam}
1380189251Ssam#endif /* LTM_NO_NEG_EXP */
1381189251Ssam
1382189251Ssam
1383189251Ssam/* shift left by a certain bit count */
1384189251Ssamstatic int mp_mul_2d (mp_int * a, int b, mp_int * c)
1385189251Ssam{
1386189251Ssam  mp_digit d;
1387189251Ssam  int      res;
1388189251Ssam
1389189251Ssam  /* copy */
1390189251Ssam  if (a != c) {
1391189251Ssam     if ((res = mp_copy (a, c)) != MP_OKAY) {
1392189251Ssam       return res;
1393189251Ssam     }
1394189251Ssam  }
1395189251Ssam
1396189251Ssam  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
1397189251Ssam     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
1398189251Ssam       return res;
1399189251Ssam     }
1400189251Ssam  }
1401189251Ssam
1402189251Ssam  /* shift by as many digits in the bit count */
1403189251Ssam  if (b >= (int)DIGIT_BIT) {
1404189251Ssam    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
1405189251Ssam      return res;
1406189251Ssam    }
1407189251Ssam  }
1408189251Ssam
1409189251Ssam  /* shift any bit count < DIGIT_BIT */
1410189251Ssam  d = (mp_digit) (b % DIGIT_BIT);
1411189251Ssam  if (d != 0) {
1412189251Ssam    register mp_digit *tmpc, shift, mask, r, rr;
1413189251Ssam    register int x;
1414189251Ssam
1415189251Ssam    /* bitmask for carries */
1416189251Ssam    mask = (((mp_digit)1) << d) - 1;
1417189251Ssam
1418189251Ssam    /* shift for msbs */
1419189251Ssam    shift = DIGIT_BIT - d;
1420189251Ssam
1421189251Ssam    /* alias */
1422189251Ssam    tmpc = c->dp;
1423189251Ssam
1424189251Ssam    /* carry */
1425189251Ssam    r    = 0;
1426189251Ssam    for (x = 0; x < c->used; x++) {
1427189251Ssam      /* get the higher bits of the current word */
1428189251Ssam      rr = (*tmpc >> shift) & mask;
1429189251Ssam
1430189251Ssam      /* shift the current word and OR in the carry */
1431189251Ssam      *tmpc = ((*tmpc << d) | r) & MP_MASK;
1432189251Ssam      ++tmpc;
1433189251Ssam
1434189251Ssam      /* set the carry to the carry bits of the current word */
1435189251Ssam      r = rr;
1436189251Ssam    }
1437189251Ssam
1438189251Ssam    /* set final carry */
1439189251Ssam    if (r != 0) {
1440189251Ssam       c->dp[(c->used)++] = r;
1441189251Ssam    }
1442189251Ssam  }
1443189251Ssam  mp_clamp (c);
1444189251Ssam  return MP_OKAY;
1445189251Ssam}
1446189251Ssam
1447189251Ssam
1448189251Ssam#ifdef BN_MP_INIT_MULTI_C
1449189251Ssamstatic int mp_init_multi(mp_int *mp, ...)
1450189251Ssam{
1451189251Ssam    mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
1452189251Ssam    int n = 0;                 /* Number of ok inits */
1453189251Ssam    mp_int* cur_arg = mp;
1454189251Ssam    va_list args;
1455189251Ssam
1456189251Ssam    va_start(args, mp);        /* init args to next argument from caller */
1457189251Ssam    while (cur_arg != NULL) {
1458189251Ssam        if (mp_init(cur_arg) != MP_OKAY) {
1459189251Ssam            /* Oops - error! Back-track and mp_clear what we already
1460189251Ssam               succeeded in init-ing, then return error.
1461189251Ssam            */
1462189251Ssam            va_list clean_args;
1463189251Ssam
1464189251Ssam            /* end the current list */
1465189251Ssam            va_end(args);
1466189251Ssam
1467189251Ssam            /* now start cleaning up */
1468189251Ssam            cur_arg = mp;
1469189251Ssam            va_start(clean_args, mp);
1470189251Ssam            while (n--) {
1471189251Ssam                mp_clear(cur_arg);
1472189251Ssam                cur_arg = va_arg(clean_args, mp_int*);
1473189251Ssam            }
1474189251Ssam            va_end(clean_args);
1475289549Srpaulo            return MP_MEM;
1476189251Ssam        }
1477189251Ssam        n++;
1478189251Ssam        cur_arg = va_arg(args, mp_int*);
1479189251Ssam    }
1480189251Ssam    va_end(args);
1481189251Ssam    return res;                /* Assumed ok, if error flagged above. */
1482189251Ssam}
1483189251Ssam#endif
1484189251Ssam
1485189251Ssam
1486189251Ssam#ifdef BN_MP_CLEAR_MULTI_C
1487189251Ssamstatic void mp_clear_multi(mp_int *mp, ...)
1488189251Ssam{
1489189251Ssam    mp_int* next_mp = mp;
1490189251Ssam    va_list args;
1491189251Ssam    va_start(args, mp);
1492189251Ssam    while (next_mp != NULL) {
1493189251Ssam        mp_clear(next_mp);
1494189251Ssam        next_mp = va_arg(args, mp_int*);
1495189251Ssam    }
1496189251Ssam    va_end(args);
1497189251Ssam}
1498189251Ssam#endif
1499189251Ssam
1500189251Ssam
1501189251Ssam/* shift left a certain amount of digits */
1502189251Ssamstatic int mp_lshd (mp_int * a, int b)
1503189251Ssam{
1504189251Ssam  int     x, res;
1505189251Ssam
1506189251Ssam  /* if its less than zero return */
1507189251Ssam  if (b <= 0) {
1508189251Ssam    return MP_OKAY;
1509189251Ssam  }
1510189251Ssam
1511189251Ssam  /* grow to fit the new digits */
1512189251Ssam  if (a->alloc < a->used + b) {
1513189251Ssam     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
1514189251Ssam       return res;
1515189251Ssam     }
1516189251Ssam  }
1517189251Ssam
1518189251Ssam  {
1519189251Ssam    register mp_digit *top, *bottom;
1520189251Ssam
1521189251Ssam    /* increment the used by the shift amount then copy upwards */
1522189251Ssam    a->used += b;
1523189251Ssam
1524189251Ssam    /* top */
1525189251Ssam    top = a->dp + a->used - 1;
1526189251Ssam
1527189251Ssam    /* base */
1528189251Ssam    bottom = a->dp + a->used - 1 - b;
1529189251Ssam
1530189251Ssam    /* much like mp_rshd this is implemented using a sliding window
1531189251Ssam     * except the window goes the otherway around.  Copying from
1532189251Ssam     * the bottom to the top.  see bn_mp_rshd.c for more info.
1533189251Ssam     */
1534189251Ssam    for (x = a->used - 1; x >= b; x--) {
1535189251Ssam      *top-- = *bottom--;
1536189251Ssam    }
1537189251Ssam
1538189251Ssam    /* zero the lower digits */
1539189251Ssam    top = a->dp;
1540189251Ssam    for (x = 0; x < b; x++) {
1541189251Ssam      *top++ = 0;
1542189251Ssam    }
1543189251Ssam  }
1544189251Ssam  return MP_OKAY;
1545189251Ssam}
1546189251Ssam
1547189251Ssam
1548189251Ssam/* returns the number of bits in an int */
1549189251Ssamstatic int mp_count_bits (mp_int * a)
1550189251Ssam{
1551189251Ssam  int     r;
1552189251Ssam  mp_digit q;
1553189251Ssam
1554189251Ssam  /* shortcut */
1555189251Ssam  if (a->used == 0) {
1556189251Ssam    return 0;
1557189251Ssam  }
1558189251Ssam
1559189251Ssam  /* get number of digits and add that */
1560189251Ssam  r = (a->used - 1) * DIGIT_BIT;
1561189251Ssam
1562189251Ssam  /* take the last digit and count the bits in it */
1563189251Ssam  q = a->dp[a->used - 1];
1564189251Ssam  while (q > ((mp_digit) 0)) {
1565189251Ssam    ++r;
1566189251Ssam    q >>= ((mp_digit) 1);
1567189251Ssam  }
1568189251Ssam  return r;
1569189251Ssam}
1570189251Ssam
1571189251Ssam
1572189251Ssam/* calc a value mod 2**b */
1573189251Ssamstatic int mp_mod_2d (mp_int * a, int b, mp_int * c)
1574189251Ssam{
1575189251Ssam  int     x, res;
1576189251Ssam
1577189251Ssam  /* if b is <= 0 then zero the int */
1578189251Ssam  if (b <= 0) {
1579189251Ssam    mp_zero (c);
1580189251Ssam    return MP_OKAY;
1581189251Ssam  }
1582189251Ssam
1583189251Ssam  /* if the modulus is larger than the value than return */
1584189251Ssam  if (b >= (int) (a->used * DIGIT_BIT)) {
1585189251Ssam    res = mp_copy (a, c);
1586189251Ssam    return res;
1587189251Ssam  }
1588189251Ssam
1589189251Ssam  /* copy */
1590189251Ssam  if ((res = mp_copy (a, c)) != MP_OKAY) {
1591189251Ssam    return res;
1592189251Ssam  }
1593189251Ssam
1594189251Ssam  /* zero digits above the last digit of the modulus */
1595189251Ssam  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
1596189251Ssam    c->dp[x] = 0;
1597189251Ssam  }
1598189251Ssam  /* clear the digit that is not completely outside/inside the modulus */
1599189251Ssam  c->dp[b / DIGIT_BIT] &=
1600189251Ssam    (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
1601189251Ssam  mp_clamp (c);
1602189251Ssam  return MP_OKAY;
1603189251Ssam}
1604189251Ssam
1605189251Ssam
1606189251Ssam#ifdef BN_MP_DIV_SMALL
1607189251Ssam
1608189251Ssam/* slower bit-bang division... also smaller */
1609189251Ssamstatic int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
1610189251Ssam{
1611189251Ssam   mp_int ta, tb, tq, q;
1612189251Ssam   int    res, n, n2;
1613189251Ssam
1614189251Ssam  /* is divisor zero ? */
1615189251Ssam  if (mp_iszero (b) == 1) {
1616189251Ssam    return MP_VAL;
1617189251Ssam  }
1618189251Ssam
1619189251Ssam  /* if a < b then q=0, r = a */
1620189251Ssam  if (mp_cmp_mag (a, b) == MP_LT) {
1621189251Ssam    if (d != NULL) {
1622189251Ssam      res = mp_copy (a, d);
1623189251Ssam    } else {
1624189251Ssam      res = MP_OKAY;
1625189251Ssam    }
1626189251Ssam    if (c != NULL) {
1627189251Ssam      mp_zero (c);
1628189251Ssam    }
1629189251Ssam    return res;
1630189251Ssam  }
1631189251Ssam
1632189251Ssam  /* init our temps */
1633289549Srpaulo  if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
1634189251Ssam     return res;
1635189251Ssam  }
1636189251Ssam
1637189251Ssam
1638189251Ssam  mp_set(&tq, 1);
1639189251Ssam  n = mp_count_bits(a) - mp_count_bits(b);
1640189251Ssam  if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
1641189251Ssam      ((res = mp_abs(b, &tb)) != MP_OKAY) ||
1642189251Ssam      ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
1643189251Ssam      ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
1644189251Ssam      goto LBL_ERR;
1645189251Ssam  }
1646189251Ssam
1647189251Ssam  while (n-- >= 0) {
1648189251Ssam     if (mp_cmp(&tb, &ta) != MP_GT) {
1649189251Ssam        if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
1650189251Ssam            ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
1651189251Ssam           goto LBL_ERR;
1652189251Ssam        }
1653189251Ssam     }
1654189251Ssam     if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
1655189251Ssam         ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
1656189251Ssam           goto LBL_ERR;
1657189251Ssam     }
1658189251Ssam  }
1659189251Ssam
1660189251Ssam  /* now q == quotient and ta == remainder */
1661189251Ssam  n  = a->sign;
1662189251Ssam  n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
1663189251Ssam  if (c != NULL) {
1664189251Ssam     mp_exch(c, &q);
1665189251Ssam     c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
1666189251Ssam  }
1667189251Ssam  if (d != NULL) {
1668189251Ssam     mp_exch(d, &ta);
1669189251Ssam     d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
1670189251Ssam  }
1671189251SsamLBL_ERR:
1672189251Ssam   mp_clear_multi(&ta, &tb, &tq, &q, NULL);
1673189251Ssam   return res;
1674189251Ssam}
1675189251Ssam
1676189251Ssam#else
1677189251Ssam
1678189251Ssam/* integer signed division.
1679189251Ssam * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
1680189251Ssam * HAC pp.598 Algorithm 14.20
1681189251Ssam *
1682189251Ssam * Note that the description in HAC is horribly
1683189251Ssam * incomplete.  For example, it doesn't consider
1684189251Ssam * the case where digits are removed from 'x' in
1685189251Ssam * the inner loop.  It also doesn't consider the
1686189251Ssam * case that y has fewer than three digits, etc..
1687189251Ssam *
1688189251Ssam * The overall algorithm is as described as
1689189251Ssam * 14.20 from HAC but fixed to treat these cases.
1690189251Ssam*/
1691189251Ssamstatic int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
1692189251Ssam{
1693189251Ssam  mp_int  q, x, y, t1, t2;
1694189251Ssam  int     res, n, t, i, norm, neg;
1695189251Ssam
1696189251Ssam  /* is divisor zero ? */
1697189251Ssam  if (mp_iszero (b) == 1) {
1698189251Ssam    return MP_VAL;
1699189251Ssam  }
1700189251Ssam
1701189251Ssam  /* if a < b then q=0, r = a */
1702189251Ssam  if (mp_cmp_mag (a, b) == MP_LT) {
1703189251Ssam    if (d != NULL) {
1704189251Ssam      res = mp_copy (a, d);
1705189251Ssam    } else {
1706189251Ssam      res = MP_OKAY;
1707189251Ssam    }
1708189251Ssam    if (c != NULL) {
1709189251Ssam      mp_zero (c);
1710189251Ssam    }
1711189251Ssam    return res;
1712189251Ssam  }
1713189251Ssam
1714189251Ssam  if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
1715189251Ssam    return res;
1716189251Ssam  }
1717189251Ssam  q.used = a->used + 2;
1718189251Ssam
1719189251Ssam  if ((res = mp_init (&t1)) != MP_OKAY) {
1720189251Ssam    goto LBL_Q;
1721189251Ssam  }
1722189251Ssam
1723189251Ssam  if ((res = mp_init (&t2)) != MP_OKAY) {
1724189251Ssam    goto LBL_T1;
1725189251Ssam  }
1726189251Ssam
1727189251Ssam  if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
1728189251Ssam    goto LBL_T2;
1729189251Ssam  }
1730189251Ssam
1731189251Ssam  if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
1732189251Ssam    goto LBL_X;
1733189251Ssam  }
1734189251Ssam
1735189251Ssam  /* fix the sign */
1736189251Ssam  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
1737189251Ssam  x.sign = y.sign = MP_ZPOS;
1738189251Ssam
1739189251Ssam  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
1740189251Ssam  norm = mp_count_bits(&y) % DIGIT_BIT;
1741189251Ssam  if (norm < (int)(DIGIT_BIT-1)) {
1742189251Ssam     norm = (DIGIT_BIT-1) - norm;
1743189251Ssam     if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
1744189251Ssam       goto LBL_Y;
1745189251Ssam     }
1746189251Ssam     if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
1747189251Ssam       goto LBL_Y;
1748189251Ssam     }
1749189251Ssam  } else {
1750189251Ssam     norm = 0;
1751189251Ssam  }
1752189251Ssam
1753189251Ssam  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
1754189251Ssam  n = x.used - 1;
1755189251Ssam  t = y.used - 1;
1756189251Ssam
1757189251Ssam  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
1758189251Ssam  if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
1759189251Ssam    goto LBL_Y;
1760189251Ssam  }
1761189251Ssam
1762189251Ssam  while (mp_cmp (&x, &y) != MP_LT) {
1763189251Ssam    ++(q.dp[n - t]);
1764189251Ssam    if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
1765189251Ssam      goto LBL_Y;
1766189251Ssam    }
1767189251Ssam  }
1768189251Ssam
1769189251Ssam  /* reset y by shifting it back down */
1770189251Ssam  mp_rshd (&y, n - t);
1771189251Ssam
1772189251Ssam  /* step 3. for i from n down to (t + 1) */
1773189251Ssam  for (i = n; i >= (t + 1); i--) {
1774189251Ssam    if (i > x.used) {
1775189251Ssam      continue;
1776189251Ssam    }
1777189251Ssam
1778189251Ssam    /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
1779189251Ssam     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
1780189251Ssam    if (x.dp[i] == y.dp[t]) {
1781189251Ssam      q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
1782189251Ssam    } else {
1783189251Ssam      mp_word tmp;
1784189251Ssam      tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
1785189251Ssam      tmp |= ((mp_word) x.dp[i - 1]);
1786189251Ssam      tmp /= ((mp_word) y.dp[t]);
1787189251Ssam      if (tmp > (mp_word) MP_MASK)
1788189251Ssam        tmp = MP_MASK;
1789189251Ssam      q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
1790189251Ssam    }
1791189251Ssam
1792189251Ssam    /* while (q{i-t-1} * (yt * b + y{t-1})) >
1793189251Ssam             xi * b**2 + xi-1 * b + xi-2
1794189251Ssam
1795189251Ssam       do q{i-t-1} -= 1;
1796189251Ssam    */
1797189251Ssam    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
1798189251Ssam    do {
1799189251Ssam      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
1800189251Ssam
1801189251Ssam      /* find left hand */
1802189251Ssam      mp_zero (&t1);
1803189251Ssam      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
1804189251Ssam      t1.dp[1] = y.dp[t];
1805189251Ssam      t1.used = 2;
1806189251Ssam      if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
1807189251Ssam        goto LBL_Y;
1808189251Ssam      }
1809189251Ssam
1810189251Ssam      /* find right hand */
1811189251Ssam      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
1812189251Ssam      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
1813189251Ssam      t2.dp[2] = x.dp[i];
1814189251Ssam      t2.used = 3;
1815189251Ssam    } while (mp_cmp_mag(&t1, &t2) == MP_GT);
1816189251Ssam
1817189251Ssam    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
1818189251Ssam    if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
1819189251Ssam      goto LBL_Y;
1820189251Ssam    }
1821189251Ssam
1822189251Ssam    if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
1823189251Ssam      goto LBL_Y;
1824189251Ssam    }
1825189251Ssam
1826189251Ssam    if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
1827189251Ssam      goto LBL_Y;
1828189251Ssam    }
1829189251Ssam
1830189251Ssam    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
1831189251Ssam    if (x.sign == MP_NEG) {
1832189251Ssam      if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
1833189251Ssam        goto LBL_Y;
1834189251Ssam      }
1835189251Ssam      if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
1836189251Ssam        goto LBL_Y;
1837189251Ssam      }
1838189251Ssam      if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
1839189251Ssam        goto LBL_Y;
1840189251Ssam      }
1841189251Ssam
1842189251Ssam      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
1843189251Ssam    }
1844189251Ssam  }
1845189251Ssam
1846189251Ssam  /* now q is the quotient and x is the remainder
1847189251Ssam   * [which we have to normalize]
1848189251Ssam   */
1849189251Ssam
1850189251Ssam  /* get sign before writing to c */
1851189251Ssam  x.sign = x.used == 0 ? MP_ZPOS : a->sign;
1852189251Ssam
1853189251Ssam  if (c != NULL) {
1854189251Ssam    mp_clamp (&q);
1855189251Ssam    mp_exch (&q, c);
1856189251Ssam    c->sign = neg;
1857189251Ssam  }
1858189251Ssam
1859189251Ssam  if (d != NULL) {
1860189251Ssam    mp_div_2d (&x, norm, &x, NULL);
1861189251Ssam    mp_exch (&x, d);
1862189251Ssam  }
1863189251Ssam
1864189251Ssam  res = MP_OKAY;
1865189251Ssam
1866189251SsamLBL_Y:mp_clear (&y);
1867189251SsamLBL_X:mp_clear (&x);
1868189251SsamLBL_T2:mp_clear (&t2);
1869189251SsamLBL_T1:mp_clear (&t1);
1870189251SsamLBL_Q:mp_clear (&q);
1871189251Ssam  return res;
1872189251Ssam}
1873189251Ssam
1874189251Ssam#endif
1875189251Ssam
1876189251Ssam
1877189251Ssam#ifdef MP_LOW_MEM
1878189251Ssam   #define TAB_SIZE 32
1879189251Ssam#else
1880189251Ssam   #define TAB_SIZE 256
1881189251Ssam#endif
1882189251Ssam
1883189251Ssamstatic int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
1884189251Ssam{
1885189251Ssam  mp_int  M[TAB_SIZE], res, mu;
1886189251Ssam  mp_digit buf;
1887189251Ssam  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
1888189251Ssam  int (*redux)(mp_int*,mp_int*,mp_int*);
1889189251Ssam
1890189251Ssam  /* find window size */
1891189251Ssam  x = mp_count_bits (X);
1892189251Ssam  if (x <= 7) {
1893189251Ssam    winsize = 2;
1894189251Ssam  } else if (x <= 36) {
1895189251Ssam    winsize = 3;
1896189251Ssam  } else if (x <= 140) {
1897189251Ssam    winsize = 4;
1898189251Ssam  } else if (x <= 450) {
1899189251Ssam    winsize = 5;
1900189251Ssam  } else if (x <= 1303) {
1901189251Ssam    winsize = 6;
1902189251Ssam  } else if (x <= 3529) {
1903189251Ssam    winsize = 7;
1904189251Ssam  } else {
1905189251Ssam    winsize = 8;
1906189251Ssam  }
1907189251Ssam
1908189251Ssam#ifdef MP_LOW_MEM
1909189251Ssam    if (winsize > 5) {
1910189251Ssam       winsize = 5;
1911189251Ssam    }
1912189251Ssam#endif
1913189251Ssam
1914189251Ssam  /* init M array */
1915189251Ssam  /* init first cell */
1916189251Ssam  if ((err = mp_init(&M[1])) != MP_OKAY) {
1917189251Ssam     return err;
1918189251Ssam  }
1919189251Ssam
1920189251Ssam  /* now init the second half of the array */
1921189251Ssam  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
1922189251Ssam    if ((err = mp_init(&M[x])) != MP_OKAY) {
1923189251Ssam      for (y = 1<<(winsize-1); y < x; y++) {
1924189251Ssam        mp_clear (&M[y]);
1925189251Ssam      }
1926189251Ssam      mp_clear(&M[1]);
1927189251Ssam      return err;
1928189251Ssam    }
1929189251Ssam  }
1930189251Ssam
1931189251Ssam  /* create mu, used for Barrett reduction */
1932189251Ssam  if ((err = mp_init (&mu)) != MP_OKAY) {
1933189251Ssam    goto LBL_M;
1934189251Ssam  }
1935189251Ssam
1936189251Ssam  if (redmode == 0) {
1937189251Ssam     if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
1938189251Ssam        goto LBL_MU;
1939189251Ssam     }
1940189251Ssam     redux = mp_reduce;
1941189251Ssam  } else {
1942189251Ssam     if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
1943189251Ssam        goto LBL_MU;
1944189251Ssam     }
1945189251Ssam     redux = mp_reduce_2k_l;
1946189251Ssam  }
1947189251Ssam
1948189251Ssam  /* create M table
1949189251Ssam   *
1950189251Ssam   * The M table contains powers of the base,
1951189251Ssam   * e.g. M[x] = G**x mod P
1952189251Ssam   *
1953189251Ssam   * The first half of the table is not
1954189251Ssam   * computed though accept for M[0] and M[1]
1955189251Ssam   */
1956189251Ssam  if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
1957189251Ssam    goto LBL_MU;
1958189251Ssam  }
1959189251Ssam
1960189251Ssam  /* compute the value at M[1<<(winsize-1)] by squaring
1961189251Ssam   * M[1] (winsize-1) times
1962189251Ssam   */
1963189251Ssam  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
1964189251Ssam    goto LBL_MU;
1965189251Ssam  }
1966189251Ssam
1967189251Ssam  for (x = 0; x < (winsize - 1); x++) {
1968189251Ssam    /* square it */
1969189251Ssam    if ((err = mp_sqr (&M[1 << (winsize - 1)],
1970189251Ssam                       &M[1 << (winsize - 1)])) != MP_OKAY) {
1971189251Ssam      goto LBL_MU;
1972189251Ssam    }
1973189251Ssam
1974189251Ssam    /* reduce modulo P */
1975189251Ssam    if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
1976189251Ssam      goto LBL_MU;
1977189251Ssam    }
1978189251Ssam  }
1979189251Ssam
1980189251Ssam  /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
1981189251Ssam   * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
1982189251Ssam   */
1983189251Ssam  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
1984189251Ssam    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
1985189251Ssam      goto LBL_MU;
1986189251Ssam    }
1987189251Ssam    if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
1988189251Ssam      goto LBL_MU;
1989189251Ssam    }
1990189251Ssam  }
1991189251Ssam
1992189251Ssam  /* setup result */
1993189251Ssam  if ((err = mp_init (&res)) != MP_OKAY) {
1994189251Ssam    goto LBL_MU;
1995189251Ssam  }
1996189251Ssam  mp_set (&res, 1);
1997189251Ssam
1998189251Ssam  /* set initial mode and bit cnt */
1999189251Ssam  mode   = 0;
2000189251Ssam  bitcnt = 1;
2001189251Ssam  buf    = 0;
2002189251Ssam  digidx = X->used - 1;
2003189251Ssam  bitcpy = 0;
2004189251Ssam  bitbuf = 0;
2005189251Ssam
2006189251Ssam  for (;;) {
2007189251Ssam    /* grab next digit as required */
2008189251Ssam    if (--bitcnt == 0) {
2009189251Ssam      /* if digidx == -1 we are out of digits */
2010189251Ssam      if (digidx == -1) {
2011189251Ssam        break;
2012189251Ssam      }
2013189251Ssam      /* read next digit and reset the bitcnt */
2014189251Ssam      buf    = X->dp[digidx--];
2015189251Ssam      bitcnt = (int) DIGIT_BIT;
2016189251Ssam    }
2017189251Ssam
2018189251Ssam    /* grab the next msb from the exponent */
2019189251Ssam    y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
2020189251Ssam    buf <<= (mp_digit)1;
2021189251Ssam
2022189251Ssam    /* if the bit is zero and mode == 0 then we ignore it
2023189251Ssam     * These represent the leading zero bits before the first 1 bit
2024189251Ssam     * in the exponent.  Technically this opt is not required but it
2025189251Ssam     * does lower the # of trivial squaring/reductions used
2026189251Ssam     */
2027189251Ssam    if (mode == 0 && y == 0) {
2028189251Ssam      continue;
2029189251Ssam    }
2030189251Ssam
2031189251Ssam    /* if the bit is zero and mode == 1 then we square */
2032189251Ssam    if (mode == 1 && y == 0) {
2033189251Ssam      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
2034189251Ssam        goto LBL_RES;
2035189251Ssam      }
2036189251Ssam      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
2037189251Ssam        goto LBL_RES;
2038189251Ssam      }
2039189251Ssam      continue;
2040189251Ssam    }
2041189251Ssam
2042189251Ssam    /* else we add it to the window */
2043189251Ssam    bitbuf |= (y << (winsize - ++bitcpy));
2044189251Ssam    mode    = 2;
2045189251Ssam
2046189251Ssam    if (bitcpy == winsize) {
2047189251Ssam      /* ok window is filled so square as required and multiply  */
2048189251Ssam      /* square first */
2049189251Ssam      for (x = 0; x < winsize; x++) {
2050189251Ssam        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
2051189251Ssam          goto LBL_RES;
2052189251Ssam        }
2053189251Ssam        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
2054189251Ssam          goto LBL_RES;
2055189251Ssam        }
2056189251Ssam      }
2057189251Ssam
2058189251Ssam      /* then multiply */
2059189251Ssam      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
2060189251Ssam        goto LBL_RES;
2061189251Ssam      }
2062189251Ssam      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
2063189251Ssam        goto LBL_RES;
2064189251Ssam      }
2065189251Ssam
2066189251Ssam      /* empty window and reset */
2067189251Ssam      bitcpy = 0;
2068189251Ssam      bitbuf = 0;
2069189251Ssam      mode   = 1;
2070189251Ssam    }
2071189251Ssam  }
2072189251Ssam
2073189251Ssam  /* if bits remain then square/multiply */
2074189251Ssam  if (mode == 2 && bitcpy > 0) {
2075189251Ssam    /* square then multiply if the bit is set */
2076189251Ssam    for (x = 0; x < bitcpy; x++) {
2077189251Ssam      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
2078189251Ssam        goto LBL_RES;
2079189251Ssam      }
2080189251Ssam      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
2081189251Ssam        goto LBL_RES;
2082189251Ssam      }
2083189251Ssam
2084189251Ssam      bitbuf <<= 1;
2085189251Ssam      if ((bitbuf & (1 << winsize)) != 0) {
2086189251Ssam        /* then multiply */
2087189251Ssam        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
2088189251Ssam          goto LBL_RES;
2089189251Ssam        }
2090189251Ssam        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
2091189251Ssam          goto LBL_RES;
2092189251Ssam        }
2093189251Ssam      }
2094189251Ssam    }
2095189251Ssam  }
2096189251Ssam
2097189251Ssam  mp_exch (&res, Y);
2098189251Ssam  err = MP_OKAY;
2099189251SsamLBL_RES:mp_clear (&res);
2100189251SsamLBL_MU:mp_clear (&mu);
2101189251SsamLBL_M:
2102189251Ssam  mp_clear(&M[1]);
2103189251Ssam  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
2104189251Ssam    mp_clear (&M[x]);
2105189251Ssam  }
2106189251Ssam  return err;
2107189251Ssam}
2108189251Ssam
2109189251Ssam
2110189251Ssam/* computes b = a*a */
2111189251Ssamstatic int mp_sqr (mp_int * a, mp_int * b)
2112189251Ssam{
2113189251Ssam  int     res;
2114189251Ssam
2115189251Ssam#ifdef BN_MP_TOOM_SQR_C
2116189251Ssam  /* use Toom-Cook? */
2117189251Ssam  if (a->used >= TOOM_SQR_CUTOFF) {
2118189251Ssam    res = mp_toom_sqr(a, b);
2119189251Ssam  /* Karatsuba? */
2120189251Ssam  } else
2121189251Ssam#endif
2122189251Ssam#ifdef BN_MP_KARATSUBA_SQR_C
2123189251Ssamif (a->used >= KARATSUBA_SQR_CUTOFF) {
2124189251Ssam    res = mp_karatsuba_sqr (a, b);
2125189251Ssam  } else
2126189251Ssam#endif
2127189251Ssam  {
2128189251Ssam#ifdef BN_FAST_S_MP_SQR_C
2129189251Ssam    /* can we use the fast comba multiplier? */
2130189251Ssam    if ((a->used * 2 + 1) < MP_WARRAY &&
2131189251Ssam         a->used <
2132189251Ssam         (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
2133189251Ssam      res = fast_s_mp_sqr (a, b);
2134189251Ssam    } else
2135189251Ssam#endif
2136189251Ssam#ifdef BN_S_MP_SQR_C
2137189251Ssam      res = s_mp_sqr (a, b);
2138189251Ssam#else
2139189251Ssam#error mp_sqr could fail
2140189251Ssam      res = MP_VAL;
2141189251Ssam#endif
2142189251Ssam  }
2143189251Ssam  b->sign = MP_ZPOS;
2144189251Ssam  return res;
2145189251Ssam}
2146189251Ssam
2147189251Ssam
2148189251Ssam/* reduces a modulo n where n is of the form 2**p - d
2149189251Ssam   This differs from reduce_2k since "d" can be larger
2150189251Ssam   than a single digit.
2151189251Ssam*/
2152189251Ssamstatic int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
2153189251Ssam{
2154189251Ssam   mp_int q;
2155189251Ssam   int    p, res;
2156189251Ssam
2157189251Ssam   if ((res = mp_init(&q)) != MP_OKAY) {
2158189251Ssam      return res;
2159189251Ssam   }
2160189251Ssam
2161189251Ssam   p = mp_count_bits(n);
2162189251Ssamtop:
2163189251Ssam   /* q = a/2**p, a = a mod 2**p */
2164189251Ssam   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
2165189251Ssam      goto ERR;
2166189251Ssam   }
2167189251Ssam
2168189251Ssam   /* q = q * d */
2169189251Ssam   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
2170189251Ssam      goto ERR;
2171189251Ssam   }
2172189251Ssam
2173189251Ssam   /* a = a + q */
2174189251Ssam   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
2175189251Ssam      goto ERR;
2176189251Ssam   }
2177189251Ssam
2178189251Ssam   if (mp_cmp_mag(a, n) != MP_LT) {
2179189251Ssam      s_mp_sub(a, n, a);
2180189251Ssam      goto top;
2181189251Ssam   }
2182189251Ssam
2183189251SsamERR:
2184189251Ssam   mp_clear(&q);
2185189251Ssam   return res;
2186189251Ssam}
2187189251Ssam
2188189251Ssam
2189189251Ssam/* determines the setup value */
2190189251Ssamstatic int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
2191189251Ssam{
2192189251Ssam   int    res;
2193189251Ssam   mp_int tmp;
2194189251Ssam
2195189251Ssam   if ((res = mp_init(&tmp)) != MP_OKAY) {
2196189251Ssam      return res;
2197189251Ssam   }
2198189251Ssam
2199189251Ssam   if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
2200189251Ssam      goto ERR;
2201189251Ssam   }
2202189251Ssam
2203189251Ssam   if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
2204189251Ssam      goto ERR;
2205189251Ssam   }
2206189251Ssam
2207189251SsamERR:
2208189251Ssam   mp_clear(&tmp);
2209189251Ssam   return res;
2210189251Ssam}
2211189251Ssam
2212189251Ssam
2213189251Ssam/* computes a = 2**b
2214189251Ssam *
2215189251Ssam * Simple algorithm which zeroes the int, grows it then just sets one bit
2216189251Ssam * as required.
2217189251Ssam */
2218189251Ssamstatic int mp_2expt (mp_int * a, int b)
2219189251Ssam{
2220189251Ssam  int     res;
2221189251Ssam
2222189251Ssam  /* zero a as per default */
2223189251Ssam  mp_zero (a);
2224189251Ssam
2225252726Srpaulo  /* grow a to accommodate the single bit */
2226189251Ssam  if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
2227189251Ssam    return res;
2228189251Ssam  }
2229189251Ssam
2230189251Ssam  /* set the used count of where the bit will go */
2231189251Ssam  a->used = b / DIGIT_BIT + 1;
2232189251Ssam
2233189251Ssam  /* put the single bit in its place */
2234189251Ssam  a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
2235189251Ssam
2236189251Ssam  return MP_OKAY;
2237189251Ssam}
2238189251Ssam
2239189251Ssam
2240189251Ssam/* pre-calculate the value required for Barrett reduction
2241189251Ssam * For a given modulus "b" it calulates the value required in "a"
2242189251Ssam */
2243189251Ssamstatic int mp_reduce_setup (mp_int * a, mp_int * b)
2244189251Ssam{
2245189251Ssam  int     res;
2246189251Ssam
2247189251Ssam  if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
2248189251Ssam    return res;
2249189251Ssam  }
2250189251Ssam  return mp_div (a, b, a, NULL);
2251189251Ssam}
2252189251Ssam
2253189251Ssam
2254189251Ssam/* reduces x mod m, assumes 0 < x < m**2, mu is
2255189251Ssam * precomputed via mp_reduce_setup.
2256189251Ssam * From HAC pp.604 Algorithm 14.42
2257189251Ssam */
2258189251Ssamstatic int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
2259189251Ssam{
2260189251Ssam  mp_int  q;
2261189251Ssam  int     res, um = m->used;
2262189251Ssam
2263189251Ssam  /* q = x */
2264189251Ssam  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
2265189251Ssam    return res;
2266189251Ssam  }
2267189251Ssam
2268189251Ssam  /* q1 = x / b**(k-1)  */
2269189251Ssam  mp_rshd (&q, um - 1);
2270189251Ssam
2271189251Ssam  /* according to HAC this optimization is ok */
2272189251Ssam  if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
2273189251Ssam    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
2274189251Ssam      goto CLEANUP;
2275189251Ssam    }
2276189251Ssam  } else {
2277189251Ssam#ifdef BN_S_MP_MUL_HIGH_DIGS_C
2278189251Ssam    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
2279189251Ssam      goto CLEANUP;
2280189251Ssam    }
2281189251Ssam#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
2282189251Ssam    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
2283189251Ssam      goto CLEANUP;
2284189251Ssam    }
2285189251Ssam#else
2286189251Ssam    {
2287189251Ssam#error mp_reduce would always fail
2288189251Ssam      res = MP_VAL;
2289189251Ssam      goto CLEANUP;
2290189251Ssam    }
2291189251Ssam#endif
2292189251Ssam  }
2293189251Ssam
2294189251Ssam  /* q3 = q2 / b**(k+1) */
2295189251Ssam  mp_rshd (&q, um + 1);
2296189251Ssam
2297189251Ssam  /* x = x mod b**(k+1), quick (no division) */
2298189251Ssam  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
2299189251Ssam    goto CLEANUP;
2300189251Ssam  }
2301189251Ssam
2302189251Ssam  /* q = q * m mod b**(k+1), quick (no division) */
2303189251Ssam  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
2304189251Ssam    goto CLEANUP;
2305189251Ssam  }
2306189251Ssam
2307189251Ssam  /* x = x - q */
2308189251Ssam  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
2309189251Ssam    goto CLEANUP;
2310189251Ssam  }
2311189251Ssam
2312189251Ssam  /* If x < 0, add b**(k+1) to it */
2313189251Ssam  if (mp_cmp_d (x, 0) == MP_LT) {
2314189251Ssam    mp_set (&q, 1);
2315189251Ssam    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
2316189251Ssam      goto CLEANUP;
2317189251Ssam    }
2318189251Ssam    if ((res = mp_add (x, &q, x)) != MP_OKAY) {
2319189251Ssam      goto CLEANUP;
2320189251Ssam    }
2321189251Ssam  }
2322189251Ssam
2323189251Ssam  /* Back off if it's too big */
2324189251Ssam  while (mp_cmp (x, m) != MP_LT) {
2325189251Ssam    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
2326189251Ssam      goto CLEANUP;
2327189251Ssam    }
2328189251Ssam  }
2329189251Ssam
2330189251SsamCLEANUP:
2331189251Ssam  mp_clear (&q);
2332189251Ssam
2333189251Ssam  return res;
2334189251Ssam}
2335189251Ssam
2336189251Ssam
2337252726Srpaulo/* multiplies |a| * |b| and only computes up to digs digits of result
2338189251Ssam * HAC pp. 595, Algorithm 14.12  Modified so you can control how
2339189251Ssam * many digits of output are created.
2340189251Ssam */
2341189251Ssamstatic int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
2342189251Ssam{
2343189251Ssam  mp_int  t;
2344189251Ssam  int     res, pa, pb, ix, iy;
2345189251Ssam  mp_digit u;
2346189251Ssam  mp_word r;
2347189251Ssam  mp_digit tmpx, *tmpt, *tmpy;
2348189251Ssam
2349281806Srpaulo#ifdef BN_FAST_S_MP_MUL_DIGS_C
2350189251Ssam  /* can we use the fast multiplier? */
2351189251Ssam  if (((digs) < MP_WARRAY) &&
2352189251Ssam      MIN (a->used, b->used) <
2353189251Ssam          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
2354189251Ssam    return fast_s_mp_mul_digs (a, b, c, digs);
2355189251Ssam  }
2356281806Srpaulo#endif
2357189251Ssam
2358189251Ssam  if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
2359189251Ssam    return res;
2360189251Ssam  }
2361189251Ssam  t.used = digs;
2362189251Ssam
2363189251Ssam  /* compute the digits of the product directly */
2364189251Ssam  pa = a->used;
2365189251Ssam  for (ix = 0; ix < pa; ix++) {
2366189251Ssam    /* set the carry to zero */
2367189251Ssam    u = 0;
2368189251Ssam
2369189251Ssam    /* limit ourselves to making digs digits of output */
2370189251Ssam    pb = MIN (b->used, digs - ix);
2371189251Ssam
2372189251Ssam    /* setup some aliases */
2373189251Ssam    /* copy of the digit from a used within the nested loop */
2374189251Ssam    tmpx = a->dp[ix];
2375189251Ssam
2376189251Ssam    /* an alias for the destination shifted ix places */
2377189251Ssam    tmpt = t.dp + ix;
2378189251Ssam
2379189251Ssam    /* an alias for the digits of b */
2380189251Ssam    tmpy = b->dp;
2381189251Ssam
2382189251Ssam    /* compute the columns of the output and propagate the carry */
2383189251Ssam    for (iy = 0; iy < pb; iy++) {
2384189251Ssam      /* compute the column as a mp_word */
2385189251Ssam      r       = ((mp_word)*tmpt) +
2386189251Ssam                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
2387189251Ssam                ((mp_word) u);
2388189251Ssam
2389189251Ssam      /* the new column is the lower part of the result */
2390189251Ssam      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
2391189251Ssam
2392189251Ssam      /* get the carry word from the result */
2393189251Ssam      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
2394189251Ssam    }
2395189251Ssam    /* set carry if it is placed below digs */
2396189251Ssam    if (ix + iy < digs) {
2397189251Ssam      *tmpt = u;
2398189251Ssam    }
2399189251Ssam  }
2400189251Ssam
2401189251Ssam  mp_clamp (&t);
2402189251Ssam  mp_exch (&t, c);
2403189251Ssam
2404189251Ssam  mp_clear (&t);
2405189251Ssam  return MP_OKAY;
2406189251Ssam}
2407189251Ssam
2408189251Ssam
2409281806Srpaulo#ifdef BN_FAST_S_MP_MUL_DIGS_C
2410189251Ssam/* Fast (comba) multiplier
2411189251Ssam *
2412189251Ssam * This is the fast column-array [comba] multiplier.  It is
2413189251Ssam * designed to compute the columns of the product first
2414189251Ssam * then handle the carries afterwards.  This has the effect
2415189251Ssam * of making the nested loops that compute the columns very
2416189251Ssam * simple and schedulable on super-scalar processors.
2417189251Ssam *
2418189251Ssam * This has been modified to produce a variable number of
2419189251Ssam * digits of output so if say only a half-product is required
2420189251Ssam * you don't have to compute the upper half (a feature
2421189251Ssam * required for fast Barrett reduction).
2422189251Ssam *
2423189251Ssam * Based on Algorithm 14.12 on pp.595 of HAC.
2424189251Ssam *
2425189251Ssam */
2426189251Ssamstatic int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
2427189251Ssam{
2428189251Ssam  int     olduse, res, pa, ix, iz;
2429189251Ssam  mp_digit W[MP_WARRAY];
2430189251Ssam  register mp_word  _W;
2431189251Ssam
2432189251Ssam  /* grow the destination as required */
2433189251Ssam  if (c->alloc < digs) {
2434189251Ssam    if ((res = mp_grow (c, digs)) != MP_OKAY) {
2435189251Ssam      return res;
2436189251Ssam    }
2437189251Ssam  }
2438189251Ssam
2439189251Ssam  /* number of output digits to produce */
2440189251Ssam  pa = MIN(digs, a->used + b->used);
2441189251Ssam
2442189251Ssam  /* clear the carry */
2443189251Ssam  _W = 0;
2444189251Ssam  for (ix = 0; ix < pa; ix++) {
2445189251Ssam      int      tx, ty;
2446189251Ssam      int      iy;
2447189251Ssam      mp_digit *tmpx, *tmpy;
2448189251Ssam
2449189251Ssam      /* get offsets into the two bignums */
2450189251Ssam      ty = MIN(b->used-1, ix);
2451189251Ssam      tx = ix - ty;
2452189251Ssam
2453189251Ssam      /* setup temp aliases */
2454189251Ssam      tmpx = a->dp + tx;
2455189251Ssam      tmpy = b->dp + ty;
2456189251Ssam
2457189251Ssam      /* this is the number of times the loop will iterrate, essentially
2458189251Ssam         while (tx++ < a->used && ty-- >= 0) { ... }
2459189251Ssam       */
2460189251Ssam      iy = MIN(a->used-tx, ty+1);
2461189251Ssam
2462189251Ssam      /* execute loop */
2463189251Ssam      for (iz = 0; iz < iy; ++iz) {
2464189251Ssam         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
2465189251Ssam
2466189251Ssam      }
2467189251Ssam
2468189251Ssam      /* store term */
2469189251Ssam      W[ix] = ((mp_digit)_W) & MP_MASK;
2470189251Ssam
2471189251Ssam      /* make next carry */
2472189251Ssam      _W = _W >> ((mp_word)DIGIT_BIT);
2473189251Ssam }
2474189251Ssam
2475189251Ssam  /* setup dest */
2476189251Ssam  olduse  = c->used;
2477189251Ssam  c->used = pa;
2478189251Ssam
2479189251Ssam  {
2480189251Ssam    register mp_digit *tmpc;
2481189251Ssam    tmpc = c->dp;
2482189251Ssam    for (ix = 0; ix < pa+1; ix++) {
2483189251Ssam      /* now extract the previous digit [below the carry] */
2484189251Ssam      *tmpc++ = W[ix];
2485189251Ssam    }
2486189251Ssam
2487189251Ssam    /* clear unused digits [that existed in the old copy of c] */
2488189251Ssam    for (; ix < olduse; ix++) {
2489189251Ssam      *tmpc++ = 0;
2490189251Ssam    }
2491189251Ssam  }
2492189251Ssam  mp_clamp (c);
2493189251Ssam  return MP_OKAY;
2494189251Ssam}
2495281806Srpaulo#endif /* BN_FAST_S_MP_MUL_DIGS_C */
2496189251Ssam
2497189251Ssam
2498189251Ssam/* init an mp_init for a given size */
2499189251Ssamstatic int mp_init_size (mp_int * a, int size)
2500189251Ssam{
2501189251Ssam  int x;
2502189251Ssam
2503189251Ssam  /* pad size so there are always extra digits */
2504189251Ssam  size += (MP_PREC * 2) - (size % MP_PREC);
2505189251Ssam
2506189251Ssam  /* alloc mem */
2507189251Ssam  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
2508189251Ssam  if (a->dp == NULL) {
2509189251Ssam    return MP_MEM;
2510189251Ssam  }
2511189251Ssam
2512189251Ssam  /* set the members */
2513189251Ssam  a->used  = 0;
2514189251Ssam  a->alloc = size;
2515189251Ssam  a->sign  = MP_ZPOS;
2516189251Ssam
2517189251Ssam  /* zero the digits */
2518189251Ssam  for (x = 0; x < size; x++) {
2519189251Ssam      a->dp[x] = 0;
2520189251Ssam  }
2521189251Ssam
2522189251Ssam  return MP_OKAY;
2523189251Ssam}
2524189251Ssam
2525189251Ssam
2526189251Ssam/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
2527189251Ssamstatic int s_mp_sqr (mp_int * a, mp_int * b)
2528189251Ssam{
2529189251Ssam  mp_int  t;
2530189251Ssam  int     res, ix, iy, pa;
2531189251Ssam  mp_word r;
2532189251Ssam  mp_digit u, tmpx, *tmpt;
2533189251Ssam
2534189251Ssam  pa = a->used;
2535189251Ssam  if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
2536189251Ssam    return res;
2537189251Ssam  }
2538189251Ssam
2539189251Ssam  /* default used is maximum possible size */
2540189251Ssam  t.used = 2*pa + 1;
2541189251Ssam
2542189251Ssam  for (ix = 0; ix < pa; ix++) {
2543189251Ssam    /* first calculate the digit at 2*ix */
2544189251Ssam    /* calculate double precision result */
2545189251Ssam    r = ((mp_word) t.dp[2*ix]) +
2546189251Ssam        ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
2547189251Ssam
2548189251Ssam    /* store lower part in result */
2549189251Ssam    t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
2550189251Ssam
2551189251Ssam    /* get the carry */
2552189251Ssam    u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
2553189251Ssam
2554189251Ssam    /* left hand side of A[ix] * A[iy] */
2555189251Ssam    tmpx        = a->dp[ix];
2556189251Ssam
2557189251Ssam    /* alias for where to store the results */
2558189251Ssam    tmpt        = t.dp + (2*ix + 1);
2559189251Ssam
2560189251Ssam    for (iy = ix + 1; iy < pa; iy++) {
2561189251Ssam      /* first calculate the product */
2562189251Ssam      r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
2563189251Ssam
2564189251Ssam      /* now calculate the double precision result, note we use
2565189251Ssam       * addition instead of *2 since it's easier to optimize
2566189251Ssam       */
2567189251Ssam      r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
2568189251Ssam
2569189251Ssam      /* store lower part */
2570189251Ssam      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
2571189251Ssam
2572189251Ssam      /* get carry */
2573189251Ssam      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
2574189251Ssam    }
2575189251Ssam    /* propagate upwards */
2576189251Ssam    while (u != ((mp_digit) 0)) {
2577189251Ssam      r       = ((mp_word) *tmpt) + ((mp_word) u);
2578189251Ssam      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
2579189251Ssam      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
2580189251Ssam    }
2581189251Ssam  }
2582189251Ssam
2583189251Ssam  mp_clamp (&t);
2584189251Ssam  mp_exch (&t, b);
2585189251Ssam  mp_clear (&t);
2586189251Ssam  return MP_OKAY;
2587189251Ssam}
2588189251Ssam
2589189251Ssam
2590189251Ssam/* multiplies |a| * |b| and does not compute the lower digs digits
2591189251Ssam * [meant to get the higher part of the product]
2592189251Ssam */
2593189251Ssamstatic int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
2594189251Ssam{
2595189251Ssam  mp_int  t;
2596189251Ssam  int     res, pa, pb, ix, iy;
2597189251Ssam  mp_digit u;
2598189251Ssam  mp_word r;
2599189251Ssam  mp_digit tmpx, *tmpt, *tmpy;
2600189251Ssam
2601189251Ssam  /* can we use the fast multiplier? */
2602189251Ssam#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
2603189251Ssam  if (((a->used + b->used + 1) < MP_WARRAY)
2604189251Ssam      && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
2605189251Ssam    return fast_s_mp_mul_high_digs (a, b, c, digs);
2606189251Ssam  }
2607189251Ssam#endif
2608189251Ssam
2609189251Ssam  if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
2610189251Ssam    return res;
2611189251Ssam  }
2612189251Ssam  t.used = a->used + b->used + 1;
2613189251Ssam
2614189251Ssam  pa = a->used;
2615189251Ssam  pb = b->used;
2616189251Ssam  for (ix = 0; ix < pa; ix++) {
2617189251Ssam    /* clear the carry */
2618189251Ssam    u = 0;
2619189251Ssam
2620189251Ssam    /* left hand side of A[ix] * B[iy] */
2621189251Ssam    tmpx = a->dp[ix];
2622189251Ssam
2623189251Ssam    /* alias to the address of where the digits will be stored */
2624189251Ssam    tmpt = &(t.dp[digs]);
2625189251Ssam
2626189251Ssam    /* alias for where to read the right hand side from */
2627189251Ssam    tmpy = b->dp + (digs - ix);
2628189251Ssam
2629189251Ssam    for (iy = digs - ix; iy < pb; iy++) {
2630189251Ssam      /* calculate the double precision result */
2631189251Ssam      r       = ((mp_word)*tmpt) +
2632189251Ssam                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
2633189251Ssam                ((mp_word) u);
2634189251Ssam
2635189251Ssam      /* get the lower part */
2636189251Ssam      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
2637189251Ssam
2638189251Ssam      /* carry the carry */
2639189251Ssam      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
2640189251Ssam    }
2641189251Ssam    *tmpt = u;
2642189251Ssam  }
2643189251Ssam  mp_clamp (&t);
2644189251Ssam  mp_exch (&t, c);
2645189251Ssam  mp_clear (&t);
2646189251Ssam  return MP_OKAY;
2647189251Ssam}
2648189251Ssam
2649189251Ssam
2650189251Ssam#ifdef BN_MP_MONTGOMERY_SETUP_C
2651189251Ssam/* setups the montgomery reduction stuff */
2652189251Ssamstatic int
2653189251Ssammp_montgomery_setup (mp_int * n, mp_digit * rho)
2654189251Ssam{
2655189251Ssam  mp_digit x, b;
2656189251Ssam
2657189251Ssam/* fast inversion mod 2**k
2658189251Ssam *
2659189251Ssam * Based on the fact that
2660189251Ssam *
2661189251Ssam * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
2662189251Ssam *                    =>  2*X*A - X*X*A*A = 1
2663189251Ssam *                    =>  2*(1) - (1)     = 1
2664189251Ssam */
2665189251Ssam  b = n->dp[0];
2666189251Ssam
2667189251Ssam  if ((b & 1) == 0) {
2668189251Ssam    return MP_VAL;
2669189251Ssam  }
2670189251Ssam
2671189251Ssam  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
2672189251Ssam  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
2673189251Ssam#if !defined(MP_8BIT)
2674189251Ssam  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
2675189251Ssam#endif
2676189251Ssam#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
2677189251Ssam  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
2678189251Ssam#endif
2679189251Ssam#ifdef MP_64BIT
2680189251Ssam  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
2681189251Ssam#endif
2682189251Ssam
2683189251Ssam  /* rho = -1/m mod b */
2684189251Ssam  *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
2685189251Ssam
2686189251Ssam  return MP_OKAY;
2687189251Ssam}
2688189251Ssam#endif
2689189251Ssam
2690189251Ssam
2691189251Ssam#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
2692189251Ssam/* computes xR**-1 == x (mod N) via Montgomery Reduction
2693189251Ssam *
2694189251Ssam * This is an optimized implementation of montgomery_reduce
2695189251Ssam * which uses the comba method to quickly calculate the columns of the
2696189251Ssam * reduction.
2697189251Ssam *
2698189251Ssam * Based on Algorithm 14.32 on pp.601 of HAC.
2699189251Ssam*/
2700252726Srpaulostatic int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
2701189251Ssam{
2702189251Ssam  int     ix, res, olduse;
2703189251Ssam  mp_word W[MP_WARRAY];
2704189251Ssam
2705189251Ssam  /* get old used count */
2706189251Ssam  olduse = x->used;
2707189251Ssam
2708189251Ssam  /* grow a as required */
2709189251Ssam  if (x->alloc < n->used + 1) {
2710189251Ssam    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
2711189251Ssam      return res;
2712189251Ssam    }
2713189251Ssam  }
2714189251Ssam
2715189251Ssam  /* first we have to get the digits of the input into
2716189251Ssam   * an array of double precision words W[...]
2717189251Ssam   */
2718189251Ssam  {
2719189251Ssam    register mp_word *_W;
2720189251Ssam    register mp_digit *tmpx;
2721189251Ssam
2722189251Ssam    /* alias for the W[] array */
2723189251Ssam    _W   = W;
2724189251Ssam
2725189251Ssam    /* alias for the digits of  x*/
2726189251Ssam    tmpx = x->dp;
2727189251Ssam
2728189251Ssam    /* copy the digits of a into W[0..a->used-1] */
2729189251Ssam    for (ix = 0; ix < x->used; ix++) {
2730189251Ssam      *_W++ = *tmpx++;
2731189251Ssam    }
2732189251Ssam
2733189251Ssam    /* zero the high words of W[a->used..m->used*2] */
2734189251Ssam    for (; ix < n->used * 2 + 1; ix++) {
2735189251Ssam      *_W++ = 0;
2736189251Ssam    }
2737189251Ssam  }
2738189251Ssam
2739189251Ssam  /* now we proceed to zero successive digits
2740189251Ssam   * from the least significant upwards
2741189251Ssam   */
2742189251Ssam  for (ix = 0; ix < n->used; ix++) {
2743189251Ssam    /* mu = ai * m' mod b
2744189251Ssam     *
2745189251Ssam     * We avoid a double precision multiplication (which isn't required)
2746189251Ssam     * by casting the value down to a mp_digit.  Note this requires
2747189251Ssam     * that W[ix-1] have  the carry cleared (see after the inner loop)
2748189251Ssam     */
2749189251Ssam    register mp_digit mu;
2750189251Ssam    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
2751189251Ssam
2752189251Ssam    /* a = a + mu * m * b**i
2753189251Ssam     *
2754189251Ssam     * This is computed in place and on the fly.  The multiplication
2755189251Ssam     * by b**i is handled by offseting which columns the results
2756189251Ssam     * are added to.
2757189251Ssam     *
2758189251Ssam     * Note the comba method normally doesn't handle carries in the
2759189251Ssam     * inner loop In this case we fix the carry from the previous
2760189251Ssam     * column since the Montgomery reduction requires digits of the
2761189251Ssam     * result (so far) [see above] to work.  This is
2762189251Ssam     * handled by fixing up one carry after the inner loop.  The
2763189251Ssam     * carry fixups are done in order so after these loops the
2764189251Ssam     * first m->used words of W[] have the carries fixed
2765189251Ssam     */
2766189251Ssam    {
2767189251Ssam      register int iy;
2768189251Ssam      register mp_digit *tmpn;
2769189251Ssam      register mp_word *_W;
2770189251Ssam
2771189251Ssam      /* alias for the digits of the modulus */
2772189251Ssam      tmpn = n->dp;
2773189251Ssam
2774189251Ssam      /* Alias for the columns set by an offset of ix */
2775189251Ssam      _W = W + ix;
2776189251Ssam
2777189251Ssam      /* inner loop */
2778189251Ssam      for (iy = 0; iy < n->used; iy++) {
2779189251Ssam          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
2780189251Ssam      }
2781189251Ssam    }
2782189251Ssam
2783189251Ssam    /* now fix carry for next digit, W[ix+1] */
2784189251Ssam    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
2785189251Ssam  }
2786189251Ssam
2787189251Ssam  /* now we have to propagate the carries and
2788189251Ssam   * shift the words downward [all those least
2789189251Ssam   * significant digits we zeroed].
2790189251Ssam   */
2791189251Ssam  {
2792189251Ssam    register mp_digit *tmpx;
2793189251Ssam    register mp_word *_W, *_W1;
2794189251Ssam
2795189251Ssam    /* nox fix rest of carries */
2796189251Ssam
2797189251Ssam    /* alias for current word */
2798189251Ssam    _W1 = W + ix;
2799189251Ssam
2800189251Ssam    /* alias for next word, where the carry goes */
2801189251Ssam    _W = W + ++ix;
2802189251Ssam
2803189251Ssam    for (; ix <= n->used * 2 + 1; ix++) {
2804189251Ssam      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
2805189251Ssam    }
2806189251Ssam
2807189251Ssam    /* copy out, A = A/b**n
2808189251Ssam     *
2809189251Ssam     * The result is A/b**n but instead of converting from an
2810189251Ssam     * array of mp_word to mp_digit than calling mp_rshd
2811189251Ssam     * we just copy them in the right order
2812189251Ssam     */
2813189251Ssam
2814189251Ssam    /* alias for destination word */
2815189251Ssam    tmpx = x->dp;
2816189251Ssam
2817189251Ssam    /* alias for shifted double precision result */
2818189251Ssam    _W = W + n->used;
2819189251Ssam
2820189251Ssam    for (ix = 0; ix < n->used + 1; ix++) {
2821189251Ssam      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
2822189251Ssam    }
2823189251Ssam
2824189251Ssam    /* zero oldused digits, if the input a was larger than
2825189251Ssam     * m->used+1 we'll have to clear the digits
2826189251Ssam     */
2827189251Ssam    for (; ix < olduse; ix++) {
2828189251Ssam      *tmpx++ = 0;
2829189251Ssam    }
2830189251Ssam  }
2831189251Ssam
2832189251Ssam  /* set the max used and clamp */
2833189251Ssam  x->used = n->used + 1;
2834189251Ssam  mp_clamp (x);
2835189251Ssam
2836189251Ssam  /* if A >= m then A = A - m */
2837189251Ssam  if (mp_cmp_mag (x, n) != MP_LT) {
2838189251Ssam    return s_mp_sub (x, n, x);
2839189251Ssam  }
2840189251Ssam  return MP_OKAY;
2841189251Ssam}
2842189251Ssam#endif
2843189251Ssam
2844189251Ssam
2845189251Ssam#ifdef BN_MP_MUL_2_C
2846189251Ssam/* b = a*2 */
2847189251Ssamstatic int mp_mul_2(mp_int * a, mp_int * b)
2848189251Ssam{
2849189251Ssam  int     x, res, oldused;
2850189251Ssam
2851252726Srpaulo  /* grow to accommodate result */
2852189251Ssam  if (b->alloc < a->used + 1) {
2853189251Ssam    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
2854189251Ssam      return res;
2855189251Ssam    }
2856189251Ssam  }
2857189251Ssam
2858189251Ssam  oldused = b->used;
2859189251Ssam  b->used = a->used;
2860189251Ssam
2861189251Ssam  {
2862189251Ssam    register mp_digit r, rr, *tmpa, *tmpb;
2863189251Ssam
2864189251Ssam    /* alias for source */
2865189251Ssam    tmpa = a->dp;
2866189251Ssam
2867189251Ssam    /* alias for dest */
2868189251Ssam    tmpb = b->dp;
2869189251Ssam
2870189251Ssam    /* carry */
2871189251Ssam    r = 0;
2872189251Ssam    for (x = 0; x < a->used; x++) {
2873189251Ssam
2874189251Ssam      /* get what will be the *next* carry bit from the
2875189251Ssam       * MSB of the current digit
2876189251Ssam       */
2877189251Ssam      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
2878189251Ssam
2879189251Ssam      /* now shift up this digit, add in the carry [from the previous] */
2880189251Ssam      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
2881189251Ssam
2882189251Ssam      /* copy the carry that would be from the source
2883189251Ssam       * digit into the next iteration
2884189251Ssam       */
2885189251Ssam      r = rr;
2886189251Ssam    }
2887189251Ssam
2888189251Ssam    /* new leading digit? */
2889189251Ssam    if (r != 0) {
2890189251Ssam      /* add a MSB which is always 1 at this point */
2891189251Ssam      *tmpb = 1;
2892189251Ssam      ++(b->used);
2893189251Ssam    }
2894189251Ssam
2895189251Ssam    /* now zero any excess digits on the destination
2896189251Ssam     * that we didn't write to
2897189251Ssam     */
2898189251Ssam    tmpb = b->dp + b->used;
2899189251Ssam    for (x = b->used; x < oldused; x++) {
2900189251Ssam      *tmpb++ = 0;
2901189251Ssam    }
2902189251Ssam  }
2903189251Ssam  b->sign = a->sign;
2904189251Ssam  return MP_OKAY;
2905189251Ssam}
2906189251Ssam#endif
2907189251Ssam
2908189251Ssam
2909189251Ssam#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
2910189251Ssam/*
2911189251Ssam * shifts with subtractions when the result is greater than b.
2912189251Ssam *
2913252726Srpaulo * The method is slightly modified to shift B unconditionally up to just under
2914252726Srpaulo * the leading bit of b.  This saves a lot of multiple precision shifting.
2915189251Ssam */
2916189251Ssamstatic int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
2917189251Ssam{
2918189251Ssam  int     x, bits, res;
2919189251Ssam
2920189251Ssam  /* how many bits of last digit does b use */
2921189251Ssam  bits = mp_count_bits (b) % DIGIT_BIT;
2922189251Ssam
2923189251Ssam  if (b->used > 1) {
2924189251Ssam     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
2925189251Ssam        return res;
2926189251Ssam     }
2927189251Ssam  } else {
2928189251Ssam     mp_set(a, 1);
2929189251Ssam     bits = 1;
2930189251Ssam  }
2931189251Ssam
2932189251Ssam
2933189251Ssam  /* now compute C = A * B mod b */
2934189251Ssam  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
2935189251Ssam    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
2936189251Ssam      return res;
2937189251Ssam    }
2938189251Ssam    if (mp_cmp_mag (a, b) != MP_LT) {
2939189251Ssam      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
2940189251Ssam        return res;
2941189251Ssam      }
2942189251Ssam    }
2943189251Ssam  }
2944189251Ssam
2945189251Ssam  return MP_OKAY;
2946189251Ssam}
2947189251Ssam#endif
2948189251Ssam
2949189251Ssam
2950189251Ssam#ifdef BN_MP_EXPTMOD_FAST_C
2951189251Ssam/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
2952189251Ssam *
2953189251Ssam * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
2954189251Ssam * The value of k changes based on the size of the exponent.
2955189251Ssam *
2956189251Ssam * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
2957189251Ssam */
2958189251Ssam
2959189251Ssamstatic int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
2960189251Ssam{
2961189251Ssam  mp_int  M[TAB_SIZE], res;
2962189251Ssam  mp_digit buf, mp;
2963189251Ssam  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
2964189251Ssam
2965189251Ssam  /* use a pointer to the reduction algorithm.  This allows us to use
2966189251Ssam   * one of many reduction algorithms without modding the guts of
2967189251Ssam   * the code with if statements everywhere.
2968189251Ssam   */
2969189251Ssam  int     (*redux)(mp_int*,mp_int*,mp_digit);
2970189251Ssam
2971189251Ssam  /* find window size */
2972189251Ssam  x = mp_count_bits (X);
2973189251Ssam  if (x <= 7) {
2974189251Ssam    winsize = 2;
2975189251Ssam  } else if (x <= 36) {
2976189251Ssam    winsize = 3;
2977189251Ssam  } else if (x <= 140) {
2978189251Ssam    winsize = 4;
2979189251Ssam  } else if (x <= 450) {
2980189251Ssam    winsize = 5;
2981189251Ssam  } else if (x <= 1303) {
2982189251Ssam    winsize = 6;
2983189251Ssam  } else if (x <= 3529) {
2984189251Ssam    winsize = 7;
2985189251Ssam  } else {
2986189251Ssam    winsize = 8;
2987189251Ssam  }
2988189251Ssam
2989189251Ssam#ifdef MP_LOW_MEM
2990189251Ssam  if (winsize > 5) {
2991189251Ssam     winsize = 5;
2992189251Ssam  }
2993189251Ssam#endif
2994189251Ssam
2995189251Ssam  /* init M array */
2996189251Ssam  /* init first cell */
2997189251Ssam  if ((err = mp_init(&M[1])) != MP_OKAY) {
2998189251Ssam     return err;
2999189251Ssam  }
3000189251Ssam
3001189251Ssam  /* now init the second half of the array */
3002189251Ssam  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
3003189251Ssam    if ((err = mp_init(&M[x])) != MP_OKAY) {
3004189251Ssam      for (y = 1<<(winsize-1); y < x; y++) {
3005189251Ssam        mp_clear (&M[y]);
3006189251Ssam      }
3007189251Ssam      mp_clear(&M[1]);
3008189251Ssam      return err;
3009189251Ssam    }
3010189251Ssam  }
3011189251Ssam
3012189251Ssam  /* determine and setup reduction code */
3013189251Ssam  if (redmode == 0) {
3014189251Ssam#ifdef BN_MP_MONTGOMERY_SETUP_C
3015189251Ssam     /* now setup montgomery  */
3016189251Ssam     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
3017189251Ssam        goto LBL_M;
3018189251Ssam     }
3019189251Ssam#else
3020189251Ssam     err = MP_VAL;
3021189251Ssam     goto LBL_M;
3022189251Ssam#endif
3023189251Ssam
3024189251Ssam     /* automatically pick the comba one if available (saves quite a few calls/ifs) */
3025189251Ssam#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
3026189251Ssam     if (((P->used * 2 + 1) < MP_WARRAY) &&
3027189251Ssam          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
3028189251Ssam        redux = fast_mp_montgomery_reduce;
3029189251Ssam     } else
3030189251Ssam#endif
3031189251Ssam     {
3032189251Ssam#ifdef BN_MP_MONTGOMERY_REDUCE_C
3033189251Ssam        /* use slower baseline Montgomery method */
3034189251Ssam        redux = mp_montgomery_reduce;
3035189251Ssam#else
3036189251Ssam        err = MP_VAL;
3037189251Ssam        goto LBL_M;
3038189251Ssam#endif
3039189251Ssam     }
3040189251Ssam  } else if (redmode == 1) {
3041189251Ssam#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
3042189251Ssam     /* setup DR reduction for moduli of the form B**k - b */
3043189251Ssam     mp_dr_setup(P, &mp);
3044189251Ssam     redux = mp_dr_reduce;
3045189251Ssam#else
3046189251Ssam     err = MP_VAL;
3047189251Ssam     goto LBL_M;
3048189251Ssam#endif
3049189251Ssam  } else {
3050189251Ssam#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
3051189251Ssam     /* setup DR reduction for moduli of the form 2**k - b */
3052189251Ssam     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
3053189251Ssam        goto LBL_M;
3054189251Ssam     }
3055189251Ssam     redux = mp_reduce_2k;
3056189251Ssam#else
3057189251Ssam     err = MP_VAL;
3058189251Ssam     goto LBL_M;
3059189251Ssam#endif
3060189251Ssam  }
3061189251Ssam
3062189251Ssam  /* setup result */
3063189251Ssam  if ((err = mp_init (&res)) != MP_OKAY) {
3064189251Ssam    goto LBL_M;
3065189251Ssam  }
3066189251Ssam
3067189251Ssam  /* create M table
3068189251Ssam   *
3069189251Ssam
3070189251Ssam   *
3071189251Ssam   * The first half of the table is not computed though accept for M[0] and M[1]
3072189251Ssam   */
3073189251Ssam
3074189251Ssam  if (redmode == 0) {
3075189251Ssam#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
3076189251Ssam     /* now we need R mod m */
3077189251Ssam     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
3078189251Ssam       goto LBL_RES;
3079189251Ssam     }
3080189251Ssam#else
3081189251Ssam     err = MP_VAL;
3082189251Ssam     goto LBL_RES;
3083189251Ssam#endif
3084189251Ssam
3085189251Ssam     /* now set M[1] to G * R mod m */
3086189251Ssam     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
3087189251Ssam       goto LBL_RES;
3088189251Ssam     }
3089189251Ssam  } else {
3090189251Ssam     mp_set(&res, 1);
3091189251Ssam     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
3092189251Ssam        goto LBL_RES;
3093189251Ssam     }
3094189251Ssam  }
3095189251Ssam
3096189251Ssam  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
3097189251Ssam  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
3098189251Ssam    goto LBL_RES;
3099189251Ssam  }
3100189251Ssam
3101189251Ssam  for (x = 0; x < (winsize - 1); x++) {
3102189251Ssam    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
3103189251Ssam      goto LBL_RES;
3104189251Ssam    }
3105189251Ssam    if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
3106189251Ssam      goto LBL_RES;
3107189251Ssam    }
3108189251Ssam  }
3109189251Ssam
3110189251Ssam  /* create upper table */
3111189251Ssam  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
3112189251Ssam    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
3113189251Ssam      goto LBL_RES;
3114189251Ssam    }
3115189251Ssam    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
3116189251Ssam      goto LBL_RES;
3117189251Ssam    }
3118189251Ssam  }
3119189251Ssam
3120189251Ssam  /* set initial mode and bit cnt */
3121189251Ssam  mode   = 0;
3122189251Ssam  bitcnt = 1;
3123189251Ssam  buf    = 0;
3124189251Ssam  digidx = X->used - 1;
3125189251Ssam  bitcpy = 0;
3126189251Ssam  bitbuf = 0;
3127189251Ssam
3128189251Ssam  for (;;) {
3129189251Ssam    /* grab next digit as required */
3130189251Ssam    if (--bitcnt == 0) {
3131189251Ssam      /* if digidx == -1 we are out of digits so break */
3132189251Ssam      if (digidx == -1) {
3133189251Ssam        break;
3134189251Ssam      }
3135189251Ssam      /* read next digit and reset bitcnt */
3136189251Ssam      buf    = X->dp[digidx--];
3137189251Ssam      bitcnt = (int)DIGIT_BIT;
3138189251Ssam    }
3139189251Ssam
3140189251Ssam    /* grab the next msb from the exponent */
3141189251Ssam    y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
3142189251Ssam    buf <<= (mp_digit)1;
3143189251Ssam
3144189251Ssam    /* if the bit is zero and mode == 0 then we ignore it
3145189251Ssam     * These represent the leading zero bits before the first 1 bit
3146189251Ssam     * in the exponent.  Technically this opt is not required but it
3147189251Ssam     * does lower the # of trivial squaring/reductions used
3148189251Ssam     */
3149189251Ssam    if (mode == 0 && y == 0) {
3150189251Ssam      continue;
3151189251Ssam    }
3152189251Ssam
3153189251Ssam    /* if the bit is zero and mode == 1 then we square */
3154189251Ssam    if (mode == 1 && y == 0) {
3155189251Ssam      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
3156189251Ssam        goto LBL_RES;
3157189251Ssam      }
3158189251Ssam      if ((err = redux (&res, P, mp)) != MP_OKAY) {
3159189251Ssam        goto LBL_RES;
3160189251Ssam      }
3161189251Ssam      continue;
3162189251Ssam    }
3163189251Ssam
3164189251Ssam    /* else we add it to the window */
3165189251Ssam    bitbuf |= (y << (winsize - ++bitcpy));
3166189251Ssam    mode    = 2;
3167189251Ssam
3168189251Ssam    if (bitcpy == winsize) {
3169189251Ssam      /* ok window is filled so square as required and multiply  */
3170189251Ssam      /* square first */
3171189251Ssam      for (x = 0; x < winsize; x++) {
3172189251Ssam        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
3173189251Ssam          goto LBL_RES;
3174189251Ssam        }
3175189251Ssam        if ((err = redux (&res, P, mp)) != MP_OKAY) {
3176189251Ssam          goto LBL_RES;
3177189251Ssam        }
3178189251Ssam      }
3179189251Ssam
3180189251Ssam      /* then multiply */
3181189251Ssam      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
3182189251Ssam        goto LBL_RES;
3183189251Ssam      }
3184189251Ssam      if ((err = redux (&res, P, mp)) != MP_OKAY) {
3185189251Ssam        goto LBL_RES;
3186189251Ssam      }
3187189251Ssam
3188189251Ssam      /* empty window and reset */
3189189251Ssam      bitcpy = 0;
3190189251Ssam      bitbuf = 0;
3191189251Ssam      mode   = 1;
3192189251Ssam    }
3193189251Ssam  }
3194189251Ssam
3195189251Ssam  /* if bits remain then square/multiply */
3196189251Ssam  if (mode == 2 && bitcpy > 0) {
3197189251Ssam    /* square then multiply if the bit is set */
3198189251Ssam    for (x = 0; x < bitcpy; x++) {
3199189251Ssam      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
3200189251Ssam        goto LBL_RES;
3201189251Ssam      }
3202189251Ssam      if ((err = redux (&res, P, mp)) != MP_OKAY) {
3203189251Ssam        goto LBL_RES;
3204189251Ssam      }
3205189251Ssam
3206189251Ssam      /* get next bit of the window */
3207189251Ssam      bitbuf <<= 1;
3208189251Ssam      if ((bitbuf & (1 << winsize)) != 0) {
3209189251Ssam        /* then multiply */
3210189251Ssam        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
3211189251Ssam          goto LBL_RES;
3212189251Ssam        }
3213189251Ssam        if ((err = redux (&res, P, mp)) != MP_OKAY) {
3214189251Ssam          goto LBL_RES;
3215189251Ssam        }
3216189251Ssam      }
3217189251Ssam    }
3218189251Ssam  }
3219189251Ssam
3220189251Ssam  if (redmode == 0) {
3221189251Ssam     /* fixup result if Montgomery reduction is used
3222189251Ssam      * recall that any value in a Montgomery system is
3223189251Ssam      * actually multiplied by R mod n.  So we have
3224189251Ssam      * to reduce one more time to cancel out the factor
3225189251Ssam      * of R.
3226189251Ssam      */
3227189251Ssam     if ((err = redux(&res, P, mp)) != MP_OKAY) {
3228189251Ssam       goto LBL_RES;
3229189251Ssam     }
3230189251Ssam  }
3231189251Ssam
3232189251Ssam  /* swap res with Y */
3233189251Ssam  mp_exch (&res, Y);
3234189251Ssam  err = MP_OKAY;
3235189251SsamLBL_RES:mp_clear (&res);
3236189251SsamLBL_M:
3237189251Ssam  mp_clear(&M[1]);
3238189251Ssam  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
3239189251Ssam    mp_clear (&M[x]);
3240189251Ssam  }
3241189251Ssam  return err;
3242189251Ssam}
3243189251Ssam#endif
3244189251Ssam
3245189251Ssam
3246189251Ssam#ifdef BN_FAST_S_MP_SQR_C
3247189251Ssam/* the jist of squaring...
3248189251Ssam * you do like mult except the offset of the tmpx [one that
3249189251Ssam * starts closer to zero] can't equal the offset of tmpy.
3250189251Ssam * So basically you set up iy like before then you min it with
3251189251Ssam * (ty-tx) so that it never happens.  You double all those
3252189251Ssam * you add in the inner loop
3253189251Ssam
3254189251SsamAfter that loop you do the squares and add them in.
3255189251Ssam*/
3256189251Ssam
3257189251Ssamstatic int fast_s_mp_sqr (mp_int * a, mp_int * b)
3258189251Ssam{
3259189251Ssam  int       olduse, res, pa, ix, iz;
3260189251Ssam  mp_digit   W[MP_WARRAY], *tmpx;
3261189251Ssam  mp_word   W1;
3262189251Ssam
3263189251Ssam  /* grow the destination as required */
3264189251Ssam  pa = a->used + a->used;
3265189251Ssam  if (b->alloc < pa) {
3266189251Ssam    if ((res = mp_grow (b, pa)) != MP_OKAY) {
3267189251Ssam      return res;
3268189251Ssam    }
3269189251Ssam  }
3270189251Ssam
3271189251Ssam  /* number of output digits to produce */
3272189251Ssam  W1 = 0;
3273189251Ssam  for (ix = 0; ix < pa; ix++) {
3274189251Ssam      int      tx, ty, iy;
3275189251Ssam      mp_word  _W;
3276189251Ssam      mp_digit *tmpy;
3277189251Ssam
3278189251Ssam      /* clear counter */
3279189251Ssam      _W = 0;
3280189251Ssam
3281189251Ssam      /* get offsets into the two bignums */
3282189251Ssam      ty = MIN(a->used-1, ix);
3283189251Ssam      tx = ix - ty;
3284189251Ssam
3285189251Ssam      /* setup temp aliases */
3286189251Ssam      tmpx = a->dp + tx;
3287189251Ssam      tmpy = a->dp + ty;
3288189251Ssam
3289189251Ssam      /* this is the number of times the loop will iterrate, essentially
3290189251Ssam         while (tx++ < a->used && ty-- >= 0) { ... }
3291189251Ssam       */
3292189251Ssam      iy = MIN(a->used-tx, ty+1);
3293189251Ssam
3294189251Ssam      /* now for squaring tx can never equal ty
3295189251Ssam       * we halve the distance since they approach at a rate of 2x
3296189251Ssam       * and we have to round because odd cases need to be executed
3297189251Ssam       */
3298189251Ssam      iy = MIN(iy, (ty-tx+1)>>1);
3299189251Ssam
3300189251Ssam      /* execute loop */
3301189251Ssam      for (iz = 0; iz < iy; iz++) {
3302189251Ssam         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
3303189251Ssam      }
3304189251Ssam
3305189251Ssam      /* double the inner product and add carry */
3306189251Ssam      _W = _W + _W + W1;
3307189251Ssam
3308189251Ssam      /* even columns have the square term in them */
3309189251Ssam      if ((ix&1) == 0) {
3310189251Ssam         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
3311189251Ssam      }
3312189251Ssam
3313189251Ssam      /* store it */
3314189251Ssam      W[ix] = (mp_digit)(_W & MP_MASK);
3315189251Ssam
3316189251Ssam      /* make next carry */
3317189251Ssam      W1 = _W >> ((mp_word)DIGIT_BIT);
3318189251Ssam  }
3319189251Ssam
3320189251Ssam  /* setup dest */
3321189251Ssam  olduse  = b->used;
3322189251Ssam  b->used = a->used+a->used;
3323189251Ssam
3324189251Ssam  {
3325189251Ssam    mp_digit *tmpb;
3326189251Ssam    tmpb = b->dp;
3327189251Ssam    for (ix = 0; ix < pa; ix++) {
3328189251Ssam      *tmpb++ = W[ix] & MP_MASK;
3329189251Ssam    }
3330189251Ssam
3331189251Ssam    /* clear unused digits [that existed in the old copy of c] */
3332189251Ssam    for (; ix < olduse; ix++) {
3333189251Ssam      *tmpb++ = 0;
3334189251Ssam    }
3335189251Ssam  }
3336189251Ssam  mp_clamp (b);
3337189251Ssam  return MP_OKAY;
3338189251Ssam}
3339189251Ssam#endif
3340189251Ssam
3341189251Ssam
3342189251Ssam#ifdef BN_MP_MUL_D_C
3343189251Ssam/* multiply by a digit */
3344189251Ssamstatic int
3345189251Ssammp_mul_d (mp_int * a, mp_digit b, mp_int * c)
3346189251Ssam{
3347189251Ssam  mp_digit u, *tmpa, *tmpc;
3348189251Ssam  mp_word  r;
3349189251Ssam  int      ix, res, olduse;
3350189251Ssam
3351189251Ssam  /* make sure c is big enough to hold a*b */
3352189251Ssam  if (c->alloc < a->used + 1) {
3353189251Ssam    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
3354189251Ssam      return res;
3355189251Ssam    }
3356189251Ssam  }
3357189251Ssam
3358189251Ssam  /* get the original destinations used count */
3359189251Ssam  olduse = c->used;
3360189251Ssam
3361189251Ssam  /* set the sign */
3362189251Ssam  c->sign = a->sign;
3363189251Ssam
3364189251Ssam  /* alias for a->dp [source] */
3365189251Ssam  tmpa = a->dp;
3366189251Ssam
3367189251Ssam  /* alias for c->dp [dest] */
3368189251Ssam  tmpc = c->dp;
3369189251Ssam
3370189251Ssam  /* zero carry */
3371189251Ssam  u = 0;
3372189251Ssam
3373189251Ssam  /* compute columns */
3374189251Ssam  for (ix = 0; ix < a->used; ix++) {
3375189251Ssam    /* compute product and carry sum for this term */
3376189251Ssam    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
3377189251Ssam
3378189251Ssam    /* mask off higher bits to get a single digit */
3379189251Ssam    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
3380189251Ssam
3381189251Ssam    /* send carry into next iteration */
3382189251Ssam    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
3383189251Ssam  }
3384189251Ssam
3385189251Ssam  /* store final carry [if any] and increment ix offset  */
3386189251Ssam  *tmpc++ = u;
3387189251Ssam  ++ix;
3388189251Ssam
3389189251Ssam  /* now zero digits above the top */
3390189251Ssam  while (ix++ < olduse) {
3391189251Ssam     *tmpc++ = 0;
3392189251Ssam  }
3393189251Ssam
3394189251Ssam  /* set used count */
3395189251Ssam  c->used = a->used + 1;
3396189251Ssam  mp_clamp(c);
3397189251Ssam
3398189251Ssam  return MP_OKAY;
3399189251Ssam}
3400189251Ssam#endif
3401