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