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