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