18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Minimal code for RSA support from LibTomMath 0.41
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * http://libtom.org/
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * http://libtom.org/files/ltm-0.41.tar.bz2
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This library was released in public domain by Tom St Denis.
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The combination in this file may not use all of the optimized algorithms
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * from LibTomMath and may be considerable slower than the LibTomMath with its
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * default settings. The main purpose of having this version here is to make it
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * easier to build bignum.c wrapper without having to install and build an
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * external library.
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * libtommath.c file instead of using the external LibTomMath library.
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CHAR_BIT
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define CHAR_BIT 8
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_INVMOD_C
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   * require BN_MP_EXPTMOD_FAST_C instead */
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_S_MP_MUL_DIGS_C
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_INVMOD_SLOW_C
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_S_MP_SQR_C
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 * would require other than mp_reduce */
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef LTM_FAST
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Use faster div at the cost of about 1 kB */
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_MUL_D_C
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_EXPTMOD_FAST_C
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_MONTGOMERY_SETUP_C
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_FAST_MP_MONTGOMERY_REDUCE_C
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_MUL_2_C
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Include faster sqr at the cost of about 0.5 kB in code */
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_FAST_S_MP_SQR_C
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt/* About 0.25 kB of code, but ~1.7kB of stack space! */
46700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt#define BN_FAST_S_MP_MUL_DIGS_C
47700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* LTM_FAST */
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_DIV_SMALL
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_INIT_MULTI_C
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_CLEAR_MULTI_C
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BN_MP_ABS_C
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LTM_FAST */
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Current uses do not require support for negative exponent in exptmod, so we
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * can save about 1.5 kB in leaving out invmod. */
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define LTM_NO_NEG_EXP
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* from tommath.h */
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef MIN
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   #define MIN(x,y) ((x)<(y)?(x):(y))
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef MAX
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   #define MAX(x,y) ((x)>(y)?(x):(y))
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define  OPT_CAST(x)
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef __x86_64__
7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidttypedef unsigned long mp_digit;
7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidttypedef unsigned long mp_word __attribute__((mode(TI)));
7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
7604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#define DIGIT_BIT 60
7704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#define MP_64BIT
7804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#else
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef unsigned long mp_digit;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef u64 mp_word;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define DIGIT_BIT          28
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_28BIT
8404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define XMALLOC  os_malloc
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define XFREE    os_free
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define XREALLOC os_realloc
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_LT        -1   /* less than */
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_EQ         0   /* equal to */
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_GT         1   /* greater than */
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_ZPOS       0   /* positive integer */
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_NEG        1   /* negative */
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_OKAY       0   /* ok result */
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_MEM        -2  /* out of mem */
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_VAL        -3  /* invalid input */
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_YES        1   /* yes response */
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_NO         0   /* no response */
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef int           mp_err;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* define this to use lower memory usage routines (exptmods mostly) */
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_LOW_MEM
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* default precision */
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef MP_PREC
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   #ifndef MP_LOW_MEM
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      #define MP_PREC                 32     /* default digits of precision */
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   #else
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      #define MP_PREC                 8      /* default digits of precision */
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   #endif
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MP_WARRAY               (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* the infamous mp_int structure */
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef struct  {
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    int used, alloc, sign;
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_digit *dp;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} mp_int;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* ---> Basic Manipulations <--- */
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define mp_isodd(a)  (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* prototypes for copied functions */
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_sqr(mp_int * a, mp_int * b);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
145700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt#ifdef BN_FAST_S_MP_MUL_DIGS_C
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
147700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt#endif
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_INIT_MULTI_C
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_init_multi(mp_int *mp, ...);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_CLEAR_MULTI_C
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_clear_multi(mp_int *mp, ...);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_lshd(mp_int * a, int b);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_set(mp_int * a, mp_digit b);
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_clamp(mp_int * a);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_exch(mp_int * a, mp_int * b);
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_rshd(mp_int * a, int b);
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_zero(mp_int * a);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mod_2d(mp_int * a, int b, mp_int * c);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_init_copy(mp_int * a, mp_int * b);
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mul_2d(mp_int * a, int b, mp_int * c);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef LTM_NO_NEG_EXP
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_div_2(mp_int * a, mp_int * b);
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LTM_NO_NEG_EXP */
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_copy(mp_int * a, mp_int * b);
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_count_bits(mp_int * a);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mod(mp_int * a, mp_int * b, mp_int * c);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_grow(mp_int * a, int size);
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_cmp_mag(mp_int * a, mp_int * b);
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_ABS_C
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_abs(mp_int * a, mp_int * b);
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_sqr(mp_int * a, mp_int * b);
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_2expt(mp_int * a, int b);
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce_setup(mp_int * a, mp_int * b);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_init_size(mp_int * a, int size);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_EXPTMOD_FAST_C
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* BN_MP_EXPTMOD_FAST_C */
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_S_MP_SQR_C
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int fast_s_mp_sqr (mp_int * a, mp_int * b);
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* BN_FAST_S_MP_SQR_C */
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MUL_D_C
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* BN_MP_MUL_D_C */
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* functions from bn_<func name>.c */
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* reverse an array, used for radix code */
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bn_reverse (unsigned char *s, int len)
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     ix, iy;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  unsigned char t;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  ix = 0;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  iy = len - 1;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (ix < iy) {
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    t     = s[ix];
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    s[ix] = s[iy];
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    s[iy] = t;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ++ix;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    --iy;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* low level addition, based on HAC pp.594, Algorithm 14.7 */
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int *x;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     olduse, res, min, max;
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* find sizes, we let |a| <= |b| which means we have to sort
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * them.  "x" will point to the input with the most digits
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used > b->used) {
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    min = b->used;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    max = a->used;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    x = a;
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    min = a->used;
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    max = b->used;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    x = b;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init result */
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (c->alloc < max + 1) {
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* get old used digit count and set new one */
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  olduse = c->used;
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  c->used = max + 1;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit u, *tmpa, *tmpb, *tmpc;
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register int i;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for digit pointers */
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* first input */
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpa = a->dp;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* second input */
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* destination */
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpc = c->dp;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* zero the carry */
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    u = 0;
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (i = 0; i < min; i++) {
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc = *tmpa++ + *tmpb++ + u;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* U = carry bit of T[i] */
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      u = *tmpc >> ((mp_digit)DIGIT_BIT);
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* take away carry bit from T[i] */
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc++ &= MP_MASK;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* now copy higher words if any, that is in A+B
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * if A or B has more digits add those in
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (min != max) {
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (; i < max; i++) {
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /* T[i] = X[i] + U */
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        *tmpc = x->dp[i] + u;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /* U = carry bit of T[i] */
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        u = *tmpc >> ((mp_digit)DIGIT_BIT);
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /* take away carry bit from T[i] */
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        *tmpc++ &= MP_MASK;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* add carry */
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    *tmpc++ = u;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* clear digits above oldused */
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (i = c->used; i < olduse; i++) {
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc++ = 0;
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (c);
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     olduse, res, min, max;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* find sizes */
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  min = b->used;
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  max = a->used;
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init result */
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (c->alloc < max) {
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (c, max)) != MP_OKAY) {
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  olduse = c->used;
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  c->used = max;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit u, *tmpa, *tmpb, *tmpc;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register int i;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for digit pointers */
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpa = a->dp;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpc = c->dp;
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* set carry to zero */
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    u = 0;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (i = 0; i < min; i++) {
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* T[i] = A[i] - B[i] - U */
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc = *tmpa++ - *tmpb++ - u;
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* U = carry bit of T[i]
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * Note this saves performing an AND operation since
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * if a carry does occur it will propagate all the way to the
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * MSB.  As a result a single shift is enough to get the carry
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       */
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* Clear carry from T[i] */
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc++ &= MP_MASK;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* now copy higher words if any, e.g. if A has more digits than B  */
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; i < max; i++) {
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* T[i] = A[i] - U */
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc = *tmpa++ - u;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* U = carry bit of T[i] */
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* Clear carry from T[i] */
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc++ &= MP_MASK;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* clear digits above used (since we may not have grown result above) */
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (i = c->used; i < olduse; i++) {
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc++ = 0;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (c);
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* init a new mp_int */
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_init (mp_int * a)
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int i;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* allocate memory required and clear it */
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->dp == NULL) {
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_MEM;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set the digits to zero */
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (i = 0; i < MP_PREC; i++) {
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->dp[i] = 0;
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set the used to zero, allocated digits to the default precision
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * and sign to positive */
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->used  = 0;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->alloc = MP_PREC;
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->sign  = MP_ZPOS;
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* clear one (frees)  */
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_clear (mp_int * a)
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int i;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* only do anything if a hasn't been freed previously */
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->dp != NULL) {
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* first zero the digits */
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (i = 0; i < a->used; i++) {
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        a->dp[i] = 0;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* free ram */
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    XFREE(a->dp);
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* reset members to make debugging easier */
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    a->dp    = NULL;
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    a->alloc = a->used = 0;
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    a->sign  = MP_ZPOS;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* high level addition (handles signs) */
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_add (mp_int * a, mp_int * b, mp_int * c)
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     sa, sb, res;
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* get sign of both inputs */
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  sa = a->sign;
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  sb = b->sign;
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* handle two cases, not four */
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (sa == sb) {
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* both positive or both negative */
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* add their magnitudes, copy the sign */
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    c->sign = sa;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = s_mp_add (a, b, c);
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* one positive, the other negative */
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* subtract the one with the greater magnitude from */
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* the one of the lesser magnitude.  The result gets */
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* the sign of the one with the greater magnitude. */
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mp_cmp_mag (a, b) == MP_LT) {
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      c->sign = sb;
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = s_mp_sub (b, a, c);
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else {
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      c->sign = sa;
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = s_mp_sub (a, b, c);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* high level subtraction (handles signs) */
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_sub (mp_int * a, mp_int * b, mp_int * c)
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     sa, sb, res;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  sa = a->sign;
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  sb = b->sign;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (sa != sb) {
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* subtract a negative from a positive, OR */
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* subtract a positive from a negative. */
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* In either case, ADD their magnitudes, */
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* and use the sign of the first number. */
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    c->sign = sa;
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = s_mp_add (a, b, c);
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* subtract a positive from a positive, OR */
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* subtract a negative from a negative. */
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* First, take the difference between their */
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* magnitudes, then... */
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mp_cmp_mag (a, b) != MP_LT) {
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* Copy the sign from the first */
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      c->sign = sa;
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* The first has a larger or equal magnitude */
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = s_mp_sub (a, b, c);
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else {
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* The result has the *opposite* sign from */
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* the first number. */
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* The second has a larger magnitude */
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = s_mp_sub (b, a, c);
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* high level multiplication (handles sign) */
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mul (mp_int * a, mp_int * b, mp_int * c)
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res, neg;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* use Toom-Cook? */
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_TOOM_MUL_C
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = mp_toom_mul(a, b, c);
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_KARATSUBA_MUL_C
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* use Karatsuba? */
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = mp_karatsuba_mul (a, b, c);
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* can we use the fast multiplier?
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * The fast multiplier can be used if the output will
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * have less than MP_WARRAY digits and the number of
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * digits won't affect carry propagation
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_S_MP_MUL_DIGS_C
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    int     digs = a->used + b->used + 1;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((digs < MP_WARRAY) &&
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        MIN(a->used, b->used) <=
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = fast_s_mp_mul_digs (a, b, c, digs);
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_S_MP_MUL_DIGS_C
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#error mp_mul could fail
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = MP_VAL;
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  c->sign = (c->used > 0) ? neg : MP_ZPOS;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* d = a * b (mod c) */
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init (&t)) != MP_OKAY) {
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_clear (&t);
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  res = mp_mod (&t, c, d);
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&t);
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* c = a mod b, 0 <= c < b */
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mod (mp_int * a, mp_int * b, mp_int * c)
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init (&t)) != MP_OKAY) {
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_clear (&t);
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (t.sign != b->sign) {
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = mp_add (b, &t, c);
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = MP_OKAY;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_exch (&t, c);
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&t);
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* this is a shell function that calls either the normal or Montgomery
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * exptmod functions.  Originally the call to the montgomery code was
5881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * embedded in the normal function but that wasted a lot of stack space
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for nothing (since 99% of the time the Montgomery code would be called)
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int dr;
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* modulus P must be positive */
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (P->sign == MP_NEG) {
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return MP_VAL;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if exponent X is negative we have to recurse */
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (X->sign == MP_NEG) {
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef LTM_NO_NEG_EXP
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return MP_VAL;
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* LTM_NO_NEG_EXP */
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_INVMOD_C
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     mp_int tmpG, tmpX;
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     int err;
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* first compute 1/G mod P */
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_init(&tmpG)) != MP_OKAY) {
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return err;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mp_clear(&tmpG);
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return err;
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* now get |X| */
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_init(&tmpX)) != MP_OKAY) {
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mp_clear(&tmpG);
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return err;
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mp_clear_multi(&tmpG, &tmpX, NULL);
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return err;
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     err = mp_exptmod(&tmpG, &tmpX, P, Y);
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     mp_clear_multi(&tmpG, &tmpX, NULL);
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return err;
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#error mp_exptmod would always fail
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* no invmod */
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return MP_VAL;
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LTM_NO_NEG_EXP */
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* modified diminished radix reduction */
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_reduce_is_2k_l(P) == MP_YES) {
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return s_mp_exptmod(G, X, P, Y, 1);
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_DR_IS_MODULUS_C
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* is it a DR modulus? */
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  dr = mp_dr_is_modulus(P);
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* default to no */
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  dr = 0;
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_REDUCE_IS_2K_C
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if not, is it a unrestricted DR modulus? */
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (dr == 0) {
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     dr = mp_reduce_is_2k(P) << 1;
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if the modulus is odd or dr != 0 use the montgomery method */
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_EXPTMOD_FAST_C
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_isodd (P) == 1 || dr !=  0) {
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return mp_exptmod_fast (G, X, P, Y, dr);
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_S_MP_EXPTMOD_C
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* otherwise use the generic Barrett reduction technique */
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return s_mp_exptmod (G, X, P, Y, 0);
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#error mp_exptmod could fail
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* no exptmod for evens */
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_VAL;
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_EXPTMOD_FAST_C
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
679700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt  if (dr == 0) {
680700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt    /* avoid compiler warnings about possibly unused variable */
681700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt  }
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* compare two ints (signed)*/
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_cmp (mp_int * a, mp_int * b)
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compare based on sign */
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->sign != b->sign) {
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if (a->sign == MP_NEG) {
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return MP_LT;
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     } else {
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return MP_GT;
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compare digits */
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->sign == MP_NEG) {
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* if negative compare opposite direction */
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return mp_cmp_mag(b, a);
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return mp_cmp_mag(a, b);
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* compare a digit */
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_cmp_d(mp_int * a, mp_digit b)
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compare based on sign */
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->sign == MP_NEG) {
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_LT;
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compare based on magnitude */
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used > 1) {
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_GT;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compare the only digit of a to b */
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->dp[0] > b) {
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_GT;
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (a->dp[0] < b) {
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_LT;
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_EQ;
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef LTM_NO_NEG_EXP
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* hac 14.61, pp608 */
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* b cannot be negative */
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_VAL;
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_MP_INVMOD_C
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if the modulus is odd we can use a faster routine instead */
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_isodd (b) == 1) {
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return fast_mp_invmod (a, b, c);
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_INVMOD_SLOW_C
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return mp_invmod_slow(a, b, c);
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef BN_FAST_MP_INVMOD_C
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef BN_MP_INVMOD_SLOW_C
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#error mp_invmod would always fail
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_VAL;
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LTM_NO_NEG_EXP */
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* get the size for an unsigned equivalent */
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_unsigned_bin_size (mp_int * a)
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     size = mp_count_bits (a);
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef LTM_NO_NEG_EXP
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* hac 14.61, pp608 */
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  x, y, u, v, A, B, C, D;
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* b cannot be negative */
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_VAL;
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init temps */
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_multi(&x, &y, &u, &v,
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                           &A, &B, &C, &D, NULL)) != MP_OKAY) {
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return res;
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* x = a, y = b */
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_copy (b, &y)) != MP_OKAY) {
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_ERR;
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* 2. [modified] if x,y are both even then return an error! */
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = MP_VAL;
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_ERR;
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_ERR;
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_ERR;
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_set (&A, 1);
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_set (&D, 1);
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttop:
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* 4.  while u is even do */
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (mp_iseven (&u) == 1) {
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* 4.1 u = u/2 */
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* 4.2 if A or B is odd then */
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* A = (A+y)/2, B = (B-x)/2 */
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         goto LBL_ERR;
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         goto LBL_ERR;
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* A = A/2, B = B/2 */
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* 5.  while v is even do */
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (mp_iseven (&v) == 1) {
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* 5.1 v = v/2 */
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* 5.2 if C or D is odd then */
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* C = (C+y)/2, D = (D-x)/2 */
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         goto LBL_ERR;
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         goto LBL_ERR;
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* C = C/2, D = D/2 */
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* 6.  if u >= v then */
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_cmp (&u, &v) != MP_LT) {
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* u = u - v, A = A - C, B = B - D */
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* v - v - u, C = C - A, D = D - B */
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if not zero goto step 4 */
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_iszero (&u) == 0)
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto top;
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now a = C, b = D, gcd == g*v */
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if v != 1 then there is no inverse */
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_cmp_d (&v, 1) != MP_EQ) {
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = MP_VAL;
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_ERR;
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if its too low */
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (mp_cmp_d(&C, 0) == MP_LT) {
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         goto LBL_ERR;
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* too big */
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (mp_cmp_mag(&C, b) != MP_LT) {
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         goto LBL_ERR;
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* C is now the inverse */
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_exch (&C, c);
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  res = MP_OKAY;
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LTM_NO_NEG_EXP */
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* compare maginitude of two ints (unsigned) */
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_cmp_mag (mp_int * a, mp_int * b)
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     n;
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit *tmpa, *tmpb;
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compare based on # of non-zero digits */
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used > b->used) {
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_GT;
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used < b->used) {
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_LT;
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* alias for a */
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  tmpa = a->dp + (a->used - 1);
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* alias for b */
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  tmpb = b->dp + (a->used - 1);
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compare based on digits  */
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (*tmpa > *tmpb) {
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return MP_GT;
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (*tmpa < *tmpb) {
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return MP_LT;
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_EQ;
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* reads a unsigned char array, assumes the msb is stored first [big endian] */
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* make sure there are at least two digits */
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->alloc < 2) {
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_grow(a, 2)) != MP_OKAY) {
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return res;
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* zero the int */
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_zero (a);
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* read the bytes in */
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (c-- > 0) {
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef MP_8BIT
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->dp[0] |= *b++;
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->used += 1;
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->dp[0] = (*b & MP_MASK);
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->dp[1] |= ((*b++ >> 7U) & 1);
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->used += 2;
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (a);
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* store in unsigned [big endian] format */
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x, res;
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x = 0;
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (mp_iszero (&t) == 0) {
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef MP_8BIT
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      b[x++] = (unsigned char) (t.dp[0] & 255);
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_clear (&t);
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bn_reverse (b, x);
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&t);
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit D, r, rr;
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x, res;
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if the shift count is <= 0 then we do no work */
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b <= 0) {
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = mp_copy (a, c);
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (d != NULL) {
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_zero (d);
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init (&t)) != MP_OKAY) {
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* get the remainder */
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (d != NULL) {
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_clear (&t);
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* copy */
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_copy (a, c)) != MP_OKAY) {
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_clear (&t);
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* shift by as many digits in the bit count */
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b >= (int)DIGIT_BIT) {
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_rshd (c, b / DIGIT_BIT);
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* shift any bit count < DIGIT_BIT */
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  D = (mp_digit) (b % DIGIT_BIT);
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (D != 0) {
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *tmpc, mask, shift;
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* mask */
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mask = (((mp_digit)1) << D) - 1;
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* shift for lsb */
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    shift = DIGIT_BIT - D;
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias */
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpc = c->dp + (c->used - 1);
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* carry */
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    r = 0;
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = c->used - 1; x >= 0; x--) {
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get the lower  bits of this word in a temp */
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      rr = *tmpc & mask;
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* shift the current word and mix in the carry bits from the previous word */
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc = (*tmpc >> D) | (r << shift);
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      --tmpc;
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* set the carry to the carry bits of the current word found above */
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r = rr;
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (c);
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (d != NULL) {
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_exch (&t, d);
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&t);
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_init_copy (mp_int * a, mp_int * b)
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init (a)) != MP_OKAY) {
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return mp_copy (b, a);
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* set to zero */
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_zero (mp_int * a)
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int       n;
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit *tmp;
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->sign = MP_ZPOS;
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->used = 0;
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  tmp = a->dp;
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (n = 0; n < a->alloc; n++) {
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *tmp++ = 0;
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* copy, b = a */
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_copy (mp_int * a, mp_int * b)
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res, n;
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if dst == src do nothing */
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a == b) {
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_OKAY;
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* grow dest */
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b->alloc < a->used) {
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return res;
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* zero b and copy the parameters over */
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *tmpa, *tmpb;
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* pointer aliases */
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* source */
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpa = a->dp;
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* destination */
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp;
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* copy all the digits */
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (n = 0; n < a->used; n++) {
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb++ = *tmpa++;
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* clear high digits */
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; n < b->used; n++) {
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb++ = 0;
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* copy used count and sign */
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->used = a->used;
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->sign = a->sign;
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* shift right a certain amount of digits */
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_rshd (mp_int * a, int b)
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x;
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if b <= 0 then ignore it */
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b <= 0) {
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return;
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if b > used then simply zero it and return */
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used <= b) {
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_zero (a);
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return;
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *bottom, *top;
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* shift the digits down */
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* bottom */
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bottom = a->dp;
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* top [offset into digits] */
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    top = a->dp + b;
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* this is implemented as a sliding window where
12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * the window is b-digits long and digits from
12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * the top of the window are copied to the bottom
12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * e.g.
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                 /\                   |      ---->
12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                  \-------------------/      ---->
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = 0; x < (a->used - b); x++) {
12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *bottom++ = *top++;
12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* zero the top digits */
12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; x < a->used; x++) {
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *bottom++ = 0;
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* remove excess digits */
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->used -= b;
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* swap the elements of two integers, for cases where you can't simply swap the
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * mp_int pointers around
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_exch (mp_int * a, mp_int * b)
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  t  = *a;
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  *a = *b;
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  *b = t;
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* trim unused digits
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This is used to ensure that leading zero digits are
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * trimed and the leading "used" digit will be non-zero
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Typically very fast.  Also fixes the sign if there
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * are no more leading digits
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_clamp (mp_int * a)
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* decrease used while the most significant digit is
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * zero.
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (a->used > 0 && a->dp[a->used - 1] == 0) {
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    --(a->used);
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* reset the sign flag if used == 0 */
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used == 0) {
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    a->sign = MP_ZPOS;
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* grow as required */
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_grow (mp_int * a, int size)
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     i;
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit *tmp;
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if the alloc size is smaller alloc more ram */
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->alloc < size) {
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* ensure there are always at least MP_PREC digits extra on top */
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    size += (MP_PREC * 2) - (size % MP_PREC);
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* reallocate the array a->dp
12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *
12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * We store the return in a temporary variable
12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * in case the operation failed we don't want
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * to overwrite the dp member of a.
12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (tmp == NULL) {
12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* reallocation failed but "a" is still valid [can be freed] */
12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return MP_MEM;
12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* reallocation succeeded so set a->dp */
12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    a->dp = tmp;
12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* zero excess digits */
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    i        = a->alloc;
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    a->alloc = size;
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; i < a->alloc; i++) {
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->dp[i] = 0;
12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_ABS_C
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* b = |a|
13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Simple function copies the input and fixes the sign to positive
13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_abs (mp_int * a, mp_int * b)
13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* copy a to b */
13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a != b) {
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_copy (a, b)) != MP_OKAY) {
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       return res;
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* force the sign of b to positive */
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->sign = MP_ZPOS;
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* set to a digit */
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_set (mp_int * a, mp_digit b)
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_zero (a);
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->dp[0] = b & MP_MASK;
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->used  = (a->dp[0] != 0) ? 1 : 0;
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef LTM_NO_NEG_EXP
13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* b = a/2 */
13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_div_2(mp_int * a, mp_int * b)
13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x, res, oldused;
13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* copy */
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b->alloc < a->used) {
13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (b, a->used)) != MP_OKAY) {
13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  oldused = b->used;
13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->used = a->used;
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit r, rr, *tmpa, *tmpb;
13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* source alias */
13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpa = a->dp + b->used - 1;
13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* dest alias */
13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp + b->used - 1;
13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* carry */
13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    r = 0;
13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = b->used - 1; x >= 0; x--) {
13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get the carry for the next iteration */
13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      rr = *tmpa & 1;
13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* shift the current digit, add in carry and store */
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* forward carry to next iteration */
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r = rr;
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* zero excess digits */
13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp + b->used;
13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = b->used; x < oldused; x++) {
13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb++ = 0;
13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->sign = a->sign;
13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (b);
13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LTM_NO_NEG_EXP */
13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* shift left by a certain bit count */
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mul_2d (mp_int * a, int b, mp_int * c)
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit d;
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int      res;
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* copy */
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a != c) {
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_copy (a, c)) != MP_OKAY) {
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       return res;
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       return res;
13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* shift by as many digits in the bit count */
14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b >= (int)DIGIT_BIT) {
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* shift any bit count < DIGIT_BIT */
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  d = (mp_digit) (b % DIGIT_BIT);
14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (d != 0) {
14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *tmpc, shift, mask, r, rr;
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register int x;
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* bitmask for carries */
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mask = (((mp_digit)1) << d) - 1;
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* shift for msbs */
14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    shift = DIGIT_BIT - d;
14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias */
14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpc = c->dp;
14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* carry */
14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    r    = 0;
14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = 0; x < c->used; x++) {
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get the higher bits of the current word */
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      rr = (*tmpc >> shift) & mask;
14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* shift the current word and OR in the carry */
14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc = ((*tmpc << d) | r) & MP_MASK;
14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ++tmpc;
14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* set the carry to the carry bits of the current word */
14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r = rr;
14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* set final carry */
14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (r != 0) {
14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       c->dp[(c->used)++] = r;
14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (c);
14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_INIT_MULTI_C
14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_init_multi(mp_int *mp, ...)
14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    int n = 0;                 /* Number of ok inits */
14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_int* cur_arg = mp;
14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    va_list args;
14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    va_start(args, mp);        /* init args to next argument from caller */
14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    while (cur_arg != NULL) {
14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (mp_init(cur_arg) != MP_OKAY) {
14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            /* Oops - error! Back-track and mp_clear what we already
14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt               succeeded in init-ing, then return error.
14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            */
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            va_list clean_args;
14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            /* end the current list */
14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            va_end(args);
14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            /* now start cleaning up */
14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            cur_arg = mp;
14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            va_start(clean_args, mp);
14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            while (n--) {
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                mp_clear(cur_arg);
14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                cur_arg = va_arg(clean_args, mp_int*);
14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            va_end(clean_args);
14754171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            return MP_MEM;
14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        n++;
14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        cur_arg = va_arg(args, mp_int*);
14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    va_end(args);
14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;                /* Assumed ok, if error flagged above. */
14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_CLEAR_MULTI_C
14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mp_clear_multi(mp_int *mp, ...)
14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_int* next_mp = mp;
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    va_list args;
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    va_start(args, mp);
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    while (next_mp != NULL) {
14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mp_clear(next_mp);
14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        next_mp = va_arg(args, mp_int*);
14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    va_end(args);
14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* shift left a certain amount of digits */
15028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_lshd (mp_int * a, int b)
15038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x, res;
15058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if its less than zero return */
15078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b <= 0) {
15088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_OKAY;
15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* grow to fit the new digits */
15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->alloc < a->used + b) {
15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       return res;
15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
15168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *top, *bottom;
15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* increment the used by the shift amount then copy upwards */
15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    a->used += b;
15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* top */
15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    top = a->dp + a->used - 1;
15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* base */
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bottom = a->dp + a->used - 1 - b;
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* much like mp_rshd this is implemented using a sliding window
15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * except the window goes the otherway around.  Copying from
15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * the bottom to the top.  see bn_mp_rshd.c for more info.
15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
15348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = a->used - 1; x >= b; x--) {
15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *top-- = *bottom--;
15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* zero the lower digits */
15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    top = a->dp;
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = 0; x < b; x++) {
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *top++ = 0;
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* returns the number of bits in an int */
15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_count_bits (mp_int * a)
15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     r;
15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit q;
15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* shortcut */
15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used == 0) {
15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return 0;
15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* get number of digits and add that */
15608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  r = (a->used - 1) * DIGIT_BIT;
15618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* take the last digit and count the bits in it */
15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  q = a->dp[a->used - 1];
15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (q > ((mp_digit) 0)) {
15658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ++r;
15668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    q >>= ((mp_digit) 1);
15678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return r;
15698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* calc a value mod 2**b */
15738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mod_2d (mp_int * a, int b, mp_int * c)
15748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x, res;
15768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if b is <= 0 then zero the int */
15788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b <= 0) {
15798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_zero (c);
15808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_OKAY;
15818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if the modulus is larger than the value than return */
15848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b >= (int) (a->used * DIGIT_BIT)) {
15858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = mp_copy (a, c);
15868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
15878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* copy */
15908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_copy (a, c)) != MP_OKAY) {
15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* zero digits above the last digit of the modulus */
15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    c->dp[x] = 0;
15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* clear the digit that is not completely outside/inside the modulus */
15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  c->dp[b / DIGIT_BIT] &=
16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (c);
16028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_DIV_SMALL
16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* slower bit-bang division... also smaller */
16098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
16108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   mp_int ta, tb, tq, q;
16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   int    res, n, n2;
16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* is divisor zero ? */
16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_iszero (b) == 1) {
16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_VAL;
16178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
16188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if a < b then q=0, r = a */
16208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_cmp_mag (a, b) == MP_LT) {
16218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (d != NULL) {
16228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = mp_copy (a, d);
16238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else {
16248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = MP_OKAY;
16258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
16268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (c != NULL) {
16278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_zero (c);
16288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
16298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
16308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
16318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init our temps */
1633cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt  if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
16348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return res;
16358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
16368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_set(&tq, 1);
16398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  n = mp_count_bits(a) - mp_count_bits(b);
16408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
16418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ((res = mp_abs(b, &tb)) != MP_OKAY) ||
16428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
16438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
16448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_ERR;
16458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
16468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (n-- >= 0) {
16488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if (mp_cmp(&tb, &ta) != MP_GT) {
16498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
16508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
16518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt           goto LBL_ERR;
16528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
16538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
16548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
16558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
16568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt           goto LBL_ERR;
16578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
16588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
16598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now q == quotient and ta == remainder */
16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  n  = a->sign;
16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (c != NULL) {
16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     mp_exch(c, &q);
16658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
16668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (d != NULL) {
16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     mp_exch(d, &ta);
16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_ERR:
16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   mp_clear_multi(&ta, &tb, &tq, &q, NULL);
16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   return res;
16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* integer signed division.
16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
16808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * HAC pp.598 Algorithm 14.20
16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
16828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note that the description in HAC is horribly
16838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * incomplete.  For example, it doesn't consider
16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the case where digits are removed from 'x' in
16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the inner loop.  It also doesn't consider the
16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * case that y has fewer than three digits, etc..
16878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
16888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The overall algorithm is as described as
16898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 14.20 from HAC but fixed to treat these cases.
16908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt*/
16918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
16928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  q, x, y, t1, t2;
16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res, n, t, i, norm, neg;
16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* is divisor zero ? */
16978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_iszero (b) == 1) {
16988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_VAL;
16998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if a < b then q=0, r = a */
17028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_cmp_mag (a, b) == MP_LT) {
17038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (d != NULL) {
17048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = mp_copy (a, d);
17058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else {
17068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = MP_OKAY;
17078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
17088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (c != NULL) {
17098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_zero (c);
17108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
17118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
17128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
17158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  q.used = a->used + 2;
17188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init (&t1)) != MP_OKAY) {
17208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_Q;
17218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init (&t2)) != MP_OKAY) {
17248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_T1;
17258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
17288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_T2;
17298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
17328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_X;
17338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* fix the sign */
17368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
17378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x.sign = y.sign = MP_ZPOS;
17388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
17408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  norm = mp_count_bits(&y) % DIGIT_BIT;
17418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (norm < (int)(DIGIT_BIT-1)) {
17428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     norm = (DIGIT_BIT-1) - norm;
17438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
17448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       goto LBL_Y;
17458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
17468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
17478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       goto LBL_Y;
17488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
17498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
17508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     norm = 0;
17518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
17548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  n = x.used - 1;
17558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  t = y.used - 1;
17568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
17588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
17598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_Y;
17608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (mp_cmp (&x, &y) != MP_LT) {
17638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ++(q.dp[n - t]);
17648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
17658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_Y;
17668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
17678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
17688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* reset y by shifting it back down */
17708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_rshd (&y, n - t);
17718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* step 3. for i from n down to (t + 1) */
17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (i = n; i >= (t + 1); i--) {
17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (i > x.used) {
17758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      continue;
17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
17778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
17798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
17808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (x.dp[i] == y.dp[t]) {
17818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else {
17838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_word tmp;
17848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
17858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmp |= ((mp_word) x.dp[i - 1]);
17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmp /= ((mp_word) y.dp[t]);
17878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (tmp > (mp_word) MP_MASK)
17888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        tmp = MP_MASK;
17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
17918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* while (q{i-t-1} * (yt * b + y{t-1})) >
17938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt             xi * b**2 + xi-1 * b + xi-2
17948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       do q{i-t-1} -= 1;
17968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    */
17978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    do {
17998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
18008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* find left hand */
18028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_zero (&t1);
18038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
18048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      t1.dp[1] = y.dp[t];
18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      t1.used = 2;
18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_Y;
18088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* find right hand */
18118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
18138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      t2.dp[2] = x.dp[i];
18148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      t2.used = 3;
18158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } while (mp_cmp_mag(&t1, &t2) == MP_GT);
18168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
18188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
18198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_Y;
18208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
18218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_Y;
18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
18258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
18278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_Y;
18288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
18298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
18318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (x.sign == MP_NEG) {
18328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
18338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_Y;
18348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
18358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
18368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_Y;
18378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
18388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
18398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_Y;
18408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
18418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
18438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
18448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
18458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now q is the quotient and x is the remainder
18478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * [which we have to normalize]
18488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
18498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* get sign before writing to c */
18518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x.sign = x.used == 0 ? MP_ZPOS : a->sign;
18528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (c != NULL) {
18548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_clamp (&q);
18558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_exch (&q, c);
18568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    c->sign = neg;
18578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
18588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (d != NULL) {
18608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_div_2d (&x, norm, &x, NULL);
18618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_exch (&x, d);
18628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
18638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  res = MP_OKAY;
18658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18668d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_Y:mp_clear (&y);
18678d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_X:mp_clear (&x);
18688d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_T2:mp_clear (&t2);
18698d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_T1:mp_clear (&t1);
18708d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_Q:mp_clear (&q);
18718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
18728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
18758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef MP_LOW_MEM
18788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   #define TAB_SIZE 32
18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
18808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   #define TAB_SIZE 256
18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
18828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
18848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  M[TAB_SIZE], res, mu;
18868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit buf;
18878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int (*redux)(mp_int*,mp_int*,mp_int*);
18898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* find window size */
18918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x = mp_count_bits (X);
18928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (x <= 7) {
18938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 2;
18948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 36) {
18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 3;
18968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 140) {
18978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 4;
18988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 450) {
18998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 5;
19008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 1303) {
19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 6;
19028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 3529) {
19038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 7;
19048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 8;
19068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef MP_LOW_MEM
19098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (winsize > 5) {
19108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       winsize = 5;
19118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
19128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
19138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init M array */
19158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init first cell */
19168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_init(&M[1])) != MP_OKAY) {
19178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return err;
19188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now init the second half of the array */
19218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
19228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = mp_init(&M[x])) != MP_OKAY) {
19238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (y = 1<<(winsize-1); y < x; y++) {
19248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mp_clear (&M[y]);
19258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
19268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_clear(&M[1]);
19278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return err;
19288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
19298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* create mu, used for Barrett reduction */
19328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_init (&mu)) != MP_OKAY) {
19338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_M;
19348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (redmode == 0) {
19378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
19388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_MU;
19398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
19408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     redux = mp_reduce;
19418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
19438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_MU;
19448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
19458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     redux = mp_reduce_2k_l;
19468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* create M table
19498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   *
19508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * The M table contains powers of the base,
19518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * e.g. M[x] = G**x mod P
19528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   *
19538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * The first half of the table is not
19548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * computed though accept for M[0] and M[1]
19558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
19568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
19578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_MU;
19588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compute the value at M[1<<(winsize-1)] by squaring
19618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * M[1] (winsize-1) times
19628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
19638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
19648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_MU;
19658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = 0; x < (winsize - 1); x++) {
19688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* square it */
19698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = mp_sqr (&M[1 << (winsize - 1)],
19708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                       &M[1 << (winsize - 1)])) != MP_OKAY) {
19718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_MU;
19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* reduce modulo P */
19758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_MU;
19778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
19788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
19818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
19828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
19838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
19848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
19858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_MU;
19868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
19878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
19888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_MU;
19898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
19908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* setup result */
19938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_init (&res)) != MP_OKAY) {
19948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_MU;
19958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
19968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_set (&res, 1);
19978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set initial mode and bit cnt */
19998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mode   = 0;
20008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bitcnt = 1;
20018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  buf    = 0;
20028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  digidx = X->used - 1;
20038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bitcpy = 0;
20048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bitbuf = 0;
20058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (;;) {
20078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* grab next digit as required */
20088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (--bitcnt == 0) {
20098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* if digidx == -1 we are out of digits */
20108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (digidx == -1) {
20118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        break;
20128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* read next digit and reset the bitcnt */
20148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      buf    = X->dp[digidx--];
20158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitcnt = (int) DIGIT_BIT;
20168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
20178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* grab the next msb from the exponent */
20198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
20208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    buf <<= (mp_digit)1;
20218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* if the bit is zero and mode == 0 then we ignore it
20238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * These represent the leading zero bits before the first 1 bit
20248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * in the exponent.  Technically this opt is not required but it
20258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * does lower the # of trivial squaring/reductions used
20268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
20278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mode == 0 && y == 0) {
20288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      continue;
20298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
20308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* if the bit is zero and mode == 1 then we square */
20328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mode == 1 && y == 0) {
20338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
20348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
20358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
20378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
20388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      continue;
20408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
20418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* else we add it to the window */
20438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bitbuf |= (y << (winsize - ++bitcpy));
20448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mode    = 2;
20458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (bitcpy == winsize) {
20478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* ok window is filled so square as required and multiply  */
20488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* square first */
20498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (x = 0; x < winsize; x++) {
20508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
20518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
20528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
20538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
20548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
20558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
20568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* then multiply */
20598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
20608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
20618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
20638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
20648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* empty window and reset */
20678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitcpy = 0;
20688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitbuf = 0;
20698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mode   = 1;
20708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
20718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
20728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if bits remain then square/multiply */
20748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mode == 2 && bitcpy > 0) {
20758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* square then multiply if the bit is set */
20768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = 0; x < bitcpy; x++) {
20778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
20788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
20798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
20818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
20828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitbuf <<= 1;
20858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((bitbuf & (1 << winsize)) != 0) {
20868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /* then multiply */
20878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
20888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
20898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
20908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
20918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
20928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
20938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
20948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
20958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
20968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_exch (&res, Y);
20988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  err = MP_OKAY;
20998d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_RES:mp_clear (&res);
21008d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_MU:mp_clear (&mu);
21018d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_M:
21028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear(&M[1]);
21038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
21048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_clear (&M[x]);
21058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
21068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return err;
21078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* computes b = a*a */
21118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_sqr (mp_int * a, mp_int * b)
21128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
21148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_TOOM_SQR_C
21168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* use Toom-Cook? */
21178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->used >= TOOM_SQR_CUTOFF) {
21188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = mp_toom_sqr(a, b);
21198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* Karatsuba? */
21208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else
21218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
21228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_KARATSUBA_SQR_C
21238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtif (a->used >= KARATSUBA_SQR_CUTOFF) {
21248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    res = mp_karatsuba_sqr (a, b);
21258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else
21268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
21278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
21288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_S_MP_SQR_C
21298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* can we use the fast comba multiplier? */
21308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((a->used * 2 + 1) < MP_WARRAY &&
21318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         a->used <
21328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
21338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = fast_s_mp_sqr (a, b);
21348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else
21358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
21368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_S_MP_SQR_C
21378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = s_mp_sqr (a, b);
21388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
21398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#error mp_sqr could fail
21408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = MP_VAL;
21418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
21428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
21438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->sign = MP_ZPOS;
21448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
21458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* reduces a modulo n where n is of the form 2**p - d
21498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   This differs from reduce_2k since "d" can be larger
21508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   than a single digit.
21518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt*/
21528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
21538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   mp_int q;
21558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   int    p, res;
21568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if ((res = mp_init(&q)) != MP_OKAY) {
21588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
21598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
21608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   p = mp_count_bits(n);
21628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttop:
21638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   /* q = a/2**p, a = a mod 2**p */
21648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
21658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto ERR;
21668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
21678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   /* q = q * d */
21698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
21708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto ERR;
21718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
21728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   /* a = a + q */
21748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
21758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto ERR;
21768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
21778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if (mp_cmp_mag(a, n) != MP_LT) {
21798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      s_mp_sub(a, n, a);
21808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto top;
21818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
21828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21838d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtERR:
21848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   mp_clear(&q);
21858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   return res;
21868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* determines the setup value */
21908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
21918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   int    res;
21938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   mp_int tmp;
21948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if ((res = mp_init(&tmp)) != MP_OKAY) {
21968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
21978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
21988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
22008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto ERR;
22018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
22028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
22048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto ERR;
22058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   }
22068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22078d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtERR:
22088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   mp_clear(&tmp);
22098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   return res;
22108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* computes a = 2**b
22148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
22158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Simple algorithm which zeroes the int, grows it then just sets one bit
22168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * as required.
22178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
22188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_2expt (mp_int * a, int b)
22198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
22218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* zero a as per default */
22238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_zero (a);
22248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt  /* grow a to accommodate the single bit */
22268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
22278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
22288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
22298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set the used count of where the bit will go */
22318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->used = b / DIGIT_BIT + 1;
22328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* put the single bit in its place */
22348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
22358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
22378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* pre-calculate the value required for Barrett reduction
22418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * For a given modulus "b" it calulates the value required in "a"
22428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
22438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce_setup (mp_int * a, mp_int * b)
22448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res;
22468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
22488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
22498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
22508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return mp_div (a, b, a, NULL);
22518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* reduces x mod m, assumes 0 < x < m**2, mu is
22558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * precomputed via mp_reduce_setup.
22568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * From HAC pp.604 Algorithm 14.42
22578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
22588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
22598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  q;
22618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res, um = m->used;
22628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* q = x */
22648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
22658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
22668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
22678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* q1 = x / b**(k-1)  */
22698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_rshd (&q, um - 1);
22708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* according to HAC this optimization is ok */
22728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
22738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
22748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto CLEANUP;
22758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
22768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
22778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_S_MP_MUL_HIGH_DIGS_C
22788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
22798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto CLEANUP;
22808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
22818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
22828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
22838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto CLEANUP;
22848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
22858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
22868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
22878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#error mp_reduce would always fail
22888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      res = MP_VAL;
22898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto CLEANUP;
22908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
22918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
22928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
22938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* q3 = q2 / b**(k+1) */
22958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_rshd (&q, um + 1);
22968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* x = x mod b**(k+1), quick (no division) */
22988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
22998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto CLEANUP;
23008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
23018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* q = q * m mod b**(k+1), quick (no division) */
23038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
23048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto CLEANUP;
23058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
23068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* x = x - q */
23088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
23098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto CLEANUP;
23108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
23118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* If x < 0, add b**(k+1) to it */
23138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_cmp_d (x, 0) == MP_LT) {
23148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_set (&q, 1);
23158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
23168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto CLEANUP;
23178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
23188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_add (x, &q, x)) != MP_OKAY) {
23198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto CLEANUP;
23208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
23218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
23228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* Back off if it's too big */
23248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (mp_cmp (x, m) != MP_LT) {
23258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
23268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto CLEANUP;
23278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
23288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
23298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23308d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtCLEANUP:
23318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&q);
23328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return res;
23348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/* multiplies |a| * |b| and only computes up to digs digits of result
23388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * HAC pp. 595, Algorithm 14.12  Modified so you can control how
23398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * many digits of output are created.
23408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
23418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
23428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
23448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res, pa, pb, ix, iy;
23458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit u;
23468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_word r;
23478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit tmpx, *tmpt, *tmpy;
23488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2349700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt#ifdef BN_FAST_S_MP_MUL_DIGS_C
23508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* can we use the fast multiplier? */
23518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (((digs) < MP_WARRAY) &&
23528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      MIN (a->used, b->used) <
23538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
23548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return fast_s_mp_mul_digs (a, b, c, digs);
23558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
2356700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt#endif
23578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
23598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
23608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
23618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  t.used = digs;
23628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compute the digits of the product directly */
23648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  pa = a->used;
23658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (ix = 0; ix < pa; ix++) {
23668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* set the carry to zero */
23678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    u = 0;
23688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* limit ourselves to making digs digits of output */
23708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    pb = MIN (b->used, digs - ix);
23718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* setup some aliases */
23738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* copy of the digit from a used within the nested loop */
23748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpx = a->dp[ix];
23758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* an alias for the destination shifted ix places */
23778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpt = t.dp + ix;
23788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* an alias for the digits of b */
23808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpy = b->dp;
23818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* compute the columns of the output and propagate the carry */
23838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (iy = 0; iy < pb; iy++) {
23848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* compute the column as a mp_word */
23858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r       = ((mp_word)*tmpt) +
23868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
23878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                ((mp_word) u);
23888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* the new column is the lower part of the result */
23908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
23918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get the carry word from the result */
23938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
23948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
23958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* set carry if it is placed below digs */
23968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (ix + iy < digs) {
23978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpt = u;
23988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
23998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
24008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (&t);
24028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_exch (&t, c);
24038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&t);
24058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
24068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
24078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2409700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt#ifdef BN_FAST_S_MP_MUL_DIGS_C
24108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Fast (comba) multiplier
24118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
24128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This is the fast column-array [comba] multiplier.  It is
24138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * designed to compute the columns of the product first
24148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * then handle the carries afterwards.  This has the effect
24158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of making the nested loops that compute the columns very
24168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * simple and schedulable on super-scalar processors.
24178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
24188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This has been modified to produce a variable number of
24198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * digits of output so if say only a half-product is required
24208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * you don't have to compute the upper half (a feature
24218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * required for fast Barrett reduction).
24228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
24238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Based on Algorithm 14.12 on pp.595 of HAC.
24248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
24258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
24268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
24278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
24288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     olduse, res, pa, ix, iz;
24298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit W[MP_WARRAY];
24308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  register mp_word  _W;
24318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* grow the destination as required */
24338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (c->alloc < digs) {
24348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (c, digs)) != MP_OKAY) {
24358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
24368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
24378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
24388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* number of output digits to produce */
24408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  pa = MIN(digs, a->used + b->used);
24418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* clear the carry */
24438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  _W = 0;
24448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (ix = 0; ix < pa; ix++) {
24458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      int      tx, ty;
24468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      int      iy;
24478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_digit *tmpx, *tmpy;
24488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get offsets into the two bignums */
24508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ty = MIN(b->used-1, ix);
24518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tx = ix - ty;
24528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* setup temp aliases */
24548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmpx = a->dp + tx;
24558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmpy = b->dp + ty;
24568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* this is the number of times the loop will iterrate, essentially
24588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         while (tx++ < a->used && ty-- >= 0) { ... }
24598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       */
24608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      iy = MIN(a->used-tx, ty+1);
24618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* execute loop */
24638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (iz = 0; iz < iy; ++iz) {
24648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
24658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
24678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* store term */
24698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      W[ix] = ((mp_digit)_W) & MP_MASK;
24708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* make next carry */
24728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      _W = _W >> ((mp_word)DIGIT_BIT);
24738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt }
24748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* setup dest */
24768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  olduse  = c->used;
24778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  c->used = pa;
24788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
24808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *tmpc;
24818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpc = c->dp;
24828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (ix = 0; ix < pa+1; ix++) {
24838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* now extract the previous digit [below the carry] */
24848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc++ = W[ix];
24858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
24868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* clear unused digits [that existed in the old copy of c] */
24888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; ix < olduse; ix++) {
24898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpc++ = 0;
24908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
24918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
24928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (c);
24938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
24948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2495700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt#endif /* BN_FAST_S_MP_MUL_DIGS_C */
24968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* init an mp_init for a given size */
24998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_init_size (mp_int * a, int size)
25008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int x;
25028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* pad size so there are always extra digits */
25048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  size += (MP_PREC * 2) - (size % MP_PREC);
25058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* alloc mem */
25078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
25088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (a->dp == NULL) {
25098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_MEM;
25108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
25118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set the members */
25138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->used  = 0;
25148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->alloc = size;
25158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  a->sign  = MP_ZPOS;
25168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* zero the digits */
25188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = 0; x < size; x++) {
25198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      a->dp[x] = 0;
25208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
25218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
25238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
25248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
25278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_sqr (mp_int * a, mp_int * b)
25288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
25308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res, ix, iy, pa;
25318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_word r;
25328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit u, tmpx, *tmpt;
25338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  pa = a->used;
25358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
25368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
25378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
25388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* default used is maximum possible size */
25408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  t.used = 2*pa + 1;
25418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (ix = 0; ix < pa; ix++) {
25438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* first calculate the digit at 2*ix */
25448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* calculate double precision result */
25458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    r = ((mp_word) t.dp[2*ix]) +
25468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
25478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* store lower part in result */
25498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
25508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* get the carry */
25528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
25538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* left hand side of A[ix] * A[iy] */
25558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpx        = a->dp[ix];
25568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for where to store the results */
25588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpt        = t.dp + (2*ix + 1);
25598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (iy = ix + 1; iy < pa; iy++) {
25618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* first calculate the product */
25628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
25638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* now calculate the double precision result, note we use
25658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * addition instead of *2 since it's easier to optimize
25668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       */
25678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
25688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* store lower part */
25708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
25718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get carry */
25738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
25748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
25758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* propagate upwards */
25768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    while (u != ((mp_digit) 0)) {
25778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r       = ((mp_word) *tmpt) + ((mp_word) u);
25788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
25798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
25808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
25818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
25828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (&t);
25848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_exch (&t, b);
25858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&t);
25868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
25878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
25888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* multiplies |a| * |b| and does not compute the lower digs digits
25918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * [meant to get the higher part of the product]
25928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
25938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
25948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  t;
25968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     res, pa, pb, ix, iy;
25978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit u;
25988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_word r;
25998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit tmpx, *tmpt, *tmpy;
26008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* can we use the fast multiplier? */
26028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
26038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (((a->used + b->used + 1) < MP_WARRAY)
26048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
26058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return fast_s_mp_mul_high_digs (a, b, c, digs);
26068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
26078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
26088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
26108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
26118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
26128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  t.used = a->used + b->used + 1;
26138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  pa = a->used;
26158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  pb = b->used;
26168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (ix = 0; ix < pa; ix++) {
26178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* clear the carry */
26188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    u = 0;
26198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* left hand side of A[ix] * B[iy] */
26218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpx = a->dp[ix];
26228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias to the address of where the digits will be stored */
26248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpt = &(t.dp[digs]);
26258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for where to read the right hand side from */
26278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpy = b->dp + (digs - ix);
26288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (iy = digs - ix; iy < pb; iy++) {
26308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* calculate the double precision result */
26318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r       = ((mp_word)*tmpt) +
26328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
26338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                ((mp_word) u);
26348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get the lower part */
26368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
26378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* carry the carry */
26398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
26408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
26418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    *tmpt = u;
26428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
26438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (&t);
26448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_exch (&t, c);
26458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear (&t);
26468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
26478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MONTGOMERY_SETUP_C
26518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* setups the montgomery reduction stuff */
26528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
26538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtmp_montgomery_setup (mp_int * n, mp_digit * rho)
26548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit x, b;
26568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* fast inversion mod 2**k
26588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
26598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Based on the fact that
26608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
26618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
26628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *                    =>  2*X*A - X*X*A*A = 1
26638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *                    =>  2*(1) - (1)     = 1
26648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
26658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b = n->dp[0];
26668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((b & 1) == 0) {
26688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return MP_VAL;
26698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
26708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
26728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
26738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if !defined(MP_8BIT)
26748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
26758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
26768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
26778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
26788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
26798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef MP_64BIT
26808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
26818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
26828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* rho = -1/m mod b */
26848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
26858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
26878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
26898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
26928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* computes xR**-1 == x (mod N) via Montgomery Reduction
26938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
26948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This is an optimized implementation of montgomery_reduce
26958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * which uses the comba method to quickly calculate the columns of the
26968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * reduction.
26978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
26988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Based on Algorithm 14.32 on pp.601 of HAC.
26998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt*/
27001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
27018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
27028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     ix, res, olduse;
27038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_word W[MP_WARRAY];
27048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* get old used count */
27068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  olduse = x->used;
27078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* grow a as required */
27098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (x->alloc < n->used + 1) {
27108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
27118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
27128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
27138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
27148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* first we have to get the digits of the input into
27168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * an array of double precision words W[...]
27178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
27188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
27198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_word *_W;
27208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *tmpx;
27218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for the W[] array */
27238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    _W   = W;
27248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for the digits of  x*/
27268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpx = x->dp;
27278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* copy the digits of a into W[0..a->used-1] */
27298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (ix = 0; ix < x->used; ix++) {
27308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *_W++ = *tmpx++;
27318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
27328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* zero the high words of W[a->used..m->used*2] */
27348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; ix < n->used * 2 + 1; ix++) {
27358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *_W++ = 0;
27368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
27378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
27388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now we proceed to zero successive digits
27408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * from the least significant upwards
27418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
27428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (ix = 0; ix < n->used; ix++) {
27438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* mu = ai * m' mod b
27448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *
27458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * We avoid a double precision multiplication (which isn't required)
27468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * by casting the value down to a mp_digit.  Note this requires
27478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * that W[ix-1] have  the carry cleared (see after the inner loop)
27488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
27498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit mu;
27508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
27518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* a = a + mu * m * b**i
27538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *
27548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * This is computed in place and on the fly.  The multiplication
27558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * by b**i is handled by offseting which columns the results
27568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * are added to.
27578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *
27588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * Note the comba method normally doesn't handle carries in the
27598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * inner loop In this case we fix the carry from the previous
27608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * column since the Montgomery reduction requires digits of the
27618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * result (so far) [see above] to work.  This is
27628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * handled by fixing up one carry after the inner loop.  The
27638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * carry fixups are done in order so after these loops the
27648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * first m->used words of W[] have the carries fixed
27658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
27668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    {
27678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      register int iy;
27688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      register mp_digit *tmpn;
27698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      register mp_word *_W;
27708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* alias for the digits of the modulus */
27728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmpn = n->dp;
27738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* Alias for the columns set by an offset of ix */
27758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      _W = W + ix;
27768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* inner loop */
27788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (iy = 0; iy < n->used; iy++) {
27798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
27808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
27818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
27828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* now fix carry for next digit, W[ix+1] */
27848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
27858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
27868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now we have to propagate the carries and
27888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * shift the words downward [all those least
27898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * significant digits we zeroed].
27908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
27918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
27928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit *tmpx;
27938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_word *_W, *_W1;
27948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* nox fix rest of carries */
27968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for current word */
27988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    _W1 = W + ix;
27998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for next word, where the carry goes */
28018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    _W = W + ++ix;
28028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; ix <= n->used * 2 + 1; ix++) {
28048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
28058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
28068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* copy out, A = A/b**n
28088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *
28098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * The result is A/b**n but instead of converting from an
28108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * array of mp_word to mp_digit than calling mp_rshd
28118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * we just copy them in the right order
28128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
28138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for destination word */
28158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpx = x->dp;
28168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for shifted double precision result */
28188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    _W = W + n->used;
28198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (ix = 0; ix < n->used + 1; ix++) {
28218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
28228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
28238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* zero oldused digits, if the input a was larger than
28258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * m->used+1 we'll have to clear the digits
28268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
28278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; ix < olduse; ix++) {
28288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpx++ = 0;
28298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
28308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
28318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set the max used and clamp */
28338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x->used = n->used + 1;
28348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (x);
28358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if A >= m then A = A - m */
28378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mp_cmp_mag (x, n) != MP_LT) {
28388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return s_mp_sub (x, n, x);
28398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
28408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
28418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
28428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
28438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MUL_2_C
28468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* b = a*2 */
28478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_mul_2(mp_int * a, mp_int * b)
28488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
28498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x, res, oldused;
28508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt  /* grow to accommodate result */
28528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b->alloc < a->used + 1) {
28538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
28548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
28558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
28568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
28578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  oldused = b->used;
28598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->used = a->used;
28608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
28628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    register mp_digit r, rr, *tmpa, *tmpb;
28638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for source */
28658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpa = a->dp;
28668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* alias for dest */
28688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp;
28698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* carry */
28718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    r = 0;
28728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = 0; x < a->used; x++) {
28738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get what will be the *next* carry bit from the
28758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * MSB of the current digit
28768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       */
28778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
28788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* now shift up this digit, add in the carry [from the previous] */
28808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
28818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* copy the carry that would be from the source
28838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * digit into the next iteration
28848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       */
28858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      r = rr;
28868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
28878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* new leading digit? */
28898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (r != 0) {
28908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* add a MSB which is always 1 at this point */
28918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb = 1;
28928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ++(b->used);
28938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
28948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* now zero any excess digits on the destination
28968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * that we didn't write to
28978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
28988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp + b->used;
28998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = b->used; x < oldused; x++) {
29008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb++ = 0;
29018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
29028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
29038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->sign = a->sign;
29048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
29058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
29068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
29078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
29108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
29118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * shifts with subtractions when the result is greater than b.
29128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
29131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * The method is slightly modified to shift B unconditionally up to just under
29141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * the leading bit of b.  This saves a lot of multiple precision shifting.
29158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
29168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
29178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
29188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     x, bits, res;
29198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* how many bits of last digit does b use */
29218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bits = mp_count_bits (b) % DIGIT_BIT;
29228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b->used > 1) {
29248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
29258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return res;
29268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
29278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
29288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     mp_set(a, 1);
29298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     bits = 1;
29308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
29318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now compute C = A * B mod b */
29348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
29358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
29368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
29378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
29388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mp_cmp_mag (a, b) != MP_LT) {
29398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
29408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return res;
29418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
29428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
29438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
29448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
29468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
29478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
29488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_EXPTMOD_FAST_C
29518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
29528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
29538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
29548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The value of k changes based on the size of the exponent.
29558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
29568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
29578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
29588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
29608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
29618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_int  M[TAB_SIZE], res;
29628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit buf, mp;
29638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
29648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* use a pointer to the reduction algorithm.  This allows us to use
29668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * one of many reduction algorithms without modding the guts of
29678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * the code with if statements everywhere.
29688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
29698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int     (*redux)(mp_int*,mp_int*,mp_digit);
29708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* find window size */
29728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  x = mp_count_bits (X);
29738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (x <= 7) {
29748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 2;
29758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 36) {
29768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 3;
29778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 140) {
29788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 4;
29798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 450) {
29808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 5;
29818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 1303) {
29828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 6;
29838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (x <= 3529) {
29848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 7;
29858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
29868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    winsize = 8;
29878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
29888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef MP_LOW_MEM
29908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (winsize > 5) {
29918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     winsize = 5;
29928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
29938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
29948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init M array */
29968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* init first cell */
29978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_init(&M[1])) != MP_OKAY) {
29988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     return err;
29998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
30008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now init the second half of the array */
30028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
30038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = mp_init(&M[x])) != MP_OKAY) {
30048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (y = 1<<(winsize-1); y < x; y++) {
30058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mp_clear (&M[y]);
30068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
30078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_clear(&M[1]);
30088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return err;
30098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
30108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
30118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* determine and setup reduction code */
30138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (redmode == 0) {
30148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MONTGOMERY_SETUP_C
30158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* now setup montgomery  */
30168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
30178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_M;
30188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
30198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
30208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     err = MP_VAL;
30218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     goto LBL_M;
30228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
30238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* automatically pick the comba one if available (saves quite a few calls/ifs) */
30258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
30268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if (((P->used * 2 + 1) < MP_WARRAY) &&
30278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
30288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        redux = fast_mp_montgomery_reduce;
30298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     } else
30308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
30318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     {
30328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MONTGOMERY_REDUCE_C
30338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /* use slower baseline Montgomery method */
30348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        redux = mp_montgomery_reduce;
30358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
30368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        err = MP_VAL;
30378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_M;
30388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
30398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
30408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else if (redmode == 1) {
30418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
30428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* setup DR reduction for moduli of the form B**k - b */
30438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     mp_dr_setup(P, &mp);
30448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     redux = mp_dr_reduce;
30458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
30468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     err = MP_VAL;
30478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     goto LBL_M;
30488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
30498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
30508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
30518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* setup DR reduction for moduli of the form 2**k - b */
30528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
30538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_M;
30548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
30558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     redux = mp_reduce_2k;
30568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
30578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     err = MP_VAL;
30588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     goto LBL_M;
30598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
30608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
30618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* setup result */
30638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_init (&res)) != MP_OKAY) {
30648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_M;
30658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
30668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* create M table
30688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   *
30698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   *
30718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   * The first half of the table is not computed though accept for M[0] and M[1]
30728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt   */
30738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (redmode == 0) {
30758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
30768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* now we need R mod m */
30778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
30788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       goto LBL_RES;
30798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
30808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
30818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     err = MP_VAL;
30828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     goto LBL_RES;
30838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
30848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* now set M[1] to G * R mod m */
30868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
30878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       goto LBL_RES;
30888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
30898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  } else {
30908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     mp_set(&res, 1);
30918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
30928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
30938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
30948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
30958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
30978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
30988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    goto LBL_RES;
30998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
31008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = 0; x < (winsize - 1); x++) {
31028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
31038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_RES;
31048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
31068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_RES;
31078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
31098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* create upper table */
31118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
31128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
31138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_RES;
31148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
31168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      goto LBL_RES;
31178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
31198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set initial mode and bit cnt */
31218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mode   = 0;
31228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bitcnt = 1;
31238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  buf    = 0;
31248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  digidx = X->used - 1;
31258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bitcpy = 0;
31268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  bitbuf = 0;
31278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (;;) {
31298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* grab next digit as required */
31308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (--bitcnt == 0) {
31318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* if digidx == -1 we are out of digits so break */
31328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if (digidx == -1) {
31338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        break;
31348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
31358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* read next digit and reset bitcnt */
31368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      buf    = X->dp[digidx--];
31378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitcnt = (int)DIGIT_BIT;
31388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* grab the next msb from the exponent */
31418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
31428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    buf <<= (mp_digit)1;
31438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* if the bit is zero and mode == 0 then we ignore it
31458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * These represent the leading zero bits before the first 1 bit
31468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * in the exponent.  Technically this opt is not required but it
31478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * does lower the # of trivial squaring/reductions used
31488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
31498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mode == 0 && y == 0) {
31508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      continue;
31518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* if the bit is zero and mode == 1 then we square */
31548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (mode == 1 && y == 0) {
31558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
31568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
31578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
31588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = redux (&res, P, mp)) != MP_OKAY) {
31598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
31608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
31618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      continue;
31628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* else we add it to the window */
31658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bitbuf |= (y << (winsize - ++bitcpy));
31668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mode    = 2;
31678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (bitcpy == winsize) {
31698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* ok window is filled so square as required and multiply  */
31708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* square first */
31718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (x = 0; x < winsize; x++) {
31728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
31738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
31748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
31758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = redux (&res, P, mp)) != MP_OKAY) {
31768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
31778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
31788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
31798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* then multiply */
31818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
31828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
31838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
31848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = redux (&res, P, mp)) != MP_OKAY) {
31858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
31868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
31878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* empty window and reset */
31898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitcpy = 0;
31908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitbuf = 0;
31918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mode   = 1;
31928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
31938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
31948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* if bits remain then square/multiply */
31968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (mode == 2 && bitcpy > 0) {
31978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* square then multiply if the bit is set */
31988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (x = 0; x < bitcpy; x++) {
31998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
32008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
32018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
32028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((err = redux (&res, P, mp)) != MP_OKAY) {
32038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        goto LBL_RES;
32048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
32058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get next bit of the window */
32078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      bitbuf <<= 1;
32088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((bitbuf & (1 << winsize)) != 0) {
32098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /* then multiply */
32108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
32118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
32128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
32138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if ((err = redux (&res, P, mp)) != MP_OKAY) {
32148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          goto LBL_RES;
32158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
32168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
32178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
32188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
32198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (redmode == 0) {
32218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     /* fixup result if Montgomery reduction is used
32228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      * recall that any value in a Montgomery system is
32238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      * actually multiplied by R mod n.  So we have
32248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      * to reduce one more time to cancel out the factor
32258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      * of R.
32268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      */
32278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     if ((err = redux(&res, P, mp)) != MP_OKAY) {
32288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       goto LBL_RES;
32298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     }
32308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
32318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* swap res with Y */
32338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_exch (&res, Y);
32348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  err = MP_OKAY;
32358d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_RES:mp_clear (&res);
32368d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLBL_M:
32378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clear(&M[1]);
32388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
32398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_clear (&M[x]);
32408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
32418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return err;
32428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
32448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_FAST_S_MP_SQR_C
32478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* the jist of squaring...
32488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * you do like mult except the offset of the tmpx [one that
32498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * starts closer to zero] can't equal the offset of tmpy.
32508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * So basically you set up iy like before then you min it with
32518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (ty-tx) so that it never happens.  You double all those
32528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * you add in the inner loop
32538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32548d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtAfter that loop you do the squares and add them in.
32558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt*/
32568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int fast_s_mp_sqr (mp_int * a, mp_int * b)
32588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
32598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int       olduse, res, pa, ix, iz;
32608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit   W[MP_WARRAY], *tmpx;
32618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_word   W1;
32628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* grow the destination as required */
32648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  pa = a->used + a->used;
32658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (b->alloc < pa) {
32668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (b, pa)) != MP_OKAY) {
32678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
32688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
32698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
32708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* number of output digits to produce */
32728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  W1 = 0;
32738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (ix = 0; ix < pa; ix++) {
32748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      int      tx, ty, iy;
32758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_word  _W;
32768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      mp_digit *tmpy;
32778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* clear counter */
32798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      _W = 0;
32808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* get offsets into the two bignums */
32828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      ty = MIN(a->used-1, ix);
32838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tx = ix - ty;
32848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* setup temp aliases */
32868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmpx = a->dp + tx;
32878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      tmpy = a->dp + ty;
32888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* this is the number of times the loop will iterrate, essentially
32908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         while (tx++ < a->used && ty-- >= 0) { ... }
32918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       */
32928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      iy = MIN(a->used-tx, ty+1);
32938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* now for squaring tx can never equal ty
32958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * we halve the distance since they approach at a rate of 2x
32968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       * and we have to round because odd cases need to be executed
32978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       */
32988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      iy = MIN(iy, (ty-tx+1)>>1);
32998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* execute loop */
33018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      for (iz = 0; iz < iy; iz++) {
33028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
33038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
33048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* double the inner product and add carry */
33068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      _W = _W + _W + W1;
33078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* even columns have the square term in them */
33098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      if ((ix&1) == 0) {
33108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
33118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      }
33128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* store it */
33148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      W[ix] = (mp_digit)(_W & MP_MASK);
33158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      /* make next carry */
33178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      W1 = _W >> ((mp_word)DIGIT_BIT);
33188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
33198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* setup dest */
33218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  olduse  = b->used;
33228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  b->used = a->used+a->used;
33238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  {
33258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mp_digit *tmpb;
33268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    tmpb = b->dp;
33278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (ix = 0; ix < pa; ix++) {
33288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb++ = W[ix] & MP_MASK;
33298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
33308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* clear unused digits [that existed in the old copy of c] */
33328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (; ix < olduse; ix++) {
33338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      *tmpb++ = 0;
33348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
33358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
33368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp (b);
33378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
33388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
33398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
33408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef BN_MP_MUL_D_C
33438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* multiply by a digit */
33448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
33458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtmp_mul_d (mp_int * a, mp_digit b, mp_int * c)
33468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
33478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_digit u, *tmpa, *tmpc;
33488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_word  r;
33498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  int      ix, res, olduse;
33508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* make sure c is big enough to hold a*b */
33528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (c->alloc < a->used + 1) {
33538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
33548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      return res;
33558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
33568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
33578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* get the original destinations used count */
33598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  olduse = c->used;
33608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set the sign */
33628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  c->sign = a->sign;
33638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* alias for a->dp [source] */
33658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  tmpa = a->dp;
33668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* alias for c->dp [dest] */
33688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  tmpc = c->dp;
33698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* zero carry */
33718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  u = 0;
33728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* compute columns */
33748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (ix = 0; ix < a->used; ix++) {
33758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* compute product and carry sum for this term */
33768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
33778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* mask off higher bits to get a single digit */
33798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
33808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /* send carry into next iteration */
33828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
33838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
33848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* store final carry [if any] and increment ix offset  */
33868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  *tmpc++ = u;
33878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  ++ix;
33888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* now zero digits above the top */
33908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  while (ix++ < olduse) {
33918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *tmpc++ = 0;
33928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
33938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  /* set used count */
33958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  c->used = a->used + 1;
33968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  mp_clamp(c);
33978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return MP_OKAY;
33998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
34008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
3401