From fd181cc841b4dde061fb62ea1d1b74ac92b0141c Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Sat, 17 May 2003 12:33:54 +0000 Subject: [PATCH] added libtommath-0.17 --- bn.pdf | Bin 231956 -> 233337 bytes bn.tex | 4 +- bn_fast_mp_invmod.c | 73 +- bn_fast_mp_montgomery_reduce.c | 4 +- bn_fast_s_mp_mul_digs.c | 38 +- bn_fast_s_mp_mul_high_digs.c | 16 +- bn_fast_s_mp_sqr.c | 18 +- bn_mp_add.c | 42 +- bn_mp_cmp.c | 13 +- bn_mp_cmp_mag.c | 8 +- bn_mp_copy.c | 9 +- bn_mp_div.c | 22 +- bn_mp_div_2.c | 8 +- bn_mp_div_2d.c | 10 +- bn_mp_dr_is_modulus.c | 34 + bn_mp_dr_reduce.c | 55 +- bn_mp_dr_setup.c | 25 + bn_mp_expt_d.c | 8 +- bn_mp_exptmod.c | 107 +- bn_mp_exptmod_fast.c | 83 +- bn_mp_gcd.c | 10 +- bn_mp_grow.c | 8 +- bn_mp_init.c | 1 - bn_mp_invmod.c | 91 +- bn_mp_jacobi.c | 2 +- bn_mp_karatsuba_mul.c | 39 +- bn_mp_karatsuba_sqr.c | 22 +- bn_mp_lshd.c | 7 +- bn_mp_montgomery_calc_normalization.c | 8 +- bn_mp_montgomery_reduce.c | 23 +- bn_mp_montgomery_setup.c | 23 +- bn_mp_mul.c | 10 +- bn_mp_mul_2.c | 37 +- bn_mp_mul_2d.c | 35 +- bn_mp_mul_d.c | 26 +- bn_mp_multi.c | 64 + bn_mp_prime_is_divisible.c | 4 +- bn_mp_prime_is_prime.c | 10 +- bn_mp_prime_next_prime.c | 14 +- bn_mp_reduce.c | 22 +- bn_mp_rshd.c | 7 +- bn_mp_set_int.c | 9 +- bn_mp_sqr.c | 3 +- bn_mp_sub.c | 43 +- bn_prime_tab.c | 5 +- bn_radix.c | 77 + bn_reverse.c | 2 +- bn_s_mp_add.c | 29 +- bn_s_mp_mul_digs.c | 26 +- bn_s_mp_mul_high_digs.c | 6 +- bn_s_mp_sub.c | 11 +- bncore.c | 16 +- booker.pl | 261 + changes.txt | 34 + demo/demo.c | 347 +- demo/test.c | 0 etc/makefile | 21 +- etc/mont.c | 45 + etc/timer.asm | 37 + etc/tune.c | 117 +- gen.pl | 37 +- logs/README | 13 + logs/add.log | 16 + logs/addsub.png | Bin 0 -> 5941 bytes logs/expt.log | 7 + logs/expt.png | Bin 0 -> 5601 bytes logs/expt_dr.log | 7 + logs/graphs.dem | 17 + logs/index.html | 24 + logs/invmod.log | 32 + logs/invmod.png | Bin 0 -> 4818 bytes logs/mult.log | 17 + logs/mult.png | Bin 0 -> 7035 bytes logs/mult_kara.log | 17 + logs/sqr.log | 17 + logs/sqr_kara.log | 17 + logs/sub.log | 16 + makefile | 44 +- makefile.msvc | 3 +- mtest/mtest.c | 134 +- pics/makefile | 17 + pics/sliding_window.TIF | Bin 0 -> 53880 bytes pics/sliding_window.sxd | Bin 0 -> 6787 bytes pre_gen/mpi.c | 12407 ++++++++++++------------ tommath.h | 113 +- tommath.src | 2459 +++++ tommath.tex | 4195 ++++++++ 87 files changed, 14780 insertions(+), 6958 deletions(-) create mode 100644 bn_mp_dr_is_modulus.c create mode 100644 bn_mp_dr_setup.c create mode 100644 bn_mp_multi.c create mode 100644 booker.pl create mode 100644 demo/test.c create mode 100644 etc/mont.c create mode 100644 etc/timer.asm create mode 100644 logs/README create mode 100644 logs/add.log create mode 100644 logs/addsub.png create mode 100644 logs/expt.log create mode 100644 logs/expt.png create mode 100644 logs/expt_dr.log create mode 100644 logs/graphs.dem create mode 100644 logs/index.html create mode 100644 logs/invmod.log create mode 100644 logs/invmod.png create mode 100644 logs/mult.log create mode 100644 logs/mult.png create mode 100644 logs/mult_kara.log create mode 100644 logs/sqr.log create mode 100644 logs/sqr_kara.log create mode 100644 logs/sub.log create mode 100644 pics/makefile create mode 100644 pics/sliding_window.TIF create mode 100644 pics/sliding_window.sxd create mode 100644 tommath.src create mode 100644 tommath.tex diff --git a/bn.pdf b/bn.pdf index d047a8382b6fe727389e7de1e65cb5d259e2f11d..b81b577c4d298507090658725ab41009451cdaec 100644 GIT binary patch delta 128541 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

! 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 delta 127278 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 z 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 while (D.sign == MP_NEG) { if ((res = mp_add (&D, b, &D)) != MP_OKAY) { - goto __D; + goto __ERR; } } mp_exch (&D, c); c->sign = neg; res = MP_OKAY; -__D:mp_clear (&D); -__B:mp_clear (&B); -__V:mp_clear (&v); -__U:mp_clear (&u); -__Y:mp_clear (&y); -__X:mp_clear (&x); -__ERR: +__ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); return res; } diff --git a/bn_fast_mp_montgomery_reduce.c b/bn_fast_mp_montgomery_reduce.c index 031b410..7591902 100644 --- a/bn_fast_mp_montgomery_reduce.c +++ b/bn_fast_mp_montgomery_reduce.c @@ -26,7 +26,7 @@ int fast_mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) { int ix, res, olduse; - mp_word W[512]; + mp_word W[MP_WARRAY]; /* get old used count */ olduse = a->used; @@ -92,7 +92,7 @@ fast_mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) /* inner loop */ for (iy = 0; iy < m->used; iy++) { - *_W++ += ((mp_word) ui) * ((mp_word) * tmpx++); + *_W++ += ((mp_word) ui) * ((mp_word) * tmpx++); } } diff --git a/bn_fast_s_mp_mul_digs.c b/bn_fast_s_mp_mul_digs.c index 3cba3e1..d09489d 100644 --- a/bn_fast_s_mp_mul_digs.c +++ b/bn_fast_s_mp_mul_digs.c @@ -16,14 +16,16 @@ /* Fast (comba) multiplier * - * This is the fast column-array [comba] multiplier. It is designed to compute - * the columns of the product first then handle the carries afterwards. This - * has the effect of making the nested loops that compute the columns very + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very * simple and schedulable on super-scalar processors. * - * This has been modified to produce a variable number of digits of output so - * if say only a half-product is required you don't have to compute the upper half - * (a feature required for fast Barrett reduction). + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). * * Based on Algorithm 14.12 on pp.595 of HAC. * @@ -32,7 +34,7 @@ int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) { int olduse, res, pa, ix; - mp_word W[512]; + mp_word W[MP_WARRAY]; /* grow the destination as required */ if (c->alloc < digs) { @@ -47,10 +49,9 @@ fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) /* calculate the columns */ pa = a->used; for (ix = 0; ix < pa; ix++) { - - /* this multiplier has been modified to allow you to control how many digits - * of output are produced. So at most we want to make upto "digs" digits - * of output. + /* this multiplier has been modified to allow you to + * control how many digits of output are produced. + * So at most we want to make upto "digs" digits of output. * * this adds products to distinct columns (at ix+iy) of W * note that each step through the loop is not dependent on @@ -73,14 +74,14 @@ fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) */ _W = W + ix; - /* the number of digits is limited by their placement. E.g. + /* the number of digits is limited by their placement. E.g. we avoid multiplying digits that will end up above the # of digits of precision requested */ pb = MIN (b->used, digs - ix); for (iy = 0; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); } } @@ -97,11 +98,12 @@ fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) * correct result we must take the extra bits from each column and * carry them down * - * Note that while this adds extra code to the multiplier it saves time - * since the carry propagation is removed from the above nested loop. - * This has the effect of reducing the work from N*(N+N*c)==N^2 + c*N^2 to - * N^2 + N*c where c is the cost of the shifting. On very small numbers - * this is slower but on most cryptographic size numbers it is faster. + * Note that while this adds extra code to the multiplier it + * saves time since the carry propagation is removed from the + * above nested loop.This has the effect of reducing the work + * from N*(N+N*c)==N**2 + c*N**2 to N**2 + N*c where c is the + * cost of the shifting. On very small numbers this is slower + * but on most cryptographic size numbers it is faster. */ tmpc = c->dp; for (ix = 1; ix < digs; ix++) { diff --git a/bn_fast_s_mp_mul_high_digs.c b/bn_fast_s_mp_mul_high_digs.c index 4a21441..1cc1639 100644 --- a/bn_fast_s_mp_mul_high_digs.c +++ b/bn_fast_s_mp_mul_high_digs.c @@ -27,7 +27,7 @@ int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) { int oldused, newused, res, pa, pb, ix; - mp_word W[512]; + mp_word W[MP_WARRAY]; /* calculate size of product and allocate more space if required */ newused = a->used + b->used + 1; @@ -55,15 +55,23 @@ fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) /* alias for right side */ tmpy = b->dp + iy; - + /* alias for the columns of output. Offset to be equal to or above the * smallest digit place requested */ - _W = &(W[digs]); + _W = W + digs; + + /* skip cases below zero where ix > digs */ + if (iy < 0) { + iy = abs(iy); + tmpy += iy; + _W += iy; + iy = 0; + } /* compute column products for digits above the minimum */ for (; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); } } } diff --git a/bn_fast_s_mp_sqr.c b/bn_fast_s_mp_sqr.c index 093bc89..7ce3839 100644 --- a/bn_fast_s_mp_sqr.c +++ b/bn_fast_s_mp_sqr.c @@ -20,7 +20,7 @@ * then the carries are computed. This has the effect of making a very simple * inner loop that is executed the most * - * W2 represents the outer products and W the inner. + * W2 represents the outer products and W the inner. * * A further optimizations is made because the inner products are of the form * "A * B * 2". The *2 part does not need to be computed until the end which is @@ -33,7 +33,7 @@ int fast_s_mp_sqr (mp_int * a, mp_int * b) { int olduse, newused, res, ix, pa; - mp_word W2[512], W[512]; + mp_word W2[MP_WARRAY], W[MP_WARRAY]; /* calculate size of product and allocate as required */ pa = a->used; @@ -44,9 +44,9 @@ fast_s_mp_sqr (mp_int * a, mp_int * b) } } - /* zero temp buffer (columns) + /* zero temp buffer (columns) * Note that there are two buffers. Since squaring requires - * a outter and inner product and the inner product requires + * a outter and inner product and the inner product requires * computing a product and doubling it (a relatively expensive * op to perform n^2 times if you don't have to) the inner and * outer products are computed in different buffers. This way @@ -60,7 +60,7 @@ fast_s_mp_sqr (mp_int * a, mp_int * b) * values in W2 are only written in even locations which means * we can collapse the array to 256 words [and fixup the memset above] * provided we also fix up the summations below. Ideally - * the fixup loop should be unrolled twice to handle the even/odd + * the fixup loop should be unrolled twice to handle the even/odd * cases, and then a final step to handle odd cases [e.g. newused == odd] * * This will not only save ~8*256 = 2KB of stack but lower the number of @@ -71,10 +71,10 @@ fast_s_mp_sqr (mp_int * a, mp_int * b) * the multiplication by two is done afterwards in the N loop. */ for (ix = 0; ix < pa; ix++) { - /* compute the outer product + /* compute the outer product * - * Note that every outer product is computed - * for a particular column only once which means that + * Note that every outer product is computed + * for a particular column only once which means that * there is no need todo a double precision addition */ W2[ix + ix] = ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); @@ -95,7 +95,7 @@ fast_s_mp_sqr (mp_int * a, mp_int * b) /* inner products */ for (iy = ix + 1; iy < pa; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); } } } diff --git a/bn_mp_add.c b/bn_mp_add.c index 02f130a..43a08ab 100644 --- a/bn_mp_add.c +++ b/bn_mp_add.c @@ -24,33 +24,25 @@ mp_add (mp_int * a, mp_int * b, mp_int * c) sa = a->sign; sb = b->sign; - /* handle four cases */ - if (sa == MP_ZPOS && sb == MP_ZPOS) { - /* both positive */ + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; res = s_mp_add (a, b, c); - c->sign = MP_ZPOS; - } else if (sa == MP_ZPOS && sb == MP_NEG) { - /* a + -b == a - b, but if b>a then we do it as -(b-a) */ - if (mp_cmp_mag (a, b) == MP_LT) { - res = s_mp_sub (b, a, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (a, b, c); - c->sign = MP_ZPOS; - } - } else if (sa == MP_NEG && sb == MP_ZPOS) { - /* -a + b == b - a, but if a>b then we do it as -(a-b) */ - if (mp_cmp_mag (a, b) == MP_GT) { - res = s_mp_sub (a, b, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (b, a, c); - c->sign = MP_ZPOS; - } } else { - /* -a + -b == -(a + b) */ - res = s_mp_add (a, b, c); - c->sign = MP_NEG; + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } } return res; } + diff --git a/bn_mp_cmp.c b/bn_mp_cmp.c index 391eca3..4bf8082 100644 --- a/bn_mp_cmp.c +++ b/bn_mp_cmp.c @@ -21,8 +21,17 @@ mp_cmp (mp_int * a, mp_int * b) /* compare based on sign */ if (a->sign == MP_NEG && b->sign == MP_ZPOS) { return MP_LT; - } else if (a->sign == MP_ZPOS && b->sign == MP_NEG) { + } + + if (a->sign == MP_ZPOS && b->sign == MP_NEG) { return MP_GT; } - return mp_cmp_mag (a, b); + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } } diff --git a/bn_mp_cmp_mag.c b/bn_mp_cmp_mag.c index a40b518..87b56d6 100644 --- a/bn_mp_cmp_mag.c +++ b/bn_mp_cmp_mag.c @@ -23,7 +23,9 @@ mp_cmp_mag (mp_int * a, mp_int * b) /* compare based on # of non-zero digits */ if (a->used > b->used) { return MP_GT; - } else if (a->used < b->used) { + } + + if (a->used < b->used) { return MP_LT; } @@ -31,7 +33,9 @@ mp_cmp_mag (mp_int * a, mp_int * b) for (n = a->used - 1; n >= 0; n--) { if (a->dp[n] > b->dp[n]) { return MP_GT; - } else if (a->dp[n] < b->dp[n]) { + } + + if (a->dp[n] < b->dp[n]) { return MP_LT; } } diff --git a/bn_mp_copy.c b/bn_mp_copy.c index 1bf5f12..ebdca5a 100644 --- a/bn_mp_copy.c +++ b/bn_mp_copy.c @@ -31,13 +31,10 @@ mp_copy (mp_int * a, mp_int * b) } /* zero b and copy the parameters over */ - b->used = a->used; - b->sign = a->sign; - { register mp_digit *tmpa, *tmpb; - /* point aliases */ + /* pointer aliases */ tmpa = a->dp; tmpb = b->dp; @@ -47,9 +44,11 @@ mp_copy (mp_int * a, mp_int * b) } /* clear high digits */ - for (; n < b->alloc; n++) { + for (; n < b->used; n++) { *tmpb++ = 0; } } + b->used = a->used; + b->sign = a->sign; return MP_OKAY; } diff --git a/bn_mp_div.c b/bn_mp_div.c index 3888a4b..3ba609d 100644 --- a/bn_mp_div.c +++ b/bn_mp_div.c @@ -75,7 +75,7 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) /* normalize both x and y, ensure that y >= b/2, [b == 2^DIGIT_BIT] */ norm = mp_count_bits(&y) % DIGIT_BIT; - if (norm < (DIGIT_BIT-1)) { + if (norm < (int)(DIGIT_BIT-1)) { norm = (DIGIT_BIT-1) - norm; if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { goto __Y; @@ -86,13 +86,13 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) } else { norm = 0; } - + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ n = x.used - 1; t = y.used - 1; /* step 2. while (x >= y*b^n-t) do { q[n-t] += 1; x -= y*b^{n-t} } */ - if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b^{n-t} */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b^{n-t} */ goto __Y; } @@ -113,14 +113,14 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) /* step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ if (x.dp[i] == y.dp[t]) { - q.dp[i - t - 1] = ((1UL << DIGIT_BIT) - 1UL); + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); } else { mp_word tmp; tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); tmp |= ((mp_word) x.dp[i - 1]); tmp /= ((mp_word) y.dp[t]); if (tmp > (mp_word) MP_MASK) - tmp = MP_MASK; + tmp = MP_MASK; q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); } @@ -135,7 +135,7 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) t1.dp[1] = y.dp[t]; t1.used = 2; if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { - goto __Y; + goto __Y; } /* find right hand */ @@ -143,7 +143,7 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; t2.dp[2] = x.dp[i]; t2.used = 3; - } while (mp_cmp (&t1, &t2) == MP_GT); + } while (mp_cmp_mag(&t1, &t2) == MP_GT); /* step 3.3 x = x - q{i-t-1} * y * b^{i-t-1} */ if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { @@ -161,19 +161,19 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) /* step 3.4 if x < 0 then { x = x + y*b^{i-t-1}; q{i-t-1} -= 1; } */ if (x.sign == MP_NEG) { if ((res = mp_copy (&y, &t1)) != MP_OKAY) { - goto __Y; + goto __Y; } if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { - goto __Y; + goto __Y; } if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { - goto __Y; + goto __Y; } q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; } } - + /* now q is the quotient and x is the remainder [which we have to normalize] */ /* get sign before writing to c */ x.sign = a->sign; diff --git a/bn_mp_div_2.c b/bn_mp_div_2.c index 858e8a4..1ade93c 100644 --- a/bn_mp_div_2.c +++ b/bn_mp_div_2.c @@ -34,19 +34,19 @@ mp_div_2 (mp_int * a, mp_int * b) /* source alias */ tmpa = a->dp + b->used - 1; - + /* dest alias */ tmpb = b->dp + b->used - 1; - + /* carry */ r = 0; for (x = b->used - 1; x >= 0; x--) { /* get the carry for the next iteration */ rr = *tmpa & 1; - + /* shift the current digit, add in carry and store */ *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); - + /* forward carry to next iteration */ r = rr; } diff --git a/bn_mp_div_2d.c b/bn_mp_div_2d.c index 75501a4..f050c29 100644 --- a/bn_mp_div_2d.c +++ b/bn_mp_div_2d.c @@ -51,7 +51,7 @@ mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) } /* shift by as many digits in the bit count */ - if (b >= DIGIT_BIT) { + if (b >= (int)DIGIT_BIT) { mp_rshd (c, b / DIGIT_BIT); } @@ -59,13 +59,13 @@ mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) D = (mp_digit) (b % DIGIT_BIT); if (D != 0) { register mp_digit *tmpc, mask; - + /* mask */ - mask = (1U << D) - 1U; - + mask = (((mp_digit)1) << D) - 1; + /* alias */ tmpc = c->dp + (c->used - 1); - + /* carry */ r = 0; for (x = c->used - 1; x >= 0; x--) { diff --git a/bn_mp_dr_is_modulus.c b/bn_mp_dr_is_modulus.c new file mode 100644 index 0000000..381af17 --- /dev/null +++ b/bn_mp_dr_is_modulus.c @@ -0,0 +1,34 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return 0; + } + } + return 1; +} + diff --git a/bn_mp_dr_reduce.c b/bn_mp_dr_reduce.c index 75fb7ba..c8488e0 100644 --- a/bn_mp_dr_reduce.c +++ b/bn_mp_dr_reduce.c @@ -16,7 +16,7 @@ /* reduce "a" in place modulo "b" using the Diminished Radix algorithm. * - * Based on algorithm from the paper + * Based on algorithm from the paper * * "Generating Efficient Primes for Discrete Log Cryptosystems" * Chae Hoon Lim, Pil Loong Lee, @@ -40,15 +40,15 @@ mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) return err; } } - + /* alias for a->dp[i] */ tmpi = a->dp + k + k - 1; - /* for (i = 2k - 1; i >= k; i = i - 1) + /* for (i = 2k - 1; i >= k; i = i - 1) * * This is the main loop of the reduction. Note that at the end * the words above position k are not zeroed as expected. The end - * result is that the digits from 0 to k-1 are the residue. So + * result is that the digits from 0 to k-1 are the residue. So * we have to clear those afterwards. */ for (i = k + k - 1; i >= k; i = i - 1) { @@ -57,10 +57,10 @@ mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) /* x[i] * mp */ r = ((mp_word) *tmpi--) * ((mp_word) mp); - /* now add r to x[i-1:i-k] + /* now add r to x[i-1:i-k] * * First add it to the first digit x[i-k] then form the carry - * then enter the main loop + * then enter the main loop */ j = i - k; @@ -74,14 +74,14 @@ mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) mu = (r >> ((mp_word) DIGIT_BIT)) + (*tmpj >> DIGIT_BIT); /* clear carry from a->dp[j] */ - *tmpj++ &= MP_MASK; + *tmpj++ &= MP_MASK; - /* now add rest of the digits - * + /* now add rest of the digits + * * Note this is basically a simple single digit addition to * a larger multiple digit number. This is optimized somewhat * because the propagation of carries is not likely to move - * more than a few digits. + * more than a few digits. * */ for (++j; mu != 0 && j <= (i - 1); ++j) { @@ -99,16 +99,16 @@ mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) *tmpj += mp; mu = *tmpj >> DIGIT_BIT; *tmpj++ &= MP_MASK; - + /* now handle carries */ for (++j; mu != 0 && j <= (i - 1); j++) { - *tmpj += mu; - mu = *tmpj >> DIGIT_BIT; - *tmpj++ &= MP_MASK; + *tmpj += mu; + mu = *tmpj >> DIGIT_BIT; + *tmpj++ &= MP_MASK; } } } - + /* zero words above k */ tmpi = a->dp + k; for (i = k; i < a->used; i++) { @@ -117,34 +117,13 @@ mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) /* clamp, sub and return */ mp_clamp (a); - + + /* if a >= b [b == modulus] then subtract the modulus to fix up */ if (mp_cmp_mag (a, b) != MP_LT) { return s_mp_sub (a, b, a); } return MP_OKAY; } -/* determines if a number is a valid DR modulus */ -int mp_dr_is_modulus(mp_int *a) -{ - int ix; - - /* must be at least two digits */ - if (a->used < 2) { - return 0; - } - - for (ix = 1; ix < a->used; ix++) { - if (a->dp[ix] != MP_MASK) { - return 0; - } - } - return 1; -} -/* determines the setup value */ -void mp_dr_setup(mp_int *a, mp_digit *d) -{ - *d = (1 << DIGIT_BIT) - a->dp[0]; -} diff --git a/bn_mp_dr_setup.c b/bn_mp_dr_setup.c new file mode 100644 index 0000000..62dba02 --- /dev/null +++ b/bn_mp_dr_setup.c @@ -0,0 +1,25 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - ((mp_word)a->dp[0])); +} + diff --git a/bn_mp_expt_d.c b/bn_mp_expt_d.c index 144ae07..1f76830 100644 --- a/bn_mp_expt_d.c +++ b/bn_mp_expt_d.c @@ -35,11 +35,11 @@ mp_expt_d (mp_int * a, mp_digit b, mp_int * c) return res; } - /* if the bit is set multiply */ - if ((b & (mp_digit) (1 << (DIGIT_BIT - 1))) != 0) { + /* if the bit is set multiply */ + if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) { if ((res = mp_mul (c, &g, c)) != MP_OKAY) { - mp_clear (&g); - return res; + mp_clear (&g); + return res; } } diff --git a/bn_mp_exptmod.c b/bn_mp_exptmod.c index b6635f5..573f760 100644 --- a/bn_mp_exptmod.c +++ b/bn_mp_exptmod.c @@ -17,7 +17,7 @@ static int f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); /* this is a shell function that calls either the normal or Montgomery - * exptmod functions. Originally the call to the montgomery code was + * exptmod functions. Originally the call to the montgomery code was * embedded in the normal function but that wasted alot of stack space * for nothing (since 99% of the time the Montgomery code would be called) */ @@ -25,10 +25,46 @@ int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) { int dr; - + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)^|X| instead of G^X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + dr = mp_dr_is_modulus(P); /* if the modulus is odd use the fast method */ - if (((mp_isodd (P) == 1 && P->used < MONTGOMERY_EXPT_CUTOFF) || dr == 1) && P->used > 4) { + if ((mp_isodd (P) == 1 || dr == 1) && P->used > 4) { return mp_exptmod_fast (G, X, P, Y, dr); } else { return f_mp_exptmod (G, X, P, Y); @@ -60,11 +96,17 @@ f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) winsize = 8; } +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + /* init G array */ for (x = 0; x < (1 << winsize); x++) { if ((err = mp_init_size (&M[x], 1)) != MP_OKAY) { for (y = 0; y < x; y++) { - mp_clear (&M[y]); + mp_clear (&M[y]); } return err; } @@ -78,7 +120,7 @@ f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) goto __MU; } - /* create M table + /* create M table * * The M table contains powers of the input base, e.g. M[x] = G^x mod P * @@ -119,30 +161,29 @@ f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) mp_set (&res, 1); /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 0; - buf = 0; + mode = 0; + bitcnt = 1; + buf = 0; digidx = X->used - 1; bitcpy = bitbuf = 0; - bitcnt = 1; for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { if (digidx == -1) { - break; + break; } buf = X->dp[digidx--]; bitcnt = (int) DIGIT_BIT; } /* grab the next msb from the exponent */ - y = (buf >> (DIGIT_BIT - 1)) & 1; - buf <<= 1; + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; - /* if the bit is zero and mode == 0 then we ignore it + /* if the bit is zero and mode == 0 then we ignore it * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it + * in the exponent. Technically this opt is not required but it * does lower the # of trivial squaring/reductions used */ if (mode == 0 && y == 0) @@ -151,10 +192,10 @@ f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) /* if the bit is zero and mode == 1 then we square */ if (mode == 1 && y == 0) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; + goto __RES; } if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; + goto __RES; } continue; } @@ -167,20 +208,20 @@ f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) /* ok window is filled so square as required and multiply */ /* square first */ for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } } /* then multiply */ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __MU; + goto __MU; } if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __MU; + goto __MU; } /* empty window and reset */ @@ -194,21 +235,21 @@ f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; + goto __RES; } if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; + goto __RES; } bitbuf <<= 1; if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } } } } diff --git a/bn_mp_exptmod_fast.c b/bn_mp_exptmod_fast.c index 0906f27..7edf736 100644 --- a/bn_mp_exptmod_fast.c +++ b/bn_mp_exptmod_fast.c @@ -19,7 +19,7 @@ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. * The value of k changes based on the size of the exponent. * - * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] */ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) @@ -28,7 +28,7 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) mp_digit buf, mp; int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; int (*redux)(mp_int*,mp_int*,mp_digit); - + /* find window size */ x = mp_count_bits (X); if (x <= 7) { @@ -47,22 +47,37 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) winsize = 8; } +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init G array */ for (x = 0; x < (1 << winsize); x++) { if ((err = mp_init (&M[x])) != MP_OKAY) { for (y = 0; y < x; y++) { - mp_clear (&M[y]); + mp_clear (&M[y]); } return err; } } - + if (redmode == 0) { /* now setup montgomery */ if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { goto __M; } - redux = mp_montgomery_reduce; + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if ( ((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else { + /* use slower baselien method */ + redux = mp_montgomery_reduce; + } } else { /* setup DR reduction */ mp_dr_setup(P, &mp); @@ -97,7 +112,7 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) goto __RES; } } - + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { goto __RES; @@ -123,42 +138,42 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) } /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 0; - buf = 0; + mode = 0; + bitcnt = 1; + buf = 0; digidx = X->used - 1; bitcpy = bitbuf = 0; - bitcnt = 1; for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { if (digidx == -1) { - break; + break; } buf = X->dp[digidx--]; bitcnt = (int) DIGIT_BIT; } /* grab the next msb from the exponent */ - y = (buf >> (DIGIT_BIT - 1)) & 1; - buf <<= 1; + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; /* if the bit is zero and mode == 0 then we ignore it * These represent the leading zero bits before the first 1 bit * in the exponent. Technically this opt is not required but it * does lower the # of trivial squaring/reductions used */ - if (mode == 0 && y == 0) + if (mode == 0 && y == 0) { continue; + } /* if the bit is zero and mode == 1 then we square */ if (mode == 1 && y == 0) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; + goto __RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; + goto __RES; } continue; } @@ -171,20 +186,20 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) /* ok window is filled so square as required and multiply */ /* square first */ for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } } /* then multiply */ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __RES; + goto __RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; + goto __RES; } /* empty window and reset */ @@ -198,21 +213,21 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; + goto __RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; + goto __RES; } bitbuf <<= 1; if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } } } } @@ -222,7 +237,7 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) if ((err = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { goto __RES; } - } + } mp_exch (&res, Y); err = MP_OKAY; diff --git a/bn_mp_gcd.c b/bn_mp_gcd.c index d7cc1d4..1c930c7 100644 --- a/bn_mp_gcd.c +++ b/bn_mp_gcd.c @@ -82,18 +82,18 @@ mp_gcd (mp_int * a, mp_int * b, mp_int * c) /* B3 (and B4). Halve t, if even */ while (t.used != 0 && mp_iseven(&t) == 1) { if ((res = mp_div_2 (&t, &t)) != MP_OKAY) { - goto __T; + goto __T; } } /* B5. if t>0 then u=t otherwise v=-t */ if (t.used != 0 && t.sign != MP_NEG) { if ((res = mp_copy (&t, &u)) != MP_OKAY) { - goto __T; + goto __T; } } else { if ((res = mp_copy (&t, &v)) != MP_OKAY) { - goto __T; + goto __T; } v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; } @@ -102,9 +102,9 @@ mp_gcd (mp_int * a, mp_int * b, mp_int * c) if ((res = mp_sub (&u, &v, &t)) != MP_OKAY) { goto __T; } - } - while (t.used != 0); + } while (mp_iszero(&t) == 0); + /* multiply by 2^k which we divided out at the beginning */ if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { goto __T; } diff --git a/bn_mp_grow.c b/bn_mp_grow.c index 9bd5118..2a8249c 100644 --- a/bn_mp_grow.c +++ b/bn_mp_grow.c @@ -18,12 +18,12 @@ int mp_grow (mp_int * a, int size) { - int i, n; + int i; /* if the alloc size is smaller alloc more ram */ if (a->alloc < size) { /* ensure there are always at least MP_PREC digits extra on top */ - size += (MP_PREC * 2) - (size & (MP_PREC - 1)); + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * size); if (a->dp == NULL) { @@ -31,9 +31,9 @@ mp_grow (mp_int * a, int size) } /* zero excess digits */ - n = a->alloc; + i = a->alloc; a->alloc = size; - for (i = n; i < a->alloc; i++) { + for (; i < a->alloc; i++) { a->dp[i] = 0; } } diff --git a/bn_mp_init.c b/bn_mp_init.c index b96e6d9..3af7499 100644 --- a/bn_mp_init.c +++ b/bn_mp_init.c @@ -18,7 +18,6 @@ int mp_init (mp_int * a) { - /* allocate ram required and clear it */ a->dp = OPT_CAST calloc (sizeof (mp_digit), MP_PREC); if (a->dp == NULL) { diff --git a/bn_mp_invmod.c b/bn_mp_invmod.c index 4e2c1f7..36ce092 100644 --- a/bn_mp_invmod.c +++ b/bn_mp_invmod.c @@ -29,63 +29,36 @@ mp_invmod (mp_int * a, mp_int * b, mp_int * c) if (mp_iseven (b) == 0) { return fast_mp_invmod (a, b, c); } - - if ((res = mp_init (&x)) != MP_OKAY) { - goto __ERR; - } - - if ((res = mp_init (&y)) != MP_OKAY) { - goto __X; - } - - if ((res = mp_init (&u)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_init (&v)) != MP_OKAY) { - goto __U; - } - - if ((res = mp_init (&A)) != MP_OKAY) { - goto __V; - } - - if ((res = mp_init (&B)) != MP_OKAY) { - goto __A; - } - - if ((res = mp_init (&C)) != MP_OKAY) { - goto __B; - } - - if ((res = mp_init (&D)) != MP_OKAY) { - goto __C; + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; } /* x = a, y = b */ if ((res = mp_copy (a, &x)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_copy (b, &y)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_abs (&x, &x)) != MP_OKAY) { - goto __D; + goto __ERR; } /* 2. [modified] if x,y are both even then return an error! */ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { res = MP_VAL; - goto __D; + goto __ERR; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ if ((res = mp_copy (&x, &u)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_copy (&y, &v)) != MP_OKAY) { - goto __D; + goto __ERR; } mp_set (&A, 1); mp_set (&D, 1); @@ -96,24 +69,24 @@ top: while (mp_iseven (&u) == 1) { /* 4.1 u = u/2 */ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __D; + goto __ERR; } /* 4.2 if A or B is odd then */ if (mp_iseven (&A) == 0 || mp_iseven (&B) == 0) { /* A = (A+y)/2, B = (B-x)/2 */ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { - goto __D; + goto __ERR; } } /* A = A/2, B = B/2 */ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { - goto __D; + goto __ERR; } } @@ -122,24 +95,24 @@ top: while (mp_iseven (&v) == 1) { /* 5.1 v = v/2 */ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __D; + goto __ERR; } /* 5.2 if C,D are even then */ if (mp_iseven (&C) == 0 || mp_iseven (&D) == 0) { /* C = (C+y)/2, D = (D-x)/2 */ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { - goto __D; + goto __ERR; } } /* C = C/2, D = D/2 */ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { - goto __D; + goto __ERR; } } @@ -147,28 +120,28 @@ top: if (mp_cmp (&u, &v) != MP_LT) { /* u = u - v, A = A - C, B = B - D */ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { - goto __D; + goto __ERR; } } else { /* v - v - u, C = C - A, D = D - B */ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { - goto __D; + goto __ERR; } if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { - goto __D; + goto __ERR; } } @@ -181,21 +154,13 @@ top: /* if v != 1 then there is no inverse */ if (mp_cmp_d (&v, 1) != MP_EQ) { res = MP_VAL; - goto __D; + goto __ERR; } /* a is now the inverse */ mp_exch (&C, c); res = MP_OKAY; -__D:mp_clear (&D); -__C:mp_clear (&C); -__B:mp_clear (&B); -__A:mp_clear (&A); -__V:mp_clear (&v); -__U:mp_clear (&u); -__Y:mp_clear (&y); -__X:mp_clear (&x); -__ERR: +__ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); return res; } diff --git a/bn_mp_jacobi.c b/bn_mp_jacobi.c index bfe7bfc..1a7573d 100644 --- a/bn_mp_jacobi.c +++ b/bn_mp_jacobi.c @@ -14,7 +14,7 @@ */ #include -/* computes the jacobi c = (a | n) (or Legendre if b is prime) +/* computes the jacobi c = (a | n) (or Legendre if n is prime) * HAC pp. 73 Algorithm 2.149 */ int diff --git a/bn_mp_karatsuba_mul.c b/bn_mp_karatsuba_mul.c index 79358fb..f720a11 100644 --- a/bn_mp_karatsuba_mul.c +++ b/bn_mp_karatsuba_mul.c @@ -36,7 +36,7 @@ int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) { - mp_int x0, x1, y0, y1, t1, t2, x0y0, x1y1; + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; int B, err; err = MP_MEM; @@ -60,10 +60,8 @@ mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) /* init temps */ if (mp_init_size (&t1, B * 2) != MP_OKAY) goto Y1; - if (mp_init_size (&t2, B * 2) != MP_OKAY) - goto T1; if (mp_init_size (&x0y0, B * 2) != MP_OKAY) - goto T2; + goto T1; if (mp_init_size (&x1y1, B * 2) != MP_OKAY) goto X0Y0; @@ -110,41 +108,40 @@ mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) mp_clamp (&y0); /* now calc the products x0y0 and x1y1 */ - if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) - goto X1Y1; /* x0y0 = x0*y0 */ + if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) /* after this x0 is no longer required, free temp [x0==t2]! */ + goto X1Y1; /* x0y0 = x0*y0 */ if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) - goto X1Y1; /* x1y1 = x1*y1 */ + goto X1Y1; /* x1y1 = x1*y1 */ /* now calc x1-x0 and y1-y0 */ if (mp_sub (&x1, &x0, &t1) != MP_OKAY) - goto X1Y1; /* t1 = x1 - x0 */ - if (mp_sub (&y1, &y0, &t2) != MP_OKAY) - goto X1Y1; /* t2 = y1 - y0 */ - if (mp_mul (&t1, &t2, &t1) != MP_OKAY) - goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ + goto X1Y1; /* t1 = x1 - x0 */ + if (mp_sub (&y1, &y0, &x0) != MP_OKAY) + goto X1Y1; /* t2 = y1 - y0 */ + if (mp_mul (&t1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ /* add x0y0 */ - if (mp_add (&x0y0, &x1y1, &t2) != MP_OKAY) - goto X1Y1; /* t2 = x0y0 + x1y1 */ - if (mp_sub (&t2, &t1, &t1) != MP_OKAY) - goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ + if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY) + goto X1Y1; /* t2 = x0y0 + x1y1 */ + if (mp_sub (&x0, &t1, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ /* shift by B */ if (mp_lshd (&t1, B) != MP_OKAY) - goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<used + b)) != MP_OKAY) { - return res; + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } } { diff --git a/bn_mp_montgomery_calc_normalization.c b/bn_mp_montgomery_calc_normalization.c index b942eba..a1ff2cd 100644 --- a/bn_mp_montgomery_calc_normalization.c +++ b/bn_mp_montgomery_calc_normalization.c @@ -15,10 +15,10 @@ #include /* calculates a = B^n mod b for Montgomery reduction - * Where B is the base [e.g. 2^DIGIT_BIT]. + * Where B is the base [e.g. 2^DIGIT_BIT]. * B^n mod b is computed by first computing * A = B^(n-1) which doesn't require a reduction but a simple OR. - * then C = A * B = B^n is computed by performing upto DIGIT_BIT + * then C = A * B = B^n is computed by performing upto DIGIT_BIT * shifts with subtractions when the result is greater than b. * * The method is slightly modified to shift B unconditionally upto just under @@ -38,13 +38,13 @@ mp_montgomery_calc_normalization (mp_int * a, mp_int * b) } /* now compute C = A * B mod b */ - for (x = bits - 1; x < DIGIT_BIT; x++) { + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { if ((res = mp_mul_2 (a, a)) != MP_OKAY) { return res; } if (mp_cmp_mag (a, b) != MP_LT) { if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { - return res; + return res; } } } diff --git a/bn_mp_montgomery_reduce.c b/bn_mp_montgomery_reduce.c index e64435c..69a5364 100644 --- a/bn_mp_montgomery_reduce.c +++ b/bn_mp_montgomery_reduce.c @@ -21,12 +21,19 @@ mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) int ix, res, digs; mp_digit ui; + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mp_mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ digs = m->used * 2 + 1; - if ((digs < 512) - && digs < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + if ((digs < MP_WARRAY) + && m->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { return fast_mp_montgomery_reduce (a, m, mp); } + /* grow the input as required */ if (a->alloc < m->used * 2 + 1) { if ((res = mp_grow (a, m->used * 2 + 1)) != MP_OKAY) { return res; @@ -50,15 +57,15 @@ mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) mu = 0; for (iy = 0; iy < m->used; iy++) { - r = ((mp_word) ui) * ((mp_word) * tmpx++) + ((mp_word) mu) + ((mp_word) * tmpy); - mu = (r >> ((mp_word) DIGIT_BIT)); - *tmpy++ = (r & ((mp_word) MP_MASK)); + r = ((mp_word) ui) * ((mp_word) * tmpx++) + ((mp_word) mu) + ((mp_word) * tmpy); + mu = (r >> ((mp_word) DIGIT_BIT)); + *tmpy++ = (r & ((mp_word) MP_MASK)); } /* propagate carries */ while (mu) { - *tmpy += mu; - mu = (*tmpy >> DIGIT_BIT) & 1; - *tmpy++ &= MP_MASK; + *tmpy += mu; + mu = (*tmpy >> DIGIT_BIT) & 1; + *tmpy++ &= MP_MASK; } } } diff --git a/bn_mp_montgomery_setup.c b/bn_mp_montgomery_setup.c index dfdc51a..e59fab6 100644 --- a/bn_mp_montgomery_setup.c +++ b/bn_mp_montgomery_setup.c @@ -18,11 +18,11 @@ int mp_montgomery_setup (mp_int * a, mp_digit * mp) { - unsigned long x, b; + mp_digit x, b; -/* fast inversion mod 2^32 +/* fast inversion mod 2^k * - * Based on the fact that + * Based on the fact that * * XA = 1 (mod 2^n) => (X(2-XA)) A = 1 (mod 2^2n) * => 2*X*A - X*X*A*A = 1 @@ -34,13 +34,20 @@ mp_montgomery_setup (mp_int * a, mp_digit * mp) return MP_VAL; } - x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2^4 */ - x *= 2 - b * x; /* here x*a==1 mod 2^8 */ - x *= 2 - b * x; /* here x*a==1 mod 2^16; each step doubles the nb of bits */ - x *= 2 - b * x; /* here x*a==1 mod 2^32 */ + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2^4 */ + x *= 2 - b * x; /* here x*a==1 mod 2^8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2^16; each step doubles the nb of bits */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2^32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2^64 */ +#endif /* t = -1/m mod b */ - *mp = ((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - (x & MP_MASK); + *mp = (((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK; return MP_OKAY; } diff --git a/bn_mp_mul.c b/bn_mp_mul.c index 5ccd6e4..258cb84 100644 --- a/bn_mp_mul.c +++ b/bn_mp_mul.c @@ -24,15 +24,15 @@ mp_mul (mp_int * a, mp_int * b, mp_int * c) res = mp_karatsuba_mul (a, b, c); } else { - /* can we use the fast multiplier? + /* can we use the fast multiplier? * - * The fast multiplier can be used if the output will have less than - * 512 digits and the number of digits won't affect carry propagation + * The fast multiplier can be used if the output will have less than + * MP_WARRAY digits and the number of digits won't affect carry propagation */ int digs = a->used + b->used + 1; - if ((digs < 512) - && digs < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + if ((digs < MP_WARRAY) + && MIN(a->used, b->used) <= (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { res = fast_s_mp_mul_digs (a, b, c, digs); } else { res = s_mp_mul (a, b, c); diff --git a/bn_mp_mul_2.c b/bn_mp_mul_2.c index fd8db1f..2bfc939 100644 --- a/bn_mp_mul_2.c +++ b/bn_mp_mul_2.c @@ -20,10 +20,9 @@ mp_mul_2 (mp_int * a, mp_int * b) { int x, res, oldused; - /* Optimization: should copy and shift at the same time */ - - if (b->alloc < a->used) { - if ((res = mp_grow (b, a->used)) != MP_OKAY) { + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { return res; } } @@ -31,7 +30,6 @@ mp_mul_2 (mp_int * a, mp_int * b) oldused = b->used; b->used = a->used; - /* shift any bit count < DIGIT_BIT */ { register mp_digit r, rr, *tmpa, *tmpb; @@ -43,37 +41,32 @@ mp_mul_2 (mp_int * a, mp_int * b) /* carry */ r = 0; - for (x = 0; x < b->used; x++) { + for (x = 0; x < a->used; x++) { - /* get what will be the *next* carry bit from the MSB of the current digit */ - rr = *tmpa >> (DIGIT_BIT - 1); + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); /* now shift up this digit, add in the carry [from the previous] */ - *tmpb++ = ((*tmpa++ << 1) | r) & MP_MASK; + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; - /* copy the carry that would be from the source digit into the next iteration */ + /* copy the carry that would be from the source + * digit into the next iteration + */ r = rr; } /* new leading digit? */ if (r != 0) { - /* do we have to grow to accomodate the new digit? */ - if (b->alloc == b->used) { - if ((res = mp_grow (b, b->used + 1)) != MP_OKAY) { - return res; - } - - /* after the grow *tmpb is no longer valid so we have to reset it! - * (this bug took me about 17 minutes to find...!) - */ - tmpb = b->dp + b->used; - } /* add a MSB which is always 1 at this point */ *tmpb = 1; ++b->used; } - /* now zero any excess digits on the destination that we didn't write to */ + /* now zero any excess digits on the destination + * that we didn't write to + */ tmpb = b->dp + b->used; for (x = b->used; x < oldused; x++) { *tmpb++ = 0; diff --git a/bn_mp_mul_2d.c b/bn_mp_mul_2d.c index 137df30..ded3a3c 100644 --- a/bn_mp_mul_2d.c +++ b/bn_mp_mul_2d.c @@ -14,24 +14,34 @@ */ #include +/* NOTE: This routine requires updating. For instance the c->used = c->alloc bit + is wrong. We should just shift c->used digits then set the carry as c->dp[c->used] = carry + + To be fixed for LTM 0.18 + */ + /* shift left by a certain bit count */ int mp_mul_2d (mp_int * a, int b, mp_int * c) { - mp_digit d, r, rr; - int x, res; + mp_digit d; + int res; /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - return res; + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } } - if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { - return res; + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 2)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 2)) != MP_OKAY) { + return res; + } } /* shift by as many digits in the bit count */ - if (b >= DIGIT_BIT) { + if (b >= (int)DIGIT_BIT) { if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { return res; } @@ -41,14 +51,15 @@ mp_mul_2d (mp_int * a, int b, mp_int * c) /* shift any bit count < DIGIT_BIT */ d = (mp_digit) (b % DIGIT_BIT); if (d != 0) { - register mp_digit *tmpc, mask; - + register mp_digit *tmpc, mask, r, rr; + register int x; + /* bitmask for carries */ - mask = (1U << d) - 1U; - + mask = (((mp_digit)1) << d) - 1; + /* alias */ tmpc = c->dp; - + /* carry */ r = 0; for (x = 0; x < c->used; x++) { diff --git a/bn_mp_mul_d.c b/bn_mp_mul_d.c index f4458bb..f17a9fb 100644 --- a/bn_mp_mul_d.c +++ b/bn_mp_mul_d.c @@ -20,6 +20,7 @@ mp_mul_d (mp_int * a, mp_digit b, mp_int * c) { int res, pa, olduse; + /* make sure c is big enough to hold a*b */ pa = a->used; if (c->alloc < pa + 1) { if ((res = mp_grow (c, pa + 1)) != MP_OKAY) { @@ -27,7 +28,10 @@ mp_mul_d (mp_int * a, mp_digit b, mp_int * c) } } + /* get the original destinations used count */ olduse = c->used; + + /* set the new temporary used count */ c->used = pa + 1; { @@ -35,21 +39,31 @@ mp_mul_d (mp_int * a, mp_digit b, mp_int * c) register mp_word r; register int ix; - tmpc = c->dp + c->used; - for (ix = c->used; ix < olduse; ix++) { - *tmpc++ = 0; - } - + /* alias for a->dp [source] */ tmpa = a->dp; + + /* alias for c->dp [dest] */ tmpc = c->dp; + /* zero carry */ u = 0; for (ix = 0; ix < pa; ix++) { + /* compute product and carry sum for this term */ r = ((mp_word) u) + ((mp_word) * tmpa++) * ((mp_word) b); + + /* mask off higher bits to get a single digit */ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); } - *tmpc = u; + /* store final carry [if any] */ + *tmpc++ = u; + + /* now zero digits above the top */ + for (; pa < olduse; pa++) { + *tmpc++ = 0; + } } mp_clamp (c); diff --git a/bn_mp_multi.c b/bn_mp_multi.c new file mode 100644 index 0000000..ef96dc6 --- /dev/null +++ b/bn_mp_multi.c @@ -0,0 +1,64 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +#include + +int mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +void mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} diff --git a/bn_mp_prime_is_divisible.c b/bn_mp_prime_is_divisible.c index dac2d0e..5b81104 100644 --- a/bn_mp_prime_is_divisible.c +++ b/bn_mp_prime_is_divisible.c @@ -14,7 +14,7 @@ */ #include -/* determines if an integers is divisible by one of the first 256 primes or not +/* determines if an integers is divisible by one of the first 256 primes or not * * sets result to 0 if not, 1 if yes */ @@ -27,7 +27,7 @@ mp_prime_is_divisible (mp_int * a, int *result) /* default to not */ *result = 0; - for (ix = 0; ix < 256; ix++) { + for (ix = 0; ix < PRIME_SIZE; ix++) { /* is it equal to the prime? */ if (mp_cmp_d (a, __prime_tab[ix]) == MP_EQ) { *result = 1; diff --git a/bn_mp_prime_is_prime.c b/bn_mp_prime_is_prime.c index 8910c87..1a782b3 100644 --- a/bn_mp_prime_is_prime.c +++ b/bn_mp_prime_is_prime.c @@ -31,10 +31,18 @@ mp_prime_is_prime (mp_int * a, int t, int *result) *result = 0; /* valid value of t? */ - if (t < 1 || t > 256) { + if (t < 1 || t > PRIME_SIZE) { return MP_VAL; } + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, __prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + /* first perform trial division */ if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { return err; diff --git a/bn_mp_prime_next_prime.c b/bn_mp_prime_next_prime.c index 932d914..cfebbe5 100644 --- a/bn_mp_prime_next_prime.c +++ b/bn_mp_prime_next_prime.c @@ -20,35 +20,35 @@ int mp_prime_next_prime(mp_int *a, int t) { int err, res; - + if (mp_iseven(a) == 1) { /* force odd */ if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { return err; } } else { - /* force to next number */ + /* force to next odd number */ if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { return err; } - } - + } + for (;;) { /* is this prime? */ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { return err; } - + if (res == 1) { break; } - + /* add two, next candidate */ if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { return err; } } - + return MP_OKAY; } diff --git a/bn_mp_reduce.c b/bn_mp_reduce.c index 5d85f42..d98dc08 100644 --- a/bn_mp_reduce.c +++ b/bn_mp_reduce.c @@ -21,8 +21,7 @@ int mp_reduce_setup (mp_int * a, mp_int * b) { int res; - - + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { return res; } @@ -30,8 +29,8 @@ mp_reduce_setup (mp_int * a, mp_int * b) return res; } -/* reduces x mod m, assumes 0 < x < m^2, mu is precomputed via mp_reduce_setup - * From HAC pp.604 Algorithm 14.42 +/* reduces x mod m, assumes 0 < x < m^2, mu is precomputed via mp_reduce_setup + * From HAC pp.604 Algorithm 14.42 */ int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) @@ -39,15 +38,15 @@ mp_reduce (mp_int * x, mp_int * m, mp_int * mu) mp_int q; int res, um = m->used; - if ((res = mp_init_copy (&q, x)) != MP_OKAY) { return res; } - mp_rshd (&q, um - 1); /* q1 = x / b^(k-1) */ + /* q1 = x / b^(k-1) */ + mp_rshd (&q, um - 1); /* according to HAC this is optimization is ok */ - if (((unsigned long) m->used) > (1UL << (unsigned long) (DIGIT_BIT - 1UL))) { + if (((unsigned long) m->used) > (((mp_digit)1) << (DIGIT_BIT - 1))) { if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { goto CLEANUP; } @@ -57,7 +56,8 @@ mp_reduce (mp_int * x, mp_int * m, mp_int * mu) } } - mp_rshd (&q, um + 1); /* q3 = q2 / b^(k+1) */ + /* q3 = q2 / b^(k+1) */ + mp_rshd (&q, um + 1); /* x = x mod b^(k+1), quick (no division) */ if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { @@ -70,8 +70,9 @@ mp_reduce (mp_int * x, mp_int * m, mp_int * mu) } /* x = x - q */ - if ((res = mp_sub (x, &q, x)) != MP_OKAY) + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { goto CLEANUP; + } /* If x < 0, add b^(k+1) to it */ if (mp_cmp_d (x, 0) == MP_LT) { @@ -84,8 +85,9 @@ mp_reduce (mp_int * x, mp_int * m, mp_int * mu) /* Back off if it's too big */ while (mp_cmp (x, m) != MP_LT) { - if ((res = s_mp_sub (x, m, x)) != MP_OKAY) + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { break; + } } CLEANUP: diff --git a/bn_mp_rshd.c b/bn_mp_rshd.c index 582c8c5..a703dda 100644 --- a/bn_mp_rshd.c +++ b/bn_mp_rshd.c @@ -26,7 +26,7 @@ mp_rshd (mp_int * a, int b) } /* if b > used then simply zero it and return */ - if (a->used < b) { + if (a->used <= b) { mp_zero (a); return; } @@ -42,8 +42,9 @@ mp_rshd (mp_int * a, int b) /* offset into digits */ tmpaa = a->dp + b; - /* this is implemented as a sliding window where the window is b-digits long - * and digits from the top of the window are copied to the bottom + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom * * e.g. diff --git a/bn_mp_set_int.c b/bn_mp_set_int.c index 1d6bce7..69a55a8 100644 --- a/bn_mp_set_int.c +++ b/bn_mp_set_int.c @@ -16,15 +16,13 @@ /* set a 32-bit const */ int -mp_set_int (mp_int * a, unsigned long b) +mp_set_int (mp_int * a, unsigned int b) { int x, res; mp_zero (a); - - /* set four bits at a time, simplest solution to the what if DIGIT_BIT==7 case */ + /* set four bits at a time */ for (x = 0; x < 8; x++) { - /* shift the number up four bits */ if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { return res; @@ -37,9 +35,8 @@ mp_set_int (mp_int * a, unsigned long b) b <<= 4; /* ensure that digits are not clamped off */ - a->used += 32 / DIGIT_BIT + 1; + a->used += 32 / DIGIT_BIT + 2; } - mp_clamp (a); return MP_OKAY; } diff --git a/bn_mp_sqr.c b/bn_mp_sqr.c index 99ebdf0..c530c9a 100644 --- a/bn_mp_sqr.c +++ b/bn_mp_sqr.c @@ -24,8 +24,7 @@ mp_sqr (mp_int * a, mp_int * b) } else { /* can we use the fast multiplier? */ - if (((a->used * 2 + 1) < 512) - && a->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT) - 1))) { + if ((a->used * 2 + 1) < 512 && a->used < (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { res = fast_s_mp_sqr (a, b); } else { res = s_mp_sqr (a, b); diff --git a/bn_mp_sub.c b/bn_mp_sub.c index 6558e5d..2bc4123 100644 --- a/bn_mp_sub.c +++ b/bn_mp_sub.c @@ -20,39 +20,34 @@ mp_sub (mp_int * a, mp_int * b, mp_int * c) { int sa, sb, res; - sa = a->sign; sb = b->sign; - /* handle four cases */ - if (sa == MP_ZPOS && sb == MP_ZPOS) { - /* both positive, a - b, but if b>a then we do -(b - a) */ - if (mp_cmp_mag (a, b) == MP_LT) { - /* b>a */ - res = s_mp_sub (b, a, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (a, b, c); - c->sign = MP_ZPOS; - } - } else if (sa == MP_ZPOS && sb == MP_NEG) { - /* a - -b == a + b */ + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; res = s_mp_add (a, b, c); - c->sign = MP_ZPOS; - } else if (sa == MP_NEG && sb == MP_ZPOS) { - /* -a - b == -(a + b) */ - res = s_mp_add (a, b, c); - c->sign = MP_NEG; } else { - /* -a - -b == b - a, but if a>b == -(a - b) */ - if (mp_cmp_mag (a, b) == MP_GT) { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ res = s_mp_sub (a, b, c); - c->sign = MP_NEG; } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ res = s_mp_sub (b, a, c); - c->sign = MP_ZPOS; } } - return res; } + diff --git a/bn_prime_tab.c b/bn_prime_tab.c index e663578..83c5469 100644 --- a/bn_prime_tab.c +++ b/bn_prime_tab.c @@ -17,7 +17,9 @@ const mp_digit __prime_tab[] = { 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, - 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, +#ifndef MP_8BIT + 0x0083, 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, @@ -49,4 +51,5 @@ const mp_digit __prime_tab[] = { 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +#endif }; diff --git a/bn_radix.c b/bn_radix.c index 3b4b639..f586d46 100644 --- a/bn_radix.c +++ b/bn_radix.c @@ -135,3 +135,80 @@ mp_radix_size (mp_int * a, int radix) mp_clear (&t); return digs + 1; } + +/* read a bigint from a file stream in ASCII */ +int mp_fread(mp_int *a, int radix, FILE *stream) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + ch = fgetc(stream); + if (ch == '-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = fgetc(stream); + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + +int mp_fwrite(mp_int *a, int radix, FILE *stream) +{ + char *buf; + int err, len, x; + + len = mp_radix_size(a, radix); + if (len == 0) { + return MP_VAL; + } + + buf = malloc(len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { + free(buf); + return err; + } + + for (x = 0; x < len; x++) { + if (fputc(buf[x], stream) == EOF) { + free(buf); + return MP_VAL; + } + } + + free(buf); + return MP_OKAY; +} + diff --git a/bn_reverse.c b/bn_reverse.c index c24aa27..4e785c4 100644 --- a/bn_reverse.c +++ b/bn_reverse.c @@ -24,7 +24,7 @@ bn_reverse (unsigned char *s, int len) ix = 0; iy = len - 1; while (ix < iy) { - t = s[ix]; + t = s[ix]; s[ix] = s[iy]; s[iy] = t; ++ix; diff --git a/bn_s_mp_add.c b/bn_s_mp_add.c index ceb2702..87aab4e 100644 --- a/bn_s_mp_add.c +++ b/bn_s_mp_add.c @@ -28,13 +28,10 @@ s_mp_add (mp_int * a, mp_int * b, mp_int * c) min = b->used; max = a->used; x = a; - } else if (a->used < b->used) { + } else { min = a->used; max = b->used; x = b; - } else { - min = max = a->used; - x = NULL; } /* init result */ @@ -44,11 +41,10 @@ s_mp_add (mp_int * a, mp_int * b, mp_int * c) } } + /* get old used digit count and set new one */ olduse = c->used; c->used = max + 1; - /* add digits from lower part */ - /* set the carry to zero */ { register mp_digit u, *tmpa, *tmpb, *tmpc; @@ -65,36 +61,39 @@ s_mp_add (mp_int * a, mp_int * b, mp_int * c) /* destination */ tmpc = c->dp; + /* zero the carry */ u = 0; for (i = 0; i < min; i++) { /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ *tmpc = *tmpa++ + *tmpb++ + u; /* U = carry bit of T[i] */ - u = *tmpc >> DIGIT_BIT; + u = *tmpc >> ((mp_digit)DIGIT_BIT); /* take away carry bit from T[i] */ *tmpc++ &= MP_MASK; } - /* now copy higher words if any, that is in A+B if A or B has more digits add those in */ + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ if (min != max) { for (; i < max; i++) { - /* T[i] = X[i] + U */ - *tmpc = x->dp[i] + u; + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; - /* U = carry bit of T[i] */ - u = *tmpc >> DIGIT_BIT; + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); - /* take away carry bit from T[i] */ - *tmpc++ &= MP_MASK; + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; } } /* add carry */ *tmpc++ = u; - /* clear digits above used (since we may not have grown result above) */ + /* clear digits above oldused */ for (i = c->used; i < olduse; i++) { *tmpc++ = 0; } diff --git a/bn_s_mp_mul_digs.c b/bn_s_mp_mul_digs.c index 0243449..c126a0c 100644 --- a/bn_s_mp_mul_digs.c +++ b/bn_s_mp_mul_digs.c @@ -15,8 +15,8 @@ #include /* multiplies |a| * |b| and only computes upto digs digits of result - * HAC pp. 595, Algorithm 14.12 Modified so you can control how many digits of - * output are created. + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. */ int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) @@ -27,6 +27,13 @@ s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) mp_word r; mp_digit tmpx, *tmpt, *tmpy; + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { return res; } @@ -42,14 +49,21 @@ s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) pb = MIN (b->used, digs - ix); /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ tmpx = a->dp[ix]; - tmpt = &(t.dp[ix]); + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ tmpy = b->dp; /* compute the columns of the output and propagate the carry */ for (iy = 0; iy < pb; iy++) { /* compute the column as a mp_word */ - r = ((mp_word) * tmpt) + ((mp_word) tmpx) * ((mp_word) * tmpy++) + ((mp_word) u); + r = ((mp_word) *tmpt) + + ((mp_word) tmpx) * ((mp_word) * tmpy++) + + ((mp_word) u); /* the new column is the lower part of the result */ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); @@ -57,8 +71,10 @@ s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) /* get the carry word from the result */ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); } - if (ix + iy < digs) + /* set carry if it is placed below digs */ + if (ix + iy < digs) { *tmpt = u; + } } mp_clamp (&t); diff --git a/bn_s_mp_mul_high_digs.c b/bn_s_mp_mul_high_digs.c index ba52d11..bbe7378 100644 --- a/bn_s_mp_mul_high_digs.c +++ b/bn_s_mp_mul_high_digs.c @@ -14,7 +14,7 @@ */ #include -/* multiplies |a| * |b| and does not compute the lower digs digits +/* multiplies |a| * |b| and does not compute the lower digs digits * [meant to get the higher part of the product] */ int @@ -28,8 +28,8 @@ s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) /* can we use the fast multiplier? */ - if (((a->used + b->used + 1) < 512) - && MAX (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { return fast_s_mp_mul_high_digs (a, b, c, digs); } diff --git a/bn_s_mp_sub.c b/bn_s_mp_sub.c index a5683dd..5f22999 100644 --- a/bn_s_mp_sub.c +++ b/bn_s_mp_sub.c @@ -14,7 +14,7 @@ */ #include -/* low level subtraction (assumes a > b), HAC pp.595 Algorithm 14.9 */ +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ int s_mp_sub (mp_int * a, mp_int * b, mp_int * c) { @@ -34,7 +34,6 @@ s_mp_sub (mp_int * a, mp_int * b, mp_int * c) c->used = max; /* sub digits from lower part */ - { register mp_digit u, *tmpa, *tmpb, *tmpc; register int i; @@ -50,12 +49,12 @@ s_mp_sub (mp_int * a, mp_int * b, mp_int * c) /* T[i] = A[i] - B[i] - U */ *tmpc = *tmpa++ - *tmpb++ - u; - /* U = carry bit of T[i] - * Note this saves performing an AND operation since + /* U = carry bit of T[i] + * Note this saves performing an AND operation since * if a carry does occur it will propagate all the way to the * MSB. As a result a single shift is required to get the carry */ - u = *tmpc >> (CHAR_BIT * sizeof (mp_digit) - 1); + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); /* Clear carry from T[i] */ *tmpc++ &= MP_MASK; @@ -67,7 +66,7 @@ s_mp_sub (mp_int * a, mp_int * b, mp_int * c) *tmpc = *tmpa++ - u; /* U = carry bit of T[i] */ - u = *tmpc >> (CHAR_BIT * sizeof (mp_digit) - 1); + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); /* Clear carry from T[i] */ *tmpc++ &= MP_MASK; diff --git a/bncore.c b/bncore.c index 3660c6d..7e7ac50 100644 --- a/bncore.c +++ b/bncore.c @@ -14,7 +14,15 @@ */ #include -/* configured for a AMD Duron Morgan core with etc/tune.c */ -int KARATSUBA_MUL_CUTOFF = 73, /* Min. number of digits before Karatsuba multiplication is used. */ - KARATSUBA_SQR_CUTOFF = 121, /* Min. number of digits before Karatsuba squaring is used. */ - MONTGOMERY_EXPT_CUTOFF = 128; /* max. number of digits that montgomery reductions will help for */ +/* Known optimal configurations + + CPU /Compiler /MUL CUTOFF/SQR CUTOFF +------------------------------------------------------------- + Intel P4 /GCC v3.2 / 81/ 110 + AMD Athlon XP /GCC v3.2 / 109/ 127 + +*/ + +/* configured for a AMD XP Thoroughbred core with etc/tune.c */ +int KARATSUBA_MUL_CUTOFF = 109, /* Min. number of digits before Karatsuba multiplication is used. */ + KARATSUBA_SQR_CUTOFF = 127; /* Min. number of digits before Karatsuba squaring is used. */ diff --git a/booker.pl b/booker.pl new file mode 100644 index 0000000..5bc6645 --- /dev/null +++ b/booker.pl @@ -0,0 +1,261 @@ +#!/bin/perl +# +#Used to prepare the book "tommath.src" for LaTeX by pre-processing it into a .tex file +# +#Essentially you write the "tommath.src" as normal LaTex except where you want code snippets you put +# +#EXAM,file +# +#This preprocessor will then open "file" and insert it as a verbatim copy. +# +#Tom St Denis + +#get graphics type +if (shift =~ /PDF/) { + $graph = ""; +} else { + $graph = ".ps"; +} + +open(IN,"tommath.tex") or die "Can't open destination file"; + +print "Scanning for sections\n"; +$chapter = $section = $subsection = 0; +$x = 0; +while () { + print "."; + if (!(++$x % 80)) { print "\n"; } + #update the headings + if (~($_ =~ /\*/)) { + if ($_ =~ /\\chapter{.+}/) { + ++$chapter; + $section = $subsection = 0; + } elsif ($_ =~ /\\section{.+}/) { + ++$section; + $subsection = 0; + } elsif ($_ =~ /\\subsection{.+}/) { + ++$subsection; + } + } + + if ($_ =~ m/MARK/) { + @m = split(",",$_); + chomp(@m[1]); + $index1{@m[1]} = $chapter; + $index2{@m[1]} = $section; + $index3{@m[1]} = $subsection; + } +} +close(IN); + +open(IN,") { + ++$readline; + ++$srcline; + + if ($_ =~ m/MARK/) { + } elsif ($_ =~ m/EXAM/ || $_ =~ m/LIST/) { + if ($_ =~ m/EXAM/) { + $skipheader = 1; + } else { + $skipheader = 0; + } + + # EXAM,file + chomp($_); + @m = split(",",$_); + open(SRC,"<$m[1]") or die "Error:$srcline:Can't open source file $m[1]"; + + print "$srcline:Inserting $m[1]:"; + + $line = 0; + $tmp = $m[1]; + $tmp =~ s/_/"\\_"/ge; + print OUT "\\index{$tmp}\n\\vspace{+3mm}\\begin{small}\n\\hspace{-5.1mm}{\\bf File}: $tmp\n\\vspace{-3mm}\n\\begin{alltt}\n"; + $wroteline += 5; + + if ($skipheader == 1) { + # scan till next end of comment, e.g. skip license + while () { + $text[$line++] = $_; + last if ($_ =~ /tommath\.h/); + } + } + + $inline = 0; + while () { + $text[$line++] = $_; + ++$inline; + chomp($_); + $_ =~ s/\t/" "/ge; + $_ =~ s/{/"^{"/ge; + $_ =~ s/}/"^}"/ge; + $_ =~ s/\\/'\symbol{92}'/ge; + $_ =~ s/\^/"\\"/ge; + + printf OUT ("%03d ", $line); + for ($x = 0; $x < length($_); $x++) { + print OUT chr(vec($_, $x, 8)); + if ($x == 75) { + print OUT "\n "; + ++$wroteline; + } + } + print OUT "\n"; + ++$wroteline; + } + $totlines = $line; + print OUT "\\end{alltt}\n\\end{small}\n"; + close(SRC); + print "$inline lines\n"; + $wroteline += 2; + } elsif ($_ =~ m/@\d+,.+@/) { + # line contains [number,text] + # e.g. @14,for (ix = 0)@ + $txt = $_; + while ($txt =~ m/@\d+,.+@/) { + @m = split("@",$txt); # splits into text, one, two + @parms = split(",",$m[1]); # splits one,two into two elements + + # now search from $parms[0] down for $parms[1] + $found1 = 0; + $found2 = 0; + for ($i = $parms[0]; $i < $totlines && $found1 == 0; $i++) { + if ($text[$i] =~ m/\Q$parms[1]\E/) { + $foundline1 = $i + 1; + $found1 = 1; + } + } + + # now search backwards + for ($i = $parms[0] - 1; $i >= 0 && $found2 == 0; $i--) { + if ($text[$i] =~ m/\Q$parms[1]\E/) { + $foundline2 = $i + 1; + $found2 = 1; + } + } + + # now use the closest match or the first if tied + if ($found1 == 1 && $found2 == 0) { + $found = 1; + $foundline = $foundline1; + } elsif ($found1 == 0 && $found2 == 1) { + $found = 1; + $foundline = $foundline2; + } elsif ($found1 == 1 && $found2 == 1) { + $found = 1; + if (($foundline1 - $parms[0]) <= ($parms[0] - $foundline2)) { + $foundline = $foundline1; + } else { + $foundline = $foundline2; + } + } else { + $found = 0; + } + + # if found replace + if ($found == 1) { + $delta = $parms[0] - $foundline; + print "Found replacement tag for \"$parms[1]\" on line $srcline which refers to line $foundline (delta $delta)\n"; + $_ =~ s/@\Q$m[1]\E@/$foundline/; + } else { + print "ERROR: The tag \"$parms[1]\" on line $srcline was not found in the most recently parsed source!\n"; + } + + # remake the rest of the line + $cnt = @m; + $txt = ""; + for ($i = 2; $i < $cnt; $i++) { + $txt = $txt . $m[$i] . "@"; + } + } + print OUT $_; + ++$wroteline; + } elsif ($_ =~ /~.+~/) { + # line contains a ~text~ pair used to refer to indexing :-) + $txt = $_; + while ($txt =~ /~.+~/) { + @m = split("~", $txt); + + # word is the second position + $word = @m[1]; + $a = $index1{$word}; + $b = $index2{$word}; + $c = $index3{$word}; + + # if chapter (a) is zero it wasn't found + if ($a == 0) { + print "ERROR: the tag \"$word\" on line $srcline was not found previously marked.\n"; + } else { + # format the tag as x, x.y or x.y.z depending on the values + $str = $a; + $str = $str . ".$b" if ($b != 0); + $str = $str . ".$c" if ($c != 0); + + if ($b == 0 && $c == 0) { + # its a chapter + if ($a <= 10) { + if ($a == 1) { + $str = "chapter one"; + } elsif ($a == 2) { + $str = "chapter two"; + } elsif ($a == 3) { + $str = "chapter three"; + } elsif ($a == 4) { + $str = "chapter four"; + } elsif ($a == 5) { + $str = "chapter five"; + } elsif ($a == 6) { + $str = "chapter six"; + } elsif ($a == 7) { + $str = "chapter seven"; + } elsif ($a == 8) { + $str = "chapter eight"; + } elsif ($a == 9) { + $str = "chapter nine"; + } elsif ($a == 2) { + $str = "chapter ten"; + } + } else { + $str = "chapter " . $str; + } + } else { + $str = "section " . $str if ($b != 0 && $c == 0); + $str = "sub-section " . $str if ($b != 0 && $c != 0); + } + + #substitute + $_ =~ s/~\Q$word\E~/$str/; + + print "Found replacement tag for marker \"$word\" on line $srcline which refers to $str\n"; + } + + # remake rest of the line + $cnt = @m; + $txt = ""; + for ($i = 2; $i < $cnt; $i++) { + $txt = $txt . $m[$i] . "~"; + } + } + print OUT $_; + ++$wroteline; + } elsif ($_ =~ m/FIGU/) { + # FIGU,file,caption + chomp($_); + @m = split(",", $_); + print OUT "\\begin{center}\n\\begin{figure}[here]\n\\includegraphics{pics/$m[1]$graph}\n"; + print OUT "\\caption{$m[2]}\n\\end{figure}\n\\end{center}\n"; + $wroteline += 4; + } else { + print OUT $_; + ++$wroteline; + } +} +print "Read $readline lines, wrote $wroteline lines\n"; + +close (OUT); +close (IN); diff --git a/changes.txt b/changes.txt index 6833bdc..997774e 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,37 @@ +May 17th, 2003 +v0.17 -- Benjamin Goldberg submitted optimized mp_add and mp_sub routines. A new gen.pl as well + as several smaller suggestions. Thanks! + -- removed call to mp_cmp in inner loop of mp_div and put mp_cmp_mag in its place :-) + -- Fixed bug in mp_exptmod that would cause it to fail for odd moduli when DIGIT_BIT != 28 + -- mp_exptmod now also returns errors if the modulus is negative and will handle negative exponents + -- mp_prime_is_prime will now return true if the input is one of the primes in the prime table + -- Damian M Gryski (dgryski@uwaterloo.ca) found a index out of bounds error in the + mp_fast_s_mp_mul_high_digs function which didn't come up before. (fixed) + -- Refactored the DR reduction code so there is only one function per file. + -- Fixed bug in the mp_mul() which would erroneously avoid the faster multiplier [comba] when it was + allowed. The bug would not cause the incorrect value to be produced just less efficient (fixed) + -- Fixed similar bug in the Montgomery reduction code. + -- Added tons of (mp_digit) casts so the 7/15/28/31 bit digit code will work flawlessly out of the box. + Also added limited support for 64-bit machines with a 60-bit digit. Both thanks to Tom Wu (tom@arcot.com) + -- Added new comments here and there, cleaned up some code [style stuff] + -- Fixed a lingering typo in mp_exptmod* that would set bitcnt to zero then one. Very silly stuff :-) + -- Fixed up mp_exptmod_fast so it would set "redux" to the comba Montgomery reduction if allowed. This + saves quite a few calls and if statements. + -- Added etc/mont.c a test of the Montgomery reduction [assuming all else works :-| ] + -- Fixed up etc/tune.c to use a wider test range [more appropriate] also added a x86 based addition which + uses RDTSC for high precision timing. + -- Updated demo/demo.c to remove MPI stuff [won't work anyways], made the tests run for 2 seconds each so its + not so insanely slow. Also made the output space delimited [and fixed up various errors] + -- Added logs directory, logs/graph.dem which will use gnuplot to make a series of PNG files + that go with the pre-made index.html. You have to build [via make timing] and run ltmtest first in the + root of the package. + -- Fixed a bug in mp_sub and mp_add where "-a - -a" or "-a + a" would produce -0 as the result [obviously invalid]. + -- Fixed a bug in mp_rshd. If the count == a.used it should zero/return [instead of shifting] + -- Fixed a "off-by-one" bug in mp_mul2d. The initial size check on alloc would be off by one if the residue + shifting caused a carry. + -- Fixed a bug where s_mp_mul_digs() would not call the Comba based routine if allowed. This made Barrett reduction + slower than it had to be. + Mar 29th, 2003 v0.16 -- Sped up mp_div by making normalization one shift call -- Sped up mp_mul_2d/mp_div_2d by aliasing pointers :-) diff --git a/demo/demo.c b/demo/demo.c index ff85903..ab8794d 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -1,21 +1,6 @@ #include - -#ifdef U_MPI -#include -#include -#include -#include -#include - #include "mpi.h" - #ifdef _MSC_VER - typedef __int64 ulong64; - #else - typedef unsigned long long ulong64; - #endif -#else - #include "tommath.h" -#endif +#include "tommath.h" #ifdef TIMER ulong64 _tt; @@ -23,19 +8,11 @@ void reset(void) { _tt = clock(); } ulong64 rdtsc(void) { return clock() - _tt; } #endif -#ifndef DEBUG -int _ifuncs; -#else -extern int _ifuncs; -extern void dump_timings(void); -extern void reset_timings(void); -#endif - void ndraw(mp_int *a, char *name) { char buf[4096]; printf("%s: ", name); - mp_toradix(a, buf, 10); + mp_toradix(a, buf, 64); printf("%s\n", buf); } @@ -56,31 +33,13 @@ int lbit(void) lfsr <<= 1; return 0; } -} - -#ifdef U_MPI -int mp_reduce_setup(mp_int *a, mp_int *b) -{ - int res; - - mp_set(a, 1); - if ((res = s_mp_lshd(a, b->used * 2)) != MP_OKAY) { - return res; - } - return mp_div(a, b, a, NULL); } -int mp_rand(mp_int *a, int c) -{ - long z = abs(rand()) & 65535; - mp_set(a, z?z:1); - while (c--) { - s_mp_lshd(a, 1); - mp_add_d(a, abs(rand()), a); - } - return MP_OKAY; -} -#endif + +#define DO2(x) x; x; +#define DO4(x) DO2(x); DO2(x); +#define DO8(x) DO4(x); DO4(x); +#define DO(x) DO8(x); DO8(x); char cmd[4096], buf[4096]; int main(void) @@ -89,12 +48,12 @@ int main(void) unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, inv_n, div2_n, mul2_n; unsigned rr; - int cnt, ix; + int cnt, ix, old_kara_m, old_kara_s; #ifdef TIMER int n; ulong64 tt; - FILE *log; + FILE *log, *logb; #endif mp_init(&a); @@ -102,11 +61,11 @@ int main(void) mp_init(&c); mp_init(&d); mp_init(&e); - mp_init(&f); - + mp_init(&f); + /* test the DR reduction */ #if 0 - + srand(time(NULL)); for (cnt = 2; cnt < 32; cnt++) { printf("%d digit modulus\n", cnt); @@ -117,89 +76,103 @@ int main(void) } a.used = cnt; mp_prime_next_prime(&a, 3); - + mp_rand(&b, cnt - 1); mp_copy(&b, &c); - + rr = 0; do { if (!(rr & 127)) { printf("%9lu\r", rr); fflush(stdout); } mp_sqr(&b, &b); mp_add_d(&b, 1, &b); mp_copy(&b, &c); - + mp_mod(&b, &a, &b); mp_dr_reduce(&c, &a, (1< %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); - fprintf(log, "%d,%9llu\n", cnt, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); + fprintf(log, "%d %9llu\n", cnt*DIGIT_BIT, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); } fclose(log); - - log = fopen("sub.log", "w"); - for (cnt = 4; cnt <= 128; cnt += 4) { + + log = fopen("logs/sub.log", "w"); + for (cnt = 8; cnt <= 128; cnt += 8) { mp_rand(&a, cnt); mp_rand(&b, cnt); reset(); - for (rr = 0; rr < 10000000; rr++) { - mp_sub(&a, &b, &c); - } + rr = 0; + do { + DO(mp_sub(&a,&b,&c)); + rr += 16; + } while (rdtsc() < (CLOCKS_PER_SEC * 2)); tt = rdtsc(); printf("Subtracting\t\t%4d-bit => %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); - fprintf(log, "%d,%9llu\n", cnt, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); + fprintf(log, "%d %9llu\n", cnt*DIGIT_BIT, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); } fclose(log); - -sqrtime: - log = fopen("sqr.log", "w"); - for (cnt = 4; cnt <= 128; cnt += 4) { - mp_rand(&a, cnt); - reset(); - for (rr = 0; rr < 250000; rr++) { - mp_sqr(&a, &b); - } - tt = rdtsc(); - printf("Squaring\t%4d-bit => %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); - fprintf(log, "%d,%9llu\n", cnt, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); - } - fclose(log); - - log = fopen("mult.log", "w"); - for (cnt = 4; cnt <= 128; cnt += 4) { - mp_rand(&a, cnt); - mp_rand(&b, cnt); - reset(); - for (rr = 0; rr < 250000; rr++) { - mp_mul(&a, &b, &c); - } - tt = rdtsc(); - printf("Multiplying\t%4d-bit => %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); - fprintf(log, "%d,%9llu\n", cnt, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); - } - fclose(log); + /* do mult/square twice, first without karatsuba and second with */ + old_kara_m = KARATSUBA_MUL_CUTOFF; + old_kara_s = KARATSUBA_SQR_CUTOFF; + for (ix = 0; ix < 2; ix++) { + printf("With%s Karatsuba\n", (ix==0)?"out":""); + + KARATSUBA_MUL_CUTOFF = (ix==0)?9999:old_kara_m; + KARATSUBA_SQR_CUTOFF = (ix==0)?9999:old_kara_s; + + log = fopen((ix==0)?"logs/sqr.log":"logs/sqr_kara.log", "w"); + for (cnt = 32; cnt <= 288; cnt += 16) { + mp_rand(&a, cnt); + reset(); + rr = 0; + do { + DO(mp_sqr(&a, &b)); + rr += 16; + } while (rdtsc() < (CLOCKS_PER_SEC * 2)); + tt = rdtsc(); + printf("Squaring\t%4d-bit => %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); + fprintf(log, "%d %9llu\n", cnt*DIGIT_BIT, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); + } + fclose(log); + + log = fopen((ix==0)?"logs/mult.log":"logs/mult_kara.log", "w"); + for (cnt = 32; cnt <= 288; cnt += 16) { + mp_rand(&a, cnt); + mp_rand(&b, cnt); + reset(); + rr = 0; + do { + DO(mp_mul(&a, &b, &c)); + rr += 16; + } while (rdtsc() < (CLOCKS_PER_SEC * 2)); + tt = rdtsc(); + printf("Multiplying\t%4d-bit => %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); + fprintf(log, "%d %9llu\n", cnt*DIGIT_BIT, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); + } + fclose(log); + } -expttime: { char *primes[] = { /* DR moduli */ @@ -210,7 +183,7 @@ expttime: "542189391331696172661670440619180536749994166415993334151601745392193484590296600979602378676624808129613777993466242203025054573692562689251250471628358318743978285860720148446448885701001277560572526947619392551574490839286458454994488665744991822837769918095117129546414124448777033941223565831420390846864429504774477949153794689948747680362212954278693335653935890352619041936727463717926744868338358149568368643403037768649616778526013610493696186055899318268339432671541328195724261329606699831016666359440874843103020666106568222401047720269951530296879490444224546654729111504346660859907296364097126834834235287147", "1487259134814709264092032648525971038895865645148901180585340454985524155135260217788758027400478312256339496385275012465661575576202252063145698732079880294664220579764848767704076761853197216563262660046602703973050798218246170835962005598561669706844469447435461092542265792444947706769615695252256130901271870341005768912974433684521436211263358097522726462083917939091760026658925757076733484173202927141441492573799914240222628795405623953109131594523623353044898339481494120112723445689647986475279242446083151413667587008191682564376412347964146113898565886683139407005941383669325997475076910488086663256335689181157957571445067490187939553165903773554290260531009121879044170766615232300936675369451260747671432073394867530820527479172464106442450727640226503746586340279816318821395210726268291535648506190714616083163403189943334431056876038286530365757187367147446004855912033137386225053275419626102417236133948503", "1095121115716677802856811290392395128588168592409109494900178008967955253005183831872715423151551999734857184538199864469605657805519106717529655044054833197687459782636297255219742994736751541815269727940751860670268774903340296040006114013971309257028332849679096824800250742691718610670812374272414086863715763724622797509437062518082383056050144624962776302147890521249477060215148275163688301275847155316042279405557632639366066847442861422164832655874655824221577849928863023018366835675399949740429332468186340518172487073360822220449055340582568461568645259954873303616953776393853174845132081121976327462740354930744487429617202585015510744298530101547706821590188733515880733527449780963163909830077616357506845523215289297624086914545378511082534229620116563260168494523906566709418166011112754529766183554579321224940951177394088465596712620076240067370589036924024728375076210477267488679008016579588696191194060127319035195370137160936882402244399699172017835144537488486396906144217720028992863941288217185353914991583400421682751000603596655790990815525126154394344641336397793791497068253936771017031980867706707490224041075826337383538651825493679503771934836094655802776331664261631740148281763487765852746577808019633679", - + /* generic unrestricted moduli */ "17933601194860113372237070562165128350027320072176844226673287945873370751245439587792371960615073855669274087805055507977323024886880985062002853331424203", "2893527720709661239493896562339544088620375736490408468011883030469939904368086092336458298221245707898933583190713188177399401852627749210994595974791782790253946539043962213027074922559572312141181787434278708783207966459019479487", @@ -219,9 +192,10 @@ expttime: "436463808505957768574894870394349739623346440601945961161254440072143298152040105676491048248110146278752857839930515766167441407021501229924721335644557342265864606569000117714935185566842453630868849121480179691838399545644365571106757731317371758557990781880691336695584799313313687287468894148823761785582982549586183756806449017542622267874275103877481475534991201849912222670102069951687572917937634467778042874315463238062009202992087620963771759666448266532858079402669920025224220613419441069718482837399612644978839925207109870840278194042158748845445131729137117098529028886770063736487420613144045836803985635654192482395882603511950547826439092832800532152534003936926017612446606135655146445620623395788978726744728503058670046885876251527122350275750995227", "11424167473351836398078306042624362277956429440521137061889702611766348760692206243140413411077394583180726863277012016602279290144126785129569474909173584789822341986742719230331946072730319555984484911716797058875905400999504305877245849119687509023232790273637466821052576859232452982061831009770786031785669030271542286603956118755585683996118896215213488875253101894663403069677745948305893849505434201763745232895780711972432011344857521691017896316861403206449421332243658855453435784006517202894181640562433575390821384210960117518650374602256601091379644034244332285065935413233557998331562749140202965844219336298970011513882564935538704289446968322281451907487362046511461221329799897350993370560697505809686438782036235372137015731304779072430260986460269894522159103008260495503005267165927542949439526272736586626709581721032189532726389643625590680105784844246152702670169304203783072275089194754889511973916207", "1214855636816562637502584060163403830270705000634713483015101384881871978446801224798536155406895823305035467591632531067547890948695117172076954220727075688048751022421198712032848890056357845974246560748347918630050853933697792254955890439720297560693579400297062396904306270145886830719309296352765295712183040773146419022875165382778007040109957609739589875590885701126197906063620133954893216612678838507540777138437797705602453719559017633986486649523611975865005712371194067612263330335590526176087004421363598470302731349138773205901447704682181517904064735636518462452242791676541725292378925568296858010151852326316777511935037531017413910506921922450666933202278489024521263798482237150056835746454842662048692127173834433089016107854491097456725016327709663199738238442164843147132789153725513257167915555162094970853584447993125488607696008169807374736711297007473812256272245489405898470297178738029484459690836250560495461579533254473316340608217876781986188705928270735695752830825527963838355419762516246028680280988020401914551825487349990306976304093109384451438813251211051597392127491464898797406789175453067960072008590614886532333015881171367104445044718144312416815712216611576221546455968770801413440778423979", - NULL + NULL }; - log = fopen("expt.log", "w"); + log = fopen("logs/expt.log", "w"); + logb = fopen("logs/expt_dr.log", "w"); for (n = 0; primes[n]; n++) { mp_read_radix(&a, primes[n], 10); mp_zero(&b); @@ -234,9 +208,11 @@ expttime: mp_mod(&b, &c, &b); mp_set(&c, 3); reset(); - for (rr = 0; rr < 50; rr++) { - mp_exptmod(&c, &b, &a, &d); - } + rr = 0; + do { + DO(mp_exptmod(&c, &b, &a, &d)); + rr += 16; + } while (rdtsc() < (CLOCKS_PER_SEC * 2)); tt = rdtsc(); mp_sub_d(&a, 1, &e); mp_sub(&e, &b, &b); @@ -248,25 +224,28 @@ expttime: exit(0); } printf("Exponentiating\t%4d-bit => %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); - fprintf(log, "%d,%9llu\n", cnt, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); + fprintf((n < 7) ? logb : log, "%d %9llu\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); + } } - } fclose(log); + fclose(logb); - log = fopen("invmod.log", "w"); + log = fopen("logs/invmod.log", "w"); for (cnt = 4; cnt <= 128; cnt += 4) { mp_rand(&a, cnt); mp_rand(&b, cnt); - + do { mp_add_d(&b, 1, &b); mp_gcd(&a, &b, &c); } while (mp_cmp_d(&c, 1) != MP_EQ); - + reset(); - for (rr = 0; rr < 10000; rr++) { - mp_invmod(&b, &a, &c); - } + rr = 0; + do { + DO(mp_invmod(&b, &a, &c)); + rr += 16; + } while (rdtsc() < (CLOCKS_PER_SEC * 2)); tt = rdtsc(); mp_mulmod(&b, &c, &a, &d); if (mp_cmp_d(&d, 1) != MP_EQ) { @@ -274,18 +253,18 @@ expttime: return 0; } printf("Inverting mod\t%4d-bit => %9llu/sec, %9llu ticks\n", mp_count_bits(&a), (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt, tt); - fprintf(log, "%d,%9llu\n", cnt, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); + fprintf(log, "%d %9llu\n", cnt*DIGIT_BIT, (((unsigned long long)rr)*CLOCKS_PER_SEC)/tt); } fclose(log); - + return 0; - + #endif - div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = + div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = cnt = 0; + for (;;) { - /* randomly clear and re-init one variable, this has the affect of triming the alloc space */ switch (abs(rand()) % 7) { case 0: mp_clear(&a); mp_init(&a); break; @@ -296,17 +275,17 @@ expttime: case 5: mp_clear(&f); mp_init(&f); break; case 6: break; /* don't clear any */ } - - + + printf("%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu ", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n, div2_n, mul2_n); fgets(cmd, 4095, stdin); cmd[strlen(cmd)-1] = 0; printf("%s ]\r",cmd); fflush(stdout); - if (!strcmp(cmd, "mul2d")) { ++mul2d_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); + if (!strcmp(cmd, "mul2d")) { ++mul2d_n; + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + mp_mul_2d(&a, rr, &a); a.sign = b.sign; if (mp_cmp(&a, &b) != MP_EQ) { @@ -315,11 +294,11 @@ expttime: draw(&b); return 0; } - } else if (!strcmp(cmd, "div2d")) { ++div2d_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); + } else if (!strcmp(cmd, "div2d")) { ++div2d_n; + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + mp_div_2d(&a, rr, &a, &e); a.sign = b.sign; if (a.used == b.used && a.used == 0) { a.sign = b.sign = MP_ZPOS; } @@ -330,19 +309,19 @@ expttime: return 0; } } else if (!strcmp(cmd, "add")) { ++add_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_add(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { - printf("add %lu failure!\n", add_n); -draw(&a);draw(&b);draw(&c);draw(&d); + printf("add %lu failure!\n", add_n); +draw(&a);draw(&b);draw(&c);draw(&d); return 0; } - + /* test the sign/unsigned storage functions */ - + rr = mp_signed_bin_size(&c); mp_to_signed_bin(&c, (unsigned char *)cmd); memset(cmd+rr, rand()&255, sizeof(cmd)-rr); @@ -353,8 +332,8 @@ draw(&a);draw(&b);draw(&c);draw(&d); draw(&d); return 0; } - - + + rr = mp_unsigned_bin_size(&c); mp_to_unsigned_bin(&c, (unsigned char *)cmd); memset(cmd+rr, rand()&255, sizeof(cmd)-rr); @@ -367,90 +346,90 @@ draw(&a);draw(&b);draw(&c);draw(&d); } } else if (!strcmp(cmd, "sub")) { ++sub_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_sub(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { - printf("sub %lu failure!\n", sub_n); -draw(&a);draw(&b);draw(&c);draw(&d); + printf("sub %lu failure!\n", sub_n); +draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "mul")) { ++mul_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_mul(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { - printf("mul %lu failure!\n", mul_n); -draw(&a);draw(&b);draw(&c);draw(&d); + printf("mul %lu failure!\n", mul_n); +draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "div")) { ++div_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 10); - + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 64); + mp_div(&a, &b, &e, &f); if (mp_cmp(&c, &e) != MP_EQ || mp_cmp(&d, &f) != MP_EQ) { - printf("div %lu failure!\n", div_n); + printf("div %lu failure!\n", div_n); draw(&a);draw(&b);draw(&c);draw(&d); draw(&e); draw(&f); return 0; } - + } else if (!strcmp(cmd, "sqr")) { ++sqr_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_copy(&a, &c); mp_sqr(&c, &c); if (mp_cmp(&b, &c) != MP_EQ) { - printf("sqr %lu failure!\n", sqr_n); + printf("sqr %lu failure!\n", sqr_n); draw(&a);draw(&b);draw(&c); return 0; } } else if (!strcmp(cmd, "gcd")) { ++gcd_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_gcd(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { - printf("gcd %lu failure!\n", gcd_n); + printf("gcd %lu failure!\n", gcd_n); draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "lcm")) { ++lcm_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_lcm(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { - printf("lcm %lu failure!\n", lcm_n); + printf("lcm %lu failure!\n", lcm_n); draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "expt")) { ++expt_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 64); mp_copy(&a, &e); mp_exptmod(&e, &b, &c, &e); if (mp_cmp(&d, &e) != MP_EQ) { - printf("expt %lu failure!\n", expt_n); + printf("expt %lu failure!\n", expt_n); draw(&a);draw(&b);draw(&c);draw(&d); draw(&e); return 0; } } else if (!strcmp(cmd, "invmod")) { ++inv_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_invmod(&a, &b, &d); mp_mulmod(&d,&a,&b,&e); if (mp_cmp_d(&e, 1) != MP_EQ) { @@ -460,10 +439,10 @@ draw(&a);draw(&b);draw(&c);draw(&d); draw(&e); return 0; } - + } else if (!strcmp(cmd, "div2")) { ++div2_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_div_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("div_2 %lu failure\n", div2_n); @@ -473,8 +452,8 @@ draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "mul2")) { ++mul2_n; - fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); - fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_mul_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("mul_2 %lu failure\n", mul2_n); @@ -483,9 +462,9 @@ draw(&a);draw(&b);draw(&c);draw(&d); draw(&c); return 0; } - } - + } + } - return 0; + return 0; } diff --git a/demo/test.c b/demo/test.c new file mode 100644 index 0000000..e69de29 diff --git a/etc/makefile b/etc/makefile index 261cd1c..dce98da 100644 --- a/etc/makefile +++ b/etc/makefile @@ -1,23 +1,40 @@ CFLAGS += -Wall -W -Wshadow -O3 -fomit-frame-pointer -funroll-loops -I../ - # default lib name (requires install with root) # LIBNAME=-ltommath # libname when you can't install the lib with install LIBNAME=../libtommath.a +#provable primes pprime: pprime.o $(CC) pprime.o $(LIBNAME) -o pprime +# portable [well requires clock()] tuning app tune: tune.o $(CC) tune.o $(LIBNAME) -o tune + +# same app but using RDTSC for higher precision [requires 80586+], coff based gcc installs [e.g. ming, cygwin, djgpp] +tune86: tune.c + nasm -f coff timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 + +#make tune86 for linux or any ELF format +tune86l: tune.c + nasm -f elf -DUSE_ELF timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86l +# spits out mersenne primes mersenne: mersenne.o $(CC) mersenne.o $(LIBNAME) -o mersenne +# fines DR safe primes for the given config drprime: drprime.o $(CC) drprime.o $(LIBNAME) -o drprime + +mont: mont.o + $(CC) mont.o $(LIBNAME) -o mont + clean: - rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime \ No newline at end of file + rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime tune86 tune86l mont \ No newline at end of file diff --git a/etc/mont.c b/etc/mont.c new file mode 100644 index 0000000..af6fd7a --- /dev/null +++ b/etc/mont.c @@ -0,0 +1,45 @@ +/* tests the montgomery routines */ +#include + +int main(void) +{ + mp_int modulus, R, p, pp; + mp_digit mp; + long x, y; + + mp_init_multi(&modulus, &R, &p, &pp, NULL); + + /* loop through various sizes */ + for (x = 4; x < 128; x++) { + printf("DIGITS == %3ld...", x); fflush(stdout); + + /* make up the odd modulus */ + mp_rand(&modulus, x); + modulus.dp[0] |= 1; + + /* now find the R value */ + mp_montgomery_calc_normalization(&R, &modulus); + mp_montgomery_setup(&modulus, &mp); + + /* now run through a bunch tests */ + for (y = 0; y < 100000; y++) { + mp_rand(&p, x/2); /* p = random */ + mp_mul(&p, &R, &pp); /* pp = R * p */ + mp_montgomery_reduce(&pp, &modulus, mp); + + /* should be equal to p */ + if (mp_cmp(&pp, &p) != MP_EQ) { + printf("FAILURE!\n"); + exit(-1); + } + } + printf("PASSED\n"); + } + + return 0; +} + + + + + diff --git a/etc/timer.asm b/etc/timer.asm new file mode 100644 index 0000000..35890d9 --- /dev/null +++ b/etc/timer.asm @@ -0,0 +1,37 @@ +; x86 timer in NASM +; +; Tom St Denis, tomstdenis@iahu.ca +[bits 32] +[section .data] +time dd 0, 0 + +[section .text] + +%ifdef USE_ELF +[global t_start] +t_start: +%else +[global _t_start] +_t_start: +%endif + push edx + push eax + rdtsc + mov [time+0],edx + mov [time+4],eax + pop eax + pop edx + ret + +%ifdef USE_ELF +[global t_read] +t_read: +%else +[global _t_read] +_t_read: +%endif + rdtsc + sub eax,[time+4] + sbb edx,[time+0] + ret + \ No newline at end of file diff --git a/etc/tune.c b/etc/tune.c index 0346677..5648496 100644 --- a/etc/tune.c +++ b/etc/tune.c @@ -5,10 +5,21 @@ #include #include -clock_t +#ifndef X86_TIMER + +/* generic ISO C timer */ +unsigned long long __T; +void t_start(void) { __T = clock(); } +unsigned long long t_read(void) { return clock() - __T; } + +#else +extern void t_start(void); +extern unsigned long long t_read(void); +#endif + +unsigned long long time_mult (void) { - clock_t t1; int x, y; mp_int a, b, c; @@ -16,137 +27,83 @@ time_mult (void) mp_init (&b); mp_init (&c); - t1 = clock (); - for (x = 4; x <= 144; x += 4) { + t_start(); + for (x = 32; x <= 288; x += 4) { mp_rand (&a, x); mp_rand (&b, x); - for (y = 0; y < 10000; y++) { + for (y = 0; y < 100; y++) { mp_mul (&a, &b, &c); } } mp_clear (&a); mp_clear (&b); mp_clear (&c); - return clock () - t1; + return t_read(); } -clock_t +unsigned long long time_sqr (void) { - clock_t t1; int x, y; mp_int a, b; mp_init (&a); mp_init (&b); - t1 = clock (); - for (x = 4; x <= 144; x += 4) { + t_start(); + for (x = 32; x <= 288; x += 4) { mp_rand (&a, x); - for (y = 0; y < 10000; y++) { + for (y = 0; y < 100; y++) { mp_sqr (&a, &b); } } mp_clear (&a); mp_clear (&b); - return clock () - t1; -} - -clock_t -time_expt (void) -{ - clock_t t1; - int x, y; - mp_int a, b, c, d; - - mp_init (&a); - mp_init (&b); - mp_init (&c); - mp_init (&d); - - t1 = clock (); - for (x = 4; x <= 144; x += 4) { - mp_rand (&a, x); - mp_rand (&b, x); - mp_rand (&c, x); - if (mp_iseven (&c) != 0) { - mp_add_d (&c, 1, &c); - } - for (y = 0; y < 10; y++) { - mp_exptmod (&a, &b, &c, &d); - } - } - mp_clear (&d); - mp_clear (&c); - mp_clear (&b); - mp_clear (&a); - - return clock () - t1; + return t_read(); } int main (void) { - int best_mult, best_square, best_exptmod; - clock_t best, ti; + int best_mult, best_square; + unsigned long long best, ti; FILE *log; - best_mult = best_square = best_exptmod = 0; - + best_mult = best_square = 0; /* tune multiplication first */ log = fopen ("mult.log", "w"); - best = CLOCKS_PER_SEC * 1000; - for (KARATSUBA_MUL_CUTOFF = 8; KARATSUBA_MUL_CUTOFF <= 144; KARATSUBA_MUL_CUTOFF++) { + best = -1; + for (KARATSUBA_MUL_CUTOFF = 8; KARATSUBA_MUL_CUTOFF <= 200; KARATSUBA_MUL_CUTOFF++) { ti = time_mult (); - printf ("%4d : %9lu\r", KARATSUBA_MUL_CUTOFF, ti); - fprintf (log, "%d, %lu\n", KARATSUBA_MUL_CUTOFF, ti); + printf ("%4d : %9llu\r", KARATSUBA_MUL_CUTOFF, ti); + fprintf (log, "%d, %llu\n", KARATSUBA_MUL_CUTOFF, ti); fflush (stdout); if (ti < best) { - printf ("New best: %lu, %d \n", ti, KARATSUBA_MUL_CUTOFF); + printf ("New best: %llu, %d \n", ti, KARATSUBA_MUL_CUTOFF); best = ti; best_mult = KARATSUBA_MUL_CUTOFF; } } fclose (log); - /* tune squaring */ log = fopen ("sqr.log", "w"); - best = CLOCKS_PER_SEC * 1000; - for (KARATSUBA_SQR_CUTOFF = 8; KARATSUBA_SQR_CUTOFF <= 144; KARATSUBA_SQR_CUTOFF++) { + best = -1; + for (KARATSUBA_SQR_CUTOFF = 8; KARATSUBA_SQR_CUTOFF <= 200; KARATSUBA_SQR_CUTOFF++) { ti = time_sqr (); - printf ("%4d : %9lu\r", KARATSUBA_SQR_CUTOFF, ti); - fprintf (log, "%d, %lu\n", KARATSUBA_SQR_CUTOFF, ti); + printf ("%4d : %9llu\r", KARATSUBA_SQR_CUTOFF, ti); + fprintf (log, "%d, %llu\n", KARATSUBA_SQR_CUTOFF, ti); fflush (stdout); if (ti < best) { - printf ("New best: %lu, %d \n", ti, KARATSUBA_SQR_CUTOFF); + printf ("New best: %llu, %d \n", ti, KARATSUBA_SQR_CUTOFF); best = ti; best_square = KARATSUBA_SQR_CUTOFF; } } fclose (log); - /* tune exptmod */ - KARATSUBA_MUL_CUTOFF = best_mult; - KARATSUBA_SQR_CUTOFF = best_square; - - log = fopen ("expt.log", "w"); - best = CLOCKS_PER_SEC * 1000; - for (MONTGOMERY_EXPT_CUTOFF = 8; MONTGOMERY_EXPT_CUTOFF <= 144; MONTGOMERY_EXPT_CUTOFF++) { - ti = time_expt (); - printf ("%4d : %9lu\r", MONTGOMERY_EXPT_CUTOFF, ti); - fflush (stdout); - fprintf (log, "%d : %lu\r", MONTGOMERY_EXPT_CUTOFF, ti); - if (ti < best) { - printf ("New best: %lu, %d\n", ti, MONTGOMERY_EXPT_CUTOFF); - best = ti; - best_exptmod = MONTGOMERY_EXPT_CUTOFF; - } - } - fclose (log); - printf - ("\n\n\nKaratsuba Multiplier Cutoff: %d\nKaratsuba Squaring Cutoff: %d\nMontgomery exptmod Cutoff: %d\n", - best_mult, best_square, best_exptmod); + ("\n\n\nKaratsuba Multiplier Cutoff: %d\nKaratsuba Squaring Cutoff: %d\n", + best_mult, best_square); return 0; } diff --git a/gen.pl b/gen.pl index fcfd57d..e6009d9 100644 --- a/gen.pl +++ b/gen.pl @@ -1,27 +1,18 @@ -#!/usr/bin/perl +#!/usr/bin/perl -w # -#Generates a "single file" you can use to quickly add the whole source -#without any makefile troubles +# Generates a "single file" you can use to quickly +# add the whole source without any makefile troubles # +use strict; -opendir(DIR,"."); -@files = readdir(DIR); -closedir(DIR); - -open(OUT,">mpi.c"); -print OUT "/* File Generated Automatically by gen.pl */\n\n"; -for (@files) { - if ($_ =~ /\.c/ && !($_ =~ /mpi\.c/)) { - $fname = $_; - open(SRC,"<$fname"); - print OUT "/* Start: $fname */\n"; - while () { - print OUT $_; - } - close(SRC); - print OUT "\n/* End: $fname */\n\n"; - } +open( OUT, ">mpi.c" ) or die "Couldn't open mpi.c for writing: $!"; +foreach my $filename (glob "bn_*.c") { + open( SRC, "<$filename" ) or die "Couldn't open $filename for reading: $!"; + print OUT "/* Start: $filename */\n"; + print OUT qq[#line 0 "$filename"\n]; + print OUT while ; + print OUT "\n/* End: $filename */\n\n"; + close SRC or die "Error closing $filename after reading: $!"; } -print OUT "\n/* EOF */\n"; -close(OUT); - \ No newline at end of file +print OUT "\b/* EOF */\n"; +close OUT or die "Error closing mpi.c after writing: $!"; \ No newline at end of file diff --git a/logs/README b/logs/README new file mode 100644 index 0000000..ea20c81 --- /dev/null +++ b/logs/README @@ -0,0 +1,13 @@ +To use the pretty graphs you have to first build/run the ltmtest from the root directory of the package. +Todo this type + +make timing ; ltmtest + +in the root. It will run for a while [about ten minutes on most PCs] and produce a series of .log files in logs/. + +After doing that run "gnuplot graphs.dem" to make the PNGs. If you managed todo that all so far just open index.html to view +them all :-) + +Have fun + +Tom \ No newline at end of file diff --git a/logs/add.log b/logs/add.log new file mode 100644 index 0000000..1e144e8 --- /dev/null +++ b/logs/add.log @@ -0,0 +1,16 @@ +224 11039864 +448 9206336 +672 8178200 +896 7432176 +1120 6433264 +1344 5847056 +1568 5270184 +1792 4943416 +2016 4520016 +2240 4256168 +2464 3999224 +2688 3714896 +2912 3572720 +3136 3340176 +3360 3222584 +3584 3036336 diff --git a/logs/addsub.png b/logs/addsub.png new file mode 100644 index 0000000000000000000000000000000000000000..1113ed3a97cb71748aa92568a30e05675d25dfd9 GIT binary patch literal 5941 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 literal 0 HcmV?d00001 diff --git a/logs/expt.log b/logs/expt.log new file mode 100644 index 0000000..fb0b718 --- /dev/null +++ b/logs/expt.log @@ -0,0 +1,7 @@ +14364 666 +21532 253 +28700 117 +57372 17 +71708 9 +86044 5 +114716 2 diff --git a/logs/expt.png b/logs/expt.png new file mode 100644 index 0000000000000000000000000000000000000000..b534a9bbf73fad513ec8a4fcb8bfc7ade99bbe3d GIT binary patch literal 5601 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 + +LibTomMath Log Plots + + + +

Addition and Subtraction

+
+
+ +

Multipliers

+
+
+ +

Exptmod

+
+
+ +

Modular Inverse

+
+
+ + + \ No newline at end of file diff --git a/logs/invmod.log b/logs/invmod.log new file mode 100644 index 0000000..e84ba9f --- /dev/null +++ b/logs/invmod.log @@ -0,0 +1,32 @@ +112 15608 +224 7840 +336 5104 +448 3376 +560 2616 +672 1984 +784 1640 +896 2056 +1008 1136 +1120 936 +1232 1240 +1344 1112 +1456 608 +1568 873 +1680 492 +1792 444 +1904 640 +2016 584 +2128 328 +2240 307 +2352 283 +2464 256 +2576 393 +2688 365 +2800 344 +2912 196 +3024 301 +3136 170 +3248 160 +3360 250 +3472 144 +3584 224 diff --git a/logs/invmod.png b/logs/invmod.png new file mode 100644 index 0000000000000000000000000000000000000000..a38bfd569534445b356ef0e778d6774960248998 GIT binary patch literal 4818 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 AE&u=k literal 0 HcmV?d00001 diff --git a/logs/mult.log b/logs/mult.log new file mode 100644 index 0000000..835dc52 --- /dev/null +++ b/logs/mult.log @@ -0,0 +1,17 @@ +896 321504 +1344 150784 +1792 90288 +2240 59760 +2688 42480 +3136 32056 +3584 24600 +4032 19656 +4480 16024 +4928 13328 +5376 11280 +5824 9624 +6272 8336 +6720 7280 +7168 1648 +7616 1464 +8064 1296 diff --git a/logs/mult.png b/logs/mult.png new file mode 100644 index 0000000000000000000000000000000000000000..c49a434adb54d41a99bffa066aab4472de203e5d GIT binary patch literal 7035 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 Rv7Mif)nOa+!h=xc{{a&?2KE2| literal 0 HcmV?d00001 diff --git a/logs/mult_kara.log b/logs/mult_kara.log new file mode 100644 index 0000000..0babf2e --- /dev/null +++ b/logs/mult_kara.log @@ -0,0 +1,17 @@ +896 321928 +1344 150752 +1792 90136 +2240 59888 +2688 42480 +3136 32080 +3584 25744 +4032 21216 +4480 17912 +4928 14896 +5376 12936 +5824 11216 +6272 9848 +6720 8896 +7168 7968 +7616 7248 +8064 6600 diff --git a/logs/sqr.log b/logs/sqr.log new file mode 100644 index 0000000..2ed78eb --- /dev/null +++ b/logs/sqr.log @@ -0,0 +1,17 @@ +896 416968 +1344 223672 +1792 141552 +2240 97280 +2688 71304 +3136 54648 +3584 16264 +4032 13000 +4480 10528 +4928 8776 +5376 7464 +5824 6440 +6272 5520 +6720 4808 +7168 4264 +7616 3784 +8064 3368 diff --git a/logs/sqr_kara.log b/logs/sqr_kara.log new file mode 100644 index 0000000..b890211 --- /dev/null +++ b/logs/sqr_kara.log @@ -0,0 +1,17 @@ +896 416656 +1344 223728 +1792 141288 +2240 97456 +2688 71152 +3136 54392 +3584 38552 +4032 32216 +4480 27384 +4928 23792 +5376 20728 +5824 18232 +6272 16160 +6720 14408 +7168 11696 +7616 10768 +8064 9920 diff --git a/logs/sub.log b/logs/sub.log new file mode 100644 index 0000000..14c519d --- /dev/null +++ b/logs/sub.log @@ -0,0 +1,16 @@ +224 9862520 +448 8562344 +672 7661400 +896 6838128 +1120 5911144 +1344 5394040 +1568 4993760 +1792 4624240 +2016 4332024 +2240 4029312 +2464 3790784 +2688 3587216 +2912 3397952 +3136 3239736 +3360 3080616 +3584 2933104 diff --git a/makefile b/makefile index 8466163..4f5a627 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ CFLAGS += -I./ -Wall -W -Wshadow -O3 -fomit-frame-pointer -funroll-loops -VERSION=0.16 +VERSION=0.17 default: libtommath.a @@ -32,7 +32,8 @@ bn_mp_count_bits.o bn_mp_read_unsigned_bin.o bn_mp_read_signed_bin.o bn_mp_to_un bn_mp_to_signed_bin.o bn_mp_unsigned_bin_size.o bn_mp_signed_bin_size.o bn_radix.o \ bn_mp_xor.o bn_mp_and.o bn_mp_or.o bn_mp_rand.o bn_mp_montgomery_calc_normalization.o \ bn_mp_prime_is_divisible.o bn_prime_tab.o bn_mp_prime_fermat.o bn_mp_prime_miller_rabin.o \ -bn_mp_prime_is_prime.o bn_mp_prime_next_prime.o bn_mp_dr_reduce.o +bn_mp_prime_is_prime.o bn_mp_prime_next_prime.o bn_mp_dr_reduce.o bn_mp_multi.o \ +bn_mp_dr_is_modulus.o bn_mp_dr_setup.o libtommath.a: $(OBJECTS) $(AR) $(ARFLAGS) libtommath.a $(OBJECTS) @@ -52,21 +53,46 @@ test: libtommath.a demo/demo.o timing: libtommath.a $(CC) $(CFLAGS) -DTIMER demo/demo.c libtommath.a -o ltmtest -s - $(CC) $(CFLAGS) -DTIMER -DU_MPI -I./mtest/ demo/demo.c mtest/mpi.c -o mpitest -s -docdvi: bn.tex - latex bn +# makes the LTM book DVI file, requires tetex, perl and makeindex [part of tetex I think] +docdvi: tommath.src + cd pics ; make + echo "hello" > tommath.ind + perl booker.pl + latex tommath > /dev/null + makeindex tommath + latex tommath > /dev/null + +# makes the LTM book PS/PDF file, requires tetex, cleans up the LaTeX temp files +docs: + cd pics ; make pdfes + echo "hello" > tommath.ind + perl booker.pl + latex tommath > /dev/null + makeindex tommath + latex tommath > /dev/null + dvips -tB5 -D600 tommath + echo "hello" > tommath.ind + perl booker.pl PDF + latex tommath > /dev/null + makeindex tommath + latex tommath > /dev/null + pdflatex tommath + rm -f tommath.log tommath.aux tommath.dvi tommath.idx tommath.toc tommath.lof tommath.ind tommath.ilg -docs: docdvi +#the old manual being phased out +manual: + latex bn pdflatex bn - rm -f bn.log bn.aux bn.dvi + rm -f bn.aux bn.dvi bn.log clean: rm -f *.pdf *.o *.a *.obj *.lib *.exe etclib/*.o demo/demo.o test ltmtest mpitest mtest/mtest mtest/mtest.exe \ - bn.log bn.aux bn.dvi *.log *.s mpi.c + tommath.idx tommath.toc tommath.log tommath.aux tommath.dvi tommath.lof tommath.ind tommath.ilg *.ps *.pdf *.log *.s mpi.c cd etc ; make clean + cd pics ; make clean -zipup: clean docs +zipup: clean manual perl gen.pl ; mv mpi.c pre_gen/ ; \ cd .. ; rm -rf ltm* libtommath-$(VERSION) ; mkdir libtommath-$(VERSION) ; \ cp -R ./libtommath/* ./libtommath-$(VERSION)/ ; tar -c libtommath-$(VERSION)/* > ltm-$(VERSION).tar ; \ diff --git a/makefile.msvc b/makefile.msvc index 4daf310..dcc14b1 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -22,7 +22,8 @@ bn_mp_count_bits.obj bn_mp_read_unsigned_bin.obj bn_mp_read_signed_bin.obj bn_mp bn_mp_to_signed_bin.obj bn_mp_unsigned_bin_size.obj bn_mp_signed_bin_size.obj bn_radix.obj \ bn_mp_xor.obj bn_mp_and.obj bn_mp_or.obj bn_mp_rand.obj bn_mp_montgomery_calc_normalization.obj \ bn_mp_prime_is_divisible.obj bn_prime_tab.obj bn_mp_prime_fermat.obj bn_mp_prime_miller_rabin.obj \ -bn_mp_prime_is_prime.obj bn_mp_prime_next_prime.obj bn_mp_dr_reduce.obj +bn_mp_prime_is_prime.obj bn_mp_prime_next_prime.obj bn_mp_dr_reduce.obj bn_mp_multi.obj \ +bn_mp_dr_is_modulus.obj bn_mp_dr_setup.obj library: $(OBJECTS) diff --git a/mtest/mtest.c b/mtest/mtest.c index fe02906..086e7bc 100644 --- a/mtest/mtest.c +++ b/mtest/mtest.c @@ -10,7 +10,7 @@ result1 result2 [... resultN] -So for example "a * b mod n" would be +So for example "a * b mod n" would be mulmod a @@ -18,7 +18,7 @@ b n a*b mod n -e.g. if a=3, b=4 n=11 then +e.g. if a=3, b=4 n=11 then mulmod 3 @@ -38,10 +38,10 @@ FILE *rng; void rand_num(mp_int *a) { int n, size; - unsigned char buf[512]; + unsigned char buf[2048]; top: - size = 1 + ((fgetc(rng)*fgetc(rng)) % 96); + size = 1 + ((fgetc(rng)*fgetc(rng)) % 1024); buf[0] = (fgetc(rng)&1)?1:0; fread(buf+1, 1, size, rng); for (n = 0; n < size; n++) { @@ -54,7 +54,7 @@ top: void rand_num2(mp_int *a) { int n, size; - unsigned char buf[512]; + unsigned char buf[2048]; top: size = 1 + ((fgetc(rng)*fgetc(rng)) % 96); @@ -67,18 +67,38 @@ top: mp_read_raw(a, buf, 1+size); } +#define mp_to64(a, b) mp_toradix(a, b, 64) + int main(void) { int n; mp_int a, b, c, d, e; char buf[4096]; - + mp_init(&a); mp_init(&b); mp_init(&c); mp_init(&d); mp_init(&e); + + /* initial (2^n - 1)^2 testing, makes sure the comba multiplier works [it has the new carry code] */ +/* + mp_set(&a, 1); + for (n = 1; n < 8192; n++) { + mp_mul(&a, &a, &c); + printf("mul\n"); + mp_to64(&a, buf); + printf("%s\n%s\n", buf, buf); + mp_to64(&c, buf); + printf("%s\n", buf); + + mp_add_d(&a, 1, &a); + mp_mul_2(&a, &a); + mp_sub_d(&a, 1, &a); + } +*/ + rng = fopen("/dev/urandom", "rb"); if (rng == NULL) { rng = fopen("/dev/random", "rb"); @@ -97,11 +117,11 @@ int main(void) rand_num(&b); mp_add(&a, &b, &c); printf("add\n"); - mp_todecimal(&a, buf); + mp_to64(&a, buf); printf("%s\n", buf); - mp_todecimal(&b, buf); + mp_to64(&b, buf); printf("%s\n", buf); - mp_todecimal(&c, buf); + mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 1) { /* sub tests */ @@ -109,11 +129,11 @@ int main(void) rand_num(&b); mp_sub(&a, &b, &c); printf("sub\n"); - mp_todecimal(&a, buf); + mp_to64(&a, buf); printf("%s\n", buf); - mp_todecimal(&b, buf); + mp_to64(&b, buf); printf("%s\n", buf); - mp_todecimal(&c, buf); + mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 2) { /* mul tests */ @@ -121,11 +141,11 @@ int main(void) rand_num(&b); mp_mul(&a, &b, &c); printf("mul\n"); - mp_todecimal(&a, buf); + mp_to64(&a, buf); printf("%s\n", buf); - mp_todecimal(&b, buf); + mp_to64(&b, buf); printf("%s\n", buf); - mp_todecimal(&c, buf); + mp_to64(&c, buf); printf("%s\n", buf); } else if (n == 3) { /* div tests */ @@ -133,22 +153,22 @@ int main(void) rand_num(&b); mp_div(&a, &b, &c, &d); printf("div\n"); - mp_todecimal(&a, buf); + mp_to64(&a, buf); printf("%s\n", buf); - mp_todecimal(&b, buf); + mp_to64(&b, buf); printf("%s\n", buf); - mp_todecimal(&c, buf); + mp_to64(&c, buf); printf("%s\n", buf); - mp_todecimal(&d, buf); + mp_to64(&d, buf); printf("%s\n", buf); } else if (n == 4) { /* sqr tests */ rand_num(&a); mp_sqr(&a, &b); printf("sqr\n"); - mp_todecimal(&a, buf); + mp_to64(&a, buf); printf("%s\n", buf); - mp_todecimal(&b, buf); + mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 5) { /* mul_2d test */ @@ -156,11 +176,11 @@ int main(void) mp_copy(&a, &b); n = fgetc(rng) & 63; mp_mul_2d(&b, n, &b); - mp_todecimal(&a, buf); + mp_to64(&a, buf); printf("mul2d\n"); printf("%s\n", buf); printf("%d\n", n); - mp_todecimal(&b, buf); + mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 6) { /* div_2d test */ @@ -168,11 +188,11 @@ int main(void) mp_copy(&a, &b); n = fgetc(rng) & 63; mp_div_2d(&b, n, &b, NULL); - mp_todecimal(&a, buf); + mp_to64(&a, buf); printf("div2d\n"); printf("%s\n", buf); printf("%d\n", n); - mp_todecimal(&b, buf); + mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 7) { /* gcd test */ @@ -182,12 +202,12 @@ int main(void) b.sign = MP_ZPOS; mp_gcd(&a, &b, &c); printf("gcd\n"); - mp_todecimal(&a, buf); - printf("%s\n", buf); - mp_todecimal(&b, buf); - printf("%s\n", buf); - mp_todecimal(&c, buf); - printf("%s\n", buf); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); } else if (n == 8) { /* lcm test */ rand_num(&a); @@ -196,12 +216,12 @@ int main(void) b.sign = MP_ZPOS; mp_lcm(&a, &b, &c); printf("lcm\n"); - mp_todecimal(&a, buf); - printf("%s\n", buf); - mp_todecimal(&b, buf); - printf("%s\n", buf); - mp_todecimal(&c, buf); - printf("%s\n", buf); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); } else if (n == 9) { /* exptmod test */ rand_num2(&a); @@ -210,14 +230,14 @@ int main(void) a.sign = b.sign = c.sign = 0; mp_exptmod(&a, &b, &c, &d); printf("expt\n"); - mp_todecimal(&a, buf); - printf("%s\n", buf); - mp_todecimal(&b, buf); - printf("%s\n", buf); - mp_todecimal(&c, buf); - printf("%s\n", buf); - mp_todecimal(&d, buf); - printf("%s\n", buf); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + mp_to64(&d, buf); + printf("%s\n", buf); } else if (n == 10) { /* invmod test */ rand_num2(&a); @@ -229,28 +249,28 @@ int main(void) if (mp_cmp_d(&b, 1) == 0) continue; mp_invmod(&a, &b, &c); printf("invmod\n"); - mp_todecimal(&a, buf); - printf("%s\n", buf); - mp_todecimal(&b, buf); - printf("%s\n", buf); - mp_todecimal(&c, buf); - printf("%s\n", buf); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); } else if (n == 11) { rand_num(&a); mp_mul_2(&a, &a); mp_div_2(&a, &b); printf("div2\n"); - mp_todecimal(&a, buf); - printf("%s\n", buf); - mp_todecimal(&b, buf); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); printf("%s\n", buf); } else if (n == 12) { rand_num2(&a); mp_mul_2(&a, &b); printf("mul2\n"); - mp_todecimal(&a, buf); - printf("%s\n", buf); - mp_todecimal(&b, buf); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); printf("%s\n", buf); } } diff --git a/pics/makefile b/pics/makefile new file mode 100644 index 0000000..4be4899 --- /dev/null +++ b/pics/makefile @@ -0,0 +1,17 @@ +# makes the images... yeah + +default: pses + + +sliding_window.ps: sliding_window.tif + tiff2ps -c -e sliding_window.tif > sliding_window.ps + +sliding_window.pdf: sliding_window.ps + epstopdf sliding_window.ps + +pses: sliding_window.ps +pdfes: sliding_window.pdf + +clean: + rm -rf *.ps *.pdf .xvpics + \ No newline at end of file diff --git a/pics/sliding_window.TIF b/pics/sliding_window.TIF new file mode 100644 index 0000000000000000000000000000000000000000..bb4cb96ebff4e06478672dd3583bd26a51d85b5d GIT binary patch literal 53880 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 DSo1$6 literal 0 HcmV?d00001 diff --git a/pics/sliding_window.sxd b/pics/sliding_window.sxd new file mode 100644 index 0000000000000000000000000000000000000000..91e7c0d9f43b612ff0a59d86a71c8928fbd695f3 GIT binary patch literal 6787 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 literal 0 HcmV?d00001 diff --git a/pre_gen/mpi.c b/pre_gen/mpi.c index 3921dc4..bd6f2ce 100644 --- a/pre_gen/mpi.c +++ b/pre_gen/mpi.c @@ -1,6051 +1,6356 @@ -/* File Generated Automatically by gen.pl */ - -/* Start: bncore.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* configured for a AMD Duron Morgan core with etc/tune.c */ -int KARATSUBA_MUL_CUTOFF = 73, /* Min. number of digits before Karatsuba multiplication is used. */ - KARATSUBA_SQR_CUTOFF = 121, /* Min. number of digits before Karatsuba squaring is used. */ - MONTGOMERY_EXPT_CUTOFF = 128; /* max. number of digits that montgomery reductions will help for */ - -/* End: bncore.c */ - -/* Start: bn_fast_mp_invmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes the modular inverse via binary extended euclidean algorithm, - * that is c = 1/a mod b - * - * Based on mp_invmod except this is optimized for the case where b is - * odd as per HAC Note 14.64 on pp. 610 - */ -int -fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int x, y, u, v, B, D; - int res, neg; - - /* init all our temps */ - if ((res = mp_init (&x)) != MP_OKAY) { - goto __ERR; - } - - if ((res = mp_init (&y)) != MP_OKAY) { - goto __X; - } - - if ((res = mp_init (&u)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_init (&v)) != MP_OKAY) { - goto __U; - } - - if ((res = mp_init (&B)) != MP_OKAY) { - goto __V; - } - - if ((res = mp_init (&D)) != MP_OKAY) { - goto __B; - } - - /* x == modulus, y == value to invert */ - if ((res = mp_copy (b, &x)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (a, &y)) != MP_OKAY) { - goto __D; - } - - /* we need |y| */ - if ((res = mp_abs (&y, &y)) != MP_OKAY) { - goto __D; - } - - /* 2. [modified] if x,y are both even then return an error! - * - * That is if gcd(x,y) = 2 * k then obviously there is no inverse. - */ - if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { - res = MP_VAL; - goto __D; - } - - /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ - if ((res = mp_copy (&x, &u)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (&y, &v)) != MP_OKAY) { - goto __D; - } - mp_set (&D, 1); - -top: - /* 4. while u is even do */ - while (mp_iseven (&u) == 1) { - /* 4.1 u = u/2 */ - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __D; - } - /* 4.2 if A or B is odd then */ - if (mp_iseven (&B) == 0) { - if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { - goto __D; - } - } - /* B = B/2 */ - if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { - goto __D; - } - } - - /* 5. while v is even do */ - while (mp_iseven (&v) == 1) { - /* 5.1 v = v/2 */ - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __D; - } - /* 5.2 if C,D are even then */ - if (mp_iseven (&D) == 0) { - /* D = (D-x)/2 */ - if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { - goto __D; - } - } - /* D = D/2 */ - if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { - goto __D; - } - } - - /* 6. if u >= v then */ - if (mp_cmp (&u, &v) != MP_LT) { - /* u = u - v, B = B - D */ - if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { - goto __D; - } - } else { - /* v - v - u, D = D - B */ - if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { - goto __D; - } - } - - /* if not zero goto step 4 */ - if (mp_iszero (&u) == 0) { - goto top; - } - - /* now a = C, b = D, gcd == g*v */ - - /* if v != 1 then there is no inverse */ - if (mp_cmp_d (&v, 1) != MP_EQ) { - res = MP_VAL; - goto __D; - } - - /* b is now the inverse */ - neg = a->sign; - while (D.sign == MP_NEG) { - if ((res = mp_add (&D, b, &D)) != MP_OKAY) { - goto __D; - } - } - mp_exch (&D, c); - c->sign = neg; - res = MP_OKAY; - -__D:mp_clear (&D); -__B:mp_clear (&B); -__V:mp_clear (&v); -__U:mp_clear (&u); -__Y:mp_clear (&y); -__X:mp_clear (&x); -__ERR: - return res; -} - -/* End: bn_fast_mp_invmod.c */ - -/* Start: bn_fast_mp_montgomery_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes xR^-1 == x (mod N) via Montgomery Reduction - * - * This is an optimized implementation of mp_montgomery_reduce - * which uses the comba method to quickly calculate the columns of the - * reduction. - * - * Based on Algorithm 14.32 on pp.601 of HAC. -*/ -int -fast_mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) -{ - int ix, res, olduse; - mp_word W[512]; - - /* get old used count */ - olduse = a->used; - - /* grow a as required */ - if (a->alloc < m->used + 1) { - if ((res = mp_grow (a, m->used + 1)) != MP_OKAY) { - return res; - } - } - - { - register mp_word *_W; - register mp_digit *tmpa; - - _W = W; - tmpa = a->dp; - - /* copy the digits of a into W[0..a->used-1] */ - for (ix = 0; ix < a->used; ix++) { - *_W++ = *tmpa++; - } - - /* zero the high words of W[a->used..m->used*2] */ - for (; ix < m->used * 2 + 1; ix++) { - *_W++ = 0; - } - } - - for (ix = 0; ix < m->used; ix++) { - /* ui = ai * m' mod b - * - * We avoid a double precision multiplication (which isn't required) - * by casting the value down to a mp_digit. Note this requires that W[ix-1] have - * the carry cleared (see after the inner loop) - */ - register mp_digit ui; - ui = (((mp_digit) (W[ix] & MP_MASK)) * mp) & MP_MASK; - - /* a = a + ui * m * b^i - * - * This is computed in place and on the fly. The multiplication - * by b^i is handled by offseting which columns the results - * are added to. - * - * Note the comba method normally doesn't handle carries in the inner loop - * In this case we fix the carry from the previous column since the Montgomery - * reduction requires digits of the result (so far) [see above] to work. This is - * handled by fixing up one carry after the inner loop. The carry fixups are done - * in order so after these loops the first m->used words of W[] have the carries - * fixed - */ - { - register int iy; - register mp_digit *tmpx; - register mp_word *_W; - - /* alias for the digits of the modulus */ - tmpx = m->dp; - - /* Alias for the columns set by an offset of ix */ - _W = W + ix; - - /* inner loop */ - for (iy = 0; iy < m->used; iy++) { - *_W++ += ((mp_word) ui) * ((mp_word) * tmpx++); - } - } - - /* now fix carry for next digit, W[ix+1] */ - W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); - } - - - { - register mp_digit *tmpa; - register mp_word *_W, *_W1; - - /* nox fix rest of carries */ - _W1 = W + ix; - _W = W + ++ix; - - for (; ix <= m->used * 2 + 1; ix++) { - *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); - } - - /* copy out, A = A/b^n - * - * The result is A/b^n but instead of converting from an array of mp_word - * to mp_digit than calling mp_rshd we just copy them in the right - * order - */ - tmpa = a->dp; - _W = W + m->used; - - for (ix = 0; ix < m->used + 1; ix++) { - *tmpa++ = *_W++ & ((mp_word) MP_MASK); - } - - /* zero oldused digits, if the input a was larger than - * m->used+1 we'll have to clear the digits */ - for (; ix < olduse; ix++) { - *tmpa++ = 0; - } - } - - /* set the max used and clamp */ - a->used = m->used + 1; - mp_clamp (a); - - /* if A >= m then A = A - m */ - if (mp_cmp_mag (a, m) != MP_LT) { - return s_mp_sub (a, m, a); - } - return MP_OKAY; -} - -/* End: bn_fast_mp_montgomery_reduce.c */ - -/* Start: bn_fast_s_mp_mul_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* Fast (comba) multiplier - * - * This is the fast column-array [comba] multiplier. It is designed to compute - * the columns of the product first then handle the carries afterwards. This - * has the effect of making the nested loops that compute the columns very - * simple and schedulable on super-scalar processors. - * - * This has been modified to produce a variable number of digits of output so - * if say only a half-product is required you don't have to compute the upper half - * (a feature required for fast Barrett reduction). - * - * Based on Algorithm 14.12 on pp.595 of HAC. - * - */ -int -fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - int olduse, res, pa, ix; - mp_word W[512]; - - /* grow the destination as required */ - if (c->alloc < digs) { - if ((res = mp_grow (c, digs)) != MP_OKAY) { - return res; - } - } - - /* clear temp buf (the columns) */ - memset (W, 0, sizeof (mp_word) * digs); - - /* calculate the columns */ - pa = a->used; - for (ix = 0; ix < pa; ix++) { - - /* this multiplier has been modified to allow you to control how many digits - * of output are produced. So at most we want to make upto "digs" digits - * of output. - * - * this adds products to distinct columns (at ix+iy) of W - * note that each step through the loop is not dependent on - * the previous which means the compiler can easily unroll - * the loop without scheduling problems - */ - { - register mp_digit tmpx, *tmpy; - register mp_word *_W; - register int iy, pb; - - /* alias for the the word on the left e.g. A[ix] * A[iy] */ - tmpx = a->dp[ix]; - - /* alias for the right side */ - tmpy = b->dp; - - /* alias for the columns, each step through the loop adds a new - term to each column - */ - _W = W + ix; - - /* the number of digits is limited by their placement. E.g. - we avoid multiplying digits that will end up above the # of - digits of precision requested - */ - pb = MIN (b->used, digs - ix); - - for (iy = 0; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); - } - } - - } - - /* setup dest */ - olduse = c->used; - c->used = digs; - - { - register mp_digit *tmpc; - - /* At this point W[] contains the sums of each column. To get the - * correct result we must take the extra bits from each column and - * carry them down - * - * Note that while this adds extra code to the multiplier it saves time - * since the carry propagation is removed from the above nested loop. - * This has the effect of reducing the work from N*(N+N*c)==N^2 + c*N^2 to - * N^2 + N*c where c is the cost of the shifting. On very small numbers - * this is slower but on most cryptographic size numbers it is faster. - */ - tmpc = c->dp; - for (ix = 1; ix < digs; ix++) { - W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); - *tmpc++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); - } - *tmpc++ = (mp_digit) (W[digs - 1] & ((mp_word) MP_MASK)); - - /* clear unused */ - for (; ix < olduse; ix++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_fast_s_mp_mul_digs.c */ - -/* Start: bn_fast_s_mp_mul_high_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* this is a modified version of fast_s_mp_mul_digs that only produces - * output digits *above* digs. See the comments for fast_s_mp_mul_digs - * to see how it works. - * - * This is used in the Barrett reduction since for one of the multiplications - * only the higher digits were needed. This essentially halves the work. - * - * Based on Algorithm 14.12 on pp.595 of HAC. - */ -int -fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - int oldused, newused, res, pa, pb, ix; - mp_word W[512]; - - /* calculate size of product and allocate more space if required */ - newused = a->used + b->used + 1; - if (c->alloc < newused) { - if ((res = mp_grow (c, newused)) != MP_OKAY) { - return res; - } - } - - /* like the other comba method we compute the columns first */ - pa = a->used; - pb = b->used; - memset (W + digs, 0, (pa + pb + 1 - digs) * sizeof (mp_word)); - for (ix = 0; ix < pa; ix++) { - { - register mp_digit tmpx, *tmpy; - register int iy; - register mp_word *_W; - - /* work todo, that is we only calculate digits that are at "digs" or above */ - iy = digs - ix; - - /* copy of word on the left of A[ix] * B[iy] */ - tmpx = a->dp[ix]; - - /* alias for right side */ - tmpy = b->dp + iy; - - /* alias for the columns of output. Offset to be equal to or above the - * smallest digit place requested - */ - _W = &(W[digs]); - - /* compute column products for digits above the minimum */ - for (; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); - } - } - } - - /* setup dest */ - oldused = c->used; - c->used = newused; - - /* now convert the array W downto what we need */ - for (ix = digs + 1; ix < newused; ix++) { - W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); - c->dp[ix - 1] = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); - } - c->dp[(pa + pb + 1) - 1] = (mp_digit) (W[(pa + pb + 1) - 1] & ((mp_word) MP_MASK)); - - for (; ix < oldused; ix++) { - c->dp[ix] = 0; - } - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_fast_s_mp_mul_high_digs.c */ - -/* Start: bn_fast_s_mp_sqr.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* fast squaring - * - * This is the comba method where the columns of the product are computed first - * then the carries are computed. This has the effect of making a very simple - * inner loop that is executed the most - * - * W2 represents the outer products and W the inner. - * - * A further optimizations is made because the inner products are of the form - * "A * B * 2". The *2 part does not need to be computed until the end which is - * good because 64-bit shifts are slow! - * - * Based on Algorithm 14.16 on pp.597 of HAC. - * - */ -int -fast_s_mp_sqr (mp_int * a, mp_int * b) -{ - int olduse, newused, res, ix, pa; - mp_word W2[512], W[512]; - - /* calculate size of product and allocate as required */ - pa = a->used; - newused = pa + pa + 1; - if (b->alloc < newused) { - if ((res = mp_grow (b, newused)) != MP_OKAY) { - return res; - } - } - - /* zero temp buffer (columns) - * Note that there are two buffers. Since squaring requires - * a outter and inner product and the inner product requires - * computing a product and doubling it (a relatively expensive - * op to perform n^2 times if you don't have to) the inner and - * outer products are computed in different buffers. This way - * the inner product can be doubled using n doublings instead of - * n^2 - */ - memset (W, 0, newused * sizeof (mp_word)); - memset (W2, 0, newused * sizeof (mp_word)); - -/* note optimization - * values in W2 are only written in even locations which means - * we can collapse the array to 256 words [and fixup the memset above] - * provided we also fix up the summations below. Ideally - * the fixup loop should be unrolled twice to handle the even/odd - * cases, and then a final step to handle odd cases [e.g. newused == odd] - * - * This will not only save ~8*256 = 2KB of stack but lower the number of - * operations required to finally fix up the columns - */ - - /* This computes the inner product. To simplify the inner N^2 loop - * the multiplication by two is done afterwards in the N loop. - */ - for (ix = 0; ix < pa; ix++) { - /* compute the outer product - * - * Note that every outer product is computed - * for a particular column only once which means that - * there is no need todo a double precision addition - */ - W2[ix + ix] = ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); - - { - register mp_digit tmpx, *tmpy; - register mp_word *_W; - register int iy; - - /* copy of left side */ - tmpx = a->dp[ix]; - - /* alias for right side */ - tmpy = a->dp + (ix + 1); - - /* the column to store the result in */ - _W = W + (ix + ix + 1); - - /* inner products */ - for (iy = ix + 1; iy < pa; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); - } - } - } - - /* setup dest */ - olduse = b->used; - b->used = newused; - - /* double first value, since the inner products are half of what they should be */ - W[0] += W[0] + W2[0]; - - /* now compute digits */ - { - register mp_digit *tmpb; - - tmpb = b->dp; - - for (ix = 1; ix < newused; ix++) { - /* double/add next digit */ - W[ix] += W[ix] + W2[ix]; - - W[ix] = W[ix] + (W[ix - 1] >> ((mp_word) DIGIT_BIT)); - *tmpb++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); - } - *tmpb++ = (mp_digit) (W[(newused) - 1] & ((mp_word) MP_MASK)); - - /* clear high */ - for (; ix < olduse; ix++) { - *tmpb++ = 0; - } - } - - mp_clamp (b); - return MP_OKAY; -} - -/* End: bn_fast_s_mp_sqr.c */ - -/* Start: bn_mp_2expt.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes a = 2^b - * - * Simple algorithm which zeroes the int, grows it then just sets one bit - * as required. - */ -int -mp_2expt (mp_int * a, int b) -{ - int res; - - mp_zero (a); - if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { - return res; - } - a->used = b / DIGIT_BIT + 1; - a->dp[b / DIGIT_BIT] = 1 << (b % DIGIT_BIT); - - return MP_OKAY; -} - -/* End: bn_mp_2expt.c */ - -/* Start: bn_mp_abs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = |a| - * - * Simple function copies the input and fixes the sign to positive - */ -int -mp_abs (mp_int * a, mp_int * b) -{ - int res; - if ((res = mp_copy (a, b)) != MP_OKAY) { - return res; - } - b->sign = MP_ZPOS; - return MP_OKAY; -} - -/* End: bn_mp_abs.c */ - -/* Start: bn_mp_add.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* high level addition (handles signs) */ -int -mp_add (mp_int * a, mp_int * b, mp_int * c) -{ - int sa, sb, res; - - /* get sign of both inputs */ - sa = a->sign; - sb = b->sign; - - /* handle four cases */ - if (sa == MP_ZPOS && sb == MP_ZPOS) { - /* both positive */ - res = s_mp_add (a, b, c); - c->sign = MP_ZPOS; - } else if (sa == MP_ZPOS && sb == MP_NEG) { - /* a + -b == a - b, but if b>a then we do it as -(b-a) */ - if (mp_cmp_mag (a, b) == MP_LT) { - res = s_mp_sub (b, a, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (a, b, c); - c->sign = MP_ZPOS; - } - } else if (sa == MP_NEG && sb == MP_ZPOS) { - /* -a + b == b - a, but if a>b then we do it as -(a-b) */ - if (mp_cmp_mag (a, b) == MP_GT) { - res = s_mp_sub (a, b, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (b, a, c); - c->sign = MP_ZPOS; - } - } else { - /* -a + -b == -(a + b) */ - res = s_mp_add (a, b, c); - c->sign = MP_NEG; - } - return res; -} - -/* End: bn_mp_add.c */ - -/* Start: bn_mp_addmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* d = a + b (mod c) */ -int -mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - int res; - mp_int t; - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_add (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); - return res; -} - -/* End: bn_mp_addmod.c */ - -/* Start: bn_mp_add_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* single digit addition */ -int -mp_add_d (mp_int * a, mp_digit b, mp_int * c) -{ - mp_int t; - int res; - - if ((res = mp_init_size(&t, 1)) != MP_OKAY) { - return res; - } - mp_set (&t, b); - res = mp_add (a, &t, c); - - mp_clear (&t); - return res; -} - -/* End: bn_mp_add_d.c */ - -/* Start: bn_mp_and.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* AND two ints together */ -int -mp_and (mp_int * a, mp_int * b, mp_int * c) -{ - int res, ix, px; - mp_int t, *x; - - if (a->used > b->used) { - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - px = b->used; - x = b; - } else { - if ((res = mp_init_copy (&t, b)) != MP_OKAY) { - return res; - } - px = a->used; - x = a; - } - - for (ix = 0; ix < px; ix++) { - t.dp[ix] &= x->dp[ix]; - } - - /* zero digits above the last from the smallest mp_int */ - for (; ix < t.used; ix++) { - t.dp[ix] = 0; - } - - mp_clamp (&t); - mp_exch (c, &t); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_and.c */ - -/* Start: bn_mp_clamp.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* trim unused digits - * - * This is used to ensure that leading zero digits are - * trimed and the leading "used" digit will be non-zero - * Typically very fast. Also fixes the sign if there - * are no more leading digits - */ -void -mp_clamp (mp_int * a) -{ - while (a->used > 0 && a->dp[a->used - 1] == 0) { - --(a->used); - } - if (a->used == 0) { - a->sign = MP_ZPOS; - } -} - -/* End: bn_mp_clamp.c */ - -/* Start: bn_mp_clear.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* clear one (frees) */ -void -mp_clear (mp_int * a) -{ - if (a->dp != NULL) { - - /* first zero the digits */ - memset (a->dp, 0, sizeof (mp_digit) * a->used); - - /* free ram */ - free (a->dp); - - /* reset members to make debugging easier */ - a->dp = NULL; - a->alloc = a->used = 0; - } -} - -/* End: bn_mp_clear.c */ - -/* Start: bn_mp_cmp.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* compare two ints (signed)*/ -int -mp_cmp (mp_int * a, mp_int * b) -{ - /* compare based on sign */ - if (a->sign == MP_NEG && b->sign == MP_ZPOS) { - return MP_LT; - } else if (a->sign == MP_ZPOS && b->sign == MP_NEG) { - return MP_GT; - } - return mp_cmp_mag (a, b); -} - -/* End: bn_mp_cmp.c */ - -/* Start: bn_mp_cmp_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* compare a digit */ -int -mp_cmp_d (mp_int * a, mp_digit b) -{ - - if (a->sign == MP_NEG) { - return MP_LT; - } - - if (a->used > 1) { - return MP_GT; - } - - if (a->dp[0] > b) { - return MP_GT; - } else if (a->dp[0] < b) { - return MP_LT; - } else { - return MP_EQ; - } -} - -/* End: bn_mp_cmp_d.c */ - -/* Start: bn_mp_cmp_mag.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* compare maginitude of two ints (unsigned) */ -int -mp_cmp_mag (mp_int * a, mp_int * b) -{ - int n; - - /* compare based on # of non-zero digits */ - if (a->used > b->used) { - return MP_GT; - } else if (a->used < b->used) { - return MP_LT; - } - - /* compare based on digits */ - for (n = a->used - 1; n >= 0; n--) { - if (a->dp[n] > b->dp[n]) { - return MP_GT; - } else if (a->dp[n] < b->dp[n]) { - return MP_LT; - } - } - return MP_EQ; -} - -/* End: bn_mp_cmp_mag.c */ - -/* Start: bn_mp_copy.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* copy, b = a */ -int -mp_copy (mp_int * a, mp_int * b) -{ - int res, n; - - /* if dst == src do nothing */ - if (a == b || a->dp == b->dp) { - return MP_OKAY; - } - - /* grow dest */ - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - - /* zero b and copy the parameters over */ - b->used = a->used; - b->sign = a->sign; - - { - register mp_digit *tmpa, *tmpb; - - /* point aliases */ - tmpa = a->dp; - tmpb = b->dp; - - /* copy all the digits */ - for (n = 0; n < a->used; n++) { - *tmpb++ = *tmpa++; - } - - /* clear high digits */ - for (; n < b->alloc; n++) { - *tmpb++ = 0; - } - } - return MP_OKAY; -} - -/* End: bn_mp_copy.c */ - -/* Start: bn_mp_count_bits.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* returns the number of bits in an int */ -int -mp_count_bits (mp_int * a) -{ - int r; - mp_digit q; - - if (a->used == 0) { - return 0; - } - - r = (a->used - 1) * DIGIT_BIT; - q = a->dp[a->used - 1]; - while (q > ((mp_digit) 0)) { - ++r; - q >>= ((mp_digit) 1); - } - return r; -} - -/* End: bn_mp_count_bits.c */ - -/* Start: bn_mp_div.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* integer signed division. c*b + d == a [e.g. a/b, c=quotient, d=remainder] - * HAC pp.598 Algorithm 14.20 - * - * Note that the description in HAC is horribly incomplete. For example, - * it doesn't consider the case where digits are removed from 'x' in the inner - * loop. It also doesn't consider the case that y has fewer than three digits, etc.. - * - * The overall algorithm is as described as 14.20 from HAC but fixed to treat these cases. -*/ -int -mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - mp_int q, x, y, t1, t2; - int res, n, t, i, norm, neg; - - - /* is divisor zero ? */ - if (mp_iszero (b) == 1) { - return MP_VAL; - } - - /* if a < b then q=0, r = a */ - if (mp_cmp_mag (a, b) == MP_LT) { - if (d != NULL) { - res = mp_copy (a, d); - } else { - res = MP_OKAY; - } - if (c != NULL) { - mp_zero (c); - } - return res; - } - - if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { - return res; - } - q.used = a->used + 2; - - if ((res = mp_init (&t1)) != MP_OKAY) { - goto __Q; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - goto __T1; - } - - if ((res = mp_init_copy (&x, a)) != MP_OKAY) { - goto __T2; - } - - if ((res = mp_init_copy (&y, b)) != MP_OKAY) { - goto __X; - } - - /* fix the sign */ - neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; - x.sign = y.sign = MP_ZPOS; - - /* normalize both x and y, ensure that y >= b/2, [b == 2^DIGIT_BIT] */ - norm = mp_count_bits(&y) % DIGIT_BIT; - if (norm < (DIGIT_BIT-1)) { - norm = (DIGIT_BIT-1) - norm; - if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { - goto __Y; - } - if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { - goto __Y; - } - } else { - norm = 0; - } - - /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ - n = x.used - 1; - t = y.used - 1; - - /* step 2. while (x >= y*b^n-t) do { q[n-t] += 1; x -= y*b^{n-t} } */ - if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b^{n-t} */ - goto __Y; - } - - while (mp_cmp (&x, &y) != MP_LT) { - ++(q.dp[n - t]); - if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { - goto __Y; - } - } - - /* reset y by shifting it back down */ - mp_rshd (&y, n - t); - - /* step 3. for i from n down to (t + 1) */ - for (i = n; i >= (t + 1); i--) { - if (i > x.used) - continue; - - /* step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ - if (x.dp[i] == y.dp[t]) { - q.dp[i - t - 1] = ((1UL << DIGIT_BIT) - 1UL); - } else { - mp_word tmp; - tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); - tmp |= ((mp_word) x.dp[i - 1]); - tmp /= ((mp_word) y.dp[t]); - if (tmp > (mp_word) MP_MASK) - tmp = MP_MASK; - q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); - } - - /* step 3.2 while (q{i-t-1} * (yt * b + y{t-1})) > xi * b^2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ - q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; - do { - q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; - - /* find left hand */ - mp_zero (&t1); - t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; - t1.dp[1] = y.dp[t]; - t1.used = 2; - if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { - goto __Y; - } - - /* find right hand */ - t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; - t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; - t2.dp[2] = x.dp[i]; - t2.used = 3; - } while (mp_cmp (&t1, &t2) == MP_GT); - - /* step 3.3 x = x - q{i-t-1} * y * b^{i-t-1} */ - if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { - goto __Y; - } - - /* step 3.4 if x < 0 then { x = x + y*b^{i-t-1}; q{i-t-1} -= 1; } */ - if (x.sign == MP_NEG) { - if ((res = mp_copy (&y, &t1)) != MP_OKAY) { - goto __Y; - } - if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { - goto __Y; - } - if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { - goto __Y; - } - - q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; - } - } - - /* now q is the quotient and x is the remainder [which we have to normalize] */ - /* get sign before writing to c */ - x.sign = a->sign; - - if (c != NULL) { - mp_clamp (&q); - mp_exch (&q, c); - c->sign = neg; - } - - if (d != NULL) { - mp_div_2d (&x, norm, &x, NULL); - mp_exch (&x, d); - } - - res = MP_OKAY; - -__Y:mp_clear (&y); -__X:mp_clear (&x); -__T2:mp_clear (&t2); -__T1:mp_clear (&t1); -__Q:mp_clear (&q); - return res; -} - -/* End: bn_mp_div.c */ - -/* Start: bn_mp_div_2.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = a/2 */ -int -mp_div_2 (mp_int * a, mp_int * b) -{ - int x, res, oldused; - - /* copy */ - if (b->alloc < a->used) { - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - } - - oldused = b->used; - b->used = a->used; - { - register mp_digit r, rr, *tmpa, *tmpb; - - /* source alias */ - tmpa = a->dp + b->used - 1; - - /* dest alias */ - tmpb = b->dp + b->used - 1; - - /* carry */ - r = 0; - for (x = b->used - 1; x >= 0; x--) { - /* get the carry for the next iteration */ - rr = *tmpa & 1; - - /* shift the current digit, add in carry and store */ - *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); - - /* forward carry to next iteration */ - r = rr; - } - - /* zero excess digits */ - tmpb = b->dp + b->used; - for (x = b->used; x < oldused; x++) { - *tmpb++ = 0; - } - } - b->sign = a->sign; - mp_clamp (b); - return MP_OKAY; -} - -/* End: bn_mp_div_2.c */ - -/* Start: bn_mp_div_2d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift right by a certain bit count (store quotient in c, remainder in d) */ -int -mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) -{ - mp_digit D, r, rr; - int x, res; - mp_int t; - - - /* if the shift count is <= 0 then we do no work */ - if (b <= 0) { - res = mp_copy (a, c); - if (d != NULL) { - mp_zero (d); - } - return res; - } - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - /* get the remainder */ - if (d != NULL) { - if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - } - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - /* shift by as many digits in the bit count */ - if (b >= DIGIT_BIT) { - mp_rshd (c, b / DIGIT_BIT); - } - - /* shift any bit count < DIGIT_BIT */ - D = (mp_digit) (b % DIGIT_BIT); - if (D != 0) { - register mp_digit *tmpc, mask; - - /* mask */ - mask = (1U << D) - 1U; - - /* alias */ - tmpc = c->dp + (c->used - 1); - - /* carry */ - r = 0; - for (x = c->used - 1; x >= 0; x--) { - /* get the lower bits of this word in a temp */ - rr = *tmpc & mask; - - /* shift the current word and mix in the carry bits from the previous word */ - *tmpc = (*tmpc >> D) | (r << (DIGIT_BIT - D)); - --tmpc; - - /* set the carry to the carry bits of the current word found above */ - r = rr; - } - } - mp_clamp (c); - res = MP_OKAY; - if (d != NULL) { - mp_exch (&t, d); - } - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_div_2d.c */ - -/* Start: bn_mp_div_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* single digit division */ -int -mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) -{ - mp_int t, t2; - int res; - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - mp_set (&t, b); - res = mp_div (a, &t, c, &t2); - - /* set remainder if not null */ - if (d != NULL) { - *d = t2.dp[0]; - } - - mp_clear (&t); - mp_clear (&t2); - return res; -} - -/* End: bn_mp_div_d.c */ - -/* Start: bn_mp_dr_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* reduce "a" in place modulo "b" using the Diminished Radix algorithm. - * - * Based on algorithm from the paper - * - * "Generating Efficient Primes for Discrete Log Cryptosystems" - * Chae Hoon Lim, Pil Loong Lee, - * POSTECH Information Research Laboratories - * - * The modulus must be of a special format [see manual] - */ -int -mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) -{ - int err, i, j, k; - mp_word r; - mp_digit mu, *tmpj, *tmpi; - - /* k = digits in modulus */ - k = b->used; - - /* ensure that "a" has at least 2k digits */ - if (a->alloc < k + k) { - if ((err = mp_grow (a, k + k)) != MP_OKAY) { - return err; - } - } - - /* alias for a->dp[i] */ - tmpi = a->dp + k + k - 1; - - /* for (i = 2k - 1; i >= k; i = i - 1) - * - * This is the main loop of the reduction. Note that at the end - * the words above position k are not zeroed as expected. The end - * result is that the digits from 0 to k-1 are the residue. So - * we have to clear those afterwards. - */ - for (i = k + k - 1; i >= k; i = i - 1) { - /* x[i - 1 : i - k] += x[i]*mp */ - - /* x[i] * mp */ - r = ((mp_word) *tmpi--) * ((mp_word) mp); - - /* now add r to x[i-1:i-k] - * - * First add it to the first digit x[i-k] then form the carry - * then enter the main loop - */ - j = i - k; - - /* alias for a->dp[j] */ - tmpj = a->dp + j; - - /* add digit */ - *tmpj += (mp_digit)(r & MP_MASK); - - /* this is the carry */ - mu = (r >> ((mp_word) DIGIT_BIT)) + (*tmpj >> DIGIT_BIT); - - /* clear carry from a->dp[j] */ - *tmpj++ &= MP_MASK; - - /* now add rest of the digits - * - * Note this is basically a simple single digit addition to - * a larger multiple digit number. This is optimized somewhat - * because the propagation of carries is not likely to move - * more than a few digits. - * - */ - for (++j; mu != 0 && j <= (i - 1); ++j) { - *tmpj += mu; - mu = *tmpj >> DIGIT_BIT; - *tmpj++ &= MP_MASK; - } - - /* if final carry */ - if (mu != 0) { - /* add mp to this to correct */ - j = i - k; - tmpj = a->dp + j; - - *tmpj += mp; - mu = *tmpj >> DIGIT_BIT; - *tmpj++ &= MP_MASK; - - /* now handle carries */ - for (++j; mu != 0 && j <= (i - 1); j++) { - *tmpj += mu; - mu = *tmpj >> DIGIT_BIT; - *tmpj++ &= MP_MASK; - } - } - } - - /* zero words above k */ - tmpi = a->dp + k; - for (i = k; i < a->used; i++) { - *tmpi++ = 0; - } - - /* clamp, sub and return */ - mp_clamp (a); - - if (mp_cmp_mag (a, b) != MP_LT) { - return s_mp_sub (a, b, a); - } - return MP_OKAY; -} - -/* determines if a number is a valid DR modulus */ -int mp_dr_is_modulus(mp_int *a) -{ - int ix; - - /* must be at least two digits */ - if (a->used < 2) { - return 0; - } - - for (ix = 1; ix < a->used; ix++) { - if (a->dp[ix] != MP_MASK) { - return 0; - } - } - return 1; -} - -/* determines the setup value */ -void mp_dr_setup(mp_int *a, mp_digit *d) -{ - *d = (1 << DIGIT_BIT) - a->dp[0]; -} - - -/* End: bn_mp_dr_reduce.c */ - -/* Start: bn_mp_exch.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* swap the elements of two integers, for cases where you can't simply swap the - * mp_int pointers around - */ -void -mp_exch (mp_int * a, mp_int * b) -{ - mp_int t; - - t = *a; - *a = *b; - *b = t; -} - -/* End: bn_mp_exch.c */ - -/* Start: bn_mp_exptmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -static int f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); - -/* this is a shell function that calls either the normal or Montgomery - * exptmod functions. Originally the call to the montgomery code was - * embedded in the normal function but that wasted alot of stack space - * for nothing (since 99% of the time the Montgomery code would be called) - */ -int -mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -{ - int dr; - - dr = mp_dr_is_modulus(P); - /* if the modulus is odd use the fast method */ - if (((mp_isodd (P) == 1 && P->used < MONTGOMERY_EXPT_CUTOFF) || dr == 1) && P->used > 4) { - return mp_exptmod_fast (G, X, P, Y, dr); - } else { - return f_mp_exptmod (G, X, P, Y); - } -} - -static int -f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -{ - mp_int M[256], res, mu; - mp_digit buf; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - - /* find window size */ - x = mp_count_bits (X); - if (x <= 7) { - winsize = 2; - } else if (x <= 36) { - winsize = 3; - } else if (x <= 140) { - winsize = 4; - } else if (x <= 450) { - winsize = 5; - } else if (x <= 1303) { - winsize = 6; - } else if (x <= 3529) { - winsize = 7; - } else { - winsize = 8; - } - - /* init G array */ - for (x = 0; x < (1 << winsize); x++) { - if ((err = mp_init_size (&M[x], 1)) != MP_OKAY) { - for (y = 0; y < x; y++) { - mp_clear (&M[y]); - } - return err; - } - } - - /* create mu, used for Barrett reduction */ - if ((err = mp_init (&mu)) != MP_OKAY) { - goto __M; - } - if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { - goto __MU; - } - - /* create M table - * - * The M table contains powers of the input base, e.g. M[x] = G^x mod P - * - * The first half of the table is not computed though accept for M[0] and M[1] - */ - if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { - goto __MU; - } - - /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ - if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __MU; - } - - for (x = 0; x < (winsize - 1); x++) { - if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { - goto __MU; - } - } - - /* create upper table */ - for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { - if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { - goto __MU; - } - } - - /* setup result */ - if ((err = mp_init (&res)) != MP_OKAY) { - goto __MU; - } - mp_set (&res, 1); - - /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 0; - buf = 0; - digidx = X->used - 1; - bitcpy = bitbuf = 0; - - bitcnt = 1; - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - if (digidx == -1) { - break; - } - buf = X->dp[digidx--]; - bitcnt = (int) DIGIT_BIT; - } - - /* grab the next msb from the exponent */ - y = (buf >> (DIGIT_BIT - 1)) & 1; - buf <<= 1; - - /* if the bit is zero and mode == 0 then we ignore it - * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it - * does lower the # of trivial squaring/reductions used - */ - if (mode == 0 && y == 0) - continue; - - /* if the bit is zero and mode == 1 then we square */ - if (mode == 1 && y == 0) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - continue; - } - - /* else we add it to the window */ - bitbuf |= (y << (winsize - ++bitcpy)); - mode = 2; - - if (bitcpy == winsize) { - /* ok window is filled so square as required and multiply */ - /* square first */ - for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - } - - /* then multiply */ - if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __MU; - } - - /* empty window and reset */ - bitcpy = bitbuf = 0; - mode = 1; - } - } - - /* if bits remain then square/multiply */ - if (mode == 2 && bitcpy > 0) { - /* square then multiply if the bit is set */ - for (x = 0; x < bitcpy; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - - bitbuf <<= 1; - if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - } - } - } - - mp_exch (&res, Y); - err = MP_OKAY; -__RES:mp_clear (&res); -__MU:mp_clear (&mu); -__M: - for (x = 0; x < (1 << winsize); x++) { - mp_clear (&M[x]); - } - return err; -} - -/* End: bn_mp_exptmod.c */ - -/* Start: bn_mp_exptmod_fast.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes Y == G^X mod P, HAC pp.616, Algorithm 14.85 - * - * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. - * The value of k changes based on the size of the exponent. - * - * Uses Montgomery or Diminished Radix reduction [whichever appropriate] - */ -int -mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) -{ - mp_int M[256], res; - mp_digit buf, mp; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - int (*redux)(mp_int*,mp_int*,mp_digit); - - /* find window size */ - x = mp_count_bits (X); - if (x <= 7) { - winsize = 2; - } else if (x <= 36) { - winsize = 3; - } else if (x <= 140) { - winsize = 4; - } else if (x <= 450) { - winsize = 5; - } else if (x <= 1303) { - winsize = 6; - } else if (x <= 3529) { - winsize = 7; - } else { - winsize = 8; - } - - /* init G array */ - for (x = 0; x < (1 << winsize); x++) { - if ((err = mp_init (&M[x])) != MP_OKAY) { - for (y = 0; y < x; y++) { - mp_clear (&M[y]); - } - return err; - } - } - - if (redmode == 0) { - /* now setup montgomery */ - if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { - goto __M; - } - redux = mp_montgomery_reduce; - } else { - /* setup DR reduction */ - mp_dr_setup(P, &mp); - redux = mp_dr_reduce; - } - - /* setup result */ - if ((err = mp_init (&res)) != MP_OKAY) { - goto __RES; - } - - /* create M table - * - * The M table contains powers of the input base, e.g. M[x] = G^x mod P - * - * The first half of the table is not computed though accept for M[0] and M[1] - */ - - if (redmode == 0) { - /* now we need R mod m */ - if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { - goto __RES; - } - - /* now set M[1] to G * R mod m */ - if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { - goto __RES; - } - } else { - mp_set(&res, 1); - if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { - goto __RES; - } - } - - /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ - if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __RES; - } - - for (x = 0; x < (winsize - 1); x++) { - if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { - goto __RES; - } - } - - /* create upper table */ - for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { - if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&M[x], P, mp)) != MP_OKAY) { - goto __RES; - } - } - - /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 0; - buf = 0; - digidx = X->used - 1; - bitcpy = bitbuf = 0; - - bitcnt = 1; - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - if (digidx == -1) { - break; - } - buf = X->dp[digidx--]; - bitcnt = (int) DIGIT_BIT; - } - - /* grab the next msb from the exponent */ - y = (buf >> (DIGIT_BIT - 1)) & 1; - buf <<= 1; - - /* if the bit is zero and mode == 0 then we ignore it - * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it - * does lower the # of trivial squaring/reductions used - */ - if (mode == 0 && y == 0) - continue; - - /* if the bit is zero and mode == 1 then we square */ - if (mode == 1 && y == 0) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - continue; - } - - /* else we add it to the window */ - bitbuf |= (y << (winsize - ++bitcpy)); - mode = 2; - - if (bitcpy == winsize) { - /* ok window is filled so square as required and multiply */ - /* square first */ - for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - } - - /* then multiply */ - if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - - /* empty window and reset */ - bitcpy = bitbuf = 0; - mode = 1; - } - } - - /* if bits remain then square/multiply */ - if (mode == 2 && bitcpy > 0) { - /* square then multiply if the bit is set */ - for (x = 0; x < bitcpy; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - - bitbuf <<= 1; - if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - } - } - } - - if (redmode == 0) { - /* fixup result */ - if ((err = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - } - - mp_exch (&res, Y); - err = MP_OKAY; -__RES:mp_clear (&res); -__M: - for (x = 0; x < (1 << winsize); x++) { - mp_clear (&M[x]); - } - return err; -} - -/* End: bn_mp_exptmod_fast.c */ - -/* Start: bn_mp_expt_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* calculate c = a^b using a square-multiply algorithm */ -int -mp_expt_d (mp_int * a, mp_digit b, mp_int * c) -{ - int res, x; - mp_int g; - - if ((res = mp_init_copy (&g, a)) != MP_OKAY) { - return res; - } - - /* set initial result */ - mp_set (c, 1); - - for (x = 0; x < (int) DIGIT_BIT; x++) { - /* square */ - if ((res = mp_sqr (c, c)) != MP_OKAY) { - mp_clear (&g); - return res; - } - - /* if the bit is set multiply */ - if ((b & (mp_digit) (1 << (DIGIT_BIT - 1))) != 0) { - if ((res = mp_mul (c, &g, c)) != MP_OKAY) { - mp_clear (&g); - return res; - } - } - - /* shift to next bit */ - b <<= 1; - } - - mp_clear (&g); - return MP_OKAY; -} - -/* End: bn_mp_expt_d.c */ - -/* Start: bn_mp_gcd.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* Greatest Common Divisor using the binary method [Algorithm B, page 338, vol2 of TAOCP] - */ -int -mp_gcd (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int u, v, t; - int k, res, neg; - - /* either zero than gcd is the largest */ - if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { - return mp_copy (b, c); - } - if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { - return mp_copy (a, c); - } - if (mp_iszero (a) == 1 && mp_iszero (b) == 1) { - mp_set (c, 1); - return MP_OKAY; - } - - /* if both are negative they share (-1) as a common divisor */ - neg = (a->sign == b->sign) ? a->sign : MP_ZPOS; - - if ((res = mp_init_copy (&u, a)) != MP_OKAY) { - return res; - } - - if ((res = mp_init_copy (&v, b)) != MP_OKAY) { - goto __U; - } - - /* must be positive for the remainder of the algorithm */ - u.sign = v.sign = MP_ZPOS; - - if ((res = mp_init (&t)) != MP_OKAY) { - goto __V; - } - - /* B1. Find power of two */ - k = 0; - while (mp_iseven(&u) == 1 && mp_iseven(&v) == 1) { - ++k; - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __T; - } - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __T; - } - } - - /* B2. Initialize */ - if (mp_isodd(&u) == 1) { - /* t = -v */ - if ((res = mp_copy (&v, &t)) != MP_OKAY) { - goto __T; - } - t.sign = MP_NEG; - } else { - /* t = u */ - if ((res = mp_copy (&u, &t)) != MP_OKAY) { - goto __T; - } - } - - do { - /* B3 (and B4). Halve t, if even */ - while (t.used != 0 && mp_iseven(&t) == 1) { - if ((res = mp_div_2 (&t, &t)) != MP_OKAY) { - goto __T; - } - } - - /* B5. if t>0 then u=t otherwise v=-t */ - if (t.used != 0 && t.sign != MP_NEG) { - if ((res = mp_copy (&t, &u)) != MP_OKAY) { - goto __T; - } - } else { - if ((res = mp_copy (&t, &v)) != MP_OKAY) { - goto __T; - } - v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; - } - - /* B6. t = u - v, if t != 0 loop otherwise terminate */ - if ((res = mp_sub (&u, &v, &t)) != MP_OKAY) { - goto __T; - } - } - while (t.used != 0); - - if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { - goto __T; - } - - mp_exch (&u, c); - c->sign = neg; - res = MP_OKAY; -__T:mp_clear (&t); -__V:mp_clear (&u); -__U:mp_clear (&v); - return res; -} - -/* End: bn_mp_gcd.c */ - -/* Start: bn_mp_grow.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* grow as required */ -int -mp_grow (mp_int * a, int size) -{ - int i, n; - - /* if the alloc size is smaller alloc more ram */ - if (a->alloc < size) { - /* ensure there are always at least MP_PREC digits extra on top */ - size += (MP_PREC * 2) - (size & (MP_PREC - 1)); - - a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * size); - if (a->dp == NULL) { - return MP_MEM; - } - - /* zero excess digits */ - n = a->alloc; - a->alloc = size; - for (i = n; i < a->alloc; i++) { - a->dp[i] = 0; - } - } - return MP_OKAY; -} - -/* End: bn_mp_grow.c */ - -/* Start: bn_mp_init.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* init a new bigint */ -int -mp_init (mp_int * a) -{ - - /* allocate ram required and clear it */ - a->dp = OPT_CAST calloc (sizeof (mp_digit), MP_PREC); - if (a->dp == NULL) { - return MP_MEM; - } - - /* set the used to zero, allocated digit to the default precision - * and sign to positive */ - a->used = 0; - a->alloc = MP_PREC; - a->sign = MP_ZPOS; - - return MP_OKAY; -} - -/* End: bn_mp_init.c */ - -/* Start: bn_mp_init_copy.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* creates "a" then copies b into it */ -int -mp_init_copy (mp_int * a, mp_int * b) -{ - int res; - - if ((res = mp_init (a)) != MP_OKAY) { - return res; - } - return mp_copy (b, a); -} - -/* End: bn_mp_init_copy.c */ - -/* Start: bn_mp_init_size.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* init a mp_init and grow it to a given size */ -int -mp_init_size (mp_int * a, int size) -{ - - /* pad size so there are always extra digits */ - size += (MP_PREC * 2) - (size & (MP_PREC - 1)); - - /* alloc mem */ - a->dp = OPT_CAST calloc (sizeof (mp_digit), size); - if (a->dp == NULL) { - return MP_MEM; - } - a->used = 0; - a->alloc = size; - a->sign = MP_ZPOS; - - return MP_OKAY; -} - -/* End: bn_mp_init_size.c */ - -/* Start: bn_mp_invmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -int -mp_invmod (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int x, y, u, v, A, B, C, D; - int res; - - /* b cannot be negative */ - if (b->sign == MP_NEG) { - return MP_VAL; - } - - /* if the modulus is odd we can use a faster routine instead */ - if (mp_iseven (b) == 0) { - return fast_mp_invmod (a, b, c); - } - - if ((res = mp_init (&x)) != MP_OKAY) { - goto __ERR; - } - - if ((res = mp_init (&y)) != MP_OKAY) { - goto __X; - } - - if ((res = mp_init (&u)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_init (&v)) != MP_OKAY) { - goto __U; - } - - if ((res = mp_init (&A)) != MP_OKAY) { - goto __V; - } - - if ((res = mp_init (&B)) != MP_OKAY) { - goto __A; - } - - if ((res = mp_init (&C)) != MP_OKAY) { - goto __B; - } - - if ((res = mp_init (&D)) != MP_OKAY) { - goto __C; - } - - /* x = a, y = b */ - if ((res = mp_copy (a, &x)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (b, &y)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_abs (&x, &x)) != MP_OKAY) { - goto __D; - } - - /* 2. [modified] if x,y are both even then return an error! */ - if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { - res = MP_VAL; - goto __D; - } - - /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ - if ((res = mp_copy (&x, &u)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (&y, &v)) != MP_OKAY) { - goto __D; - } - mp_set (&A, 1); - mp_set (&D, 1); - - -top: - /* 4. while u is even do */ - while (mp_iseven (&u) == 1) { - /* 4.1 u = u/2 */ - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __D; - } - /* 4.2 if A or B is odd then */ - if (mp_iseven (&A) == 0 || mp_iseven (&B) == 0) { - /* A = (A+y)/2, B = (B-x)/2 */ - if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { - goto __D; - } - if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { - goto __D; - } - } - /* A = A/2, B = B/2 */ - if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { - goto __D; - } - if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { - goto __D; - } - } - - - /* 5. while v is even do */ - while (mp_iseven (&v) == 1) { - /* 5.1 v = v/2 */ - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __D; - } - /* 5.2 if C,D are even then */ - if (mp_iseven (&C) == 0 || mp_iseven (&D) == 0) { - /* C = (C+y)/2, D = (D-x)/2 */ - if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { - goto __D; - } - if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { - goto __D; - } - } - /* C = C/2, D = D/2 */ - if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { - goto __D; - } - if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { - goto __D; - } - } - - /* 6. if u >= v then */ - if (mp_cmp (&u, &v) != MP_LT) { - /* u = u - v, A = A - C, B = B - D */ - if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { - goto __D; - } - } else { - /* v - v - u, C = C - A, D = D - B */ - if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { - goto __D; - } - } - - /* if not zero goto step 4 */ - if (mp_iszero (&u) == 0) - goto top; - - /* now a = C, b = D, gcd == g*v */ - - /* if v != 1 then there is no inverse */ - if (mp_cmp_d (&v, 1) != MP_EQ) { - res = MP_VAL; - goto __D; - } - - /* a is now the inverse */ - mp_exch (&C, c); - res = MP_OKAY; - -__D:mp_clear (&D); -__C:mp_clear (&C); -__B:mp_clear (&B); -__A:mp_clear (&A); -__V:mp_clear (&v); -__U:mp_clear (&u); -__Y:mp_clear (&y); -__X:mp_clear (&x); -__ERR: - return res; -} - -/* End: bn_mp_invmod.c */ - -/* Start: bn_mp_jacobi.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes the jacobi c = (a | n) (or Legendre if b is prime) - * HAC pp. 73 Algorithm 2.149 - */ -int -mp_jacobi (mp_int * a, mp_int * n, int *c) -{ - mp_int a1, n1, e; - int s, r, res; - mp_digit residue; - - /* step 1. if a == 0, return 0 */ - if (mp_iszero (a) == 1) { - *c = 0; - return MP_OKAY; - } - - /* step 2. if a == 1, return 1 */ - if (mp_cmp_d (a, 1) == MP_EQ) { - *c = 1; - return MP_OKAY; - } - - /* default */ - s = 0; - - /* step 3. write a = a1 * 2^e */ - if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&n1)) != MP_OKAY) { - goto __A1; - } - - if ((res = mp_init (&e)) != MP_OKAY) { - goto __N1; - } - - while (mp_iseven (&a1) == 1) { - if ((res = mp_add_d (&e, 1, &e)) != MP_OKAY) { - goto __E; - } - - if ((res = mp_div_2 (&a1, &a1)) != MP_OKAY) { - goto __E; - } - } - - /* step 4. if e is even set s=1 */ - if (mp_iseven (&e) == 1) { - s = 1; - } else { - /* else set s=1 if n = 1/7 (mod 8) or s=-1 if n = 3/5 (mod 8) */ - if ((res = mp_mod_d (n, 8, &residue)) != MP_OKAY) { - goto __E; - } - - if (residue == 1 || residue == 7) { - s = 1; - } else if (residue == 3 || residue == 5) { - s = -1; - } - } - - /* step 5. if n == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ - if ((res = mp_mod_d (n, 4, &residue)) != MP_OKAY) { - goto __E; - } - if (residue == 3) { - if ((res = mp_mod_d (&a1, 4, &residue)) != MP_OKAY) { - goto __E; - } - if (residue == 3) { - s = -s; - } - } - - /* if a1 == 1 we're done */ - if (mp_cmp_d (&a1, 1) == MP_EQ) { - *c = s; - } else { - /* n1 = n mod a1 */ - if ((res = mp_mod (n, &a1, &n1)) != MP_OKAY) { - goto __E; - } - if ((res = mp_jacobi (&n1, &a1, &r)) != MP_OKAY) { - goto __E; - } - *c = s * r; - } - - /* done */ - res = MP_OKAY; -__E:mp_clear (&e); -__N1:mp_clear (&n1); -__A1:mp_clear (&a1); - return res; -} - -/* End: bn_mp_jacobi.c */ - -/* Start: bn_mp_karatsuba_mul.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* c = |a| * |b| using Karatsuba Multiplication using three half size multiplications - * - * Let B represent the radix [e.g. 2**DIGIT_BIT] and let n represent half of the number of digits in the min(a,b) - * - * a = a1 * B^n + a0 - * b = b1 * B^n + b0 - * - * Then, a * b => a1b1 * B^2n + ((a1 - b1)(a0 - b0) + a0b0 + a1b1) * B + a0b0 - * - * Note that a1b1 and a0b0 are used twice and only need to be computed once. So in total - * three half size (half # of digit) multiplications are performed, a0b0, a1b1 and (a1-b1)(a0-b0) - * - * Note that a multiplication of half the digits requires 1/4th the number of single precision - * multiplications so in total after one call 25% of the single precision multiplications are saved. - * Note also that the call to mp_mul can end up back in this function if the a0, a1, b0, or b1 are above - * the threshold. This is known as divide-and-conquer and leads to the famous O(N^lg(3)) or O(N^1.584) work which - * is asymptopically lower than the standard O(N^2) that the baseline/comba methods use. Generally though the - * overhead of this method doesn't pay off until a certain size (N ~ 80) is reached. - */ -int -mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int x0, x1, y0, y1, t1, t2, x0y0, x1y1; - int B, err; - - err = MP_MEM; - - /* min # of digits */ - B = MIN (a->used, b->used); - - /* now divide in two */ - B = B / 2; - - /* init copy all the temps */ - if (mp_init_size (&x0, B) != MP_OKAY) - goto ERR; - if (mp_init_size (&x1, a->used - B) != MP_OKAY) - goto X0; - if (mp_init_size (&y0, B) != MP_OKAY) - goto X1; - if (mp_init_size (&y1, b->used - B) != MP_OKAY) - goto Y0; - - /* init temps */ - if (mp_init_size (&t1, B * 2) != MP_OKAY) - goto Y1; - if (mp_init_size (&t2, B * 2) != MP_OKAY) - goto T1; - if (mp_init_size (&x0y0, B * 2) != MP_OKAY) - goto T2; - if (mp_init_size (&x1y1, B * 2) != MP_OKAY) - goto X0Y0; - - /* now shift the digits */ - x0.sign = x1.sign = a->sign; - y0.sign = y1.sign = b->sign; - - x0.used = y0.used = B; - x1.used = a->used - B; - y1.used = b->used - B; - - { - register int x; - register mp_digit *tmpa, *tmpb, *tmpx, *tmpy; - - /* we copy the digits directly instead of using higher level functions - * since we also need to shift the digits - */ - tmpa = a->dp; - tmpb = b->dp; - - tmpx = x0.dp; - tmpy = y0.dp; - for (x = 0; x < B; x++) { - *tmpx++ = *tmpa++; - *tmpy++ = *tmpb++; - } - - tmpx = x1.dp; - for (x = B; x < a->used; x++) { - *tmpx++ = *tmpa++; - } - - tmpy = y1.dp; - for (x = B; x < b->used; x++) { - *tmpy++ = *tmpb++; - } - } - - /* only need to clamp the lower words since by definition the upper words x1/y1 must - * have a known number of digits - */ - mp_clamp (&x0); - mp_clamp (&y0); - - /* now calc the products x0y0 and x1y1 */ - if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) - goto X1Y1; /* x0y0 = x0*y0 */ - if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) - goto X1Y1; /* x1y1 = x1*y1 */ - - /* now calc x1-x0 and y1-y0 */ - if (mp_sub (&x1, &x0, &t1) != MP_OKAY) - goto X1Y1; /* t1 = x1 - x0 */ - if (mp_sub (&y1, &y0, &t2) != MP_OKAY) - goto X1Y1; /* t2 = y1 - y0 */ - if (mp_mul (&t1, &t2, &t1) != MP_OKAY) - goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ - - /* add x0y0 */ - if (mp_add (&x0y0, &x1y1, &t2) != MP_OKAY) - goto X1Y1; /* t2 = x0y0 + x1y1 */ - if (mp_sub (&t2, &t1, &t1) != MP_OKAY) - goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ - - /* shift by B */ - if (mp_lshd (&t1, B) != MP_OKAY) - goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< - -/* Karatsuba squaring, computes b = a*a using three half size squarings - * - * See comments of mp_karatsuba_mul for details. It is essentially the same algorithm - * but merely tuned to perform recursive squarings. - */ -int -mp_karatsuba_sqr (mp_int * a, mp_int * b) -{ - mp_int x0, x1, t1, t2, x0x0, x1x1; - int B, err; - - err = MP_MEM; - - /* min # of digits */ - B = a->used; - - /* now divide in two */ - B = B / 2; - - /* init copy all the temps */ - if (mp_init_size (&x0, B) != MP_OKAY) - goto ERR; - if (mp_init_size (&x1, a->used - B) != MP_OKAY) - goto X0; - - /* init temps */ - if (mp_init_size (&t1, a->used * 2) != MP_OKAY) - goto X1; - if (mp_init_size (&t2, a->used * 2) != MP_OKAY) - goto T1; - if (mp_init_size (&x0x0, B * 2) != MP_OKAY) - goto T2; - if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) - goto X0X0; - - { - register int x; - register mp_digit *dst, *src; - - src = a->dp; - - /* now shift the digits */ - dst = x0.dp; - for (x = 0; x < B; x++) { - *dst++ = *src++; - } - - dst = x1.dp; - for (x = B; x < a->used; x++) { - *dst++ = *src++; - } - } - - x0.used = B; - x1.used = a->used - B; - - mp_clamp (&x0); - - /* now calc the products x0*x0 and x1*x1 */ - if (mp_sqr (&x0, &x0x0) != MP_OKAY) - goto X1X1; /* x0x0 = x0*x0 */ - if (mp_sqr (&x1, &x1x1) != MP_OKAY) - goto X1X1; /* x1x1 = x1*x1 */ - - /* now calc x1-x0 and y1-y0 */ - if (mp_sub (&x1, &x0, &t1) != MP_OKAY) - goto X1X1; /* t1 = x1 - x0 */ - if (mp_sqr (&t1, &t1) != MP_OKAY) - goto X1X1; /* t1 = (x1 - x0) * (y1 - y0) */ - - /* add x0y0 */ - if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) - goto X1X1; /* t2 = x0y0 + x1y1 */ - if (mp_sub (&t2, &t1, &t1) != MP_OKAY) - goto X1X1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ - - /* shift by B */ - if (mp_lshd (&t1, B) != MP_OKAY) - goto X1X1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< - -/* computes least common multiple as a*b/(a, b) */ -int -mp_lcm (mp_int * a, mp_int * b, mp_int * c) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_mul (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - if ((res = mp_gcd (a, b, c)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - res = mp_div (&t, c, c, NULL); - mp_clear (&t); - return res; -} - -/* End: bn_mp_lcm.c */ - -/* Start: bn_mp_lshd.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift left a certain amount of digits */ -int -mp_lshd (mp_int * a, int b) -{ - int x, res; - - - /* if its less than zero return */ - if (b <= 0) { - return MP_OKAY; - } - - /* grow to fit the new digits */ - if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { - return res; - } - - { - register mp_digit *tmpa, *tmpaa; - - /* increment the used by the shift amount than copy upwards */ - a->used += b; - - /* top */ - tmpa = a->dp + a->used - 1; - - /* base */ - tmpaa = a->dp + a->used - 1 - b; - - /* much like mp_rshd this is implemented using a sliding window - * except the window goes the otherway around. Copying from - * the bottom to the top. see bn_mp_rshd.c for more info. - */ - for (x = a->used - 1; x >= b; x--) { - *tmpa-- = *tmpaa--; - } - - /* zero the lower digits */ - tmpa = a->dp; - for (x = 0; x < b; x++) { - *tmpa++ = 0; - } - } - return MP_OKAY; -} - -/* End: bn_mp_lshd.c */ - -/* Start: bn_mp_mod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* c = a mod b, 0 <= c < b */ -int -mp_mod (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int t; - int res; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - if (t.sign == MP_NEG) { - res = mp_add (b, &t, c); - } else { - res = MP_OKAY; - mp_exch (&t, c); - } - - mp_clear (&t); - return res; -} - -/* End: bn_mp_mod.c */ - -/* Start: bn_mp_mod_2d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* calc a value mod 2^b */ -int -mp_mod_2d (mp_int * a, int b, mp_int * c) -{ - int x, res; - - - /* if b is <= 0 then zero the int */ - if (b <= 0) { - mp_zero (c); - return MP_OKAY; - } - - /* if the modulus is larger than the value than return */ - if (b > (int) (a->used * DIGIT_BIT)) { - res = mp_copy (a, c); - return res; - } - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - return res; - } - - /* zero digits above the last digit of the modulus */ - for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { - c->dp[x] = 0; - } - /* clear the digit that is not completely outside/inside the modulus */ - c->dp[b / DIGIT_BIT] &= - (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_mp_mod_2d.c */ - -/* Start: bn_mp_mod_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -int -mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) -{ - mp_int t, t2; - int res; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - mp_set (&t, b); - mp_div (a, &t, NULL, &t2); - - if (t2.sign == MP_NEG) { - if ((res = mp_add_d (&t2, b, &t2)) != MP_OKAY) { - mp_clear (&t); - mp_clear (&t2); - return res; - } - } - *c = t2.dp[0]; - mp_clear (&t); - mp_clear (&t2); - return MP_OKAY; -} - -/* End: bn_mp_mod_d.c */ - -/* Start: bn_mp_montgomery_calc_normalization.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* calculates a = B^n mod b for Montgomery reduction - * Where B is the base [e.g. 2^DIGIT_BIT]. - * B^n mod b is computed by first computing - * A = B^(n-1) which doesn't require a reduction but a simple OR. - * then C = A * B = B^n is computed by performing upto DIGIT_BIT - * shifts with subtractions when the result is greater than b. - * - * The method is slightly modified to shift B unconditionally upto just under - * the leading bit of b. This saves alot of multiple precision shifting. - */ -int -mp_montgomery_calc_normalization (mp_int * a, mp_int * b) -{ - int x, bits, res; - - /* how many bits of last digit does b use */ - bits = mp_count_bits (b) % DIGIT_BIT; - - /* compute A = B^(n-1) * 2^(bits-1) */ - if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { - return res; - } - - /* now compute C = A * B mod b */ - for (x = bits - 1; x < DIGIT_BIT; x++) { - if ((res = mp_mul_2 (a, a)) != MP_OKAY) { - return res; - } - if (mp_cmp_mag (a, b) != MP_LT) { - if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { - return res; - } - } - } - - return MP_OKAY; -} - -/* End: bn_mp_montgomery_calc_normalization.c */ - -/* Start: bn_mp_montgomery_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes xR^-1 == x (mod N) via Montgomery Reduction */ -int -mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) -{ - int ix, res, digs; - mp_digit ui; - - digs = m->used * 2 + 1; - if ((digs < 512) - && digs < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - return fast_mp_montgomery_reduce (a, m, mp); - } - - if (a->alloc < m->used * 2 + 1) { - if ((res = mp_grow (a, m->used * 2 + 1)) != MP_OKAY) { - return res; - } - } - a->used = m->used * 2 + 1; - - for (ix = 0; ix < m->used; ix++) { - /* ui = ai * m' mod b */ - ui = (a->dp[ix] * mp) & MP_MASK; - - /* a = a + ui * m * b^i */ - { - register int iy; - register mp_digit *tmpx, *tmpy, mu; - register mp_word r; - - /* aliases */ - tmpx = m->dp; - tmpy = a->dp + ix; - - mu = 0; - for (iy = 0; iy < m->used; iy++) { - r = ((mp_word) ui) * ((mp_word) * tmpx++) + ((mp_word) mu) + ((mp_word) * tmpy); - mu = (r >> ((mp_word) DIGIT_BIT)); - *tmpy++ = (r & ((mp_word) MP_MASK)); - } - /* propagate carries */ - while (mu) { - *tmpy += mu; - mu = (*tmpy >> DIGIT_BIT) & 1; - *tmpy++ &= MP_MASK; - } - } - } - - /* A = A/b^n */ - mp_rshd (a, m->used); - - /* if A >= m then A = A - m */ - if (mp_cmp_mag (a, m) != MP_LT) { - return s_mp_sub (a, m, a); - } - - return MP_OKAY; -} - -/* End: bn_mp_montgomery_reduce.c */ - -/* Start: bn_mp_montgomery_setup.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* setups the montgomery reduction stuff */ -int -mp_montgomery_setup (mp_int * a, mp_digit * mp) -{ - unsigned long x, b; - -/* fast inversion mod 2^32 - * - * Based on the fact that - * - * XA = 1 (mod 2^n) => (X(2-XA)) A = 1 (mod 2^2n) - * => 2*X*A - X*X*A*A = 1 - * => 2*(1) - (1) = 1 - */ - b = a->dp[0]; - - if ((b & 1) == 0) { - return MP_VAL; - } - - x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2^4 */ - x *= 2 - b * x; /* here x*a==1 mod 2^8 */ - x *= 2 - b * x; /* here x*a==1 mod 2^16; each step doubles the nb of bits */ - x *= 2 - b * x; /* here x*a==1 mod 2^32 */ - - /* t = -1/m mod b */ - *mp = ((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - (x & MP_MASK); - - return MP_OKAY; -} - -/* End: bn_mp_montgomery_setup.c */ - -/* Start: bn_mp_mul.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* high level multiplication (handles sign) */ -int -mp_mul (mp_int * a, mp_int * b, mp_int * c) -{ - int res, neg; - neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; - if (MIN (a->used, b->used) > KARATSUBA_MUL_CUTOFF) { - res = mp_karatsuba_mul (a, b, c); - } else { - - /* can we use the fast multiplier? - * - * The fast multiplier can be used if the output will have less than - * 512 digits and the number of digits won't affect carry propagation - */ - int digs = a->used + b->used + 1; - - if ((digs < 512) - && digs < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - res = fast_s_mp_mul_digs (a, b, c, digs); - } else { - res = s_mp_mul (a, b, c); - } - - } - c->sign = neg; - return res; -} - -/* End: bn_mp_mul.c */ - -/* Start: bn_mp_mulmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* d = a * b (mod c) */ -int -mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_mul (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); - return res; -} - -/* End: bn_mp_mulmod.c */ - -/* Start: bn_mp_mul_2.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = a*2 */ -int -mp_mul_2 (mp_int * a, mp_int * b) -{ - int x, res, oldused; - - /* Optimization: should copy and shift at the same time */ - - if (b->alloc < a->used) { - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - } - - oldused = b->used; - b->used = a->used; - - /* shift any bit count < DIGIT_BIT */ - { - register mp_digit r, rr, *tmpa, *tmpb; - - /* alias for source */ - tmpa = a->dp; - - /* alias for dest */ - tmpb = b->dp; - - /* carry */ - r = 0; - for (x = 0; x < b->used; x++) { - - /* get what will be the *next* carry bit from the MSB of the current digit */ - rr = *tmpa >> (DIGIT_BIT - 1); - - /* now shift up this digit, add in the carry [from the previous] */ - *tmpb++ = ((*tmpa++ << 1) | r) & MP_MASK; - - /* copy the carry that would be from the source digit into the next iteration */ - r = rr; - } - - /* new leading digit? */ - if (r != 0) { - /* do we have to grow to accomodate the new digit? */ - if (b->alloc == b->used) { - if ((res = mp_grow (b, b->used + 1)) != MP_OKAY) { - return res; - } - - /* after the grow *tmpb is no longer valid so we have to reset it! - * (this bug took me about 17 minutes to find...!) - */ - tmpb = b->dp + b->used; - } - /* add a MSB which is always 1 at this point */ - *tmpb = 1; - ++b->used; - } - - /* now zero any excess digits on the destination that we didn't write to */ - tmpb = b->dp + b->used; - for (x = b->used; x < oldused; x++) { - *tmpb++ = 0; - } - } - b->sign = a->sign; - return MP_OKAY; -} - -/* End: bn_mp_mul_2.c */ - -/* Start: bn_mp_mul_2d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift left by a certain bit count */ -int -mp_mul_2d (mp_int * a, int b, mp_int * c) -{ - mp_digit d, r, rr; - int x, res; - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - return res; - } - - if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { - return res; - } - - /* shift by as many digits in the bit count */ - if (b >= DIGIT_BIT) { - if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { - return res; - } - } - c->used = c->alloc; - - /* shift any bit count < DIGIT_BIT */ - d = (mp_digit) (b % DIGIT_BIT); - if (d != 0) { - register mp_digit *tmpc, mask; - - /* bitmask for carries */ - mask = (1U << d) - 1U; - - /* alias */ - tmpc = c->dp; - - /* carry */ - r = 0; - for (x = 0; x < c->used; x++) { - /* get the higher bits of the current word */ - rr = (*tmpc >> (DIGIT_BIT - d)) & mask; - - /* shift the current word and OR in the carry */ - *tmpc = ((*tmpc << d) | r) & MP_MASK; - ++tmpc; - - /* set the carry to the carry bits of the current word */ - r = rr; - } - } - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_mp_mul_2d.c */ - -/* Start: bn_mp_mul_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* multiply by a digit */ -int -mp_mul_d (mp_int * a, mp_digit b, mp_int * c) -{ - int res, pa, olduse; - - pa = a->used; - if (c->alloc < pa + 1) { - if ((res = mp_grow (c, pa + 1)) != MP_OKAY) { - return res; - } - } - - olduse = c->used; - c->used = pa + 1; - - { - register mp_digit u, *tmpa, *tmpc; - register mp_word r; - register int ix; - - tmpc = c->dp + c->used; - for (ix = c->used; ix < olduse; ix++) { - *tmpc++ = 0; - } - - tmpa = a->dp; - tmpc = c->dp; - - u = 0; - for (ix = 0; ix < pa; ix++) { - r = ((mp_word) u) + ((mp_word) * tmpa++) * ((mp_word) b); - *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - *tmpc = u; - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_mp_mul_d.c */ - -/* Start: bn_mp_neg.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = -a */ -int -mp_neg (mp_int * a, mp_int * b) -{ - int res; - if ((res = mp_copy (a, b)) != MP_OKAY) { - return res; - } - b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; - return MP_OKAY; -} - -/* End: bn_mp_neg.c */ - -/* Start: bn_mp_n_root.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* find the n'th root of an integer - * - * Result found such that (c)^b <= a and (c+1)^b > a - * - * This algorithm uses Newton's approximation x[i+1] = x[i] - f(x[i])/f'(x[i]) - * which will find the root in log(N) time where each step involves a fair bit. This - * is not meant to find huge roots [square and cube at most]. - */ -int -mp_n_root (mp_int * a, mp_digit b, mp_int * c) -{ - mp_int t1, t2, t3; - int res, neg; - - /* input must be positive if b is even */ - if ((b & 1) == 0 && a->sign == MP_NEG) { - return MP_VAL; - } - - if ((res = mp_init (&t1)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - goto __T1; - } - - if ((res = mp_init (&t3)) != MP_OKAY) { - goto __T2; - } - - /* if a is negative fudge the sign but keep track */ - neg = a->sign; - a->sign = MP_ZPOS; - - /* t2 = 2 */ - mp_set (&t2, 2); - - do { - /* t1 = t2 */ - if ((res = mp_copy (&t2, &t1)) != MP_OKAY) { - goto __T3; - } - - /* t2 = t1 - ((t1^b - a) / (b * t1^(b-1))) */ - if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) */ - goto __T3; - } - - /* numerator */ - if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { /* t2 = t1^b */ - goto __T3; - } - - if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { /* t2 = t1^b - a */ - goto __T3; - } - - if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) * b */ - goto __T3; - } - - if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { /* t3 = (t1^b - a)/(b * t1^(b-1)) */ - goto __T3; - } - - if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { - goto __T3; - } - } - while (mp_cmp (&t1, &t2) != MP_EQ); - - /* result can be off by a few so check */ - for (;;) { - if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) { - goto __T3; - } - - if (mp_cmp (&t2, a) == MP_GT) { - if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) { - goto __T3; - } - } else { - break; - } - } - - /* reset the sign of a first */ - a->sign = neg; - - /* set the result */ - mp_exch (&t1, c); - - /* set the sign of the result */ - c->sign = neg; - - res = MP_OKAY; - -__T3:mp_clear (&t3); -__T2:mp_clear (&t2); -__T1:mp_clear (&t1); - return res; -} - -/* End: bn_mp_n_root.c */ - -/* Start: bn_mp_or.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* OR two ints together */ -int -mp_or (mp_int * a, mp_int * b, mp_int * c) -{ - int res, ix, px; - mp_int t, *x; - - if (a->used > b->used) { - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - px = b->used; - x = b; - } else { - if ((res = mp_init_copy (&t, b)) != MP_OKAY) { - return res; - } - px = a->used; - x = a; - } - - for (ix = 0; ix < px; ix++) { - t.dp[ix] |= x->dp[ix]; - } - mp_clamp (&t); - mp_exch (c, &t); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_or.c */ - -/* Start: bn_mp_prime_fermat.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* performs one Fermat test. - * - * If "a" were prime then b^a == b (mod a) since the order of - * the multiplicative sub-group would be phi(a) = a-1. That means - * it would be the same as b^(a mod (a-1)) == b^1 == b (mod a). - * - * Sets result to 1 if the congruence holds, or zero otherwise. - */ -int -mp_prime_fermat (mp_int * a, mp_int * b, int *result) -{ - mp_int t; - int err; - - /* default to fail */ - *result = 0; - - /* init t */ - if ((err = mp_init (&t)) != MP_OKAY) { - return err; - } - - /* compute t = b^a mod a */ - if ((err = mp_exptmod (b, a, a, &t)) != MP_OKAY) { - goto __T; - } - - /* is it equal to b? */ - if (mp_cmp (&t, b) == MP_EQ) { - *result = 1; - } - - err = MP_OKAY; -__T:mp_clear (&t); - return err; -} - -/* End: bn_mp_prime_fermat.c */ - -/* Start: bn_mp_prime_is_divisible.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* determines if an integers is divisible by one of the first 256 primes or not - * - * sets result to 0 if not, 1 if yes - */ -int -mp_prime_is_divisible (mp_int * a, int *result) -{ - int err, ix; - mp_digit res; - - /* default to not */ - *result = 0; - - for (ix = 0; ix < 256; ix++) { - /* is it equal to the prime? */ - if (mp_cmp_d (a, __prime_tab[ix]) == MP_EQ) { - *result = 1; - return MP_OKAY; - } - - /* what is a mod __prime_tab[ix] */ - if ((err = mp_mod_d (a, __prime_tab[ix], &res)) != MP_OKAY) { - return err; - } - - /* is the residue zero? */ - if (res == 0) { - *result = 1; - return MP_OKAY; - } - } - - return MP_OKAY; -} - -/* End: bn_mp_prime_is_divisible.c */ - -/* Start: bn_mp_prime_is_prime.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* performs a variable number of rounds of Miller-Rabin - * - * Probability of error after t rounds is no more than - * (1/4)^t when 1 <= t <= 256 - * - * Sets result to 1 if probably prime, 0 otherwise - */ -int -mp_prime_is_prime (mp_int * a, int t, int *result) -{ - mp_int b; - int ix, err, res; - - /* default to no */ - *result = 0; - - /* valid value of t? */ - if (t < 1 || t > 256) { - return MP_VAL; - } - - /* first perform trial division */ - if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { - return err; - } - if (res == 1) { - return MP_OKAY; - } - - /* now perform the miller-rabin rounds */ - if ((err = mp_init (&b)) != MP_OKAY) { - return err; - } - - for (ix = 0; ix < t; ix++) { - /* set the prime */ - mp_set (&b, __prime_tab[ix]); - - if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { - goto __B; - } - - if (res == 0) { - goto __B; - } - } - - /* passed the test */ - *result = 1; -__B:mp_clear (&b); - return err; -} - -/* End: bn_mp_prime_is_prime.c */ - -/* Start: bn_mp_prime_miller_rabin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* Miller-Rabin test of "a" to the base of "b" as described in - * HAC pp. 139 Algorithm 4.24 - * - * Sets result to 0 if definitely composite or 1 if probably prime. - * Randomly the chance of error is no more than 1/4 and often - * very much lower. - */ -int -mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) -{ - mp_int n1, y, r; - int s, j, err; - - /* default */ - *result = 0; - - /* get n1 = a - 1 */ - if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { - return err; - } - if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { - goto __N1; - } - - /* set 2^s * r = n1 */ - if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { - goto __N1; - } - s = 0; - while (mp_iseven (&r) == 1) { - ++s; - if ((err = mp_div_2 (&r, &r)) != MP_OKAY) { - goto __R; - } - } - - /* compute y = b^r mod a */ - if ((err = mp_init (&y)) != MP_OKAY) { - goto __R; - } - if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { - goto __Y; - } - - /* if y != 1 and y != n1 do */ - if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { - j = 1; - /* while j <= s-1 and y != n1 */ - while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { - if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { - goto __Y; - } - - /* if y == 1 then composite */ - if (mp_cmp_d (&y, 1) == MP_EQ) { - goto __Y; - } - - ++j; - } - - /* if y != n1 then composite */ - if (mp_cmp (&y, &n1) != MP_EQ) { - goto __Y; - } - } - - /* probably prime now */ - *result = 1; -__Y:mp_clear (&y); -__R:mp_clear (&r); -__N1:mp_clear (&n1); - return err; -} - -/* End: bn_mp_prime_miller_rabin.c */ - -/* Start: bn_mp_prime_next_prime.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* finds the next prime after the number "a" using "t" trials - * of Miller-Rabin. - */ -int mp_prime_next_prime(mp_int *a, int t) -{ - int err, res; - - if (mp_iseven(a) == 1) { - /* force odd */ - if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { - return err; - } - } else { - /* force to next number */ - if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { - return err; - } - } - - for (;;) { - /* is this prime? */ - if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { - return err; - } - - if (res == 1) { - break; - } - - /* add two, next candidate */ - if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { - return err; - } - } - - return MP_OKAY; -} - - -/* End: bn_mp_prime_next_prime.c */ - -/* Start: bn_mp_rand.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* makes a pseudo-random int of a given size */ -int -mp_rand (mp_int * a, int digits) -{ - int res; - mp_digit d; - - mp_zero (a); - if (digits <= 0) { - return MP_OKAY; - } - - /* first place a random non-zero digit */ - do { - d = ((mp_digit) abs (rand ())); - } while (d == 0); - - if ((res = mp_add_d (a, d, a)) != MP_OKAY) { - return res; - } - - while (digits-- > 0) { - if ((res = mp_lshd (a, 1)) != MP_OKAY) { - return res; - } - - if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) { - return res; - } - } - - return MP_OKAY; -} - -/* End: bn_mp_rand.c */ - -/* Start: bn_mp_read_signed_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* read signed bin, big endian, first byte is 0==positive or 1==negative */ -int -mp_read_signed_bin (mp_int * a, unsigned char *b, int c) -{ - int res; - - if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) { - return res; - } - a->sign = ((b[0] == (unsigned char) 0) ? MP_ZPOS : MP_NEG); - return MP_OKAY; -} - -/* End: bn_mp_read_signed_bin.c */ - -/* Start: bn_mp_read_unsigned_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* reads a unsigned char array, assumes the msb is stored first [big endian] */ -int -mp_read_unsigned_bin (mp_int * a, unsigned char *b, int c) -{ - int res; - mp_zero (a); - while (c-- > 0) { - if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { - return res; - } - - if (DIGIT_BIT != 7) { - a->dp[0] |= *b++; - a->used += 1; - } else { - a->dp[0] = (*b & MP_MASK); - a->dp[1] |= ((*b++ >> 7U) & 1); - a->used += 2; - } - } - mp_clamp (a); - return MP_OKAY; -} - -/* End: bn_mp_read_unsigned_bin.c */ - -/* Start: bn_mp_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* pre-calculate the value required for Barrett reduction - * For a given modulus "b" it calulates the value required in "a" - */ -int -mp_reduce_setup (mp_int * a, mp_int * b) -{ - int res; - - - if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { - return res; - } - res = mp_div (a, b, a, NULL); - return res; -} - -/* reduces x mod m, assumes 0 < x < m^2, mu is precomputed via mp_reduce_setup - * From HAC pp.604 Algorithm 14.42 - */ -int -mp_reduce (mp_int * x, mp_int * m, mp_int * mu) -{ - mp_int q; - int res, um = m->used; - - - if ((res = mp_init_copy (&q, x)) != MP_OKAY) { - return res; - } - - mp_rshd (&q, um - 1); /* q1 = x / b^(k-1) */ - - /* according to HAC this is optimization is ok */ - if (((unsigned long) m->used) > (1UL << (unsigned long) (DIGIT_BIT - 1UL))) { - if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { - goto CLEANUP; - } - } else { - if ((res = s_mp_mul_high_digs (&q, mu, &q, um - 1)) != MP_OKAY) { - goto CLEANUP; - } - } - - mp_rshd (&q, um + 1); /* q3 = q2 / b^(k+1) */ - - /* x = x mod b^(k+1), quick (no division) */ - if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { - goto CLEANUP; - } - - /* q = q * m mod b^(k+1), quick (no division) */ - if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { - goto CLEANUP; - } - - /* x = x - q */ - if ((res = mp_sub (x, &q, x)) != MP_OKAY) - goto CLEANUP; - - /* If x < 0, add b^(k+1) to it */ - if (mp_cmp_d (x, 0) == MP_LT) { - mp_set (&q, 1); - if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) - goto CLEANUP; - if ((res = mp_add (x, &q, x)) != MP_OKAY) - goto CLEANUP; - } - - /* Back off if it's too big */ - while (mp_cmp (x, m) != MP_LT) { - if ((res = s_mp_sub (x, m, x)) != MP_OKAY) - break; - } - -CLEANUP: - mp_clear (&q); - - return res; -} - -/* End: bn_mp_reduce.c */ - -/* Start: bn_mp_rshd.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift right a certain amount of digits */ -void -mp_rshd (mp_int * a, int b) -{ - int x; - - /* if b <= 0 then ignore it */ - if (b <= 0) { - return; - } - - /* if b > used then simply zero it and return */ - if (a->used < b) { - mp_zero (a); - return; - } - - { - register mp_digit *tmpa, *tmpaa; - - /* shift the digits down */ - - /* base */ - tmpa = a->dp; - - /* offset into digits */ - tmpaa = a->dp + b; - - /* this is implemented as a sliding window where the window is b-digits long - * and digits from the top of the window are copied to the bottom - * - * e.g. - - b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> - /\ | ----> - \-------------------/ ----> - */ - for (x = 0; x < (a->used - b); x++) { - *tmpa++ = *tmpaa++; - } - - /* zero the top digits */ - for (; x < a->used; x++) { - *tmpa++ = 0; - } - } - mp_clamp (a); -} - -/* End: bn_mp_rshd.c */ - -/* Start: bn_mp_set.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* set to a digit */ -void -mp_set (mp_int * a, mp_digit b) -{ - mp_zero (a); - a->dp[0] = b & MP_MASK; - a->used = (a->dp[0] != 0) ? 1 : 0; -} - -/* End: bn_mp_set.c */ - -/* Start: bn_mp_set_int.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* set a 32-bit const */ -int -mp_set_int (mp_int * a, unsigned long b) -{ - int x, res; - - mp_zero (a); - - /* set four bits at a time, simplest solution to the what if DIGIT_BIT==7 case */ - for (x = 0; x < 8; x++) { - - /* shift the number up four bits */ - if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { - return res; - } - - /* OR in the top four bits of the source */ - a->dp[0] |= (b >> 28) & 15; - - /* shift the source up to the next four bits */ - b <<= 4; - - /* ensure that digits are not clamped off */ - a->used += 32 / DIGIT_BIT + 1; - } - - mp_clamp (a); - return MP_OKAY; -} - -/* End: bn_mp_set_int.c */ - -/* Start: bn_mp_shrink.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shrink a bignum */ -int -mp_shrink (mp_int * a) -{ - if (a->alloc != a->used) { - if ((a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * a->used)) == NULL) { - return MP_MEM; - } - a->alloc = a->used; - } - return MP_OKAY; -} - -/* End: bn_mp_shrink.c */ - -/* Start: bn_mp_signed_bin_size.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* get the size for an signed equivalent */ -int -mp_signed_bin_size (mp_int * a) -{ - return 1 + mp_unsigned_bin_size (a); -} - -/* End: bn_mp_signed_bin_size.c */ - -/* Start: bn_mp_sqr.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes b = a*a */ -int -mp_sqr (mp_int * a, mp_int * b) -{ - int res; - if (a->used > KARATSUBA_SQR_CUTOFF) { - res = mp_karatsuba_sqr (a, b); - } else { - - /* can we use the fast multiplier? */ - if (((a->used * 2 + 1) < 512) - && a->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT) - 1))) { - res = fast_s_mp_sqr (a, b); - } else { - res = s_mp_sqr (a, b); - } - } - b->sign = MP_ZPOS; - return res; -} - -/* End: bn_mp_sqr.c */ - -/* Start: bn_mp_sqrmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* c = a * a (mod b) */ -int -mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_sqr (a, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, b, c); - mp_clear (&t); - return res; -} - -/* End: bn_mp_sqrmod.c */ - -/* Start: bn_mp_sub.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* high level subtraction (handles signs) */ -int -mp_sub (mp_int * a, mp_int * b, mp_int * c) -{ - int sa, sb, res; - - - sa = a->sign; - sb = b->sign; - - /* handle four cases */ - if (sa == MP_ZPOS && sb == MP_ZPOS) { - /* both positive, a - b, but if b>a then we do -(b - a) */ - if (mp_cmp_mag (a, b) == MP_LT) { - /* b>a */ - res = s_mp_sub (b, a, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (a, b, c); - c->sign = MP_ZPOS; - } - } else if (sa == MP_ZPOS && sb == MP_NEG) { - /* a - -b == a + b */ - res = s_mp_add (a, b, c); - c->sign = MP_ZPOS; - } else if (sa == MP_NEG && sb == MP_ZPOS) { - /* -a - b == -(a + b) */ - res = s_mp_add (a, b, c); - c->sign = MP_NEG; - } else { - /* -a - -b == b - a, but if a>b == -(a - b) */ - if (mp_cmp_mag (a, b) == MP_GT) { - res = s_mp_sub (a, b, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (b, a, c); - c->sign = MP_ZPOS; - } - } - - return res; -} - -/* End: bn_mp_sub.c */ - -/* Start: bn_mp_submod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* d = a - b (mod c) */ -int -mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_sub (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); - return res; -} - -/* End: bn_mp_submod.c */ - -/* Start: bn_mp_sub_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* single digit subtraction */ -int -mp_sub_d (mp_int * a, mp_digit b, mp_int * c) -{ - mp_int t; - int res; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - mp_set (&t, b); - res = mp_sub (a, &t, c); - - mp_clear (&t); - return res; -} - -/* End: bn_mp_sub_d.c */ - -/* Start: bn_mp_to_signed_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* store in signed [big endian] format */ -int -mp_to_signed_bin (mp_int * a, unsigned char *b) -{ - int res; - - if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) { - return res; - } - b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1); - return MP_OKAY; -} - -/* End: bn_mp_to_signed_bin.c */ - -/* Start: bn_mp_to_unsigned_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* store in unsigned [big endian] format */ -int -mp_to_unsigned_bin (mp_int * a, unsigned char *b) -{ - int x, res; - mp_int t; - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - - x = 0; - while (mp_iszero (&t) == 0) { - if (DIGIT_BIT != 7) { - b[x++] = (unsigned char) (t.dp[0] & 255); - } else { - b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); - } - if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { - mp_clear (&t); - return res; - } - } - bn_reverse (b, x); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_to_unsigned_bin.c */ - -/* Start: bn_mp_unsigned_bin_size.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* get the size for an unsigned equivalent */ -int -mp_unsigned_bin_size (mp_int * a) -{ - int size = mp_count_bits (a); - return (size / 8 + ((size & 7) != 0 ? 1 : 0)); -} - -/* End: bn_mp_unsigned_bin_size.c */ - -/* Start: bn_mp_xor.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* XOR two ints together */ -int -mp_xor (mp_int * a, mp_int * b, mp_int * c) -{ - int res, ix, px; - mp_int t, *x; - - if (a->used > b->used) { - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - px = b->used; - x = b; - } else { - if ((res = mp_init_copy (&t, b)) != MP_OKAY) { - return res; - } - px = a->used; - x = a; - } - - for (ix = 0; ix < px; ix++) { - t.dp[ix] ^= x->dp[ix]; - } - mp_clamp (&t); - mp_exch (c, &t); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_xor.c */ - -/* Start: bn_mp_zero.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* set to zero */ -void -mp_zero (mp_int * a) -{ - a->sign = MP_ZPOS; - a->used = 0; - memset (a->dp, 0, sizeof (mp_digit) * a->alloc); -} - -/* End: bn_mp_zero.c */ - -/* Start: bn_prime_tab.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include -const mp_digit __prime_tab[] = { - 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, - 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, - 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, - 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, - 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, - 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, - 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, - 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, - - 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, - 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, - 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, - 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, - 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, - 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, - 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, - 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, - - 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, - 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, - 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, - 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, - 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, - 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, - 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, - 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, - - 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, - 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, - 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, - 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, - 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, - 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, - 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, - 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 -}; - -/* End: bn_prime_tab.c */ - -/* Start: bn_radix.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* chars used in radix conversions */ -static const char *s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; - -/* read a string [ASCII] in a given radix */ -int -mp_read_radix (mp_int * a, char *str, int radix) -{ - int y, res, neg; - char ch; - - if (radix < 2 || radix > 64) { - return MP_VAL; - } - - if (*str == '-') { - ++str; - neg = MP_NEG; - } else { - neg = MP_ZPOS; - } - - mp_zero (a); - while (*str) { - ch = (char) ((radix < 36) ? toupper (*str) : *str); - for (y = 0; y < 64; y++) { - if (ch == s_rmap[y]) { - break; - } - } - - if (y < radix) { - if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { - return res; - } - if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { - return res; - } - } else { - break; - } - ++str; - } - a->sign = neg; - return MP_OKAY; -} - -/* stores a bignum as a ASCII string in a given radix (2..64) */ -int -mp_toradix (mp_int * a, char *str, int radix) -{ - int res, digs; - mp_int t; - mp_digit d; - char *_s = str; - - if (radix < 2 || radix > 64) { - return MP_VAL; - } - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - - if (t.sign == MP_NEG) { - ++_s; - *str++ = '-'; - t.sign = MP_ZPOS; - } - - digs = 0; - while (mp_iszero (&t) == 0) { - if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { - mp_clear (&t); - return res; - } - *str++ = s_rmap[d]; - ++digs; - } - bn_reverse ((unsigned char *)_s, digs); - *str++ = '\0'; - mp_clear (&t); - return MP_OKAY; -} - -/* returns size of ASCII reprensentation */ -int -mp_radix_size (mp_int * a, int radix) -{ - int res, digs; - mp_int t; - mp_digit d; - - /* special case for binary */ - if (radix == 2) { - return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; - } - - if (radix < 2 || radix > 64) { - return 0; - } - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return 0; - } - - digs = 0; - if (t.sign == MP_NEG) { - ++digs; - t.sign = MP_ZPOS; - } - - while (mp_iszero (&t) == 0) { - if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { - mp_clear (&t); - return 0; - } - ++digs; - } - mp_clear (&t); - return digs + 1; -} - -/* End: bn_radix.c */ - -/* Start: bn_reverse.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* reverse an array, used for radix code */ -void -bn_reverse (unsigned char *s, int len) -{ - int ix, iy; - unsigned char t; - - ix = 0; - iy = len - 1; - while (ix < iy) { - t = s[ix]; - s[ix] = s[iy]; - s[iy] = t; - ++ix; - --iy; - } -} - -/* End: bn_reverse.c */ - -/* Start: bn_s_mp_add.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* low level addition, based on HAC pp.594, Algorithm 14.7 */ -int -s_mp_add (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int *x; - int olduse, res, min, max; - - /* find sizes, we let |a| <= |b| which means we have to sort - * them. "x" will point to the input with the most digits - */ - if (a->used > b->used) { - min = b->used; - max = a->used; - x = a; - } else if (a->used < b->used) { - min = a->used; - max = b->used; - x = b; - } else { - min = max = a->used; - x = NULL; - } - - /* init result */ - if (c->alloc < max + 1) { - if ((res = mp_grow (c, max + 1)) != MP_OKAY) { - return res; - } - } - - olduse = c->used; - c->used = max + 1; - - /* add digits from lower part */ - - /* set the carry to zero */ - { - register mp_digit u, *tmpa, *tmpb, *tmpc; - register int i; - - /* alias for digit pointers */ - - /* first input */ - tmpa = a->dp; - - /* second input */ - tmpb = b->dp; - - /* destination */ - tmpc = c->dp; - - u = 0; - for (i = 0; i < min; i++) { - /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ - *tmpc = *tmpa++ + *tmpb++ + u; - - /* U = carry bit of T[i] */ - u = *tmpc >> DIGIT_BIT; - - /* take away carry bit from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* now copy higher words if any, that is in A+B if A or B has more digits add those in */ - if (min != max) { - for (; i < max; i++) { - /* T[i] = X[i] + U */ - *tmpc = x->dp[i] + u; - - /* U = carry bit of T[i] */ - u = *tmpc >> DIGIT_BIT; - - /* take away carry bit from T[i] */ - *tmpc++ &= MP_MASK; - } - } - - /* add carry */ - *tmpc++ = u; - - /* clear digits above used (since we may not have grown result above) */ - for (i = c->used; i < olduse; i++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_s_mp_add.c */ - -/* Start: bn_s_mp_mul_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* multiplies |a| * |b| and only computes upto digs digits of result - * HAC pp. 595, Algorithm 14.12 Modified so you can control how many digits of - * output are created. - */ -int -s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - mp_int t; - int res, pa, pb, ix, iy; - mp_digit u; - mp_word r; - mp_digit tmpx, *tmpt, *tmpy; - - if ((res = mp_init_size (&t, digs)) != MP_OKAY) { - return res; - } - t.used = digs; - - /* compute the digits of the product directly */ - pa = a->used; - for (ix = 0; ix < pa; ix++) { - /* set the carry to zero */ - u = 0; - - /* limit ourselves to making digs digits of output */ - pb = MIN (b->used, digs - ix); - - /* setup some aliases */ - tmpx = a->dp[ix]; - tmpt = &(t.dp[ix]); - tmpy = b->dp; - - /* compute the columns of the output and propagate the carry */ - for (iy = 0; iy < pb; iy++) { - /* compute the column as a mp_word */ - r = ((mp_word) * tmpt) + ((mp_word) tmpx) * ((mp_word) * tmpy++) + ((mp_word) u); - - /* the new column is the lower part of the result */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get the carry word from the result */ - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - if (ix + iy < digs) - *tmpt = u; - } - - mp_clamp (&t); - mp_exch (&t, c); - - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_s_mp_mul_digs.c */ - -/* Start: bn_s_mp_mul_high_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* multiplies |a| * |b| and does not compute the lower digs digits - * [meant to get the higher part of the product] - */ -int -s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - mp_int t; - int res, pa, pb, ix, iy; - mp_digit u; - mp_word r; - mp_digit tmpx, *tmpt, *tmpy; - - - /* can we use the fast multiplier? */ - if (((a->used + b->used + 1) < 512) - && MAX (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - return fast_s_mp_mul_high_digs (a, b, c, digs); - } - - if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { - return res; - } - t.used = a->used + b->used + 1; - - pa = a->used; - pb = b->used; - for (ix = 0; ix < pa; ix++) { - /* clear the carry */ - u = 0; - - /* left hand side of A[ix] * B[iy] */ - tmpx = a->dp[ix]; - - /* alias to the address of where the digits will be stored */ - tmpt = &(t.dp[digs]); - - /* alias for where to read the right hand side from */ - tmpy = b->dp + (digs - ix); - - for (iy = digs - ix; iy < pb; iy++) { - /* calculate the double precision result */ - r = ((mp_word) * tmpt) + ((mp_word) tmpx) * ((mp_word) * tmpy++) + ((mp_word) u); - - /* get the lower part */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* carry the carry */ - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - *tmpt = u; - } - mp_clamp (&t); - mp_exch (&t, c); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_s_mp_mul_high_digs.c */ - -/* Start: bn_s_mp_sqr.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ -int -s_mp_sqr (mp_int * a, mp_int * b) -{ - mp_int t; - int res, ix, iy, pa; - mp_word r, u; - mp_digit tmpx, *tmpt; - - pa = a->used; - if ((res = mp_init_size (&t, pa + pa + 1)) != MP_OKAY) { - return res; - } - t.used = pa + pa + 1; - - for (ix = 0; ix < pa; ix++) { - /* first calculate the digit at 2*ix */ - /* calculate double precision result */ - r = ((mp_word) t.dp[ix + ix]) + ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); - - /* store lower part in result */ - t.dp[ix + ix] = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get the carry */ - u = (r >> ((mp_word) DIGIT_BIT)); - - /* left hand side of A[ix] * A[iy] */ - tmpx = a->dp[ix]; - - /* alias for where to store the results */ - tmpt = &(t.dp[ix + ix + 1]); - for (iy = ix + 1; iy < pa; iy++) { - /* first calculate the product */ - r = ((mp_word) tmpx) * ((mp_word) a->dp[iy]); - - /* now calculate the double precision result, note we use - * addition instead of *2 since its easier to optimize - */ - r = ((mp_word) * tmpt) + r + r + ((mp_word) u); - - /* store lower part */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get carry */ - u = (r >> ((mp_word) DIGIT_BIT)); - } - r = ((mp_word) * tmpt) + u; - *tmpt = (mp_digit) (r & ((mp_word) MP_MASK)); - u = (r >> ((mp_word) DIGIT_BIT)); - /* propagate upwards */ - ++tmpt; - while (u != ((mp_word) 0)) { - r = ((mp_word) * tmpt) + ((mp_word) 1); - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - u = (r >> ((mp_word) DIGIT_BIT)); - } - } - - mp_clamp (&t); - mp_exch (&t, b); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_s_mp_sqr.c */ - -/* Start: bn_s_mp_sub.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* low level subtraction (assumes a > b), HAC pp.595 Algorithm 14.9 */ -int -s_mp_sub (mp_int * a, mp_int * b, mp_int * c) -{ - int olduse, res, min, max; - - /* find sizes */ - min = b->used; - max = a->used; - - /* init result */ - if (c->alloc < max) { - if ((res = mp_grow (c, max)) != MP_OKAY) { - return res; - } - } - olduse = c->used; - c->used = max; - - /* sub digits from lower part */ - - { - register mp_digit u, *tmpa, *tmpb, *tmpc; - register int i; - - /* alias for digit pointers */ - tmpa = a->dp; - tmpb = b->dp; - tmpc = c->dp; - - /* set carry to zero */ - u = 0; - for (i = 0; i < min; i++) { - /* T[i] = A[i] - B[i] - U */ - *tmpc = *tmpa++ - *tmpb++ - u; - - /* U = carry bit of T[i] - * Note this saves performing an AND operation since - * if a carry does occur it will propagate all the way to the - * MSB. As a result a single shift is required to get the carry - */ - u = *tmpc >> (CHAR_BIT * sizeof (mp_digit) - 1); - - /* Clear carry from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* now copy higher words if any, e.g. if A has more digits than B */ - for (; i < max; i++) { - /* T[i] = A[i] - U */ - *tmpc = *tmpa++ - u; - - /* U = carry bit of T[i] */ - u = *tmpc >> (CHAR_BIT * sizeof (mp_digit) - 1); - - /* Clear carry from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* clear digits above used (since we may not have grown result above) */ - for (i = c->used; i < olduse; i++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_s_mp_sub.c */ - - -/* EOF */ +/* Start: bn_fast_mp_invmod.c */ +#line 0 "bn_fast_mp_invmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on mp_invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +int +fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto __ERR; + } + + /* we need y = |a| */ + if ((res = mp_abs (a, &y)) != MP_OKAY) { + goto __ERR; + } + + /* 2. [modified] if x,y are both even then return an error! + * + * That is if gcd(x,y) = 2 * k then obviously there is no inverse. + */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_iseven (&B) == 0) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if C,D are even then */ + if (mp_iseven (&D) == 0) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* D = D/2 */ + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto __ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +__ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); + return res; +} + +/* End: bn_fast_mp_invmod.c */ + +/* Start: bn_fast_mp_montgomery_reduce.c */ +#line 0 "bn_fast_mp_montgomery_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes xR^-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of mp_montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int +fast_mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = a->used; + + /* grow a as required */ + if (a->alloc < m->used + 1) { + if ((res = mp_grow (a, m->used + 1)) != MP_OKAY) { + return res; + } + } + + { + register mp_word *_W; + register mp_digit *tmpa; + + _W = W; + tmpa = a->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < a->used; ix++) { + *_W++ = *tmpa++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < m->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + for (ix = 0; ix < m->used; ix++) { + /* ui = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires that W[ix-1] have + * the carry cleared (see after the inner loop) + */ + register mp_digit ui; + ui = (((mp_digit) (W[ix] & MP_MASK)) * mp) & MP_MASK; + + /* a = a + ui * m * b^i + * + * This is computed in place and on the fly. The multiplication + * by b^i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the inner loop + * In this case we fix the carry from the previous column since the Montgomery + * reduction requires digits of the result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The carry fixups are done + * in order so after these loops the first m->used words of W[] have the carries + * fixed + */ + { + register int iy; + register mp_digit *tmpx; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpx = m->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < m->used; iy++) { + *_W++ += ((mp_word) ui) * ((mp_word) * tmpx++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + + { + register mp_digit *tmpa; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + _W1 = W + ix; + _W = W + ++ix; + + for (; ix <= m->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b^n + * + * The result is A/b^n but instead of converting from an array of mp_word + * to mp_digit than calling mp_rshd we just copy them in the right + * order + */ + tmpa = a->dp; + _W = W + m->used; + + for (ix = 0; ix < m->used + 1; ix++) { + *tmpa++ = *_W++ & ((mp_word) MP_MASK); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits */ + for (; ix < olduse; ix++) { + *tmpa++ = 0; + } + } + + /* set the max used and clamp */ + a->used = m->used + 1; + mp_clamp (a); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (a, m) != MP_LT) { + return s_mp_sub (a, m, a); + } + return MP_OKAY; +} + +/* End: bn_fast_mp_montgomery_reduce.c */ + +/* Start: bn_fast_s_mp_mul_digs.c */ +#line 0 "bn_fast_s_mp_mul_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +int +fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix; + mp_word W[MP_WARRAY]; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* clear temp buf (the columns) */ + memset (W, 0, sizeof (mp_word) * digs); + + /* calculate the columns */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* this multiplier has been modified to allow you to + * control how many digits of output are produced. + * So at most we want to make upto "digs" digits of output. + * + * this adds products to distinct columns (at ix+iy) of W + * note that each step through the loop is not dependent on + * the previous which means the compiler can easily unroll + * the loop without scheduling problems + */ + { + register mp_digit tmpx, *tmpy; + register mp_word *_W; + register int iy, pb; + + /* alias for the the word on the left e.g. A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for the right side */ + tmpy = b->dp; + + /* alias for the columns, each step through the loop adds a new + term to each column + */ + _W = W + ix; + + /* the number of digits is limited by their placement. E.g. + we avoid multiplying digits that will end up above the # of + digits of precision requested + */ + pb = MIN (b->used, digs - ix); + + for (iy = 0; iy < pb; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } + + } + + /* setup dest */ + olduse = c->used; + c->used = digs; + + { + register mp_digit *tmpc; + + /* At this point W[] contains the sums of each column. To get the + * correct result we must take the extra bits from each column and + * carry them down + * + * Note that while this adds extra code to the multiplier it + * saves time since the carry propagation is removed from the + * above nested loop.This has the effect of reducing the work + * from N*(N+N*c)==N**2 + c*N**2 to N**2 + N*c where c is the + * cost of the shifting. On very small numbers this is slower + * but on most cryptographic size numbers it is faster. + */ + tmpc = c->dp; + for (ix = 1; ix < digs; ix++) { + W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + *tmpc++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + *tmpc++ = (mp_digit) (W[digs - 1] & ((mp_word) MP_MASK)); + + /* clear unused */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_mul_digs.c */ + +/* Start: bn_fast_s_mp_mul_high_digs.c */ +#line 0 "bn_fast_s_mp_mul_high_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* this is a modified version of fast_s_mp_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mp_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +int +fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int oldused, newused, res, pa, pb, ix; + mp_word W[MP_WARRAY]; + + /* calculate size of product and allocate more space if required */ + newused = a->used + b->used + 1; + if (c->alloc < newused) { + if ((res = mp_grow (c, newused)) != MP_OKAY) { + return res; + } + } + + /* like the other comba method we compute the columns first */ + pa = a->used; + pb = b->used; + memset (W + digs, 0, (pa + pb + 1 - digs) * sizeof (mp_word)); + for (ix = 0; ix < pa; ix++) { + { + register mp_digit tmpx, *tmpy; + register int iy; + register mp_word *_W; + + /* work todo, that is we only calculate digits that are at "digs" or above */ + iy = digs - ix; + + /* copy of word on the left of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias for right side */ + tmpy = b->dp + iy; + + /* alias for the columns of output. Offset to be equal to or above the + * smallest digit place requested + */ + _W = W + digs; + + /* skip cases below zero where ix > digs */ + if (iy < 0) { + iy = abs(iy); + tmpy += iy; + _W += iy; + iy = 0; + } + + /* compute column products for digits above the minimum */ + for (; iy < pb; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } + } + + /* setup dest */ + oldused = c->used; + c->used = newused; + + /* now convert the array W downto what we need */ + for (ix = digs + 1; ix < newused; ix++) { + W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + c->dp[ix - 1] = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + c->dp[(pa + pb + 1) - 1] = (mp_digit) (W[(pa + pb + 1) - 1] & ((mp_word) MP_MASK)); + + for (; ix < oldused; ix++) { + c->dp[ix] = 0; + } + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_mul_high_digs.c */ + +/* Start: bn_fast_s_mp_sqr.c */ +#line 0 "bn_fast_s_mp_sqr.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* fast squaring + * + * This is the comba method where the columns of the product are computed first + * then the carries are computed. This has the effect of making a very simple + * inner loop that is executed the most + * + * W2 represents the outer products and W the inner. + * + * A further optimizations is made because the inner products are of the form + * "A * B * 2". The *2 part does not need to be computed until the end which is + * good because 64-bit shifts are slow! + * + * Based on Algorithm 14.16 on pp.597 of HAC. + * + */ +int +fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, newused, res, ix, pa; + mp_word W2[MP_WARRAY], W[MP_WARRAY]; + + /* calculate size of product and allocate as required */ + pa = a->used; + newused = pa + pa + 1; + if (b->alloc < newused) { + if ((res = mp_grow (b, newused)) != MP_OKAY) { + return res; + } + } + + /* zero temp buffer (columns) + * Note that there are two buffers. Since squaring requires + * a outter and inner product and the inner product requires + * computing a product and doubling it (a relatively expensive + * op to perform n^2 times if you don't have to) the inner and + * outer products are computed in different buffers. This way + * the inner product can be doubled using n doublings instead of + * n^2 + */ + memset (W, 0, newused * sizeof (mp_word)); + memset (W2, 0, newused * sizeof (mp_word)); + +/* note optimization + * values in W2 are only written in even locations which means + * we can collapse the array to 256 words [and fixup the memset above] + * provided we also fix up the summations below. Ideally + * the fixup loop should be unrolled twice to handle the even/odd + * cases, and then a final step to handle odd cases [e.g. newused == odd] + * + * This will not only save ~8*256 = 2KB of stack but lower the number of + * operations required to finally fix up the columns + */ + + /* This computes the inner product. To simplify the inner N^2 loop + * the multiplication by two is done afterwards in the N loop. + */ + for (ix = 0; ix < pa; ix++) { + /* compute the outer product + * + * Note that every outer product is computed + * for a particular column only once which means that + * there is no need todo a double precision addition + */ + W2[ix + ix] = ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); + + { + register mp_digit tmpx, *tmpy; + register mp_word *_W; + register int iy; + + /* copy of left side */ + tmpx = a->dp[ix]; + + /* alias for right side */ + tmpy = a->dp + (ix + 1); + + /* the column to store the result in */ + _W = W + (ix + ix + 1); + + /* inner products */ + for (iy = ix + 1; iy < pa; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } + } + + /* setup dest */ + olduse = b->used; + b->used = newused; + + /* double first value, since the inner products are half of what they should be */ + W[0] += W[0] + W2[0]; + + /* now compute digits */ + { + register mp_digit *tmpb; + + tmpb = b->dp; + + for (ix = 1; ix < newused; ix++) { + /* double/add next digit */ + W[ix] += W[ix] + W2[ix]; + + W[ix] = W[ix] + (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + *tmpb++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + *tmpb++ = (mp_digit) (W[(newused) - 1] & ((mp_word) MP_MASK)); + + /* clear high */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + + mp_clamp (b); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_sqr.c */ + +/* Start: bn_mp_2expt.c */ +#line 0 "bn_mp_2expt.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes a = 2^b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +int +mp_2expt (mp_int * a, int b) +{ + int res; + + mp_zero (a); + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + a->used = b / DIGIT_BIT + 1; + a->dp[b / DIGIT_BIT] = 1 << (b % DIGIT_BIT); + + return MP_OKAY; +} + +/* End: bn_mp_2expt.c */ + +/* Start: bn_mp_abs.c */ +#line 0 "bn_mp_abs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + b->sign = MP_ZPOS; + return MP_OKAY; +} + +/* End: bn_mp_abs.c */ + +/* Start: bn_mp_add.c */ +#line 0 "bn_mp_add.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level addition (handles signs) */ +int +mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* End: bn_mp_add.c */ + +/* Start: bn_mp_add_d.c */ +#line 0 "bn_mp_add_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit addition */ +int +mp_add_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init_size(&t, 1)) != MP_OKAY) { + return res; + } + mp_set (&t, b); + res = mp_add (a, &t, c); + + mp_clear (&t); + return res; +} + +/* End: bn_mp_add_d.c */ + +/* Start: bn_mp_addmod.c */ +#line 0 "bn_mp_addmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a + b (mod c) */ +int +mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_add (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_addmod.c */ + +/* Start: bn_mp_and.c */ +#line 0 "bn_mp_and.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* AND two ints together */ +int +mp_and (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] &= x->dp[ix]; + } + + /* zero digits above the last from the smallest mp_int */ + for (; ix < t.used; ix++) { + t.dp[ix] = 0; + } + + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_and.c */ + +/* Start: bn_mp_clamp.c */ +#line 0 "bn_mp_clamp.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +void +mp_clamp (mp_int * a) +{ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + +/* End: bn_mp_clamp.c */ + +/* Start: bn_mp_clear.c */ +#line 0 "bn_mp_clear.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* clear one (frees) */ +void +mp_clear (mp_int * a) +{ + if (a->dp != NULL) { + + /* first zero the digits */ + memset (a->dp, 0, sizeof (mp_digit) * a->used); + + /* free ram */ + free (a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + } +} + +/* End: bn_mp_clear.c */ + +/* Start: bn_mp_cmp.c */ +#line 0 "bn_mp_cmp.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare two ints (signed)*/ +int +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG && b->sign == MP_ZPOS) { + return MP_LT; + } + + if (a->sign == MP_ZPOS && b->sign == MP_NEG) { + return MP_GT; + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + +/* End: bn_mp_cmp.c */ + +/* Start: bn_mp_cmp_d.c */ +#line 0 "bn_mp_cmp_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare a digit */ +int +mp_cmp_d (mp_int * a, mp_digit b) +{ + + if (a->sign == MP_NEG) { + return MP_LT; + } + + if (a->used > 1) { + return MP_GT; + } + + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + +/* End: bn_mp_cmp_d.c */ + +/* Start: bn_mp_cmp_mag.c */ +#line 0 "bn_mp_cmp_mag.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare maginitude of two ints (unsigned) */ +int +mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* compare based on digits */ + for (n = a->used - 1; n >= 0; n--) { + if (a->dp[n] > b->dp[n]) { + return MP_GT; + } + + if (a->dp[n] < b->dp[n]) { + return MP_LT; + } + } + return MP_EQ; +} + +/* End: bn_mp_cmp_mag.c */ + +/* Start: bn_mp_copy.c */ +#line 0 "bn_mp_copy.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* copy, b = a */ +int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b || a->dp == b->dp) { + return MP_OKAY; + } + + /* grow dest */ + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + tmpa = a->dp; + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + +/* End: bn_mp_copy.c */ + +/* Start: bn_mp_count_bits.c */ +#line 0 "bn_mp_count_bits.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* returns the number of bits in an int */ +int +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + if (a->used == 0) { + return 0; + } + + r = (a->used - 1) * DIGIT_BIT; + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + +/* End: bn_mp_count_bits.c */ + +/* Start: bn_mp_div.c */ +#line 0 "bn_mp_div.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* integer signed division. c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly incomplete. For example, + * it doesn't consider the case where digits are removed from 'x' in the inner + * loop. It also doesn't consider the case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as 14.20 from HAC but fixed to treat these cases. +*/ +int +mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto __Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto __T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto __X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2^DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto __Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* step 2. while (x >= y*b^n-t) do { q[n-t] += 1; x -= y*b^{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b^{n-t} */ + goto __Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto __Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) + continue; + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* step 3.2 while (q{i-t-1} * (yt * b + y{t-1})) > xi * b^2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b^{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + /* step 3.4 if x < 0 then { x = x + y*b^{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder [which we have to normalize] */ + /* get sign before writing to c */ + x.sign = a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +__Y:mp_clear (&y); +__X:mp_clear (&x); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); +__Q:mp_clear (&q); + return res; +} + +/* End: bn_mp_div.c */ + +/* Start: bn_mp_div_2.c */ +#line 0 "bn_mp_div_2.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = a/2 */ +int +mp_div_2 (mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} + +/* End: bn_mp_div_2.c */ + +/* Start: bn_mp_div_2d.c */ +#line 0 "bn_mp_div_2d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift right by a certain bit count (store quotient in c, remainder in d) */ +int +mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << (DIGIT_BIT - D)); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + res = MP_OKAY; + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_div_2d.c */ + +/* Start: bn_mp_div_d.c */ +#line 0 "bn_mp_div_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit division */ +int +mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) +{ + mp_int t, t2; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + mp_set (&t, b); + res = mp_div (a, &t, c, &t2); + + /* set remainder if not null */ + if (d != NULL) { + *d = t2.dp[0]; + } + + mp_clear (&t); + mp_clear (&t2); + return res; +} + +/* End: bn_mp_div_d.c */ + +/* Start: bn_mp_dr_is_modulus.c */ +#line 0 "bn_mp_dr_is_modulus.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return 0; + } + } + return 1; +} + + +/* End: bn_mp_dr_is_modulus.c */ + +/* Start: bn_mp_dr_reduce.c */ +#line 0 "bn_mp_dr_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduce "a" in place modulo "b" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Loong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + */ +int +mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) +{ + int err, i, j, k; + mp_word r; + mp_digit mu, *tmpj, *tmpi; + + /* k = digits in modulus */ + k = b->used; + + /* ensure that "a" has at least 2k digits */ + if (a->alloc < k + k) { + if ((err = mp_grow (a, k + k)) != MP_OKAY) { + return err; + } + } + + /* alias for a->dp[i] */ + tmpi = a->dp + k + k - 1; + + /* for (i = 2k - 1; i >= k; i = i - 1) + * + * This is the main loop of the reduction. Note that at the end + * the words above position k are not zeroed as expected. The end + * result is that the digits from 0 to k-1 are the residue. So + * we have to clear those afterwards. + */ + for (i = k + k - 1; i >= k; i = i - 1) { + /* x[i - 1 : i - k] += x[i]*mp */ + + /* x[i] * mp */ + r = ((mp_word) *tmpi--) * ((mp_word) mp); + + /* now add r to x[i-1:i-k] + * + * First add it to the first digit x[i-k] then form the carry + * then enter the main loop + */ + j = i - k; + + /* alias for a->dp[j] */ + tmpj = a->dp + j; + + /* add digit */ + *tmpj += (mp_digit)(r & MP_MASK); + + /* this is the carry */ + mu = (r >> ((mp_word) DIGIT_BIT)) + (*tmpj >> DIGIT_BIT); + + /* clear carry from a->dp[j] */ + *tmpj++ &= MP_MASK; + + /* now add rest of the digits + * + * Note this is basically a simple single digit addition to + * a larger multiple digit number. This is optimized somewhat + * because the propagation of carries is not likely to move + * more than a few digits. + * + */ + for (++j; mu != 0 && j <= (i - 1); ++j) { + *tmpj += mu; + mu = *tmpj >> DIGIT_BIT; + *tmpj++ &= MP_MASK; + } + + /* if final carry */ + if (mu != 0) { + /* add mp to this to correct */ + j = i - k; + tmpj = a->dp + j; + + *tmpj += mp; + mu = *tmpj >> DIGIT_BIT; + *tmpj++ &= MP_MASK; + + /* now handle carries */ + for (++j; mu != 0 && j <= (i - 1); j++) { + *tmpj += mu; + mu = *tmpj >> DIGIT_BIT; + *tmpj++ &= MP_MASK; + } + } + } + + /* zero words above k */ + tmpi = a->dp + k; + for (i = k; i < a->used; i++) { + *tmpi++ = 0; + } + + /* clamp, sub and return */ + mp_clamp (a); + + /* if a >= b [b == modulus] then subtract the modulus to fix up */ + if (mp_cmp_mag (a, b) != MP_LT) { + return s_mp_sub (a, b, a); + } + return MP_OKAY; +} + + + + +/* End: bn_mp_dr_reduce.c */ + +/* Start: bn_mp_dr_setup.c */ +#line 0 "bn_mp_dr_setup.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - ((mp_word)a->dp[0])); +} + + +/* End: bn_mp_dr_setup.c */ + +/* Start: bn_mp_exch.c */ +#line 0 "bn_mp_exch.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +void +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + +/* End: bn_mp_exch.c */ + +/* Start: bn_mp_expt_d.c */ +#line 0 "bn_mp_expt_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calculate c = a^b using a square-multiply algorithm */ +int +mp_expt_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, x; + mp_int g; + + if ((res = mp_init_copy (&g, a)) != MP_OKAY) { + return res; + } + + /* set initial result */ + mp_set (c, 1); + + for (x = 0; x < (int) DIGIT_BIT; x++) { + /* square */ + if ((res = mp_sqr (c, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + + /* if the bit is set multiply */ + if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) { + if ((res = mp_mul (c, &g, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + } + + /* shift to next bit */ + b <<= 1; + } + + mp_clear (&g); + return MP_OKAY; +} + +/* End: bn_mp_expt_d.c */ + +/* Start: bn_mp_exptmod.c */ +#line 0 "bn_mp_exptmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +static int f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +int +mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)^|X| instead of G^X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + + dr = mp_dr_is_modulus(P); + /* if the modulus is odd use the fast method */ + if ((mp_isodd (P) == 1 || dr == 1) && P->used > 4) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { + return f_mp_exptmod (G, X, P, Y); + } +} + +static int +f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + mp_int M[256], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init G array */ + for (x = 0; x < (1 << winsize); x++) { + if ((err = mp_init_size (&M[x], 1)) != MP_OKAY) { + for (y = 0; y < x; y++) { + mp_clear (&M[y]); + } + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto __M; + } + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto __MU; + } + + /* create M table + * + * The M table contains powers of the input base, e.g. M[x] = G^x mod P + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto __MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) + continue; + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __MU; + } + + /* empty window and reset */ + bitcpy = bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__MU:mp_clear (&mu); +__M: + for (x = 0; x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* End: bn_mp_exptmod.c */ + +/* Start: bn_mp_exptmod_fast.c */ +#line 0 "bn_mp_exptmod_fast.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes Y == G^X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ +int +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[256], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + + /* init G array */ + for (x = 0; x < (1 << winsize); x++) { + if ((err = mp_init (&M[x])) != MP_OKAY) { + for (y = 0; y < x; y++) { + mp_clear (&M[y]); + } + return err; + } + } + + if (redmode == 0) { + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto __M; + } + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if ( ((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else { + /* use slower baselien method */ + redux = mp_montgomery_reduce; + } + } else { + /* setup DR reduction */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __RES; + } + + /* create M table + * + * The M table contains powers of the input base, e.g. M[x] = G^x mod P + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto __RES; + } + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + /* empty window and reset */ + bitcpy = bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result */ + if ((err = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__M: + for (x = 0; x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* End: bn_mp_exptmod_fast.c */ + +/* Start: bn_mp_gcd.c */ +#line 0 "bn_mp_gcd.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Greatest Common Divisor using the binary method [Algorithm B, page 338, vol2 of TAOCP] + */ +int +mp_gcd (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int u, v, t; + int k, res, neg; + + /* either zero than gcd is the largest */ + if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { + return mp_copy (b, c); + } + if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { + return mp_copy (a, c); + } + if (mp_iszero (a) == 1 && mp_iszero (b) == 1) { + mp_set (c, 1); + return MP_OKAY; + } + + /* if both are negative they share (-1) as a common divisor */ + neg = (a->sign == b->sign) ? a->sign : MP_ZPOS; + + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init_copy (&v, b)) != MP_OKAY) { + goto __U; + } + + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; + + if ((res = mp_init (&t)) != MP_OKAY) { + goto __V; + } + + /* B1. Find power of two */ + k = 0; + while (mp_iseven(&u) == 1 && mp_iseven(&v) == 1) { + ++k; + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __T; + } + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __T; + } + } + + /* B2. Initialize */ + if (mp_isodd(&u) == 1) { + /* t = -v */ + if ((res = mp_copy (&v, &t)) != MP_OKAY) { + goto __T; + } + t.sign = MP_NEG; + } else { + /* t = u */ + if ((res = mp_copy (&u, &t)) != MP_OKAY) { + goto __T; + } + } + + do { + /* B3 (and B4). Halve t, if even */ + while (t.used != 0 && mp_iseven(&t) == 1) { + if ((res = mp_div_2 (&t, &t)) != MP_OKAY) { + goto __T; + } + } + + /* B5. if t>0 then u=t otherwise v=-t */ + if (t.used != 0 && t.sign != MP_NEG) { + if ((res = mp_copy (&t, &u)) != MP_OKAY) { + goto __T; + } + } else { + if ((res = mp_copy (&t, &v)) != MP_OKAY) { + goto __T; + } + v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + } + + /* B6. t = u - v, if t != 0 loop otherwise terminate */ + if ((res = mp_sub (&u, &v, &t)) != MP_OKAY) { + goto __T; + } + } while (mp_iszero(&t) == 0); + + /* multiply by 2^k which we divided out at the beginning */ + if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { + goto __T; + } + + mp_exch (&u, c); + c->sign = neg; + res = MP_OKAY; +__T:mp_clear (&t); +__V:mp_clear (&u); +__U:mp_clear (&v); + return res; +} + +/* End: bn_mp_gcd.c */ + +/* Start: bn_mp_grow.c */ +#line 0 "bn_mp_grow.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* grow as required */ +int +mp_grow (mp_int * a, int size) +{ + int i; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); + + a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + +/* End: bn_mp_grow.c */ + +/* Start: bn_mp_init.c */ +#line 0 "bn_mp_init.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* init a new bigint */ +int +mp_init (mp_int * a) +{ + /* allocate ram required and clear it */ + a->dp = OPT_CAST calloc (sizeof (mp_digit), MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the used to zero, allocated digit to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* End: bn_mp_init.c */ + +/* Start: bn_mp_init_copy.c */ +#line 0 "bn_mp_init_copy.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* creates "a" then copies b into it */ +int +mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + +/* End: bn_mp_init_copy.c */ + +/* Start: bn_mp_init_size.c */ +#line 0 "bn_mp_init_size.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* init a mp_init and grow it to a given size */ +int +mp_init_size (mp_int * a, int size) +{ + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); + + /* alloc mem */ + a->dp = OPT_CAST calloc (sizeof (mp_digit), size); + if (a->dp == NULL) { + return MP_MEM; + } + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* End: bn_mp_init_size.c */ + +/* Start: bn_mp_invmod.c */ +#line 0 "bn_mp_invmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int +mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ + if (mp_iseven (b) == 0) { + return fast_mp_invmod (a, b, c); + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_copy (a, &x)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_abs (&x, &x)) != MP_OKAY) { + goto __ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_iseven (&A) == 0 || mp_iseven (&B) == 0) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if C,D are even then */ + if (mp_iseven (&C) == 0 || mp_iseven (&D) == 0) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* a is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; + +__ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} + +/* End: bn_mp_invmod.c */ + +/* Start: bn_mp_jacobi.c */ +#line 0 "bn_mp_jacobi.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + */ +int +mp_jacobi (mp_int * a, mp_int * n, int *c) +{ + mp_int a1, n1, e; + int s, r, res; + mp_digit residue; + + /* step 1. if a == 0, return 0 */ + if (mp_iszero (a) == 1) { + *c = 0; + return MP_OKAY; + } + + /* step 2. if a == 1, return 1 */ + if (mp_cmp_d (a, 1) == MP_EQ) { + *c = 1; + return MP_OKAY; + } + + /* default */ + s = 0; + + /* step 3. write a = a1 * 2^e */ + if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&n1)) != MP_OKAY) { + goto __A1; + } + + if ((res = mp_init (&e)) != MP_OKAY) { + goto __N1; + } + + while (mp_iseven (&a1) == 1) { + if ((res = mp_add_d (&e, 1, &e)) != MP_OKAY) { + goto __E; + } + + if ((res = mp_div_2 (&a1, &a1)) != MP_OKAY) { + goto __E; + } + } + + /* step 4. if e is even set s=1 */ + if (mp_iseven (&e) == 1) { + s = 1; + } else { + /* else set s=1 if n = 1/7 (mod 8) or s=-1 if n = 3/5 (mod 8) */ + if ((res = mp_mod_d (n, 8, &residue)) != MP_OKAY) { + goto __E; + } + + if (residue == 1 || residue == 7) { + s = 1; + } else if (residue == 3 || residue == 5) { + s = -1; + } + } + + /* step 5. if n == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ((res = mp_mod_d (n, 4, &residue)) != MP_OKAY) { + goto __E; + } + if (residue == 3) { + if ((res = mp_mod_d (&a1, 4, &residue)) != MP_OKAY) { + goto __E; + } + if (residue == 3) { + s = -s; + } + } + + /* if a1 == 1 we're done */ + if (mp_cmp_d (&a1, 1) == MP_EQ) { + *c = s; + } else { + /* n1 = n mod a1 */ + if ((res = mp_mod (n, &a1, &n1)) != MP_OKAY) { + goto __E; + } + if ((res = mp_jacobi (&n1, &a1, &r)) != MP_OKAY) { + goto __E; + } + *c = s * r; + } + + /* done */ + res = MP_OKAY; +__E:mp_clear (&e); +__N1:mp_clear (&n1); +__A1:mp_clear (&a1); + return res; +} + +/* End: bn_mp_jacobi.c */ + +/* Start: bn_mp_karatsuba_mul.c */ +#line 0 "bn_mp_karatsuba_mul.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = |a| * |b| using Karatsuba Multiplication using three half size multiplications + * + * Let B represent the radix [e.g. 2**DIGIT_BIT] and let n represent half of the number of digits in the min(a,b) + * + * a = a1 * B^n + a0 + * b = b1 * B^n + b0 + * + * Then, a * b => a1b1 * B^2n + ((a1 - b1)(a0 - b0) + a0b0 + a1b1) * B + a0b0 + * + * Note that a1b1 and a0b0 are used twice and only need to be computed once. So in total + * three half size (half # of digit) multiplications are performed, a0b0, a1b1 and (a1-b1)(a0-b0) + * + * Note that a multiplication of half the digits requires 1/4th the number of single precision + * multiplications so in total after one call 25% of the single precision multiplications are saved. + * Note also that the call to mp_mul can end up back in this function if the a0, a1, b0, or b1 are above + * the threshold. This is known as divide-and-conquer and leads to the famous O(N^lg(3)) or O(N^1.584) work which + * is asymptopically lower than the standard O(N^2) that the baseline/comba methods use. Generally though the + * overhead of this method doesn't pay off until a certain size (N ~ 80) is reached. + */ +int +mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = MIN (a->used, b->used); + + /* now divide in two */ + B = B / 2; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + if (mp_init_size (&y0, B) != MP_OKAY) + goto X1; + if (mp_init_size (&y1, b->used - B) != MP_OKAY) + goto Y0; + + /* init temps */ + if (mp_init_size (&t1, B * 2) != MP_OKAY) + goto Y1; + if (mp_init_size (&x0y0, B * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x1y1, B * 2) != MP_OKAY) + goto X0Y0; + + /* now shift the digits */ + x0.sign = x1.sign = a->sign; + y0.sign = y1.sign = b->sign; + + x0.used = y0.used = B; + x1.used = a->used - B; + y1.used = b->used - B; + + { + register int x; + register mp_digit *tmpa, *tmpb, *tmpx, *tmpy; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + tmpa = a->dp; + tmpb = b->dp; + + tmpx = x0.dp; + tmpy = y0.dp; + for (x = 0; x < B; x++) { + *tmpx++ = *tmpa++; + *tmpy++ = *tmpb++; + } + + tmpx = x1.dp; + for (x = B; x < a->used; x++) { + *tmpx++ = *tmpa++; + } + + tmpy = y1.dp; + for (x = B; x < b->used; x++) { + *tmpy++ = *tmpb++; + } + } + + /* only need to clamp the lower words since by definition the upper words x1/y1 must + * have a known number of digits + */ + mp_clamp (&x0); + mp_clamp (&y0); + + /* now calc the products x0y0 and x1y1 */ + if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) /* after this x0 is no longer required, free temp [x0==t2]! */ + goto X1Y1; /* x0y0 = x0*y0 */ + if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) + goto X1Y1; /* x1y1 = x1*y1 */ + + /* now calc x1-x0 and y1-y0 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x1 - x0 */ + if (mp_sub (&y1, &y0, &x0) != MP_OKAY) + goto X1Y1; /* t2 = y1 - y0 */ + if (mp_mul (&t1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ + + /* add x0y0 */ + if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY) + goto X1Y1; /* t2 = x0y0 + x1y1 */ + if (mp_sub (&x0, &t1, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< + +/* Karatsuba squaring, computes b = a*a using three half size squarings + * + * See comments of mp_karatsuba_mul for details. It is essentially the same algorithm + * but merely tuned to perform recursive squarings. + */ +int +mp_karatsuba_sqr (mp_int * a, mp_int * b) +{ + mp_int x0, x1, t1, t2, x0x0, x1x1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = a->used; + + /* now divide in two */ + B = B / 2; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + + /* init temps */ + if (mp_init_size (&t1, a->used * 2) != MP_OKAY) + goto X1; + if (mp_init_size (&t2, a->used * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x0x0, B * 2) != MP_OKAY) + goto T2; + if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) + goto X0X0; + + { + register int x; + register mp_digit *dst, *src; + + src = a->dp; + + /* now shift the digits */ + dst = x0.dp; + for (x = 0; x < B; x++) { + *dst++ = *src++; + } + + dst = x1.dp; + for (x = B; x < a->used; x++) { + *dst++ = *src++; + } + } + + x0.used = B; + x1.used = a->used - B; + + mp_clamp (&x0); + + /* now calc the products x0*x0 and x1*x1 */ + if (mp_sqr (&x0, &x0x0) != MP_OKAY) + goto X1X1; /* x0x0 = x0*x0 */ + if (mp_sqr (&x1, &x1x1) != MP_OKAY) + goto X1X1; /* x1x1 = x1*x1 */ + + /* now calc (x1-x0)^2 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1X1; /* t1 = x1 - x0 */ + if (mp_sqr (&t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ + + /* add x0y0 */ + if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) + goto X1X1; /* t2 = x0y0 + x1y1 */ + if (mp_sub (&t2, &t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1X1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< + +/* computes least common multiple as a*b/(a, b) */ +int +mp_lcm (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if ((res = mp_gcd (a, b, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + res = mp_div (&t, c, c, NULL); + mp_clear (&t); + return res; +} + +/* End: bn_mp_lcm.c */ + +/* Start: bn_mp_lshd.c */ +#line 0 "bn_mp_lshd.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift left a certain amount of digits */ +int +mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *tmpa, *tmpaa; + + /* increment the used by the shift amount than copy upwards */ + a->used += b; + + /* top */ + tmpa = a->dp + a->used - 1; + + /* base */ + tmpaa = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *tmpa-- = *tmpaa--; + } + + /* zero the lower digits */ + tmpa = a->dp; + for (x = 0; x < b; x++) { + *tmpa++ = 0; + } + } + return MP_OKAY; +} + +/* End: bn_mp_lshd.c */ + +/* Start: bn_mp_mod.c */ +#line 0 "bn_mp_mod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = a mod b, 0 <= c < b */ +int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign == MP_NEG) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + +/* End: bn_mp_mod.c */ + +/* Start: bn_mp_mod_2d.c */ +#line 0 "bn_mp_mod_2d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calc a value mod 2^b */ +int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b > (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mod_2d.c */ + +/* Start: bn_mp_mod_d.c */ +#line 0 "bn_mp_mod_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int +mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) +{ + mp_int t, t2; + int res; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + mp_set (&t, b); + mp_div (a, &t, NULL, &t2); + + if (t2.sign == MP_NEG) { + if ((res = mp_add_d (&t2, b, &t2)) != MP_OKAY) { + mp_clear (&t); + mp_clear (&t2); + return res; + } + } + *c = t2.dp[0]; + mp_clear (&t); + mp_clear (&t2); + return MP_OKAY; +} + +/* End: bn_mp_mod_d.c */ + +/* Start: bn_mp_montgomery_calc_normalization.c */ +#line 0 "bn_mp_montgomery_calc_normalization.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calculates a = B^n mod b for Montgomery reduction + * Where B is the base [e.g. 2^DIGIT_BIT]. + * B^n mod b is computed by first computing + * A = B^(n-1) which doesn't require a reduction but a simple OR. + * then C = A * B = B^n is computed by performing upto DIGIT_BIT + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +int +mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + /* compute A = B^(n-1) * 2^(bits-1) */ + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_calc_normalization.c */ + +/* Start: bn_mp_montgomery_reduce.c */ +#line 0 "bn_mp_montgomery_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes xR^-1 == x (mod N) via Montgomery Reduction */ +int +mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) +{ + int ix, res, digs; + mp_digit ui; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mp_mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = m->used * 2 + 1; + if ((digs < MP_WARRAY) + && m->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (a, m, mp); + } + + /* grow the input as required */ + if (a->alloc < m->used * 2 + 1) { + if ((res = mp_grow (a, m->used * 2 + 1)) != MP_OKAY) { + return res; + } + } + a->used = m->used * 2 + 1; + + for (ix = 0; ix < m->used; ix++) { + /* ui = ai * m' mod b */ + ui = (a->dp[ix] * mp) & MP_MASK; + + /* a = a + ui * m * b^i */ + { + register int iy; + register mp_digit *tmpx, *tmpy, mu; + register mp_word r; + + /* aliases */ + tmpx = m->dp; + tmpy = a->dp + ix; + + mu = 0; + for (iy = 0; iy < m->used; iy++) { + r = ((mp_word) ui) * ((mp_word) * tmpx++) + ((mp_word) mu) + ((mp_word) * tmpy); + mu = (r >> ((mp_word) DIGIT_BIT)); + *tmpy++ = (r & ((mp_word) MP_MASK)); + } + /* propagate carries */ + while (mu) { + *tmpy += mu; + mu = (*tmpy >> DIGIT_BIT) & 1; + *tmpy++ &= MP_MASK; + } + } + } + + /* A = A/b^n */ + mp_rshd (a, m->used); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (a, m) != MP_LT) { + return s_mp_sub (a, m, a); + } + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_reduce.c */ + +/* Start: bn_mp_montgomery_setup.c */ +#line 0 "bn_mp_montgomery_setup.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (mp_int * a, mp_digit * mp) +{ + mp_digit x, b; + +/* fast inversion mod 2^k + * + * Based on the fact that + * + * XA = 1 (mod 2^n) => (X(2-XA)) A = 1 (mod 2^2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = a->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2^4 */ + x *= 2 - b * x; /* here x*a==1 mod 2^8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2^16; each step doubles the nb of bits */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2^32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2^64 */ +#endif + + /* t = -1/m mod b */ + *mp = (((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_setup.c */ + +/* Start: bn_mp_mul.c */ +#line 0 "bn_mp_mul.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level multiplication (handles sign) */ +int +mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + if (MIN (a->used, b->used) > KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else { + + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will have less than + * MP_WARRAY digits and the number of digits won't affect carry propagation + */ + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) + && MIN(a->used, b->used) <= (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else { + res = s_mp_mul (a, b, c); + } + + } + c->sign = neg; + return res; +} + +/* End: bn_mp_mul.c */ + +/* Start: bn_mp_mul_2.c */ +#line 0 "bn_mp_mul_2.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = a*2 */ +int +mp_mul_2 (mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++b->used; + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} + +/* End: bn_mp_mul_2.c */ + +/* Start: bn_mp_mul_2d.c */ +#line 0 "bn_mp_mul_2d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* NOTE: This routine requires updating. For instance the c->used = c->alloc bit + is wrong. We should just shift c->used digits then set the carry as c->dp[c->used] = carry + + To be fixed for LTM 0.18 + */ + +/* shift left by a certain bit count */ +int +mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 2)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 2)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + c->used = c->alloc; + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> (DIGIT_BIT - d)) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mul_2d.c */ + +/* Start: bn_mp_mul_d.c */ +#line 0 "bn_mp_mul_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiply by a digit */ +int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, pa, olduse; + + /* make sure c is big enough to hold a*b */ + pa = a->used; + if (c->alloc < pa + 1) { + if ((res = mp_grow (c, pa + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the new temporary used count */ + c->used = pa + 1; + + { + register mp_digit u, *tmpa, *tmpc; + register mp_word r; + register int ix; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + for (ix = 0; ix < pa; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word) * tmpa++) * ((mp_word) b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* store final carry [if any] */ + *tmpc++ = u; + + /* now zero digits above the top */ + for (; pa < olduse; pa++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mul_d.c */ + +/* Start: bn_mp_mulmod.c */ +#line 0 "bn_mp_mulmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a * b (mod c) */ +int +mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_mulmod.c */ + +/* Start: bn_mp_multi.c */ +#line 0 "bn_mp_multi.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +#include + +int mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +void mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} + +/* End: bn_mp_multi.c */ + +/* Start: bn_mp_n_root.c */ +#line 0 "bn_mp_n_root.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* find the n'th root of an integer + * + * Result found such that (c)^b <= a and (c+1)^b > a + * + * This algorithm uses Newton's approximation x[i+1] = x[i] - f(x[i])/f'(x[i]) + * which will find the root in log(N) time where each step involves a fair bit. This + * is not meant to find huge roots [square and cube at most]. + */ +int +mp_n_root (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t1, t2, t3; + int res, neg; + + /* input must be positive if b is even */ + if ((b & 1) == 0 && a->sign == MP_NEG) { + return MP_VAL; + } + + if ((res = mp_init (&t1)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } + + if ((res = mp_init (&t3)) != MP_OKAY) { + goto __T2; + } + + /* if a is negative fudge the sign but keep track */ + neg = a->sign; + a->sign = MP_ZPOS; + + /* t2 = 2 */ + mp_set (&t2, 2); + + do { + /* t1 = t2 */ + if ((res = mp_copy (&t2, &t1)) != MP_OKAY) { + goto __T3; + } + + /* t2 = t1 - ((t1^b - a) / (b * t1^(b-1))) */ + if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) */ + goto __T3; + } + + /* numerator */ + if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { /* t2 = t1^b */ + goto __T3; + } + + if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { /* t2 = t1^b - a */ + goto __T3; + } + + if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) * b */ + goto __T3; + } + + if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { /* t3 = (t1^b - a)/(b * t1^(b-1)) */ + goto __T3; + } + + if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { + goto __T3; + } + } + while (mp_cmp (&t1, &t2) != MP_EQ); + + /* result can be off by a few so check */ + for (;;) { + if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) { + goto __T3; + } + + if (mp_cmp (&t2, a) == MP_GT) { + if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) { + goto __T3; + } + } else { + break; + } + } + + /* reset the sign of a first */ + a->sign = neg; + + /* set the result */ + mp_exch (&t1, c); + + /* set the sign of the result */ + c->sign = neg; + + res = MP_OKAY; + +__T3:mp_clear (&t3); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); + return res; +} + +/* End: bn_mp_n_root.c */ + +/* Start: bn_mp_neg.c */ +#line 0 "bn_mp_neg.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = -a */ +int +mp_neg (mp_int * a, mp_int * b) +{ + int res; + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + return MP_OKAY; +} + +/* End: bn_mp_neg.c */ + +/* Start: bn_mp_or.c */ +#line 0 "bn_mp_or.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* OR two ints together */ +int +mp_or (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] |= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_or.c */ + +/* Start: bn_mp_prime_fermat.c */ +#line 0 "bn_mp_prime_fermat.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* performs one Fermat test. + * + * If "a" were prime then b^a == b (mod a) since the order of + * the multiplicative sub-group would be phi(a) = a-1. That means + * it would be the same as b^(a mod (a-1)) == b^1 == b (mod a). + * + * Sets result to 1 if the congruence holds, or zero otherwise. + */ +int +mp_prime_fermat (mp_int * a, mp_int * b, int *result) +{ + mp_int t; + int err; + + /* default to fail */ + *result = 0; + + /* init t */ + if ((err = mp_init (&t)) != MP_OKAY) { + return err; + } + + /* compute t = b^a mod a */ + if ((err = mp_exptmod (b, a, a, &t)) != MP_OKAY) { + goto __T; + } + + /* is it equal to b? */ + if (mp_cmp (&t, b) == MP_EQ) { + *result = 1; + } + + err = MP_OKAY; +__T:mp_clear (&t); + return err; +} + +/* End: bn_mp_prime_fermat.c */ + +/* Start: bn_mp_prime_is_divisible.c */ +#line 0 "bn_mp_prime_is_divisible.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if an integers is divisible by one of the first 256 primes or not + * + * sets result to 0 if not, 1 if yes + */ +int +mp_prime_is_divisible (mp_int * a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = 0; + + for (ix = 0; ix < PRIME_SIZE; ix++) { + /* is it equal to the prime? */ + if (mp_cmp_d (a, __prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + + /* what is a mod __prime_tab[ix] */ + if ((err = mp_mod_d (a, __prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = 1; + return MP_OKAY; + } + } + + return MP_OKAY; +} + +/* End: bn_mp_prime_is_divisible.c */ + +/* Start: bn_mp_prime_is_prime.c */ +#line 0 "bn_mp_prime_is_prime.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* performs a variable number of rounds of Miller-Rabin + * + * Probability of error after t rounds is no more than + * (1/4)^t when 1 <= t <= 256 + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int +mp_prime_is_prime (mp_int * a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = 0; + + /* valid value of t? */ + if (t < 1 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, __prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + if (res == 1) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, __prime_tab[ix]); + + if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { + goto __B; + } + + if (res == 0) { + goto __B; + } + } + + /* passed the test */ + *result = 1; +__B:mp_clear (&b); + return err; +} + +/* End: bn_mp_prime_is_prime.c */ + +/* Start: bn_mp_prime_miller_rabin.c */ +#line 0 "bn_mp_prime_miller_rabin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + */ +int +mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = 0; + + /* get n1 = a - 1 */ + if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { + goto __N1; + } + + /* set 2^s * r = n1 */ + if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { + goto __N1; + } + s = 0; + while (mp_iseven (&r) == 1) { + ++s; + if ((err = mp_div_2 (&r, &r)) != MP_OKAY) { + goto __R; + } + } + + /* compute y = b^r mod a */ + if ((err = mp_init (&y)) != MP_OKAY) { + goto __R; + } + if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y != 1 and y != n1 do */ + if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { + if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d (&y, 1) == MP_EQ) { + goto __Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp (&y, &n1) != MP_EQ) { + goto __Y; + } + } + + /* probably prime now */ + *result = 1; +__Y:mp_clear (&y); +__R:mp_clear (&r); +__N1:mp_clear (&n1); + return err; +} + +/* End: bn_mp_prime_miller_rabin.c */ + +/* Start: bn_mp_prime_next_prime.c */ +#line 0 "bn_mp_prime_next_prime.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + */ +int mp_prime_next_prime(mp_int *a, int t) +{ + int err, res; + + if (mp_iseven(a) == 1) { + /* force odd */ + if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { + return err; + } + } else { + /* force to next odd number */ + if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { + return err; + } + } + + for (;;) { + /* is this prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + return err; + } + + if (res == 1) { + break; + } + + /* add two, next candidate */ + if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { + return err; + } + } + + return MP_OKAY; +} + + +/* End: bn_mp_prime_next_prime.c */ + +/* Start: bn_mp_rand.c */ +#line 0 "bn_mp_rand.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* makes a pseudo-random int of a given size */ +int +mp_rand (mp_int * a, int digits) +{ + int res; + mp_digit d; + + mp_zero (a); + if (digits <= 0) { + return MP_OKAY; + } + + /* first place a random non-zero digit */ + do { + d = ((mp_digit) abs (rand ())); + } while (d == 0); + + if ((res = mp_add_d (a, d, a)) != MP_OKAY) { + return res; + } + + while (digits-- > 0) { + if ((res = mp_lshd (a, 1)) != MP_OKAY) { + return res; + } + + if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) { + return res; + } + } + + return MP_OKAY; +} + +/* End: bn_mp_rand.c */ + +/* Start: bn_mp_read_signed_bin.c */ +#line 0 "bn_mp_read_signed_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* read signed bin, big endian, first byte is 0==positive or 1==negative */ +int +mp_read_signed_bin (mp_int * a, unsigned char *b, int c) +{ + int res; + + if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) { + return res; + } + a->sign = ((b[0] == (unsigned char) 0) ? MP_ZPOS : MP_NEG); + return MP_OKAY; +} + +/* End: bn_mp_read_signed_bin.c */ + +/* Start: bn_mp_read_unsigned_bin.c */ +#line 0 "bn_mp_read_unsigned_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int +mp_read_unsigned_bin (mp_int * a, unsigned char *b, int c) +{ + int res; + mp_zero (a); + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + + if (DIGIT_BIT != 7) { + a->dp[0] |= *b++; + a->used += 1; + } else { + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; + } + } + mp_clamp (a); + return MP_OKAY; +} + +/* End: bn_mp_read_unsigned_bin.c */ + +/* Start: bn_mp_reduce.c */ +#line 0 "bn_mp_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int +mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + res = mp_div (a, b, a, NULL); + return res; +} + +/* reduces x mod m, assumes 0 < x < m^2, mu is precomputed via mp_reduce_setup + * From HAC pp.604 Algorithm 14.42 + */ +int +mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b^(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this is optimization is ok */ + if (((unsigned long) m->used) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { + if ((res = s_mp_mul_high_digs (&q, mu, &q, um - 1)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* q3 = q2 / b^(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b^(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b^(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b^(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if ((res = mp_add (x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + break; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + +/* End: bn_mp_reduce.c */ + +/* Start: bn_mp_rshd.c */ +#line 0 "bn_mp_rshd.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift right a certain amount of digits */ +void +mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *tmpa, *tmpaa; + + /* shift the digits down */ + + /* base */ + tmpa = a->dp; + + /* offset into digits */ + tmpaa = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *tmpa++ = *tmpaa++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *tmpa++ = 0; + } + } + mp_clamp (a); +} + +/* End: bn_mp_rshd.c */ + +/* Start: bn_mp_set.c */ +#line 0 "bn_mp_set.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set to a digit */ +void +mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + +/* End: bn_mp_set.c */ + +/* Start: bn_mp_set_int.c */ +#line 0 "bn_mp_set_int.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set a 32-bit const */ +int +mp_set_int (mp_int * a, unsigned int b) +{ + int x, res; + + mp_zero (a); + /* set four bits at a time */ + for (x = 0; x < 8; x++) { + /* shift the number up four bits */ + if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { + return res; + } + + /* OR in the top four bits of the source */ + a->dp[0] |= (b >> 28) & 15; + + /* shift the source up to the next four bits */ + b <<= 4; + + /* ensure that digits are not clamped off */ + a->used += 32 / DIGIT_BIT + 2; + } + mp_clamp (a); + return MP_OKAY; +} + +/* End: bn_mp_set_int.c */ + +/* Start: bn_mp_shrink.c */ +#line 0 "bn_mp_shrink.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shrink a bignum */ +int +mp_shrink (mp_int * a) +{ + if (a->alloc != a->used) { + if ((a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->alloc = a->used; + } + return MP_OKAY; +} + +/* End: bn_mp_shrink.c */ + +/* Start: bn_mp_signed_bin_size.c */ +#line 0 "bn_mp_signed_bin_size.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* get the size for an signed equivalent */ +int +mp_signed_bin_size (mp_int * a) +{ + return 1 + mp_unsigned_bin_size (a); +} + +/* End: bn_mp_signed_bin_size.c */ + +/* Start: bn_mp_sqr.c */ +#line 0 "bn_mp_sqr.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes b = a*a */ +int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + if (a->used > KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else { + + /* can we use the fast multiplier? */ + if ((a->used * 2 + 1) < 512 && a->used < (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else { + res = s_mp_sqr (a, b); + } + } + b->sign = MP_ZPOS; + return res; +} + +/* End: bn_mp_sqr.c */ + +/* Start: bn_mp_sqrmod.c */ +#line 0 "bn_mp_sqrmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = a * a (mod b) */ +int +mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} + +/* End: bn_mp_sqrmod.c */ + +/* Start: bn_mp_sub.c */ +#line 0 "bn_mp_sub.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level subtraction (handles signs) */ +int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* End: bn_mp_sub.c */ + +/* Start: bn_mp_sub_d.c */ +#line 0 "bn_mp_sub_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit subtraction */ +int +mp_sub_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t; + int res; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + mp_set (&t, b); + res = mp_sub (a, &t, c); + + mp_clear (&t); + return res; +} + +/* End: bn_mp_sub_d.c */ + +/* Start: bn_mp_submod.c */ +#line 0 "bn_mp_submod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a - b (mod c) */ +int +mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_submod.c */ + +/* Start: bn_mp_to_signed_bin.c */ +#line 0 "bn_mp_to_signed_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* store in signed [big endian] format */ +int +mp_to_signed_bin (mp_int * a, unsigned char *b) +{ + int res; + + if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) { + return res; + } + b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1); + return MP_OKAY; +} + +/* End: bn_mp_to_signed_bin.c */ + +/* Start: bn_mp_to_unsigned_bin.c */ +#line 0 "bn_mp_to_unsigned_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* store in unsigned [big endian] format */ +int +mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { + if (DIGIT_BIT != 7) { + b[x++] = (unsigned char) (t.dp[0] & 255); + } else { + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); + } + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_to_unsigned_bin.c */ + +/* Start: bn_mp_unsigned_bin_size.c */ +#line 0 "bn_mp_unsigned_bin_size.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* get the size for an unsigned equivalent */ +int +mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + +/* End: bn_mp_unsigned_bin_size.c */ + +/* Start: bn_mp_xor.c */ +#line 0 "bn_mp_xor.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* XOR two ints together */ +int +mp_xor (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] ^= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_xor.c */ + +/* Start: bn_mp_zero.c */ +#line 0 "bn_mp_zero.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set to zero */ +void +mp_zero (mp_int * a) +{ + a->sign = MP_ZPOS; + a->used = 0; + memset (a->dp, 0, sizeof (mp_digit) * a->alloc); +} + +/* End: bn_mp_zero.c */ + +/* Start: bn_prime_tab.c */ +#line 0 "bn_prime_tab.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +const mp_digit __prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, +#ifndef MP_8BIT + 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +#endif +}; + +/* End: bn_prime_tab.c */ + +/* Start: bn_radix.c */ +#line 0 "bn_radix.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* chars used in radix conversions */ +static const char *s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +/* read a string [ASCII] in a given radix */ +int +mp_read_radix (mp_int * a, char *str, int radix) +{ + int y, res, neg; + char ch; + + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if (*str == '-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + mp_zero (a); + while (*str) { + ch = (char) ((radix < 36) ? toupper (*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == s_rmap[y]) { + break; + } + } + + if (y < radix) { + if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { + return res; + } + if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { + return res; + } + } else { + break; + } + ++str; + } + a->sign = neg; + return MP_OKAY; +} + +/* stores a bignum as a ASCII string in a given radix (2..64) */ +int +mp_toradix (mp_int * a, char *str, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + if (t.sign == MP_NEG) { + ++_s; + *str++ = '-'; + t.sign = MP_ZPOS; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *str++ = s_rmap[d]; + ++digs; + } + bn_reverse ((unsigned char *)_s, digs); + *str++ = '\0'; + mp_clear (&t); + return MP_OKAY; +} + +/* returns size of ASCII reprensentation */ +int +mp_radix_size (mp_int * a, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + + /* special case for binary */ + if (radix == 2) { + return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + } + + if (radix < 2 || radix > 64) { + return 0; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return 0; + } + + digs = 0; + if (t.sign == MP_NEG) { + ++digs; + t.sign = MP_ZPOS; + } + + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return 0; + } + ++digs; + } + mp_clear (&t); + return digs + 1; +} + +/* read a bigint from a file stream in ASCII */ +int mp_fread(mp_int *a, int radix, FILE *stream) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + ch = fgetc(stream); + if (ch == '-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = fgetc(stream); + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + +int mp_fwrite(mp_int *a, int radix, FILE *stream) +{ + char *buf; + int err, len, x; + + len = mp_radix_size(a, radix); + if (len == 0) { + return MP_VAL; + } + + buf = malloc(len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { + free(buf); + return err; + } + + for (x = 0; x < len; x++) { + if (fputc(buf[x], stream) == EOF) { + free(buf); + return MP_VAL; + } + } + + free(buf); + return MP_OKAY; +} + + +/* End: bn_radix.c */ + +/* Start: bn_reverse.c */ +#line 0 "bn_reverse.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reverse an array, used for radix code */ +void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + +/* End: bn_reverse.c */ + +/* Start: bn_s_mp_add.c */ +#line 0 "bn_s_mp_add.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + /* set the carry to zero */ + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_s_mp_add.c */ + +/* Start: bn_s_mp_mul_digs.c */ +#line 0 "bn_s_mp_mul_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +int +s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word) *tmpt) + + ((mp_word) tmpx) * ((mp_word) * tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_mul_digs.c */ + +/* Start: bn_s_mp_mul_high_digs.c */ +#line 0 "bn_s_mp_mul_high_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + + /* can we use the fast multiplier? */ + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word) * tmpt) + ((mp_word) tmpx) * ((mp_word) * tmpy++) + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_mul_high_digs.c */ + +/* Start: bn_s_mp_sqr.c */ +#line 0 "bn_s_mp_sqr.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +int +s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r, u; + mp_digit tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, pa + pa + 1)) != MP_OKAY) { + return res; + } + t.used = pa + pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[ix + ix]) + ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); + + /* store lower part in result */ + t.dp[ix + ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = &(t.dp[ix + ix + 1]); + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word) tmpx) * ((mp_word) a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since its easier to optimize + */ + r = ((mp_word) * tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (r >> ((mp_word) DIGIT_BIT)); + } + r = ((mp_word) * tmpt) + u; + *tmpt = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (r >> ((mp_word) DIGIT_BIT)); + /* propagate upwards */ + ++tmpt; + while (u != ((mp_word) 0)) { + r = ((mp_word) * tmpt) + ((mp_word) 1); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_sqr.c */ + +/* Start: bn_s_mp_sub.c */ +#line 0 "bn_s_mp_sub.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + /* sub digits from lower part */ + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is required to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_s_mp_sub.c */ + +/* EOF */ diff --git a/tommath.h b/tommath.h index cfd9da1..0d56f02 100644 --- a/tommath.h +++ b/tommath.h @@ -1,11 +1,11 @@ /* LibTomMath, multiple-precision integer library -- Tom St Denis * - * LibTomMath is library that provides for multiple-precision + * LibTomMath is library that provides for multiple-precision * integer arithmetic as well as number theoretic functionality. - * + * * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. * * The library is free for all purposes without any express * guarantee it works. @@ -34,18 +34,18 @@ extern "C" { #else -/* C on the other hand dosen't care */ -#define OPT_CAST +/* C on the other hand doesn't care */ +#define OPT_CAST #endif -/* some default configurations. +/* some default configurations. * - * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits - * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits + * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits + * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits * - * At the very least a mp_digit must be able to hold 7 bits - * [any size beyond that is ok provided it overflow the data type] + * At the very least a mp_digit must be able to hold 7 bits + * [any size beyond that is ok provided it doesn't overflow the data type] */ #ifdef MP_8BIT typedef unsigned char mp_digit; @@ -53,7 +53,21 @@ extern "C" { #elif defined(MP_16BIT) typedef unsigned short mp_digit; typedef unsigned long mp_word; +#elif defined(MP_64BIT) + /* for GCC only on supported platforms */ +#ifndef CRYPT + typedef unsigned long long ulong64; + typedef signed long long long64; +#endif + + typedef ulong64 mp_digit; + typedef unsigned long mp_word __attribute__ ((mode(TI))); + + #define DIGIT_BIT 60 #else + /* this is the default case, 28-bit digits */ + + /* this is to make porting into LibTomCrypt easier :-) */ #ifndef CRYPT #ifdef _MSC_VER typedef unsigned __int64 ulong64; @@ -61,23 +75,24 @@ extern "C" { #else typedef unsigned long long ulong64; typedef signed long long long64; - #endif -#endif + #endif +#endif - /* default case */ typedef unsigned long mp_digit; typedef ulong64 mp_word; - - #define DIGIT_BIT 28 -#endif + #define DIGIT_BIT 28 +#endif + +/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */ #ifndef DIGIT_BIT #define DIGIT_BIT ((CHAR_BIT * sizeof(mp_digit) - 1)) /* bits per digit */ #endif + #define MP_DIGIT_BIT DIGIT_BIT #define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) -#define MP_DIGIT_MAX MP_MASK +#define MP_DIGIT_MAX MP_MASK /* equalities */ #define MP_LT -1 /* less than */ @@ -99,7 +114,14 @@ extern int KARATSUBA_MUL_CUTOFF, KARATSUBA_SQR_CUTOFF, MONTGOMERY_EXPT_CUTOFF; -#define MP_PREC 64 /* default digits of precision */ +/* various build options */ +#define MP_PREC 64 /* default digits of precision (must be power of two) */ + +/* define this to use lower memory usage routines (exptmods mostly) */ +/* #define MP_LOW_MEM */ + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) typedef struct { int used, alloc, sign; @@ -118,6 +140,12 @@ int mp_init(mp_int *a); /* free a bignum */ void mp_clear(mp_int *a); +/* init a null terminated series of arguments */ +int mp_init_multi(mp_int *mp, ...); + +/* clear a null terminated series of arguments */ +void mp_clear_multi(mp_int *mp, ...); + /* exchange two ints */ void mp_exch(mp_int *a, mp_int *b); @@ -143,7 +171,7 @@ void mp_zero(mp_int *a); void mp_set(mp_int *a, mp_digit b); /* set a 32-bit const */ -int mp_set_int(mp_int *a, unsigned long b); +int mp_set_int(mp_int *a, unsigned int b); /* copy, b = a */ int mp_copy(mp_int *a, mp_int *b); @@ -162,22 +190,22 @@ void mp_rshd(mp_int *a, int b); /* left shift by "b" digits */ int mp_lshd(mp_int *a, int b); -/* c = a / 2^b */ +/* c = a / 2**b */ int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d); /* b = a/2 */ int mp_div_2(mp_int *a, mp_int *b); -/* c = a * 2^b */ +/* c = a * 2**b */ int mp_mul_2d(mp_int *a, int b, mp_int *c); /* b = a*2 */ int mp_mul_2(mp_int *a, mp_int *b); -/* c = a mod 2^d */ +/* c = a mod 2**d */ int mp_mod_2d(mp_int *a, int b, mp_int *c); -/* computes a = 2^b */ +/* computes a = 2**b */ int mp_2expt(mp_int *a, int b); /* makes a pseudo-random int of a given size */ @@ -216,7 +244,7 @@ int mp_sub(mp_int *a, mp_int *b, mp_int *c); /* c = a * b */ int mp_mul(mp_int *a, mp_int *b, mp_int *c); -/* b = a^2 */ +/* b = a*a */ int mp_sqr(mp_int *a, mp_int *b); /* a/b => cb + d == a */ @@ -242,7 +270,7 @@ int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); /* a/b => cb + d == a */ int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); -/* c = a^b */ +/* c = a**b */ int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); /* c = a mod b, 0 <= c < b */ @@ -271,7 +299,7 @@ int mp_gcd(mp_int *a, mp_int *b, mp_int *c); /* c = [a, b] or (a*b)/(a, b) */ int mp_lcm(mp_int *a, mp_int *b, mp_int *c); -/* finds one of the b'th root of a, such that |c|^b <= |a| +/* finds one of the b'th root of a, such that |c|**b <= |a| * * returns error if a < 0 and b is even */ @@ -288,7 +316,7 @@ int mp_reduce_setup(mp_int *a, mp_int *b); /* Barrett Reduction, computes a (mod b) with a precomputed value c * - * Assumes that 0 < a <= b^2, note if 0 > a > -(b^2) then you can merely + * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. */ int mp_reduce(mp_int *a, mp_int *b, mp_int *c); @@ -296,12 +324,12 @@ int mp_reduce(mp_int *a, mp_int *b, mp_int *c); /* setups the montgomery reduction */ int mp_montgomery_setup(mp_int *a, mp_digit *mp); -/* computes a = B^n mod b without division or multiplication useful for +/* computes a = B**n mod b without division or multiplication useful for * normalizing numbers in a Montgomery system. */ int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); -/* computes xR^-1 == x (mod N) via Montgomery Reduction */ +/* computes x/R == x (mod N) via Montgomery Reduction */ int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); /* returns 1 if a is a valid DR modulus */ @@ -313,32 +341,38 @@ void mp_dr_setup(mp_int *a, mp_digit *d); /* reduces a modulo b using the Diminished Radix method */ int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); -/* d = a^b (mod c) */ +/* d = a**b (mod c) */ int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); /* ---> Primes <--- */ -#define PRIME_SIZE 256 /* number of primes */ -/* table of first 256 primes */ +/* number of primes */ +#ifdef MP_8BIT + #define PRIME_SIZE 31 +#else + #define PRIME_SIZE 256 +#endif + +/* table of first PRIME_SIZE primes */ extern const mp_digit __prime_tab[]; -/* result=1 if a is divisible by one of the first 256 primes */ +/* result=1 if a is divisible by one of the first PRIME_SIZE primes */ int mp_prime_is_divisible(mp_int *a, int *result); -/* performs one Fermat test of "a" using base "b". - * Sets result to 0 if composite or 1 if probable prime +/* performs one Fermat test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime */ int mp_prime_fermat(mp_int *a, mp_int *b, int *result); /* performs one Miller-Rabin test of "a" using base "b". - * Sets result to 0 if composite or 1 if probable prime + * Sets result to 0 if composite or 1 if probable prime */ int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result); /* performs t rounds of Miller-Rabin on "a" using the first * t prime bases. Also performs an initial sieve of trial * division. Determines if "a" is prime with probability - * of error no more than (1/4)^t. + * of error no more than (1/4)**t. * * Sets result to 1 if probably prime, 0 otherwise */ @@ -365,6 +399,9 @@ int mp_read_radix(mp_int *a, char *str, int radix); int mp_toradix(mp_int *a, char *str, int radix); int mp_radix_size(mp_int *a, int radix); +int mp_fread(mp_int *a, int radix, FILE *stream); +int mp_fwrite(mp_int *a, int radix, FILE *stream); + #define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) #define mp_raw_size(mp) mp_signed_bin_size(mp) #define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) diff --git a/tommath.src b/tommath.src new file mode 100644 index 0000000..f04f324 --- /dev/null +++ b/tommath.src @@ -0,0 +1,2459 @@ +\documentclass[b5paper]{book} +\usepackage{makeidx} +\usepackage{amssymb} +\usepackage{color} +\usepackage{alltt} +\usepackage{graphicx} +\usepackage{layout} +\def\union{\cup} +\def\intersect{\cap} +\def\getsrandom{\stackrel{\rm R}{\gets}} +\def\cross{\times} +\def\cat{\hspace{0.5em} \| \hspace{0.5em}} +\def\catn{$\|$} +\def\divides{\hspace{0.3em} | \hspace{0.3em}} +\def\nequiv{\not\equiv} +\def\approx{\raisebox{0.2ex}{\mbox{\small $\sim$}}} +\def\lcm{{\rm lcm}} +\def\gcd{{\rm gcd}} +\def\log{{\rm log}} +\def\ord{{\rm ord}} +\def\abs{{\mathit abs}} +\def\rep{{\mathit rep}} +\def\mod{{\mathit\ mod\ }} +\renewcommand{\pmod}[1]{\ ({\rm mod\ }{#1})} +\newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} +\newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} +\def\Or{{\rm\ or\ }} +\def\And{{\rm\ and\ }} +\def\iff{\hspace{1em}\Longleftrightarrow\hspace{1em}} +\def\implies{\Rightarrow} +\def\undefined{{\rm ``undefined"}} +\def\Proof{\vspace{1ex}\noindent {\bf Proof:}\hspace{1em}} +\let\oldphi\phi +\def\phi{\varphi} +\def\Pr{{\rm Pr}} +\newcommand{\str}[1]{{\mathbf{#1}}} +\def\F{{\mathbb F}} +\def\N{{\mathbb N}} +\def\Z{{\mathbb Z}} +\def\R{{\mathbb R}} +\def\C{{\mathbb C}} +\def\Q{{\mathbb Q}} +\definecolor{DGray}{gray}{0.5} +\newcommand{\url}[1]{\mbox{$<${#1}$>$}} +\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}} +\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} +\def\gap{\vspace{0.5ex}} +\makeindex +\begin{document} +\frontmatter +\pagestyle{empty} +\title{Multiple-Precision Integer Arithmetic, \\ A Case Study Involving the LibTomMath Project \\ - DRAFT - } +\author{\mbox{ +%\begin{small} +\begin{tabular}{c} +Tom St Denis \\ +Algonquin College \\ +\\ +Mads Rasmussen \\ +Open Communications Security \\ +\\ +Gregory Rose \\ +Qualcomm \\ +\end{tabular} +%\end{small} +} +} +\maketitle +This text in its entirety is copyrighted \copyright{}2003 by Tom St Denis. It may not be redistributed +electronically or otherwise without the sole permission of the author. The text is freely re distributable as long as +it is packaged along with the LibTomMath project in a non-commercial project. Contact the +author for other redistribution rights. + +This text corresponds to the v0.17 release of the LibTomMath project. + +\begin{alltt} +Tom St Denis +111 Banning Rd +Ottawa, Ontario +K2L 1C3 +Canada + +Phone: 1-613-836-3160 +Email: tomstdenis@iahu.ca +\end{alltt} + +This text is formatted to the international B5 paper size of 176mm wide by 250mm tall using the \LaTeX{} +{\em book} macro package and the Perl {\em booker} package. + +\tableofcontents +\listoffigures +\chapter*{Preface} +Blah. + +\mainmatter +\pagestyle{headings} +\chapter{Introduction} +\section{Multiple Precision Arithmetic} +\subsection{The Need for Multiple Precision Arithmetic} +The most prevalent use for multiple precision arithmetic (\textit{often referred to as bignum math}) is within public +key cryptography. Algorithms such as RSA, Diffie-Hellman and Elliptic Curve Cryptography require large integers in order to +resist known cryptanalytic attacks. Typical modern programming languages such as C and Java only provide small +single-precision data types which are incapable of precisely representing integers which are often hundreds of bits long. + +For example, consider multiplying $1,234,567$ by $9,876,543$ in C with an ``unsigned long'' data type. With an +x86 machine the result is $4,136,875,833$ while the true result is $12,193,254,061,881$. The original inputs +were approximately $21$ and $24$ bits respectively. If the C language cannot multiply two relatively small values +together precisely how does anyone expect it to multiply two values which are considerably larger? + +Most advancements in fast multiple precision arithmetic stems from the desire for faster cryptographic primitives. However, cryptography +is not the only field of study that can benefit fast large integer routines. Another auxiliary use for multiple precision integers is +high precision floating point data types. The basic IEEE standard floating point type is made up of an integer mantissa $q$ and an exponent $e$. +Numbers are given in the form $n = q \cdot b^e$ where $b = 2$ is convention. Since IEEE is meant to be implemented in +hardware the precision of the mantissa is often fairly small (\textit{roughly 23 bits}). Since the mantissa is merely an +integer a large multiple precision integer could be used. In effect very high precision floating point arithmetic +could be performed. This would be useful where scientific applications must minimize the total output error over long simulations. + +\subsection{Multiple Precision Arithmetic} +\index{multiple precision} +Multiple precision arithmetic attempts to the solve the shortcomings of single precision data types such as those from +the C and Java programming languages. In essence multiple precision arithmetic is a set of operations that can be +performed on members of an algebraic group whose precision is not fixed. The algorithms when implemented to be multiple +precision can allow a developer to work with any practical precision required. + +Typically the arithmetic is performed over the ring of integers denoted by a $\Z$ and referred to casually as ``bignum'' +routines. However, it is possible to have rings of polynomials as well typically denoted by $\Z/p\Z \left [ X \right ]$ +which could have variable precision (\textit{or degree}). This text will discuss implementation of the former, however, +implementing polynomial basis routines should be relatively easy after reading this text. + +\subsection{Benefits of Multiple Precision Arithmetic} +\index{precision} \index{accuracy} +Precision is defined loosely as the proximity to the real value a given representation is. Accuracy is defined as the +reproducibility of the result. For example, the calculation $1/3 = 0.25$ is imprecise but can be accurate provided +it is reproducible. + +The benefit of multiple precision representations over single precision representations is that +often no precision is lost while representing the result of an operation which requires excess precision. For example, +the multiplication of two $n$-bit integers requires at least $2n$ bits to represent the result. A multiple precision +system would augment the precision of the destination to accomodate the result while a single precision system would +truncate excess bits to maintain a fixed level of precision. + +Multiple precision representations allow for the precision to be very high (\textit{if not exacting}) but at a cost of +modest computer resources. The only reasonable case where a multiple precision system will lose precision is when +emulating a floating point data type. However, with multiple precision integer arithmetic no precision is lost. + +\subsection{Basis of Operations} +At the heart of all multiple precision integer operations are the ``long-hand'' algorithms we all learnt as children +in grade school. For example, to multiply $1,234$ by $981$ the student is not taught to memorize the times table for +$1,234$ instead they are taught how to long-multiply. That is to multiply each column using simple single digit +multiplications and add the resulting products by column. The representation that most are familiar with is known as +decimal or formally as radix-10. A radix-$n$ representation simply means there are $n$ possible values per digit. +For example, binary would be a radix-2 representation. + +In essence computer based multiple precision arithmetic is very much the same. The most notable difference is the usage +of a binary friendly radix. That is to use a radix of the form $2^k$ where $k$ is typically the size of a machine +register. Also occasionally more optimal algorithms are used to perform certain operations such as multiplication and +squaring instead of traditional long-hand algorithms. + +\section{Purpose of This Text} +The purpose of this text is to instruct the reader regarding how to implement multiple precision algorithms. That is +to not only explain the core theoretical algorithms but also the various ``house keeping'' tasks that are neglected by +authors of other texts on the subject. Texts such as Knuths' ``The Art of Computer Programming, vol 2.'' and the +Handbook of Applied Cryptography (\textit{HAC}) give considerably detailed explanations of the theoretical aspects of +the algorithms and very little regarding the practical aspects. + +That is how an algorithm is explained and how it is actually implemented are two very different +realities. For example, algorithm 14.7 on page 594 of HAC lists a relatively simple algorithm for performing multiple +precision integer addition. However, what the description lacks is any discussion concerning the fact that the two +integer inputs may be of differing magnitudes. Similarly the division routine (\textit{Algorithm 14.20, pp. 598}) +does not discuss how to handle sign or handle the dividends decreasing magnitude in the main loop (\textit{Step \#3}). + +As well as the numerous practical oversights both of the texts do not discuss several key optimal algorithms required +such as ``Comba'' and Karatsuba multipliers and fast modular inversion. These optimal algorithms are considerably +vital to achieve any form of useful performance in non-trivial applications. + +To solve this problem the focus of this text is on the practical aspects of implementing the algorithms that +constitute a multiple precision integer package with light cursory discussions on the theoretical aspects. As a case +study the ``LibTomMath''\footnote{Available freely at http://math.libtomcrypt.org} package is used to demonstrate +algorithms with implementations that have been field tested and work very well. + +\section{Discussion and Notation} +\subsection{Notation} +A multiple precision integer of $n$-digits shall be denoted as $x = (x_n ... x_1 x_0)_{ \beta }$ to be the +multiple precision notation for the integer $x \equiv \sum_{i=0}^{n} x_i\beta^i$. The elements of the array $x$ are +said to be the radix $\beta$ digits of the integer. For example, $x = (15,0,7)_{\beta}$ would represent the +integer $15\cdot\beta^2 + 0\cdot\beta^1 + 7\cdot\beta^0$. + +A ``mp\_int'' shall refer to a composite structure which contains the digits of the integer as well as auxilary data +required to manipulate the data. These additional members are discussed in ~BASICOP~. For the purposes of this text +a ``multiple precision integer'' and a ``mp\_int'' are synonymous. + +\index{single-precision} \index{double-precision} \index{mp\_digit} \index{mp\_word} +For the purposes of this text a single-precision variable must be able to represent integers in the range $0 \le x < 2 \beta$ while +a double-precision variable must be able to represent integers in the range $0 \le x < 2 \beta^2$. Within the source code that will be +presented the data type \textbf{mp\_digit} will represent a single-precision type while \textbf{mp\_word} will represent a +double-precision type. In several algorithms (\textit{notably the Comba routines}) temporary results +will be stored in a double-precision arrays. For the purposes of this text $x_j$ will refer to the +$j$'th digit of a single-precision array and $\hat x_j$ will refer to the $j$'th digit of a double-precision +array. + +\subsection{Work Effort} +\index{big-O} +To measure the efficiency of various algorithms a modified big-O notation is used. In this system all +single precision operations are considered to have the same cost\footnote{Except where explicitly noted.}. +That is a single precision addition, multiplication and division are assumed to take the same time to +complete. While this is generally not true in practice it will simplify the discussions considerably. + +Some algorithms have slight advantages over others which is why some constants will not be removed in +the notation. For example, a normal multiplication requires $O(n^2)$ work while a squaring requires +$O({{n^2 + n}\over 2})$ work. In standard big-O notation these would be said to be equivalent. However, in the +context of the this text the magnitude of the inputs will not approach an infinite size. This means the conventional limit +notation wisdom does not apply to the cancellation of constants. + +Throughout the discussions various ``work levels'' will be discussed. These levels are the $O(1)$, +$O(n)$, $O(n^2)$, ..., $O(n^k)$ work efforts. For example, operations at the $O(n^k)$ ``level'' are said to be +executed more frequently than operations at the $O(n^m)$ ``level'' when $k > m$. Obviously most optimizations will pay +off the most at the higher levels since they represent the bulk of the effort required. + +\section{Exercises} +Within the more advanced chapters a section will be set aside to give the reader some challenging exercises. These exercises are not +designed to be prize winning problems yet instead to be thought provoking. Wherever possible the problems are foreward minded stating +problems that will be answered in subsequent chapters. The reader is encouraged to finish the exercises as they appear to get a +better understanding of the subject material. + +Similar to the exercises of \cite{TAOCPV2} as explained on pp.\textit{ix} these exercises are given a scoring system. However, unlike +\cite{TAOCPV2} the problems do not get nearly as hard as often. The scoring of these exercises ranges from one (\textit{the easiest}) to +five (\textit{the hardest}). The following table sumarizes the scoring. + +\vspace{5mm} +\begin{tabular}{cl} +$\left [ 1 \right ]$ & An easy problem that should only take the reader a manner of \\ + & minutes to solve. Usually does not involve much computer time. \\ + & \\ +$\left [ 2 \right ]$ & An easy problem that involves a marginal amount of computer \\ + & time usage. Usually requires a program to be written to \\ + & solve the problem. \\ + & \\ +$\left [ 3 \right ]$ & A moderately hard problem that requires a non-trivial amount \\ + & of work. Usually involves trivial research and development of \\ + & new theory from the perspective of a student. \\ + & \\ +$\left [ 4 \right ]$ & A moderately hard problem that involves a non-trivial amount \\ + & of work and research. The solution to which will demonstrate \\ + & a higher mastery of the subject matter. \\ + & \\ +$\left [ 5 \right ]$ & A hard problem that involves concepts that are non-trivial. \\ + & Solutions to these problems will demonstrate a complete mastery \\ + & of the given subject. \\ + & \\ +\end{tabular} + +Essentially problems at the first level are meant to be simple questions that the reader can answer quickly without programming a solution or +devising new theory. These problems are quick tests to see if the material is understood. Problems at the second level are also +designed to be easy but will require a program or algorithm to be implemented to arrive at the answer. + +Problems at the third level are meant to be a bit more difficult. Often the answer is fairly obvious but arriving at an exacting solution +requires some thought and skill. These problems will almost always involve devising a new algorithm or implementing a variation of +another algorithm. + +Problems at the fourth level are meant to be even more difficult as well as involve some research. The reader will most likely not know +the answer right away nor will this text provide the exact details of the answer (\textit{or at least not until a subsequent chapter}). Problems +at the fifth level are meant to be the hardest problems relative to all the other problems in the chapter. People who can correctly +answer fifth level problems have a mastery of the subject matter at hand. + +Often problems will be tied together. The purpose of this is to start a chain of thought that will be discussed in future chapters. The reader +is encouraged to answer the follow-up problems and try to draw the relevence of problems. + +\chapter{Introduction to LibTomMath} + +\section{What is the LibTomMath?} +LibTomMath is a free and open source multiple precision number theoretic library written in portable ISO C +source code. By portable it is meant that the library does not contain any code that is platform dependent or otherwise +problematic to use on any given platform. The library has been successfully tested under numerous operating systems +including Solaris, MacOS, Windows, Linux, PalmOS and on standalone hardware such as the Gameboy Advance. The +library is designed to contain enough functionality to be able to develop number theoretic applications such as public +key cryptosystems. + +\section{Goals of the LibTomMath} + +Even though the library is written entirely in portable ISO C considerable care has been taken to +optimize the algorithm implementations within the library. Specifically the code has been written to work well with +the GNU C Compiler (\textit{GCC}) on both x86 and ARMv4 processors. Wherever possible optimal +algorithms (\textit{such as Karatsuba multiplication, sliding window exponentiation and Montgomery reduction.}) have +been provided to make the library as efficient as possible. Even with the optimal and sometimes specialized +algorithms that have been included the API has been kept as simple as possible. Often generic place holder routines +will make use of specialized algorithms automatically without the developers attention. One such example +is the generic multiplication algorithm \textbf{mp\_mul()} which will automatically use Karatsuba multiplication if the +inputs are of a specific size. + +Making LibTomMath as efficient as possible is not the only goal of the LibTomMath project. Ideally the library should +be source compatible with another popular library which makes it more attractive for developers to use. In this case the +MPI library was used as a API template for all the basic functions. + +The project is also meant to act as a learning tool for students. The logic being that no easy to follow ``bignum'' +library exists which can be used to teach computer science students how to perform fast and reliable multiple precision +arithmetic. To this end the source code has been given quite a few comments and algorithm discussion points. Often +where applicable routines have more comments than lines of code. + +\section{Choice of LibTomMath} +LibTomMath was chosen as the case study of this text not only because the author of both projects is one and the same but +for more worthy reasons. Other libraries such as GMP, MPI, LIP and OpenSSL have multiple precision +integer arithmetic routines but would not be ideal for this text for numerous reasons as will be explained in the +following sub-sections. + +\subsection{Code Base} +The LibTomMath code base is all portable ISO C source code. This means that there are no platform dependent conditional +segments of code littered throughout the source. This clean and uncluttered approach to the library means that a +developer can more readily ascertain the true intent of a given section of source code without trying to keep track of +what conditional code will be used. + +The code base of LibTomMath is also exceptionally well organized. Each function is in its own separate source code file +which allows the reader to find a given function very fast. When compiled with GCC for the x86 processor the entire +library is a mere 87,760 bytes (\textit{$116,182$ bytes for ARMv4 processors}). This includes every single function +LibTomMath provides from basic arithmetic to various number theoretic functions such as modular exponentiation, various +reduction algorithms and Jacobi symbol computation. + +By comparison MPI which has fewer number theoretic functions than LibTomMath compiled with the same conditions is +45,429 bytes (\textit{$54,536$ for ARMv4}). GMP which has rather large collection of functions with the default +configuration on an x86 Athlon is 2,950,688 bytes. Note that while LibTomMath has fewer functions than GMP it has been +been used as the sole basis for several public key cryptosystems without having to seek additional outside functions +to supplement the library. + +\subsection{API Simplicity} +LibTomMath is designed after the MPI library and shares the API design. Quite often programs that use MPI will build +with LibTomMath without change. The function names are relatively straight forward as to what they perform. Almost all of the +functions except for a few minor exceptions which as will be discussed are for good reasons share the same parameter passing +convention. The learning curve is fairly shallow with the API provided which is an extremely valuable benefit for the +student and developer alike. + +The LIP library is an example of a library with an API that is awkward to work with. LIP uses function names that are often ``compressed'' to +illegible short hand. LibTomMath does not share this fault. + +\subsection{Optimizations} +While LibTomMath is certainly not the fastest library (\textit{GMP often beats LibTomMath by a factor of two}) it does +feature a set of optimal algorithms for tasks ranging from modular reduction to squaring. GMP and LIP also feature +such optimizations while MPI only uses baseline algorithms with no optimizations. + +LibTomMath is almost always a magnitude faster than the MPI library at computationally expensive tasks such as modular +exponentiation. In the grand scheme of ``bignum'' libraries LibTomMath is faster than the average library and usually +slower than the best libraries such as GMP and OpenSSL by a small factor. + +\subsection{Portability and Stability} +LibTomMath will build ``out of the box'' on any platform equipped with a modern version of the GNU C Compiler +(\textit{GCC}). This means that without changes the library will build without configuration or setting up any +variables. LIP and MPI will build ``out of the box'' as well but have numerous known bugs. Most notably the author of +MPI is not working on his library anymore. + +GMP requires a configuration script to run and will not build out of the box. GMP and LibTomMath are still in active +development and are very stable across a variety of platforms. + +\subsection{Choice} +LibTomMath is a relatively compact, well documented, highly optimized and portable library which seems only natural for +the case study of this text. Various source files from the LibTomMath project will be included within the text. However, the +reader is encouraged to download their own copy of the library to actually be able to work with the library. + +\chapter{Getting Started} +MARK,BASICOP +\section{Library Basics} +To get the ``ball rolling'' so to speak a primitive data type and a series of primitive algorithms must be established. First a data +type that will hold the information required to maintain a multiple precision integer must be designed. With this basic data type of a series +of low level algorithms for initializing, clearing, growing and clamping integers can be developed to form the basis of the entire +package of algorithms. + +\section{The mp\_int structure} +First the data type for storing multiple precision integers must be designed. This data type must be able to hold information to +maintain an array of digits, how many are actually used in the representation and the sign. The ISO C standard does not provide for +any such data type but it does provide for making composite data types known as structures. The following is the structure definition +used within LibTomMath. + +\index{mp\_int} +\begin{verbatim} +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; +\end{verbatim} + +The \textbf{used} parameter denotes how many digits of the array \textbf{dp} are actually being used. The array +\textbf{dp} holds the digits that represent the integer desired. The \textbf{alloc} parameter denotes how +many digits are available in the array to use by functions before it has to increase in size. When the \textbf{used} count +of a result would exceed the \textbf{alloc} count all LibTomMath routines will automatically increase the size of the +array to accommodate the precision of the result. The \textbf{sign} parameter denotes the sign as either zero/positive +(\textbf{MP\_ZPOS}) or negative (\textbf{MP\_NEG}). + +\section{Argument Passing} +A convention of arugment passing must be adopted early on in the development of any library. Making the function prototypes +consistent will help eliminate many headaches in the future as the library grows to significant complexity. In LibTomMath the multiple precision +integer functions accept parameters from left to right as pointers to mp\_int structures. That means that the source operands are +placed on the left and the destination on the right. Consider the following examples. + +\begin{verbatim} + mp_mul(&a, &b, &c); /* c = a * b */ + mp_add(&a, &b, &a); /* a = a + b */ + mp_sqr(&a, &b); /* b = a * a */ +\end{verbatim} + +The left to right order is a fairly natural way to implement the functions since it lets the developer read aloud the +functions and make sense of them. For example, the first function would read ``multiply a and b and store in c''. + +Certain libraries (\textit{LIP by Lenstra for instance}) accept parameters the other way around. That is the destination +on the left and arguments on the right. In truth it is entirely a matter of preference. + +Another very useful design consideration is whether to allow argument sources to also be a destination. For example, the +second example (\textit{mp\_add}) adds $a$ to $b$ and stores in $a$. This is an important feature to implement since it +allows the higher up functions to cut down on the number of variables. However, to implement this feature specific +care has to be given to ensure the destination is not written before the source is fully read. + +\section{Return Values} +A well implemented library, no matter what its purpose, should trap as many runtime errors as possible and return them to the +caller. By catching runtime errors a library can be guaranteed to prevent undefined behaviour within reason. In a multiple precision +library the only errors that are bound to occur are related to inappropriate inputs (\textit{division by zero for instance}) or +memory allocation errors. + +In LibTomMath any function that can cause a runtime error will return an error as an \textbf{int} data type with one of the +following values. + +\index{MP\_OKAY} \index{MP\_VAL} \index{MP\_MEM} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Value} & \textbf{Meaning} \\ +\hline \textbf{MP\_OKAY} & The function was successful \\ +\hline \textbf{MP\_VAL} & One of the input value(s) was invalid \\ +\hline \textbf{MP\_MEM} & The function ran out of heap memory \\ +\hline +\end{tabular} +\end{center} + +When an error is detected within a function it should free any memory they allocated and return as soon as possible. The goal +is to leave the system in the same state the system was when the function was called. Error checking with this style of API is fairly simple. + +\begin{verbatim} + int err; + if ((err = mp_add(&a, &b, &c)) != MP_OKAY) { + printf("Error: %d\n", err); + exit(EXIT_FAILURE); + } +\end{verbatim} + +The GMP library uses C style \textit{signals} to flag errors which is of questionable use. Not all errors are fatal +and it is not ideal to force developers to have signal handlers for such cases. + +\section{Initialization and Clearing} +The logical starting point when actually writing multiple precision integer functions is the initialization and +clearing of the integers. These two functions will be used by far the most throughout the algorithms whenever +temporary integers are required. + +Given the basic mp\_int structure an initialization routine must first allocate memory to hold the digits of +the integer. Often it is optimal to allocate a sufficiently large pre-set number of digits even considering +the initial integer will represent zero. If only a single digit were allocated quite a few re-allocations +would occur for the majority of inputs. There exists a tradeoff between how many default digits to allocate +and how many re-allocations are tolerable. + +If the memory for the digits has been successfully allocated then the rest of the members of the structure must +be initialized. Since the initial state is to represent a zero integer the digits allocated must all be zeroed. The +\textbf{used} count set to zero and \textbf{sign} set to \textbf{MP\_ZPOS}. + +\subsection{Initializing an mp\_int} +To initialize an mp\_int the mp\_init algorithm shall be used. The purpose of this algorithm is to allocate +the memory required and initialize the integer to a default representation of zero. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Allocate memory for the digits and set to a zero state. \\ +\hline \\ +1. Allocate memory for \textbf{MP\_PREC} digits. \\ +2. If the allocation failed then return(\textit{MP\_MEM}) \\ +3. for $n$ from $0$ to $MP\_PREC - 1$ do \\ +\hspace{3mm}3.1 $a_n \leftarrow 0$\\ +4. $a.sign \leftarrow MP\_ZPOS$\\ +5. $a.used \leftarrow 0$\\ +6. $a.alloc \leftarrow MP\_PREC$\\ +7. Return(\textit{MP\_OKAY})\\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init} +\end{figure} + +\textbf{Algorithm mp\_init.} +The \textbf{MP\_PREC} variable is a simple constant used to dictate minimal precision of allocated integers. It is ideally at least equal to $32$ but +can be any reasonable power of two. Step one and two allocate the memory and account for it. If the allocation fails the algorithm returns +immediately to signal the failure. Step three will ensure that all the digits are in the default state of zero. Finally steps +four through six set the default settings of the \textbf{sign}, \textbf{used} and \textbf{alloc} members of the mp\_int structure. + +EXAM,bn_mp_init.c + +The \textbf{OPT\_CAST} type cast on line @22,OPT_CAST@ is designed to allow C++ compilers to build the code out of +the box. Microsoft C V5.00 is known to cause problems without the cast. Also note that if the memory +allocation fails the other members of the mp\_int will be in an undefined state. The code from +line @29,a->used@ to line @31,a->sign@ sets the default state for a mp\_int which is zero, positive and no used digits. + +\subsection{Clearing an mp\_int} +When an mp\_int is no longer required the memory allocated for it can be cleared from the heap with +the mp\_clear algorithm. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_clear}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. The memory for $a$ is cleared. \\ +\hline \\ +1. If $a$ has been previously freed then return(\textit{MP\_OKAY}). \\ +2. Free the digits of $a$ and mark $a$ as freed. \\ +3. $a.used \leftarrow 0$ \\ +4. $a.alloc \leftarrow 0$ \\ +5. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_clear} +\end{figure} + +\textbf{Algorithm mp\_clear.} +In steps one and two the memory for the digits are only free'd if they had not been previously released before. +This is more of concern for the implementation since it is used to prevent ``double-free'' errors. It also helps catch +code errors where mp\_ints are used after being cleared. Simiarly steps three and four set the +\textbf{used} and \textbf{alloc} to known values which would be easy to spot during debugging. For example, if an mp\_int is expected +to be non-zero and its \textbf{used} member observed to be zero (\textit{due to being cleared}) then an obvious bug in the code has been +spotted. + +EXAM,bn_mp_clear.c + +The \textbf{if} statement on line @21,a->dp != NULL@ prevents the heap from being corrupted if a user double-frees an +mp\_int. For example, a trivial case of this bug would be as follows. + +\begin{verbatim} +mp_int a; +mp_init(&a); +mp_clear(&a); +mp_clear(&a); +\end{verbatim} + +Without that check the code would try to free the memory allocated for the digits twice which will cause most standard C +libraries to cause a fault. Also by setting the pointer to \textbf{NULL} it helps debug code that may inadvertently +free the mp\_int before it is truly not needed. The allocated digits are set to zero before being freed on line @24,memset@. +This is ideal for cryptographic situations where the mp\_int is a secret parameter. + +The following snippet is an example of using both the init and clear functions. + +\begin{small} +\begin{verbatim} +#include +#include +#include +int main(void) +{ + mp_int num; + int err; + + /* init the bignum */ + if ((err = mp_init(&num)) != MP_OKAY) { + printf("Error: %d\n", err); + return EXIT_FAILURE; + } + + /* do work with it ... */ + + /* clear up */ + mp_clear(&num); + + return EXIT_SUCCESS; +} +\end{verbatim} +\end{small} + +\section{Other Initialization Routines} + +It is often helpful to have specialized initialization algorithms to simplify the design of other algorithms. For example, an +initialization followed by a copy is a common operation when temporary copies of integers are required. It is quite +beneficial to have a series of simple helper functions available. + +\subsection{Initializing Variable Sized mp\_int Structures} +Occasionally the number of digits required will be known in advance of an initialization. In these +cases the mp\_init\_size algorithm can be of use. The purpose of this algorithm is similar to mp\_init except that +it will allocate \textit{at least} a specified number of digits. This is ideal to prevent re-allocations when the +input size is known. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init\_size}. \\ +\textbf{Input}. An mp\_int $a$ and the requested number of digits $b$\\ +\textbf{Output}. $a$ is initialized to hold at least $b$ digits. \\ +\hline \\ +1. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ +2. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ +3. Allocate $v$ digits. \\ +4. If the allocation failed then return(\textit{MP\_MEM}). \\ +5. for $n$ from $0$ to $v - 1$ do \\ +\hspace{3mm}5.1 $a_n \leftarrow 0$ \\ +6. $a.sign \leftarrow MP\_ZPOS$\\ +7. $a.used \leftarrow 0$\\ +8. $a.alloc \leftarrow v$\\ +9. Return(\textit{MP\_OKAY})\\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init\_size} +\end{figure} + +\textbf{Algorithm mp\_init\_size.} +The value of $v$ is calculated to be at least the requested amount of digits $b$ plus additional padding. The padding is calculated +to be at least \textbf{MP\_PREC} digits plus enough digits to make the digit count a multiple of \textbf{MP\_PREC}. This padding is used to +prevent trivial allocations from becomming a bottleneck in the rest of the algorithms that depend on this. + +EXAM,bn_mp_init_size.c + +Line @23,MP_PREC@ will ensure that the number of digits actually allocated is padded up to the next multiple of +\textbf{MP\_PREC} plus an additional \textbf{MP\_PREC}. This ensures that the number of allocated digit is +always greater than the amount requested. As a result it prevents many trivial memory allocations. The value of +\textbf{MP\_PREC} is defined in ``tommath.h'' and must be a power of two. + +\subsection{Creating a Clone} +Another common sequence of operations is to make a local temporary copy of an argument. To initialize then copy a mp\_int will be known as +creating a clone. This is useful within functions that need to modify an integer argument but do not wish to actually modify the original copy. +The mp\_init\_copy algorithm will perform this very task. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init\_copy}. \\ +\textbf{Input}. An mp\_int $a$ and $b$\\ +\textbf{Output}. $a$ is initialized to be a copy of $b$. \\ +\hline \\ +1. Init $a$. (\textit{hint: use mp\_init}) \\ +2. If the init of $a$ was unsuccessful return(\textit{MP\_MEM}) \\ +3. Copy $b$ to $a$. (\textit{hint: use mp\_copy}) \\ +4. Return the status of the copy operation. \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init\_copy} +\end{figure} + +\textbf{Algorithm mp\_init\_copy.} +This algorithm will initialize a mp\_int variable and copy another previously initialized mp\_int variable into it. The algorithm will +detect when the initialization fails and returns the error to the calling algorithm. As such this algorithm will perform two operations +in one step. + +EXAM,bn_mp_init_copy.c + +This will initialize \textbf{a} and make it a verbatim copy of the contents of \textbf{b}. Note that +\textbf{a} will have its own memory allocated which means that \textbf{b} may be cleared after the call +and \textbf{a} will be left intact. + +\subsection{Multiple Integer Initializations} +Occasionally a function will require a series of mp\_int data types to be made available. The mp\_init\_multi algorithm +is provided to simplify such cases. The purpose of this algorithm is to initialize a variable length array of mp\_int +structures at once. As a result algorithms that require multiple integers only has to use +one algorithm to initialize all the mp\_int variables. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init\_multi}. \\ +\textbf{Input}. Variable length array of mp\_int variables of length $k$. \\ +\textbf{Output}. The array is initialized such that each each mp\_int is ready to use. \\ +\hline \\ +1. for $n$ from 0 to $k - 1$ do \\ +\hspace{+3mm}1.1. Initialize the $n$'th mp\_int (\textit{hint: use mp\_init}) \\ +\hspace{+3mm}1.2. If initialization failed then do \\ +\hspace{+6mm}1.2.1. for $j$ from $0$ to $n$ do \\ +\hspace{+9mm}1.2.1.1. Free the $j$'th mp\_int (\textit{hint: use mp\_clear}) \\ +\hspace{+6mm}1.2.2. Return(\textit{MP\_MEM}) \\ +2. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init\_multi} +\end{figure} + +\textbf{Algorithm mp\_init\_multi.} +The algorithm will initialize the array of mp\_int variables one at a time. As soon as an runtime error is detected (\textit{step 1.2}) all of +the previously initialized variables are cleared. The goal is an ``all or nothing'' initialization which allows for quick recovery from runtime +errors. + +\subsection{Multiple Integer Clearing} +Similarly to clear a variable length list of mp\_int structures the mp\_clear\_multi algorithm will be used. + +EXAM,bn_mp_multi.c + +Consider the following snippet which demonstrates how to use both routines. +\begin{small} +\begin{verbatim} +#include +#include +#include +int main(void) +{ + mp_int num1, num2, num3; + int err; + + if ((err = mp_init_multi(&num1, &num2, &num3, NULL)) !- MP_OKAY) { + printf("Error: %d\n", err); + return EXIT_FAILURE; + } + + /* at this point num1/num2/num3 are ready */ + + /* free them */ + mp_clear_multi(&num1, &num2, &num3, NULL); + + return EXIT_SUCCESS; +} +\end{verbatim} +\end{small} + +\section{Maintenance} +A small useful collection of mp\_int maintenance functions will also prove useful. + +\subsection{Augmenting Integer Precision} +When storing a value in an mp\_int sufficient digits must be available to accomodate the entire value without +loss of precision. Quite often the size of the array given by the \textbf{alloc} member is large enough to simply +increase the \textbf{used} digit count. However, when the size of the array is too small it must be re-sized +appropriately to accomodate the result. The mp\_grow algorithm will provide this functionality. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_grow}. \\ +\textbf{Input}. An mp\_int $a$ and an integer $b$. \\ +\textbf{Output}. $a$ is expanded to accomodate $b$ digits. \\ +\hline \\ +1. if $a.alloc \ge b$ then return(\textit{MP\_OKAY}) \\ +2. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ +3. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ +4. Re-Allocate the array of digits $a$ to size $v$ \\ +5. If the allocation failed then return(\textit{MP\_MEM}). \\ +6. for n from a.alloc to $v - 1$ do \\ +\hspace{+3mm}6.1 $a_n \leftarrow 0$ \\ +7. $a.alloc \leftarrow v$ \\ +8. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_grow} +\end{figure} + +\textbf{Algorithm mp\_grow.} +Step one will prevent a re-allocation from being performed if it was not required. This is useful to prevent mp\_ints +from growing excessively in code that erroneously calls mp\_grow. Similar to mp\_init\_size the requested digit count +is padded to provide more digits than requested. + +In step four it is assumed that the reallocation leaves the lower $a.alloc$ digits intact. Much akin to how the +\textit{realloc} function from the standard C library works. Since the newly allocated digits are assumed to contain +undefined values they are also initially zeroed. + +EXAM,bn_mp_grow.c + +The first step is to see if we actually need to perform a re-allocation at all. This is tested for on line +@24,a->alloc < size@. Similar to mp\_init\_size the same code on line @26,MP_PREC - 1@ was used to resize the +digits requested. A simple for loop from line @34,a->alloc@ to line @38,}@ will zero all digits that were above the +old \textbf{alloc} limit to make sure the integer is in a known state. + +\subsection{Clamping Excess Digits} +When a function anticipates a result will be $n$ digits it is simpler to assume this is true within the body of +the function. For example, a multiplication of a $i$ digit number by a $j$ digit produces a result of at most +$i + j + 1$ digits. It is entirely possible that the result is $i + j$ though, with no final carry into the last +position. However, suppose the destination had to be first expanded (\textit{via mp\_grow}) to accomodate $i + j$ +digits than further expanded to accomodate the final carry. That would be a considerable waste of time since heap +operations are relatively slow. + +The ideal solution is to always assume the result is $i + j + 1$ and fix up the \textbf{used} count after the function +terminates. This way a single heap operation (\textit{at most}) is required. However, if the result was not checked +there would be an excess high order zero digit. + +For example, suppose the product of two integers was $x_n = (0x_{n-1}x_{n-2}...x_0)_{\beta}$. The leading zero digit +will not contribute to the precision of the result. In fact, through subsequent operations more leading zero digits would +accumulate to the point the size of the integer would be prohibitive. As a result even though the precision is very +low the representation is excessively large. + +The mp\_clamp algorithm is designed to solve this very problem. It will trim leading zeros by decrementing the +\textbf{used} count until a non-zero leading digit is found. Also in this system, zero is considered to be a positive +number which means that if the \textbf{used} count is decremented to zero the sign must be set to \textbf{MP\_ZPOS}. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_clamp}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Any excess leading zero digits of $a$ are removed \\ +\hline \\ +1. while $a.used > 0$ and $a_{a.used - 1} = 0$ do \\ +\hspace{+3mm}1.1 $a.used \leftarrow a.used - 1$ \\ +2. if $a.used = 0$ then do \\ +\hspace{+3mm}2.1 $a.sign \leftarrow MP\_ZPOS$ \\ +\hline \\ +\end{tabular} +\end{center} +\caption{Algorithm mp\_clamp} +\end{figure} + +\textbf{Algorithm mp\_clamp.} +As can be expected this algorithm is very simple. The loop on step one is indended to be iterate only once or twice at +the most. For example, for cases where there is not a carry to fill the last position. Step two fixes the sign for +when all of the digits are zero to ensure that the mp\_int is valid at all times. + +EXAM,bn_mp_clamp.c + +Note on line @27,while@ how to test for the \textbf{used} count is made on the left of the \&\& operator. In the C programming +language the terms to \&\& are evaluated left to right with a boolean short-circuit if any condition fails. This is +important since if the \textbf{used} is zero the test on the right would fetch below the array. That is obviously +undesirable. The parenthesis on line @28,a->used@ is used to make sure the \textbf{used} count is decremented and not +the pointer ``a''. + +\section*{Exercises} +\begin{tabular}{cl} +$\left [ 1 \right ]$ & Discuss the relevance of the \textbf{used} member of the mp\_int structure. \\ + & \\ +$\left [ 1 \right ]$ & Discuss the consequences of not using padding when performing allocations. \\ + & \\ +$\left [ 2 \right ]$ & Estimate an ideal value for \textbf{MP\_PREC} when performing 1024-bit RSA \\ + & encryption when $\beta = 2^{28}$. \\ + & \\ +$\left [ 1 \right ]$ & Discuss the relevance of the algorithm mp\_clamp. What does it prevent? \\ + & \\ +$\left [ 1 \right ]$ & Give an example of when the algorithm mp\_init\_copy might be useful. \\ + & \\ +\end{tabular} + + +\chapter{Basic Operations} +\section{Copying an Integer} +After the various house-keeping routines are in place, simpl algorithms can be designed to take advantage of them. Being able +to make a verbatim copy of an integer is a very useful function to have. To copy an integer the mp\_copy algorithm will be used. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_copy}. \\ +\textbf{Input}. An mp\_int $a$ and $b$. \\ +\textbf{Output}. Store a copy of $a$ in $b$. \\ +\hline \\ +1. Check if $a$ and $b$ point to the same location in memory. \\ +2. If true then return(\textit{MP\_OKAY}). \\ +3. If $b.alloc < a.used$ then grow $b$ to $a.used$ digits. (\textit{hint: use mp\_grow}) \\ +4. If failed to grow then return(\textit{MP\_MEM}). \\ +5. for $n$ from 0 to $a.used - 1$ do \\ +\hspace{3mm}5.1 $b_{n} \leftarrow a_{n}$ \\ +6. if $a.used < b.used - 1$ then \\ +\hspace{3mm}6.1. for $n$ from $a.used$ to $b.used - 1$ do \\ +\hspace{6mm}6.1.1 $b_{n} \leftarrow 0$ \\ +7. $b.used \leftarrow a.used$ \\ +8. $b.sign \leftarrow a.sign$ \\ +9. return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_copy} +\end{figure} + +\textbf{Algorithm mp\_copy.} +Step 1 and 2 make sure that the two mp\_ints are unique. This allows the user to call the copy function with +potentially the same input and not waste time. Step 3 and 4 ensure that the destination is large enough to +hold a copy of the input $a$. Note that the \textbf{used} member of $b$ may be smaller than the \textbf{used} +member of $a$ but a memory re-allocation is only required if the \textbf{alloc} member of $b$ is smaller. This +prevents trivial memory reallocations. + +Step 5 copies the digits from $a$ to $b$ while step 6 ensures that if initially $\vert b \vert > \vert a \vert$, +the leading digits of $b$ will be zeroed. Finally steps 7 and 8 copies the \textbf{used} and \textbf{sign} members over +which completes the copy operation. + +EXAM,bn_mp_copy.c + +Source lines @23,if dst ==@-@31,}@ do the initial house keeping. That is to see if the input is unique and if so to +make sure there is enough room. If not enough space is available it returns the error and leaves the destination variable +intact. + +The inner loop of the copy operation is contained between lines @34,{@ and @50,}@. Many LibTomMath routines are designed with this source code style +in mind, making aliases to shorten lengthy pointers (\textit{see line @38,->@ and @39,->@}) for rapid to use. Also the +use of nested braces creates a simple way to denote various portions of code that reside on various work levels. Here, the copy loop is at the +$O(n)$ level. + +\section{Zeroing an Integer} +Reseting an mp\_int to the default state is a common step in many algorithms. The mp\_zero algorithm will be the algorithm used to +perform this task. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_zero}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Zero the contents of $a$ \\ +\hline \\ +1. $a.used \leftarrow 0$ \\ +2. $a.sign \leftarrow$ MP\_ZPOS \\ +3. for $n$ from 0 to $a.alloc - 1$ do \\ +\hspace{3mm}3.1 $a_n \leftarrow 0$ \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_zero} +\end{figure} + +\textbf{Algorithm mp\_zero.} +This algorithm simply resets a mp\_int to the default state. + +EXAM,bn_mp_zero.c + +After the function is completed, all of the digits are zeroed, the \textbf{used} count is zeroed and the +\textbf{sign} variable is set to \textbf{MP\_ZPOS}. + +\section{Sign Manipulation} +\subsection{Absolute Value} +With the mp\_int representation of an integer, calculating the absolute value is trivial. The mp\_abs algorithm will compute +the absolute value of an mp\_int. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_abs}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Computes $b = \vert a \vert$ \\ +\hline \\ +1. Copy $a$ to $b$. (\textit{hint: use mp\_copy}) \\ +2. If the copy failed return(\textit{MP\_MEM}). \\ +3. $b.sign \leftarrow MP\_ZPOS$ \\ +4. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_abs} +\end{figure} + +\textbf{Algorithm mp\_abs.} +This algorithm computes the absolute of an mp\_int input. As can be expected the algorithm is very trivial. + +EXAM,bn_mp_abs.c + +\subsection{Integer Negation} +With the mp\_int representation of an integer, calculating the negation is also trivial. The mp\_neg algorithm will compute +the negative of an mp\_int input. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_neg}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Computes $b = -a$ \\ +\hline \\ +1. Copy $a$ to $b$. (\textit{hint: use mp\_copy}) \\ +2. If the copy failed return(\textit{MP\_MEM}). \\ +3. If $a.sign = MP\_ZPOS$ then do \\ +\hspace{3mm}3.1 $b.sign = MP\_NEG$. \\ +4. else do \\ +\hspace{3mm}4.1 $b.sign = MP\_ZPOS$. \\ +5. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_neg} +\end{figure} + +\textbf{Algorithm mp\_neg.} +This algorithm computes the negation of an input. + +EXAM,bn_mp_neg.c + +\section{Small Constants} +\subsection{Setting Small Constants} +Often a mp\_int must be set to a relatively small value such as $1$ or $2$. For these cases the mp\_set algorithm is useful. + +\newpage\begin{figure} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_set}. \\ +\textbf{Input}. An mp\_int $a$ and a digit $b$ \\ +\textbf{Output}. Make $a$ equivalent to $b$ \\ +\hline \\ +1. Zero $a$ (\textit{hint: use mp\_zero}). \\ +2. $a_0 \leftarrow b \mbox{ (mod }\beta\mbox{)}$ \\ +3. $a.used \leftarrow \left \lbrace \begin{array}{ll} + 1 & \mbox{if }a_0 > 0 \\ + 0 & \mbox{if }a_0 = 0 + \end{array} \right .$ \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_set} +\end{figure} + +\textbf{Algorithm mp\_set.} +This algorithm sets a mp\_int to a small single digit value. Step number 1 ensures that the integer is reset to the default state. The +single digit is set (\textit{modulo $\beta$}) and the \textbf{used} count is adjusted accordingly. + +EXAM,bn_mp_set.c + +Line @21,mp_zero@ calls mp\_zero() to clear the mp\_int and reset the sign. Line @22,MP_MASK@ actually copies digit +into the least significant location. Note the usage of a new constant \textbf{MP\_MASK}. This constant is used to quickly +reduce an integer modulo $\beta$. Since $\beta = 2^k$ it suffices to perform a binary AND with $MP\_MASK = 2^k - 1$ to perform +the reduction. Finally line @23,a->used@ will set the \textbf{used} member with respect to the digit actually set. This function +will always make the integer positive. + +One important limitation of this function is that it will only set one digit. The size of a digit is not fixed, meaning source that uses +this function should take that into account. The define \textbf{DIGIT\_BIT} in ``tommath.h'' +defines how many bits per digit are available. Generally at least seven bits are guaranteed to be available per +digit. This means that trivially small constants can be set using this function. + +\subsection{Setting Large Constants} +To overcome the limitations of the mp\_set algorithm the mp\_set\_int algorithm is provided. It accepts a ``long'' +data type as input and will always treat it as a 32-bit integer. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_set\_int}. \\ +\textbf{Input}. An mp\_int $a$ and a ``long'' integer $b$ \\ +\textbf{Output}. Make $a$ equivalent to $b$ \\ +\hline \\ +1. Zero $a$ (\textit{hint: use mp\_zero}) \\ +2. for $n$ from 0 to 7 do \\ +\hspace{3mm}2.1 $a \leftarrow a \cdot 16$ (\textit{hint: use mp\_mul2d}) \\ +\hspace{3mm}2.2 $u \leftarrow \lfloor b / 2^{4(7 - n)} \rfloor \mbox{ (mod }16\mbox{)}$\\ +\hspace{3mm}2.3 $a_0 \leftarrow a_0 + u$ \\ +\hspace{3mm}2.4 $a.used \leftarrow a.used + \lfloor 32 / lg(\beta) \rfloor + 1$ \\ +3. Clamp excess used digits (\textit{hint: use mp\_clamp}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_set\_int} +\end{figure} + +\textbf{Algorithm mp\_set\_int.} +The algorithm performs eight iterations of a simple loop where in each iteration four bits from the source are added to the +mp\_int. Step 2.1 will multiply the current result by sixteen making room for four more bits. In step 2.2 the +next four bits from the source are extracted. The four bits are added to the mp\_int and the \textbf{used} digit count is +incremented. The \textbf{used} digit counter is incremented since if any of the leading digits were zero the mp\_int would have +zero digits used and the newly added four bits would be ignored. + +Excess zero digits are trimmed in steps 2.1 and 3 by using higher level algorithms mp\_mul2d and mp\_clamp. + +EXAM,bn_mp_set_int.c + +This function sets four bits of the number at a time to handle all practical \textbf{DIGIT\_BIT} sizes. The weird +addition on line @38,a->used@ ensures that the newly added in bits are added to the number of digits. While it may not +seem obvious as to why the digit counter does not grow exceedingly large it is because of the shift on line @27,mp_mul_2d@ +as well as the call to mp\_clamp() on line @40,mp_clamp@. Both functions will clamp excess leading digits which keeps +the number of used digits low. + +\section{Comparisons} +\subsection{Unsigned Comparisions} +Comparing a multiple precision integer is performed with the exact same algorithm used to compare two decimal numbers. For example, +to compare $1,234$ to $1,264$ the digits are extracted by their positions. That is we compare $1 \cdot 10^3 + 2 \cdot 10^2 + 3 \cdot 10^1 + 4 \cdot 10^0$ +to $1 \cdot 10^3 + 2 \cdot 10^2 + 6 \cdot 10^1 + 4 \cdot 10^0$ by comparing single digits at a time starting with the highest magnitude +positions. If any leading digit of one integer is greater than a digit in the same position of another integer then obviously it must be greater. + +The first comparision routine that will be developed is the unsigned magnitude compare which will perform a comparison based on the digits of two +mp\_int variables alone. It will ignore the sign of the two inputs. Such a function is useful when an absolute comparison is required or if the +signs are known to agree in advance. + +To facilitate working with the results of the comparison functions three constants are required. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{|r|l|} +\hline \textbf{Constant} & \textbf{Meaning} \\ +\hline \textbf{MP\_GT} & Greater Than \\ +\hline \textbf{MP\_EQ} & Equal To \\ +\hline \textbf{MP\_LT} & Less Than \\ +\hline +\end{tabular} +\end{center} +\caption{Comparison Return Codes} +\end{figure} + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_cmp\_mag}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$. \\ +\textbf{Output}. Unsigned comparison results ($a$ to the left of $b$). \\ +\hline \\ +1. If $a.used > b.used$ then return(\textit{MP\_GT}) \\ +2. If $a.used < b.used$ then return(\textit{MP\_LT}) \\ +3. for n from $a.used - 1$ to 0 do \\ +\hspace{+3mm}3.1 if $a_n > b_n$ then return(\textit{MP\_GT}) \\ +\hspace{+3mm}3.2 if $a_n < b_n$ then return(\textit{MP\_LT}) \\ +4. Return(\textit{MP\_EQ}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_cmp\_mag} +\end{figure} + +\textbf{Algorithm mp\_cmp\_mag.} +By saying ``$a$ to the left of $b$'' it is meant that the comparison is with respect to $a$, that is if $a$ is greater than $b$ it will return +\textbf{MP\_GT} and similar with respect to when $a = b$ and $a < b$. The first two steps compare the number of digits used in both $a$ and $b$. +Obviously if the digit counts differ there would be an imaginary zero digit in the smaller number where the leading digit of the larger number is. +If both have the same number of digits than the actual digits themselves must be compared starting at the leading digit. + +By step three both inputs must have the same number of digits so its safe to start from either $a.used - 1$ or $b.used - 1$ and count down to +the zero'th digit. If after all of the digits have been compared and no difference found the algorithm simply returns \textbf{MP\_EQ}. + +EXAM,bn_mp_cmp_mag.c + +The two if statements on lines @24,if@ and @28,if@ compare the number of digits in the two inputs. These two are performed before all of the digits +are compared since it is a very cheap test to perform and can potentially save considerable time. The implementation given is also not valid +without those two statements. $b.alloc$ may be smaller than $a.used$, meaning that undefined values will be read from $b$ passed the end of the +array of digits. + +\subsection{Signed Comparisons} +Comparing with sign considerations is also fairly critical in several routines (\textit{division for example}). Based on an unsigned magnitude +comparison a trivial signed comparison algorithm can be written. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_cmp}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. Signed Comparison Results ($a$ to the left of $b$) \\ +\hline \\ +1. if $a.sign = MP\_NEG$ and $b.sign = MP\_ZPOS$ then return(\textit{MP\_LT}) \\ +2. if $a.sign = MP\_ZPOS$ and $b.sign = MP\_NEG$ then return(\textit{MP\_GT}) \\ +3. if $a.sign = MP\_NEG$ then \\ +\hspace{+3mm}3.1 Return the unsigned comparison of $b$ and $a$ (\textit{hint: use mp\_cmp\_mag}) \\ +4 Otherwise \\ +\hspace{+3mm}4.1 Return the unsigned comparison of $a$ and $b$ \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_cmp} +\end{figure} + +\textbf{Algorithm mp\_cmp.} +The first two steps compare the signs of the two inputs. If the signs do not agree then it can return right away with the appropriate +comparison code. When the signs are equal the digits of the inputs must be compared to determine the correct result. In step +three the unsigned comparision flips the order of the arguments since they are both negative. For instance, if $-a > -b$ then +$\vert a \vert < \vert b \vert$. Step number four will compare the two when they are both positive. + +EXAM,bn_mp_cmp.c + +The two if statements on lines @22,if@ and @26,if@ perform the initial sign comparison. If the signs are not the equal then which ever +has the positive sign is larger. At line @30,if@, the inputs are compared based on magnitudes. If the signs were both negative then +the unsigned comparison is performed in the opposite direction (\textit{line @31,mp_cmp_mag@}). Otherwise, the signs are assumed to +be both positive and a forward direction unsigned comparison is performed. + +\section*{Exercises} +\begin{tabular}{cl} +$\left [ 2 \right ]$ & Modify algorithm mp\_set\_int to accept as input a variable length array of bits. \\ + & \\ +$\left [ 3 \right ]$ & Give the probability that algorithm mp\_cmp\_mag will have to compare $k$ digits \\ + & of two random digits (of equal magnitude) before a difference is found. \\ + & \\ +$\left [ 1 \right ]$ & Suggest a simple method to speed up the implementation of mp\_cmp\_mag based \\ + & on the observations made in the previous problem. \\ + & +\end{tabular} + +\chapter{Basic Arithmetic} +\section{Building Blocks} +At this point algorithms for initialization, de-initialization, zeroing, copying, comparing and setting small constants have been +established. The next logical set of algorithms to develop are the addition, subtraction and digit movement algorithms. These +algorithms make use of the lower level algorithms and are the cruicial building block for the multipliers. It is very important that these +algorithms are highly optimized. On their own they are simple $O(n)$ algorithms but they can be called from higher level algorithms +which easily places them at $O(n^2)$ or even $O(n^3)$ work levels. + +MARK,SHIFTS +All nine algorithms within this chapter make use of the logical bit shift operations denoted by $<<$ and $>>$ for left and right +logical shifts respectively. A logical shift is analogous to sliding the decimal point of radix-10 representations. For example, the real +number $0.9345$ is equivalent to $93.45\%$ which is found by sliding the the decimal two places to the right (\textit{multiplying by $10^2$}). +Mathematically a logical shift is equivalent to a division or multiplication by a power of two. +For example, $a << k = a \cdot 2^k$ while $a >> k = \lfloor a/2^k \rfloor$. + +One significant difference between a logical shift and the way decimals are shifted is that digits below the zero'th position are removed +from the number. For example, consider $1101_2 >> 1$ using decimal notation this would produce $110.1_2$. However, with a logical shift the +result is $110_2$. + +\section{Addition and Subtraction} +In normal fixed precision arithmetic negative numbers are easily represented by subtraction from the modulus. For example, with 32-bit integers +$a - b\mbox{ (mod }2^{32}\mbox{)}$ is the same as $a + (2^{32} - b) \mbox{ (mod }2^{32}\mbox{)}$ since $2^{32} \equiv 0 \mbox{ (mod }2^{32}\mbox{)}$. +As a result subtraction can be performed with a trivial series of logical operations and an addition. + +However, in multiple precision arithmetic negative numbers are not represented in the same way. Instead a sign flag is used to keep track of the +sign of the integer. As a result signed addition and subtraction are actually implemented as conditional usage of lower level addition or +subtraction algorithms with the sign fixed up appropriately. + +The lower level algorithms will add or subtract integers without regard to the sign flag. That is they will add or subtract the magnitude of +the integers respectively. + +\subsection{Low Level Addition} +An unsigned addition of multiple precision integers is performed with the same long-hand algorithm used to add decimal numbers. That is to add the +trailing digits first and propagate the resulting carry upwards. Since this is a lower level algorithm the name will have a ``s\_'' prefix. +Historically that convention stems from the MPI library where ``s\_'' stood for static functions that were hidden from the developer entirely. + +\newpage +\begin{figure}[!here] +\begin{center} +\begin{small} +\begin{tabular}{l} +\hline Algorithm \textbf{s\_mp\_add}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. The unsigned addition $c = \vert a \vert + \vert b \vert$. \\ +\hline \\ +1. if $a.used > b.used$ then \\ +\hspace{+3mm}1.1 $min \leftarrow b.used$ \\ +\hspace{+3mm}1.2 $max \leftarrow a.used$ \\ +\hspace{+3mm}1.3 $x \leftarrow a$ \\ +2. else \\ +\hspace{+3mm}2.1 $min \leftarrow a.used$ \\ +\hspace{+3mm}2.2 $max \leftarrow b.used$ \\ +\hspace{+3mm}2.3 $x \leftarrow b$ \\ +3. If $c.alloc < max + 1$ then grow $c$ to hold at least $max + 1$ digits (\textit{hint: use mp\_grow}) \\ +4. If failed to grow $c$ return(\textit{MP\_MEM}) \\ +5. $oldused \leftarrow c.used$ \\ +6. $c.used \leftarrow max + 1$ \\ +7. $u \leftarrow 0$ \\ +8. for $n$ from $0$ to $min - 1$ do \\ +\hspace{+3mm}8.1 $c_n \leftarrow a_n + b_n + u$ \\ +\hspace{+3mm}8.2 $u \leftarrow c_n >> lg(\beta)$ \\ +\hspace{+3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +9. if $min \ne max$ then do \\ +\hspace{+3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ +\hspace{+6mm}9.1.1 $c_n \leftarrow x_n + u$ \\ +\hspace{+6mm}9.1.2 $u \leftarrow c_n >> lg(\beta)$ \\ +\hspace{+6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +10. $c_{max} \leftarrow u$ \\ +11. if $olduse > max$ then \\ +\hspace{+3mm}11.1 for $n$ from $max + 1$ to $olduse - 1$ do \\ +\hspace{+6mm}11.1.1 $c_n \leftarrow 0$ \\ +12. Clamp excess digits in $c$. (\textit{hint: use mp\_clamp}) \\ +13. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Algorithm s\_mp\_add} +\end{figure} + +\textbf{Algorithm s\_mp\_add.} +This algorithm is loosely based on algorithm 14.7 of \cite[pp. 594]{HAC} but has been extended to allow the inputs to have different magnitudes. +Coincidentally the description of algorithm A in \cite[pp. 266]{TAOCPV2} shares the same flaw as that from \cite{HAC}. Even the MIX pseudo +machine code presented \cite[pp. 266-267]{TAOCPV2} is incapable of handling inputs which are of different magnitudes. + +Steps 1 and 2 will sort the two inputs based on their \textbf{used} digit count. This allows the inputs to have varying magnitudes which not +only makes it more efficient than the trivial algorithm presented in the other references but more flexible. The variable $min$ is given the lowest +digit count while $max$ is given the highest digit count. If both inputs have the same \textbf{used} digit count both $min$ and $max$ are +set to the same. The variable $x$ is an \textit{alias} for the largest input and not meant to be a copy of it. After the inputs are sorted steps +3 and 4 will ensure that the destination $c$ can accommodate the result. The old \textbf{used} count from $c$ is copied to $oldused$ and the +new count is set to $max + 1$. + +At step 7 the carry variable $u$ is set to zero and the first leg of the addition loop can begin. The first step of the loop (\textit{8.1}) adds +digits from the two inputs together along with the carry variable $u$. The following step extracts the carry bit by shifting the result of the +preceding step right $lg(\beta)$ positions. The shift to extract the carry is similar to how carry extraction works with decimal addition. + +Consider adding $77$ to $65$, the first addition of the first column is $7 + 5$ which produces the result $12$. The trailing digit of the result +is $2 \equiv 12 \mbox{ (mod }10\mbox{)}$ and the carry is found by dividing (\textit{and ignoring the remainder}) $12$ by the radix or in this case $10$. The +division and multiplication of $10$ is simply a logical shift right or left respectively of the digits. In otherwords the carry can be extracted +by shifting one digit to the right. + +Note that $lg()$ is simply the base two logarithm such that $lg(2^k) = k$. This implies that $lg(\beta)$ is the number of bits in a radix-$\beta$ +digit. Therefore, a logical shift right of the single digit by $lg(\beta)$ will extract the carry. The final step of the loop reduces the digit +modulo the radix $\beta$ to ensure it is in range. + +After step 8 the smallest input (\textit{or both if they are the same magnitude}) has been exhausted. Step 9 decides whether +the inputs were of equal magnitude. If not than another loop similar to that in step 8 must be executed. The loop at step +number 9.1 differs from the previous loop since it only adds the mp\_int $x$ along with the carry. + +Step 10 finishes the addition phase by copying the final carry to the highest location in the result $c_{max}$. Step 11 ensures that +leading digits that were originally present in $c$ are cleared. Finally excess leading digits are clamped and the algorithm returns success. + +EXAM,bn_s_mp_add.c + +Lines @27,if@ to @35,}@ perform the initial sorting of the inputs and determine the $min$ and $max$ variables. Note that $x$ is pointer to a +mp\_int assigned to the largest input, in effect it is a local alias. Lines @37,init@ to @42,}@ ensure that the destination is grown to +accomodate the result of the addition. + +Similar to the implementation of mp\_copy this function uses the braced code and local aliases coding style. The three aliases on +lines @56,tmpa@, @59,tmpb@ and @62,tmpc@ are the for the two inputs and destination respectively. These aliases are used to ensure the +compiler does not have to dereference $a$, $b$ or $c$ (respectively) to access the digits of the respective mp\_int. + +The initial carry $u$ is cleared on line @65,u = 0@, note that $u$ is of type mp\_digit which ensures type compatibility within the +implementation. The initial addition loop begins on line @66,for@ and ends on line @75,}@. Similarly the conditional addition loop +begins on line @81,for@ and ends on line @90,}@. The addition is finished with the final carry being stored in $tmpc$ on line @94,tmpc++@. +Note the ``++'' operator on the same line. After line @94,tmpc++@ $tmpc$ will point to the $c.used$'th digit of the mp\_int $c$. This is useful +for the next loop on lines @97,for@ to @99,}@ which set any old upper digits to zero. + +\subsection{Low Level Subtraction} +The low level unsigned subtraction algorithm is very similar to the low level unsigned addition algorithm. The principle difference is that the +unsigned subtraction algorithm requires the result to be positive. That is when computing $a - b$ the condition $\vert a \vert \ge \vert b\vert$ must +be met for this algorithm to function properly. Keep in mind this low level algorithm is not meant to be used in higher level algorithms directly. +This algorithm as will be shown can be used to create functional signed addition and subtraction algorithms. + +MARK,GAMMA + +For this algorithm a new variable is required to make the description simpler. Recall from section 1.3.1 that a mp\_digit must be able to represent +the range $0 \le x < 2\beta$. It is allowable that a mp\_digit represent a larger range of values. For this algorithm we will assume that +the variable $\gamma$ represents the number of bits available in a mp\_digit (\textit{this implies $2^{\gamma} > \beta$}). + +\newpage\begin{figure}[!here] +\begin{center} +\begin{small} +\begin{tabular}{l} +\hline Algorithm \textbf{s\_mp\_sub}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ ($\vert a \vert \ge \vert b \vert$) \\ +\textbf{Output}. The unsigned subtraction $c = \vert a \vert - \vert b \vert$. \\ +\hline \\ +1. $min \leftarrow b.used$ \\ +2. $max \leftarrow a.used$ \\ +3. If $c.alloc < max$ then grow $c$ to hold at least $max$ digits. (\textit{hint: use mp\_grow}) \\ +4. If the reallocation failed return(\textit{MP\_MEM}). \\ +5. $oldused \leftarrow c.used$ \\ +6. $c.used \leftarrow max$ \\ +7. $u \leftarrow 0$ \\ +8. for $n$ from $0$ to $min - 1$ do \\ +\hspace{3mm}8.1 $c_n \leftarrow a_n - b_n - u$ \\ +\hspace{3mm}8.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ +\hspace{3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +9. if $min < max$ then do \\ +\hspace{3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ +\hspace{6mm}9.1.1 $c_n \leftarrow a_n - u$ \\ +\hspace{6mm}9.1.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ +\hspace{6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +10. if $oldused > max$ then do \\ +\hspace{3mm}10.1 for $n$ from $max$ to $oldused - 1$ do \\ +\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ +11. Clamp excess digits of $c$. (\textit{hint: use mp\_clamp}). \\ +12. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Algorithm s\_mp\_sub} +\end{figure} + +\textbf{Algorithm s\_mp\_sub.} +This algorithm performs the unsigned subtraction of two mp\_int variables under the restriction that the result must be positive. That is when +passing variables $a$ and $b$ the condition that $\vert a \vert \ge \vert b \vert$ must be met for the algorithm to function correctly. This +algorithm is loosely based on algorithm 14.9 \cite[pp. 595]{HAC} and is similar to algorithm S in \cite[pp. 267]{TAOCPV2} as well. As was the case +of the algorithm s\_mp\_add both other references lack discussion concerning various practical details such as when the inputs differ in magnitude. + +The initial sorting of the inputs is trivial in this algorithm since $a$ is guaranteed to have at least the same magnitude of $b$. Steps 1 and 2 +set the $min$ and $max$ variables. Unlike the addition routine there is guaranteed to be no carry which means that the final result can be at +most $max$ digits in length as oppose to $max + 1$. Similar to the addition algorithm the \textbf{used} count of $c$ is copied locally and +set to the maximal count for the operation. + +The subtraction loop that begins on step 8 is essentially the same as the addition loop of algorithm s\_mp\_add except single precision +subtraction is used instead. Note the use of the $\gamma$ variable to extract the carry within the subtraction loops. Under the assumption +that two's complement single precision arithmetic is used this will successfully extract the carry. + +For example, consider subtracting $0101_2$ from +$0100_2$ where $\gamma = 4$. The least significant bit will force a carry upwards to the third bit which will be set to zero after the borrow. After +the very first bit has been subtracted $4 - 1 \equiv 0011_2$ will remain, When the third bit of $0101_2$ is subtracted from the result it will cause +another carry. In this case though the carry will be forced to propagate all the way to the most significant bit. + +Recall that $\beta < 2^{\gamma}$. This means that if a carry does occur it will propagate all the way to the most significant bit. Therefore a single +logical shift right by $\gamma - 1$ positions is sufficient to extract the carry. This method of carry extraction may seem awkward but the reason for +it becomes apparent when the implementation is discussed. + +If $b$ has a smaller magnitude than $a$ then step 9 will force the carry and copy operation to propagate through the larger input $a$ into $c$. Step +10 will ensure that any leading digits of $c$ above the $max$'th position are zeroed. + +EXAM,bn_s_mp_sub.c + +Line @24,min@ and @25,max@ perform the initial hardcoded sorting. In reality they are only aliases and are only used to make the source easier to +read. Again the pointer alias optimization is used within this algorithm. Lines @42,tmpa@, @43,tmpb@ and @44,tmpc@ initialize the aliases for +$a$, $b$ and $c$ respectively. + +The first subtraction loop occurs on lines @47,u = 0@ through @61,}@. The theory behind the subtraction loop is exactly the same as that for +the addition loop. As remarked earlier there is an implementation reason for using the ``awkward'' method of extracting the carry +(\textit{see line @57, >>@}). The traditional method for extracting the carry would be to shift by $lg(\beta)$ positions and logically AND +the least significant bit. The AND operation is required because all of the bits above the $\lg(\beta)$'th bit will be set to one after a carry +occurs from subtraction. This carry extraction requires two relatively cheap operations to extract the carry. The other method is to simply +shift the most significant bit to the least significant bit thus extracting the carry with a single cheap operation. This optimization only works on +twos compliment machines which is a safe assumption to make. + +If $a$ has a higher magnitude than $b$ an additional loop (\textit{see lines @64,for@ through @73,}@}) is required to propagate the carry through +$a$ and copy the result to $c$. + +\subsection{High Level Addition} +Now that both lower level addition and subtraction algorithms have been established an effective high level signed addition algorithm can be +established. This high level addition algorithm will be what other algorithms and developers will use to perform addition of mp\_int data +types. + +Recall from section 5.2 that an mp\_int represents an integer with an unsigned mantissa (\textit{the array of digits}) and a \textbf{sign} +flag. A high level addition is actually performed as a series of eight seperate cases which can be optimized down to three unique cases. + +\newpage\begin{figure}[!here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_add}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. The signed addition $c = a + b$. \\ +\hline \\ +1. if $a.sign = b.sign$ then do \\ +\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ +\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{hint: use s\_mp\_add})\\ +2. else do \\ +\hspace{3mm}2.1 if $\vert a \vert < \vert b \vert$ then do (\textit{hint: use mp\_cmp\_mag}) \\ +\hspace{6mm}2.1.1 $c.sign \leftarrow b.sign$ \\ +\hspace{6mm}2.1.2 $c \leftarrow \vert b \vert - \vert a \vert$ (\textit{hint: use s\_mp\_sub}) \\ +\hspace{3mm}2.2 else do \\ +\hspace{6mm}2.2.1 $c.sign \leftarrow a.sign$ \\ +\hspace{6mm}2.2.2 $c \leftarrow \vert a \vert - \vert b \vert$ \\ +3. If any of the lower level operations failed return(\textit{MP\_MEM}) \\ +4. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_add} +\end{figure} + +\textbf{Algorithm mp\_add.} +This algorithm performs the signed addition of two mp\_int variables. There is no reference algorithm to draw upon from either \cite{TAOCPV2} or +\cite{HAC} since they both only provide unsigned operations. The algorithm is fairly straightforward but restricted since subtraction can only +produce positive results. Consider the following chart of possible inputs. + +\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|c|c|} +\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert > \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ +\hline $+$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $+$ & $+$ & No & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $-$ & No & $c = a + b$ & $a.sign$ \\ +\hline &&&&\\ + +\hline $+$ & $-$ & No & $c = b - a$ & $b.sign$ \\ +\hline $-$ & $+$ & No & $c = b - a$ & $b.sign$ \\ + +\hline &&&&\\ + +\hline $+$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ +\hline $-$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ + +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Addition Guide Chart} +\end{figure} + +The chart lists all of the eight possible input combinations and is sorted to show that only three specific cases need to be handled. The +return code of the unsigned operations at step 1.2, 2.1.2 and 2.2.2 are forwarded to step 3 to check for errors. This simpliies the description +of the algorithm considerably and best follows how the implementation actually was achieved. + +Also note how the \textbf{sign} is set before the unsigned addition or subtraction is performed. Recall from the descriptions of algorithms +s\_mp\_add and s\_mp\_sub that the mp\_clamp function is used at the end to trim excess digits. The mp\_clamp algorithm will set the \textbf{sign} +to \textbf{MP\_ZPOS} when the \textbf{used} digit count reaches zero. + +For example, consider performing $-a + a$ with algorithm mp\_add. By the description of the algorithm the sign is set to \textbf{MP\_NEG} which would +produce a result of $-0$. However, since the sign is set first then the unsigned addition is performed the subsequent usage of algorithm mp\_clamp +within algorithm s\_mp\_add will force $-0$ to become $0$. + +EXAM,bn_mp_add.c + +The source code follows the algorithm fairly closely. The most notable new source code addition is the usage of the $res$ integer variable which +is used to pass result of the unsigned operations forward. Unlike in the algorithm, the variable $res$ is merely returned as is without +explicitly checking it and returning the constant \textbf{MP\_OKAY}. The observation is this algorithm will succeed or fail only if the lower +level functions do so. Returning their return code is sufficient. + +\subsection{High Level Subtraction} +The high level signed subtraction algorithm is essentially the same as the high level signed addition algorithm. + +\begin{figure}[!here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_sub}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. The signed subtraction $c = a - b$. \\ +\hline \\ +1. if $a.sign \ne b.sign$ then do \\ +\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ +\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{hint: use s\_mp\_add}) \\ +2. else do \\ +\hspace{3mm}2.1 if $\vert a \vert \ge \vert b \vert$ then do (\textit{hint: use mp\_cmp\_mag}) \\ +\hspace{6mm}2.1.1 $c.sign \leftarrow a.sign$ \\ +\hspace{6mm}2.1.2 $c \leftarrow \vert a \vert - \vert b \vert$ (\textit{hint: use s\_mp\_sub}) \\ +\hspace{3mm}2.2 else do \\ +\hspace{6mm}2.2.1 $c.sign \leftarrow \left \lbrace \begin{array}{ll} + MP\_ZPOS & \mbox{if }a.sign = MP\_NEG \\ + MP\_NEG & \mbox{otherwise} \\ + \end{array} \right .$ \\ +\hspace{6mm}2.2.2 $c \leftarrow \vert b \vert - \vert a \vert$ \\ +3. If any of the lower level operations failed return(\textit{MP\_MEM}). \\ +4. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_sub} +\end{figure} + +\textbf{Algorithm mp\_sub.} +This algorithm performs the signed subtraction of two inputs. Similar to algorithm mp\_add there is no reference in either \cite{TAOCPV2} or +\cite{HAC}. Also this algorithm is restricted by algorithm s\_mp\_sub. The following chart lists the eight possible inputs and +the operations required. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|c|c|} +\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert \ge \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ +\hline $+$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $+$ & $-$ & No & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $+$ & No & $c = a + b$ & $a.sign$ \\ +\hline &&&& \\ +\hline $+$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ +\hline $-$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ +\hline &&&& \\ +\hline $+$ & $+$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ +\hline $-$ & $-$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Subtraction Guide Chart} +\end{figure} + +Similar to the case of algorithm mp\_add the \textbf{sign} is set first before the unsigned addition or subtraction. That is to prevent the +algorithm from producing $-a - -a = -0$ as a result. + +EXAM,bn_mp_sub.c + +Much like the implementation of algorithm mp\_add the variable $res$ is used to catch the return code of the unsigned addition or subtraction operations +and forward it to the end of the function. On line @38, != MP_LT@ the ``not equal to'' \textbf{MP\_LT} expression is used to emulate a +``greater than or equal to'' comparison. + +\section{Bit and Digit Shifting} +MARK,POLY +It is quite common to think of a multiple precision integer as a polynomial in $x$, that is $y = f(\beta)$ where $f(x) = \sum_{i=0}^{n-1} a_i x^i$. +This notation arises within discussion of Montgomery and Diminished Radix Reduction as well as Karatsuba multiplication and squaring. + +In order to facilitate operations on polynomials in $x$ as above a series of simple ``digit'' algorithms have to be established. That is to shift +the digits left or right as well to shift individual bits of the digits left and right. It is important to note that not all ``shift'' operations +are on radix-$\beta$ digits. + +\subsection{Multiplication by Two} + +In a binary system where the radix is a power of two multiplication by two not only arises often in other algorithms it is a fairly efficient +operation to perform. A single precision logical shift left is sufficient to multiply a single digit by two. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_mul\_2}. \\ +\textbf{Input}. One mp\_int $a$ \\ +\textbf{Output}. $b = 2a$. \\ +\hline \\ +1. If $b.alloc < a.used + 1$ then grow $b$ to hold $a.used + 1$ digits. (\textit{hint: use mp\_grow}) \\ +2. If the reallocation failed return(\textit{MP\_MEM}). \\ +3. $oldused \leftarrow b.used$ \\ +4. $b.used \leftarrow a.used$ \\ +5. $r \leftarrow 0$ \\ +6. for $n$ from 0 to $a.used - 1$ do \\ +\hspace{3mm}6.1 $rr \leftarrow a_n >> (lg(\beta) - 1)$ \\ +\hspace{3mm}6.2 $b_n \leftarrow (a_n << 1) + r \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{3mm}6.3 $r \leftarrow rr$ \\ +7. If $r \ne 0$ then do \\ +\hspace{3mm}7.1 $b_{a.used} = 1$ \\ +\hspace{3mm}7.2 $b.used \leftarrow b.used + 1$ \\ +8. If $b.used < oldused - 1$ then do \\ +\hspace{3mm}8.1 for $n$ from $b.used$ to $oldused - 1$ do \\ +\hspace{6mm}8.1.1 $b_n \leftarrow 0$ \\ +9. $b.sign \leftarrow a.sign$ \\ +10. Return(\textit{MP\_OKAY}).\\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_mul\_2} +\end{figure} + +\textbf{Algorithm mp\_mul\_2.} +This algorithm will quickly multiply a mp\_int by two provided $\beta$ is a power of two. Neither \cite{TAOCPV2} nor \cite{HAC} describe such +an algorithm despite the fact it arises often in other algorithms. The algorithm is setup much like the lower level algorithm s\_mp\_add since +it is for all intents and purposes equivalent to the operation $b = \vert a \vert + \vert a \vert$. + +Step 1 and 2 grow the input as required to accomodate the maximum number of \textbf{used} digits in the result. The initial \textbf{used} count +is set to $a.used$ at step 4. Only if there is a final carry will the \textbf{used} count require adjustment. + +Step 6 is an optimization implementation of the addition loop for this specific case. That is since the two values being added together +are the same there is no need to perform two reads from the digits of $a$. Step 6.1 performs a single precision shift on the current digit $a_n$ to +obtain what will be the carry for the next iteration. Step 6.2 calculates the $n$'th digit of the result as single precision shift of $a_n$ plus +the previous carry. Recall from ~SHIFTS~ that $a_n << 1$ is equivalent to $a_n \cdot 2$. An iteration of the addition loop is finished with +forwarding the carry to the next iteration. + +Step 7 takes care of any final carry by setting the $a.used$'th digit of the result to one and augmenting the \textbf{used} count. Step 8 clears +any original leading digits of $b$. + +EXAM,bn_mp_mul_2.c + +This implementation is essentially an optimized implementation of s\_mp\_add for the case of doubling an input. The only noteworthy difference +is the use of the logical shift operator on line @52,<<@ to perform a single precision doubling. + +\subsection{Division by Two} +A division by two can just as easily be accomplished with a logical shift right as multiplication by two can be with a logical shift left. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_div\_2}. \\ +\textbf{Input}. One mp\_int $a$ \\ +\textbf{Output}. $b = a/2$. \\ +\hline \\ +1. If $b.alloc < a.used$ then grow $b$ to hold $a.used$ digits. (\textit{hint: use mp\_grow}) \\ +2. If the reallocation failed return(\textit{MP\_MEM}). \\ +3. $oldused \leftarrow b.used$ \\ +4. $b.used \leftarrow a.used$ \\ +5. $r \leftarrow 0$ \\ +6. for $n$ from $b.used - 1$ to $0$ do \\ +\hspace{3mm}6.1 $rr \leftarrow a_n \mbox{ (mod }2\mbox{)}$\\ +\hspace{3mm}6.2 $b_n \leftarrow (a_n >> 1) + (r << (lg(\beta) - 1)) \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{3mm}6.3 $r \leftarrow rr$ \\ +7. If $b.used < oldused - 1$ then do \\ +\hspace{3mm}7.1 for $n$ from $b.used$ to $oldused - 1$ do \\ +\hspace{6mm}7.1.1 $b_n \leftarrow 0$ \\ +8. $b.sign \leftarrow a.sign$ \\ +9. Return(\textit{MP\_OKAY}).\\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_div\_2} +\end{figure} + +\textbf{Algorithm mp\_div\_2.} +This algorithm will divide an mp\_int by two using logical shifts to the right. Like mp\_mul\_2 it uses a modified low level addition +core as the basis of the algorithm. Unlike mp\_mul\_2 the shift operations work from the leading digit to the trailing digit. The algorithm +could be written to work from the trailing digit to the leading digit however, it would have to stop one short of $a.used - 1$ digits to prevent +reading passed the end of the array of digits. + +Essentially the loop at step 6 is similar to that of mp\_mul\_2 except the logical shifts go in the opposite direction and the carry is at the +least significant bit not the most significant bit. + +EXAM,bn_mp_div_2.c + +\section{Polynomial Basis Operations} +Recall from ~POLY~ that any integer can be represented as a polynomial in $x$ as $y = f(\beta)$. Such a representation is also known as +the polynomial basis \cite[pp. 48]{ROSE}. Given such a notation a multiplication or division by $x$ amounts to shifting whole digits a single +place. The need for such operations arises in several other higher level algorithms such as Barrett and Montgomery reduction, integer +division and Karatsuba multiplication. + +Converting from an array of digits to polynomial basis is very simple. Consider the integer $y \equiv (a_2, a_1, a_0)_{\beta}$ and recall that +$y = \sum_{i=0}^{2} a_i \beta^i$. Simply replace $\beta$ with $x$ and the expression is in polynomial basis. For example, $f(x) = 8x + 9$ is the +polynomial basis representation for $89$ using radix ten. That is, $f(10) = 8(10) + 9 = 89$. + +\subsection{Multiplication by $x$} + +Given a polynomial in $x$ such as $f(x) = a_n x^n + a_{n-1} x^{n-1} + ... + a_0$ multiplying by $x$ amounts to shifting the coefficients up one +degree. In this case $f(x) \cdot x = a_n x^{n+1} + a_{n-1} x^n + ... + a_0 x$. From a scalar basis point of view multiplying by $x$ is equivalent to +multiplying by the integer $\beta$. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_lshd}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $a \leftarrow a \cdot \beta^b$ (Multiply by $x^b$). \\ +\hline \\ +1. If $b \le 0$ then return(\textit{MP\_OKAY}). \\ +2. If $a.alloc < a.used + b$ then grow $a$ to at least $a.used + b$ digits. (\textit{hint: use mp\_grow}). \\ +3. If the reallocation failed return(\textit{MP\_MEM}). \\ +4. $a.used \leftarrow a.used + b$ \\ +5. $i \leftarrow a.used - 1$ \\ +6. $j \leftarrow a.used - 1 - b$ \\ +7. for $n$ from $a.used - 1$ to $b$ do \\ +\hspace{3mm}7.1 $a_{i} \leftarrow a_{j}$ \\ +\hspace{3mm}7.2 $i \leftarrow i - 1$ \\ +\hspace{3mm}7.3 $j \leftarrow j - 1$ \\ +8. for $n$ from 0 to $b - 1$ do \\ +\hspace{3mm}8.1 $a_n \leftarrow 0$ \\ +9. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_lshd} +\end{figure} + +\textbf{Algorithm mp\_lshd.} +This algorithm multiplies an mp\_int by the $b$'th power of $x$. This is equivalent to multiplying by $\beta^b$. The algorithm differs +from the other algorithms presented so far as it performs the operation in place instead storing the result in a seperate location. The algorithm +will return success immediately if $b \le 0$ since the rest of algorithm is only valid when $b > 0$. + +First the destination $a$ is grown as required to accomodate the result. The counters $i$ and $j$ are used to form a \textit{sliding window} over +the digits of $a$ of length $b$. The head of the sliding window is at $i$ (\textit{the leading digit}) and the tail at $j$ (\textit{the trailing digit}). +The loop on step 7 copies the digit from the tail to the head. In each iteration the window is moved down one digit. The last loop on +step 8 sets the lower $b$ digits to zero. + +\newpage +FIGU,sliding_window,Sliding Window Movement + +EXAM,bn_mp_lshd.c + +The if statement on line @24,if@ ensures that the $b$ variable is greater than zero. The \textbf{used} count is incremented by $b$ before +the copy loop begins. This elminates the need for an additional variable in the for loop. The variable $tmpa$ on line @42,tmpa@ is an alias +for the leading digit while $tmpaa$ on line @45,tmpaa@ is an alias for the trailing edge. The aliases form a window of exactly $b$ digits +over the input. + +\subsection{Division by $x$} + +Division by powers of $x$ is easily achieved by shifting the digits right and removing any that will end up to the right of the zero'th digit. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_rshd}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $a \leftarrow a / \beta^b$ (Divide by $x^b$). \\ +\hline \\ +1. If $b \le 0$ then return. \\ +2. If $a.used \le b$ then do \\ +\hspace{3mm}2.1 Zero $a$. (\textit{hint: use mp\_zero}). \\ +\hspace{3mm}2.2 Return. \\ +3. $i \leftarrow 0$ \\ +4. $j \leftarrow b$ \\ +5. for $n$ from 0 to $a.used - b - 1$ do \\ +\hspace{3mm}5.1 $a_i \leftarrow a_j$ \\ +\hspace{3mm}5.2 $i \leftarrow i + 1$ \\ +\hspace{3mm}5.3 $j \leftarrow j + 1$ \\ +6. for $n$ from $a.used - b$ to $a.used - 1$ do \\ +\hspace{3mm}6.1 $a_n \leftarrow 0$ \\ +7. Clamp excess digits. (\textit{hint: use mp\_clamp}). \\ +8. Return. \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_rshd} +\end{figure} + +\textbf{Algorithm mp\_rshd.} +This algorithm divides the input in place by the $b$'th power of $x$. It is analogous to dividing by a $\beta^b$ but much quicker since +it does not require single precision division. This algorithm does not actually return an error code as it cannot fail. + +If the input $b$ is less than one the algorithm quickly returns without performing any work. If the \textbf{used} count is less than or equal +to the shift count $b$ then it will simply zero the input and return. + +After the trivial cases of inputs have been handled the sliding window is setup. Much like the case of algorithm mp\_lshd a sliding window that +is $b$ digits wide is used to copy the digits. Unlike mp\_lshd the window slides in the opposite direction from the trailing to the leading digit. +Also the digits are copied from the leading to the trailing edge. + +Once the window copy is complete the upper digits must be zeroed. Finally algorithm mp\_clamp is used to trim excess digits. + +EXAM,bn_mp_rshd.c + +The only noteworthy element of this routine is the lack of a return type. This function cannot fail and as such it is more optimal to not +return anything. + +\section{Powers of Two} + +Now that algorithms for moving single bits as well as whole digits exist algorithms for moving the ``in between'' distances are required. For +example, to quickly multiply by $2^k$ for any $k$ without using a full multiplier algorithm would prove useful. Instead of performing single +shifts $k$ times to achieve a multiplication by $2^{\pm k}$ a mixture of whole digit shifting and partial digit shifting is employed. + +\subsection{Multiplication by Power of Two} + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_mul\_2d}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $c \leftarrow a \cdot 2^b$. \\ +\hline \\ +1. $c \leftarrow a$. (\textit{hint: use mp\_copy}) \\ +2. If $c.alloc < c.used + \lfloor b / lg(\beta) \rfloor + 2$ then grow $c$ accordingly. \\ +3. If the reallocation failed return(\textit{MP\_MEM}). \\ +4. If $b \ge lg(\beta)$ then \\ +\hspace{3mm}4.1 $c \leftarrow c \cdot \beta^{\lfloor b / lg(\beta) \rfloor}$ (\textit{hint: use mp\_lshd}). \\ +\hspace{3mm}4.2 If step 4.1 failed return(\textit{MP\_MEM}). \\ +5. $d \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ +6. If $d \ne 0$ then do \\ +\hspace{3mm}6.1 $mask \leftarrow 2^d$ \\ +\hspace{3mm}6.2 $r \leftarrow 0$ \\ +\hspace{3mm}6.3 for $n$ from $0$ to $c.used - 1$ do \\ +\hspace{6mm}6.3.1 $rr \leftarrow c_n >> (lg(\beta) - d) \mbox{ (mod }mask\mbox{)}$ \\ +\hspace{6mm}6.3.2 $c_n \leftarrow (c_n << d) + r \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ +\hspace{3mm}6.4 If $r > 0$ then do \\ +\hspace{6mm}6.4.1 $c_{c.used} \leftarrow r$ \\ +\hspace{6mm}6.4.2 $c.used \leftarrow c.used + 1$ \\ +7. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_mul\_2d} +\end{figure} + +\textbf{Algorithm mp\_mul\_2d.} +This algorithm multiplies $a$ by $2^b$ and stores the result in $c$. The algorithm uses algorithm mp\_lshd and a derivative of algorithm mp\_mul\_2 to +quickly compute the product. + +First the algorithm will multiply $a$ by $x^{\lfloor b / lg(\beta) \rfloor}$ which will ensure that the remainder multiplicand is less than +$\beta$. For example, if $b = 37$ and $\beta = 2^{28}$ then this step will multiply by $x$ leaving a multiplication by $2^{37 - 28} = 2^{9}$ +left. + +The logarithm of the residue is calculated on step 5. If it is non-zero a modified shift loop is used to calculate the remaining product. +Essentially the loop is a generic version of algorith mp\_mul2 designed to handle any shift count in the range $1 \le x < lg(\beta)$. The $mask$ +variable is used to extract the upper $d$ bits to form the carry for the next iteration. + +This algorithm is loosely measured as a $O(2n)$ algorithm which means that if the input is $n$-digits that it takes $2n$ ``time'' to +complete. It is possible to optimize this algorithm down to a $O(n)$ algorithm at a cost of making the algorithm slightly harder to follow. + +EXAM,bn_mp_mul_2d.c + +Notes to be revised when code is updated. -- Tom + +\subsection{Division by Power of Two} + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_div\_2d}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $c \leftarrow \lfloor a / 2^b \rfloor, d \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ +\hline \\ +1. If $b \le 0$ then do \\ +\hspace{3mm}1.1 $c \leftarrow a$ (\textit{hint: use mp\_copy}) \\ +\hspace{3mm}1.2 $d \leftarrow 0$ (\textit{hint: use mp\_zero}) \\ +\hspace{3mm}1.3 Return(\textit{MP\_OKAY}). \\ +2. $c \leftarrow a$ \\ +3. $d \leftarrow a \mbox{ (mod }2^b\mbox{)}$ (\textit{hint: use mp\_mod\_2d}) \\ +4. If $b \ge lg(\beta)$ then do \\ +\hspace{3mm}4.1 $c \leftarrow \lfloor c/\beta^{\lfloor b/lg(\beta) \rfloor} \rfloor$ (\textit{hint: use mp\_rshd}). \\ +5. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ +6. If $k \ne 0$ then do \\ +\hspace{3mm}6.1 $mask \leftarrow 2^k$ \\ +\hspace{3mm}6.2 $r \leftarrow 0$ \\ +\hspace{3mm}6.3 for $n$ from $c.used - 1$ to $0$ do \\ +\hspace{6mm}6.3.1 $rr \leftarrow c_n \mbox{ (mod }mask\mbox{)}$ \\ +\hspace{6mm}6.3.2 $c_n \leftarrow (c_n >> k) + (r << (lg(\beta) - k))$ \\ +\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ +7. Clamp excess digits of $c$. (\textit{hint: use mp\_clamp}) \\ +8. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_div\_2d} +\end{figure} + +\textbf{Algorithm mp\_div\_2d.} +This algorithm will divide an input $a$ by $2^b$ and produce the quotient and remainder. The algorithm is designed much like algorithm +mp\_mul\_2d by first using whole digit shifts then single precision shifts. This algorithm will also produce the remainder of the division +by using algorithm mp\_mod\_2d. + +EXAM,bn_mp_div_2d.c + +The implementation of algorithm mp\_div\_2d is slightly different than the algorithm specifies. The remainder $d$ may be optionally +ignored by passing \textbf{NULL} as the pointer to the mp\_int variable. The temporary mp\_int variable $t$ is used to hold the +result of the remainder operation until the end. This allows $d = a$ to be true without overwriting the input before they are no longer required. + +The remainder of the source code is essentially the same as the source code for mp\_mul\_2d. (-- Fix this paragraph up later, Tom). + +\subsection{Remainder of Division by Power of Two} + +The last algorithm in the series of polynomial basis power of two algorithms is calculating the remainder of division by $2^b$. This +algorithm benefits from the fact that in twos complement arithmetic $a \mbox{ (mod }2^b\mbox{)}$ is the same as $a$ AND $2^b - 1$. + +\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_mod\_2d}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $c \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ +\hline \\ +1. If $b \le 0$ then do \\ +\hspace{3mm}1.1 $c \leftarrow 0$ (\textit{hint: use mp\_zero}) \\ +\hspace{3mm}1.2 Return(\textit{MP\_OKAY}). \\ +2. If $b > a.used \cdot lg(\beta)$ then do \\ +\hspace{3mm}2.1 $c \leftarrow a$ (\textit{hint: use mp\_copy}) \\ +\hspace{3mm}2.2 Return the result of step 2.1. \\ +3. $c \leftarrow a$ \\ +4. If step 3 failed return(\textit{MP\_MEM}). \\ +5. for $n$ from $\lceil b / lg(\beta) \rceil$ to $c.used$ do \\ +\hspace{3mm}5.1 $c_n \leftarrow 0$ \\ +6. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ +7. $c_{\lfloor b / lg(\beta) \rfloor} \leftarrow c_{\lfloor b / lg(\beta) \rfloor} \mbox{ (mod }2^{k}\mbox{)}$. \\ +8. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_mod\_2d} +\end{figure} + +\textbf{Algorithm mp\_mod\_2d.} +This algorithm will quickly calculate the value of $a \mbox{ (mod }2^b\mbox{)}$. First if $b$ is less than or equal to zero the +result is set to zero. If $b$ is greater than the number of bits in $a$ then it simply copies $a$ to $c$ and returns. Otherwise, $a$ +is copied to $b$, leading digits are removed and the remaining leading digit is trimed to the exact bit count. + +EXAM,bn_mp_mod_2d.c + +-- Add comments later, Tom. + +\section*{Exercises} +\begin{tabular}{cl} +$\left [ 3 \right ] $ & Devise an algorithm that performs $a \cdot 2^b$ for generic values of $b$ \\ + & in $O(n)$ time. \\ + &\\ +$\left [ 3 \right ] $ & Devise an efficient algorithm to multiply by small low hamming \\ + & weight values such as $3$, $5$ and $9$. Extend it to handle all values \\ + & upto $64$ with a hamming weight less than three. \\ + &\\ +$\left [ 2 \right ] $ & Modify the preceding algorithm to handle values of the form \\ + & $2^k - 1$ as well. \\ + &\\ +$\left [ 3 \right ] $ & Using only algorithms mp\_mul\_2, mp\_div\_2 and mp\_add create an \\ + & algorithm to multiply two integers in roughly $O(2n^2)$ time for \\ + & any $n$-bit input. Note that the time of addition is ignored in the \\ + & calculation. \\ + & \\ +$\left [ 5 \right ] $ & Improve the previous algorithm to have a working time of at most \\ + & $O \left (2^{(k-1)}n + \left ({2n^2 \over k} \right ) \right )$ for an appropriate choice of $k$. Again ignore \\ + & the cost of addition. \\ + & \\ +$\left [ 1 \right ] $ & There exists an improvement on the previous algorithm to \\ + & slightly reduce the number of additions required. Modify the \\ + & previous algorithm to include this improvement. \\ + & \\ +$\left [ 2 \right ] $ & Devise a chart to find optimal values of $k$ for the previous problem \\ + & for $n = 64 \ldots 1024$ in steps of $64$. \\ + & \\ +$\left [ 2 \right ] $ & Using only algorithms mp\_abs and mp\_sub devise another method for \\ + & calculating the result of a signed comparison. \\ + & +\end{tabular} + +\chapter{Multiplication and Squaring} +\section{The Multipliers} +For most number theoretic systems including public key cryptographic algorithms the set of algorithms collectively known as the +``multipliers'' form the most important subset of algorithms of any multiple precision integer package. The set of multipliers +include multiplication, squaring and modular reduction algorithms. + +The importance of these algorithms is driven by the fact that most popular public key algorithms are based on modular +exponentiation. That is performing $d \equiv a^b \mbox{ (mod }c\mbox{)}$ for some arbitrary choice of $a$, $b$, $c$ and $d$. Roughly +speaking the a modular exponentiation will spend about 40\% of the time in modular reductions, 35\% of the time in squaring and 25\% of +the time in multiplications. Only a small trivial amount of time is spent on lower level algorithms such as mp\_clamp, mp\_init, etc... + +This chapter will discuss only two of the multipliers algorithms, multiplication and squaring. As will be discussed shortly very efficient +multiplier algorithms are not always straightforward and deserve a lot of attention. + +\section{Multiplication} +\subsection{The Baseline Multiplication} +\index{baseline multiplication} +Computing the product of two integers in software can be achieved using a trivial adaptation of the standard $O(n^2)$ long-hand multiplication +algorithm school children are taught. The ``baseline multiplication'' algorithm is designed to act as the ``catch-all'' algorithm only called +when the faster algorithms cannot be used. This algorithm does not use any particularly interesting optimizations. + +The first algorithm to review is the unsigned multiplication algorithm from which a signed multiplication algorithm can be established. One important +facet of this algorithm to note is that it has been modified to only produce a certain amount of output digits as resolution. Recall that for +a $n$ and $m$ digit input the product will be at most $n + m + 1$ digits. Therefore, this algorithm can be reduced to a full multiplier by +telling it to produce $n + m + 1$ digits. + +Recall from ~GAMMA~ the definition of $\gamma$ as the number of bits in the type \textbf{mp\_digit}. We shall now extend this variable set to +include $\alpha$ which shall represent the number of bits in the type \textbf{mp\_word}. This implies that $2^{\alpha} > 2 \cdot \beta^2$. The +constant $\delta = 2^{\alpha - 2lg(\beta)}$ will represent the maximal weight of any column in a product (\textit{see ~COMBA~ for more information}). + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{s\_mp\_mul\_digs}. \\ +\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ +\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ +\hline \\ +1. If min$(a.used, b.used) < \delta$ then do \\ +\hspace{3mm}1.1 Calculate $c = \vert a \vert \cdot \vert b \vert$ by the Comba method. \\ +\hspace{3mm}1.2 Return the result of step 1.1 \\ +\\ +Allocate and initialize a temporary mp\_int. \\ +2. Init $t$ to be of size $digs$ \\ +3. If step 2 failed return(\textit{MP\_MEM}). \\ +4. $t.used \leftarrow digs$ \\ +\\ +Compute the product. \\ +5. for $ix$ from $0$ to $a.used - 1$ do \\ +\hspace{3mm}5.1 $u \leftarrow 0$ \\ +\hspace{3mm}5.2 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ +\hspace{3mm}5.3 If $pb < 1$ then goto step 6. \\ +\hspace{3mm}5.4 for $iy$ from $0$ to $pb - 1$ do \\ +\hspace{6mm}5.4.1 $\hat r \leftarrow t_{iy + ix} + a_{ix} \cdot b_{iy} + u$ \\ +\hspace{6mm}5.4.2 $t_{iy + ix} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{6mm}5.4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ +\hspace{3mm}5.5 if $ix + iy < digs$ then do \\ +\hspace{6mm}5.5.1 $t_{ix + pb} \leftarrow u$ \\ +6. Clamp excess digits of $t$. \\ +7. Swap $c$ with $t$ \\ +8. Clear $t$ \\ +9. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm s\_mp\_mul\_digs} +\end{figure} + +\textbf{Algorithm s\_mp\_mul\_digs.} +This algorithm computes the unsigned product of two inputs $a$ and $c$ limited to an output precision of $digs$ digits. While it may seem +a bit awkward to modify the function from its simple $O(n^2)$ description the usefulness of partial multipliers will arise in a future +algorithm. The algorithm is loosely based on algorithm 14.12 from \cite[pp. 595]{HAC} and is similar to Algorithm M \cite[pp. 268]{TAOCPV2}. The +algorithm differs from those cited references because it can produce a variable output precision regardless of the precision of the inputs. + +The first thing this algorithm checks for is whether a Comba multiplier can be used instead. That is if the minimal digit count of either +input is less than $\delta$ the Comba method is used. After the Comba method is ruled out the baseline algorithm begins. A +temporary mp\_int variable $t$ is used to hold the intermediate result of the product. This allows the algorithm to be used to +compute products when either $a = c$ or $b = c$ without overwriting the inputs. + +All of step 5 is the infamous $O(n^2)$ multiplication loop slightly modified to only produce upto $digs$ digits of output. The $pb$ variable +is given the count of digits to read from $b$ inside the nested loop. If $pb < 0$ then no more output digits can be produced and the algorithm +will exit the loop. The best way to think of the loops are as a series of $pb \times 1$ multiplication. That is, in each pass of the +innermost loop $a_{ix}$ is multiplied against $b$ and the result is added (\textit{with an appropriate shift}) to $t$. + +For example, consider multiplying $576$ by $241$. That is equivalent to computing $10^0(1)(576) + 10^1(4)(576) + 10^2(2)(576)$ which is best +visualized as the following table. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{|c|c|c|c|c|c|c|} +\hline && & 5 & 7 & 6 & \\ +\hline $\times$&& & 2 & 4 & 1 & \\ +\hline &&&&&&\\ + && & 5 & 7 & 6 & $10^0(1)(576)$ \\ + &2 & 3 & 0 & 4 & 0 & $10^1(4)(576)$ \\ + 1 & 1 & 5 & 2 & 0 & 0 & $10^2(2)(576)$ \\ +\hline +\end{tabular} +\end{center} +\caption{Long-Hand Multiplication Diagram} +\end{figure} + +Each row of the product is added to the result after being shifted to the left (\textit{multiplied by a power of the radix}) by the appropriate +count. That is in pass $ix$ of the inner loop the product is added starting at the $ix$'th digit of the reult. + +Step 5.4.1 introduces the hat symbol (\textit{e.g. $\hat x$}) which represents a double precision variable. The multiplication on that step +is assumed to be a double wide output single precision multiplication. That is, two single precision variables are multiplied to produce a +double precision result. The step is somewhat optimized from a long-hand multiplication algorithm because the carry from the addition in step +5.4.1 is forwarded through the nested loop. If the carry was ignored it would overflow the single precision digit $t_{ix+iy}$ and the result +would be lost. + +At step 5.5 the nested loop is finished and any carry that was left over should be forwarded. That is provided $ix + iy < digs$ otherwise the +carry is ignored since it will not be part of the result anyways. + +EXAM,bn_s_mp_mul_digs.c + +Lines @31,if@ to @35,}@ determine if the Comba method can be used first. The conditions for using the Comba routine are that min$(a.used, b.used) < \delta$ and +the number of digits of output is less than \textbf{MP\_WARRAY}. This new constant is used to control the stack usage in the Comba routines. By +default it is set to $\delta$ but can be reduced when memory is at a premium. + +Of particular importance is the calculation of the $ix+iy$'th column on lines @64,mp_word@, @65,mp_word@ and @66,mp_word@. Note how all of the +variables are cast to the type \textbf{mp\_word}. That is to ensure that double precision operations are used instead of single precision. The +multiplication on line @65,) * (@ is a bit of a GCC optimization. On the outset it looks like the compiler will have to use a double precision +multiplication to produce the result required. Such an operation would be horribly slow on most processors and drag this to a crawl. However, +GCC is smart enough to realize that double wide output single precision multipliers can be used. For example, the instruction ``MUL'' on the +x86 processor can multiply two 32-bit values and produce a 64-bit result. + +\subsection{Faster Multiplication by the ``Comba'' Method} +MARK,COMBA + +One of the huge drawbacks of the ``baseline'' algorithms is that at the $O(n^2)$ level the carry must be computed and propagated upwards. This +makes the nested loop very sequential and hard to unroll and implement in parallel. The ``Comba'' method is named after little known +(\textit{in cryptographic venues}) Paul G. Comba where in \cite{COMBA} a method of implementing fast multipliers that do not require nested +carry fixup operations was presented. + +At the heart of algorithm is once again the long-hand algorithm for multiplication. Except in this case a slight twist is placed on how +the columns of the result are produced. In the standard long-hand algorithm rows of products are produced then added together to form the +final result. In the baseline algorithm the columns are added together to get the result instantaneously. + +In the Comba algorithm however, the columns of the result are produced entirely independently of each other. That is at the $O(n^2)$ level a +simple multiplication and addition step is performed. Or more succintly that + +\begin{equation} +x_n = \sum_{i+j = n} a_ib_j +\end{equation} + +Where $x_n$ is the $n'th$ column of the output vector. To see how this works consider once again multiplying $576$ by $241$. + +\begin{figure}[here] +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|c|c|c|} + \hline & & 5 & 7 & 6 & First Input\\ + \hline $\times$ & & 2 & 4 & 1 & Second Input\\ +\hline & & $1 \cdot 5 = 5$ & $1 \cdot 7 = 7$ & $1 \cdot 6 = 6$ & First pass \\ + & $4 \cdot 5 = 20$ & $4 \cdot 7+5=33$ & $4 \cdot 6+7=31$ & 6 & Second pass \\ + $2 \cdot 5 = 10$ & $2 \cdot 7 + 20 = 34$ & $2 \cdot 6+33=45$ & 31 & 6 & Third pass \\ +\hline 10 & 34 & 45 & 31 & 6 & Final Result \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Comba Multiplication Diagram} +\end{figure} + +At this point the vector $x = \left < 10, 34, 45, 31, 6 \right >$ is the result of the first step of the Comba multipler. +Now the columns must be fixed by propagating the carry upwards. The following trivial algorithm will accomplish this. + +\begin{enumerate} + \item for $n$ from 0 to $k - 1$ do + \item \hspace{3mm} $x_{n+1} \leftarrow x_{n+1} + \lfloor x_{n}/\beta \rfloor$ + \item \hspace{3mm} $x_{n} \leftarrow x_{n} \mbox{ (mod }\beta\mbox{)}$ +\end{enumerate} + +With that algorithm and $k = 5$ and $\beta = 10$ the following vector is produced $y = \left < 1, 3, 8, 8, 1, 6 \right >$. In this case +$241 \cdot 576$ is in fact $138816$ and the procedure succeeded. If the algorithm is correct and as will be demonstrated shortly more +efficient than the baseline algorithm why not simply always use this algorithm? + +\subsubsection{Column Weight.} +At the nested $O(n^2)$ level the Comba method adds the product of two single precision variables to a each column of the output +independently. A serious obstacle is if the carry is lost due to lack of precision before the algorithm has a chance to fix +the carries. For example, in the multiplication of two three-digit numbers the third column of output will be the sum of +three single precision multiplications. If the precision of the accumulator for the output digits is less then $3 \cdot (\beta - 1)^2$ then +an overflow can occur and the carry information will be lost. For any $m$ and $n$ digit input the maximal weight of any column is +min$(m, n)$ which is fairly obvious. + +The maximal number of terms in any column of a product is known as the ``column weight'' and strictly governs when the algorithm can be used. Recall +from earlier that a double precision type has $\alpha$ bits of resolution and a single precision digit has $lg(\beta)$ bits of precision. Given these +two quantities we may not violate the following + +\begin{equation} +k \cdot \left (\beta - 1 \right )^2 < 2^{\alpha} +\end{equation} + +Which reduces to + +\begin{equation} +k \cdot \left ( \beta^2 - 2\beta + 1 \right ) < 2^{\alpha} +\end{equation} + +Let $\rho = lg(\beta)$ represent the number of bits in a single precision digit. By further re-arrangement of the equation the final solution is +found. + +\begin{equation} +k \cdot \left (2^{2\rho} - 2^{\rho + 1} + 1 \right ) < 2^{\alpha} +\end{equation} + +The defaults for LibTomMath are $\beta = 2^{28}, \alpha = 2^{64}$ which simplies to $72057593501057025 \cdot k < 2^{64}$ which when divided out +result in $k < 257$. This implies that the smallest input may not have more than $256$ digits if the Comba method is to be used in +this configuration. This is quite satisfactory for most applications since $256$ digits would be allow for numbers in the range of $2^{7168}$ +which is much larger than the typical $2^{100}$ to $2^{4000}$ range most public key cryptographic algorithms use. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{fast\_s\_mp\_mul\_digs}. \\ +\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ +\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ +\hline \\ +Place an array of \textbf{MP\_WARRAY} double precision digits named $\hat W$ on the stack. \\ +1. If $c.alloc < digs$ then grow $c$ to $digs$ digits. (\textit{hint: use mp\_grow}) \\ +2. If step 1 failed return(\textit{MP\_MEM}).\\ +\\ +Zero the temporary array $\hat W$. \\ +3. for $n$ from $0$ to $digs - 1$ do \\ +\hspace{3mm}3.1 $\hat W_n \leftarrow 0$ \\ +\\ +Compute the columns. \\ +4. for $ix$ from $0$ to $a.used - 1$ do \\ +\hspace{3mm}4.1 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ +\hspace{3mm}4.2 If $pb < 1$ then goto step 5. \\ +\hspace{3mm}4.3 for $iy$ from $0$ to $pb - 1$ do \\ +\hspace{6mm}4.3.1 $\hat W_{ix+iy} \leftarrow \hat W_{ix+iy} + a_{ix}b_{iy}$ \\ +\\ +Propagate the carries upwards. \\ +5. $oldused \leftarrow c.used$ \\ +6. $c.used \leftarrow digs$ \\ +7. If $digs > 1$ then do \\ +\hspace{3mm}7.1. for $ix$ from $1$ to $digs - 1$ do \\ +\hspace{6mm}7.1.1 $\hat W_{ix} \leftarrow \hat W_{ix} + \lfloor \hat W_{ix-1} / \beta \rfloor$ \\ +\hspace{6mm}7.1.2 $c_{ix - 1} \leftarrow \hat W_{ix - 1} \mbox{ (mod }\beta\mbox{)}$ \\ +8. else do \\ +\hspace{3mm}8.1 $ix \leftarrow 0$ \\ +9. $c_{ix} \leftarrow \hat W_{ix} \mbox{ (mod }\beta\mbox{)}$ \\ +\\ +Zero excess digits. \\ +10. If $digs < oldused$ then do \\ +\hspace{3mm}10.1 for $n$ from $digs$ to $oldused - 1$ do \\ +\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ +11. Clamp excessive digits of $c$. (\textit{hint: use mp\_clamp}) \\ +12. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm fast\_s\_mp\_mul\_digs} +\end{figure} + +\textbf{Algorithm fast\_s\_mp\_mul\_digs.} +This algorithm performs the unsigned multiplication of $a$ and $b$ using the Comba method limited to $digs$ digits of precision. The algorithm +essentially peforms the same calculation as algorithm s\_mp\_mul\_digs but much faster. + +The array $\hat W$ is meant to be on the stack when the algorithm is used. The size of the array does not change which is ideal. Note also that +unlike algorithm s\_mp\_mul\_digs no temporary mp\_int is required since the result is calculated in place in $\hat W$. + +The $O(n^2)$ loop on step four is where the Comba method starts to show through. First there is no carry variable in the loop. Second the +double precision multiply and add step does not have a carry fixup of any sort. In fact the nested loop is very simple and can be implemented +in parallel. + +What makes the Comba method so attractive is that the carry propagation only takes place outside the $O(n^2)$ nested loop. For example, if the +cost in terms of time of a multiply and add is $p$ and the cost of a carry propagation is $q$ then a baseline multiplication would require +$O \left ((p + q)n^2 \right )$ time to multiply two $n$-digit numbers. The Comba method only requires $pn^2 + qn$ time, however, in practice +the speed increase is actually much more. With $O(n)$ space the algorithm can be reduced to $O(pn + qn)$ time by implementing the $n$ multiply +and add operations in the nested loop in parallel. + +The carry propagation loop on step 7 is fairly straightforward. It could have been written phased the other direction, that is, to assign +to $c_{ix}$ instead of $c_{ix-1}$ in each iteration. However, it would still require pre-caution to make sure that $\hat W_{ix+1}$ is not beyond +the \textbf{MP\_WARRAY} words set aside. + +EXAM,bn_fast_s_mp_mul_digs.c + +The memset on line @47,memset@ clears the initial $\hat W$ array to zero in a single step. Like the slower baseline multiplication +implementation a series of aliases (\textit{lines @67, tmpx@, @70, tmpy@ and @75,_W@}) are used to simplify the inner $O(n^2)$ loop. +In this case a new alias $\_\hat W$ has been added which refers to the double precision columns offset by $ix$ in each pass. + +The inner loop on line @84,mp_word@ is where the algorithm will spend the majority of the time. Which is why it has been stripped to the +bones of any extra baggage\footnote{Hence the pointer aliases.}. On x86 processors the multiply and add amounts to at the very least five +instructions (\textit{two loads, two additions, one multiply}) while on the ARMv4 processors it amounts to only three (\textit{one load, one store, +one multiply-add}). On both the x86 and ARMv4 processors GCC v3.2 does a very good job at unrolling the loop and scheduling it so there +are very few dependency stalls. + +In theory the difference between the baseline and comba algorithms is a mere $O(qn)$ time difference. However, in the $O(n^2)$ nested loop of the +baseline method there are dependency stalls as the algorithm must wait for the multiplier to finish before propagating the carry to the next +digit. As a result fewer of the often multiple execution units\footnote{The AMD Athlon has three execution units and the Intel P4 has four.} can +be simultaneously used. + +\subsection{Multiplication at New Bounds by Karatsuba Method} +So far two methods of multiplication have been presented. Both of the algorithms require asymptotically $O(n^2)$ time to multiply two $n$-digit +numbers together. While the Comba method is much faster than the baseline algorithm it still requires far too much time to multiply +large inputs together. In fact it was not until \cite{KARA} in 1962 that a faster algorithm had been proposed at all. + +The idea behind Karatsubas method is that an input can be represented in polynomial basis as two halves then multiplied. For example, if +$f(x) = ax + b$ and $g(x) = cx + b$ then the product of the two polynomials $h(x) = f(x)g(x)$ will allow $h(\beta) = (f(\beta))(g(\beta))$. + +So how does this help? First expand the product $h(x)$. + +\begin{center} +\begin{tabular}{rcl} +$h(x)$ & $=$ & $f(x)g(x)$ \\ + & $=$ & $(ax + b)(cx + d)$ \\ + & $=$ & $acx^2 + adx + bcx + bd$ \\ +\end{tabular} +\end{center} + +The next equation is a bit of genius on the part of Karatsuba. He proved that the previous equation is equivalent to + +\begin{equation} +h(x) = acx^2 + ((a - c)(b - d) + bd + ac)x + bd +\end{equation} + +Essentially the proof lies in some fairly light algebraic number theory (\textit{see \cite{KARAP} for details}) that is not important for +the discussion. At first glance it appears that the Karatsuba method is actually harder than the straight $O(n^2)$ approach. +However, further investigation will prove otherwise. + +The first important observation is that both $f(x)$ and $g(x)$ are the polynomial basis representation of two-digit numbers. This means that +$\left < a, b, c, d \right >$ are single digit values. Using either the baseline or straight polynomial multiplication the old method requires +$O \left (4(n/2)^2 \right ) = O(n^2)$ single precision multiplications. Looking closer at Karatsubas equation there are only three unique multiplications +required which are $ac$, $bd$ and $(a - c)(b - d)$. As a result only $O \left (3 \cdot (n/2)^2 \right ) = O \left ( {3 \over 4}n^2 \right )$ +multiplications are required. + +So far the algorithm has been discussed from the point of view of ``two-digit'' numbers. However, there is no reason why two digits implies a range of +$\beta^2$. It could just as easily represent a range of $\left (\beta^k \right)^2$ as well. For example, the polynomial +$f(x) = a_3x^3 + a_2x^2 + a_1x + a_0$ could also be written as $f'(x) = a'_1x + a'_0$ where $f(\beta) = f'(\beta^2)$. Fortunately representing an +integer which is already in an array of radix-$\beta$ digits in polynomial basis in terms of a power of $\beta$ is very simple. + +\subsubsection{Recursion} +The Karatsuba multiplication algorithm can be applied to practically any size of input. Therefore, it is possible that the Karatsuba method itself +be used for the three multiplications required. For example, when multiplying two four-digit numbers there will be three multiplications of two-digit +numbers. In this case the smaller multiplication requires $p(n) = {3 \over 4}n^2$ time to complete while the larger multiplication requires +$q(n) = 3 \cdot p(n/2)$ multiplications. + +By expanding $q(n)$ the following equation is achieved. + +\begin{center} +\begin{tabular}{rcl} +$q(n)$ & $=$ & $3 \cdot p(n/2)$ \\ + & $=$ & $3 \cdot (3 \cdot ((n/2)/2)^2)$ \\ + & $=$ & $9 \cdot (n/4)^2$ \\ + & $=$ & ${9 \over 16}n^2$ \\ +\end{tabular} +\end{center} + +The generic expression for the multiplicand is simply $\left ( {3 \over 4} \right )^k$ for $k \ge 1$ recurisions. The maximal number of recursions +is approximately $lg(n)$. Putting this all in terms of a base $n$ logarithm the asymptotic running time can be deduced. + +\begin{center} +\begin{tabular}{rcl} +$lg_n \left ( \left ( {3 \over 4} \right )^{lg_2 n} \cdot n^2 \right )$ & $=$ & $lg_2 n \cdot lg_n \left ( { 3 \over 4 } \right ) + 2$ \\ + & $=$ & $\left ( {log N \over log 2} \right ) \cdot \left ( {log \left ( {3 \over 4} \right ) \over log N } \right ) + 2$ \\ + & $=$ & ${ log 3 - log 2^2 + 2 \cdot log 2} \over log 2$ \\ + & $=$ & $log 3 \over log 2$ \\ +\end{tabular} +\end{center} + +Which leads to a running time of $O \left ( n^{lg(3)} \right )$ which is approximately $O(n^{1.584})$. This can lead to +impressive savings with fairly moderate sized numbers. For example, when multiplying two 128-digit numbers the Karatsuba +method saves $14,197$ (\textit{or $86\%$ of the total}) single precision multiplications. + +The immediate question becomes why not simply use Karatsuba multiplication all the time and forget about the baseline and Comba algorithms? + +\subsubsection{Overhead} +While the Karatsuba method saves on the number of single precision multiplications required this savings is not entirely free. The product +of three half size products must be stored somewhere as well as four additions and two subtractions performed. These operations incur sufficient +overhead that often for fairly trivial sized inputs the Karatsuba method is slower. + +\index{cutoff point} +The \textit{cutoff point} for Karatsuba multiplication is the point at which the Karatsuba multiplication and baseline (\textit{or Comba}) meet. +For the purposes of this discussion call this value $x$. For any input with $n$ digits such that $n < x$ Karatsuba multiplication will be slower +and for $n > x$ it will be faster. Often the break between the two algorithms is not so clean cut in reality. The cleaner the cut the more +efficient multiplication will be which is why tuning the multiplication is a very important process. For example, a properly tuned Karatsuba +multiplication algorithm can multiply two $4,096$ bit numbers up to five times faster on an Athlon processor compared to the standard baseline +algorithm. + +The exact placement of the value of $x$ depends on several key factors. The cost of allocating storage for the temporary variables, the cost of +performing the additions and most importantly the cost of performing a single precision multiplication. With a processor where single precision +multiplication is fast\footnote{The AMD Athlon for instance has a six cycle multiplier compared to the Intel P4 which has a 15 cycle multiplier.} the +cutoff point will move upwards. Similarly with a slower processor the cutoff point will move downwards. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_karatsuba\_mul}. \\ +\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ +\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert$ \\ +\hline \\ +1. $B \leftarrow \mbox{min}(a.used, b.used)/2$ \\ +2. Init the following mp\_int variables: $x0$, $x1$, $y0$, $y1$, $t1$, $x0y0$, $x1y1$.\\ +3. If step 2 failed then return(\textit{MP\_MEM}). \\ +\\ +Split the input. e.g. $a = x1 \cdot \beta^B + x0$ \\ +4. $x0 \leftarrow a \mbox{ (mod }\beta^B\mbox{)}$ (\textit{hint: use mp\_mod\_2d}) \\ +5. $y0 \leftarrow b \mbox{ (mod }\beta^B\mbox{)}$ \\ +6. $x1 \leftarrow \lfloor a / \beta^B \rfloor$ (\textit{hint: use mp\_rshd}) \\ +7. $y1 \leftarrow \lfloor b / \beta^B \rfloor$ \\ +\\ +Calculate the three products. \\ +8. $x0y0 \leftarrow x0 \cdot y0$ (\textit{hint: use mp\_mul}) \\ +9. $x1y1 \leftarrow x1 \cdot y1$ \\ +10. $t1 \leftarrow x1 - x0$ (\textit{hint: use mp\_sub}) \\ +11. $x0 \leftarrow y1 - y0$ \\ +12. $t1 \leftarrow t1 \cdot x0$ \\ +\\ +Calculate the middle term. \\ +13. $x0 \leftarrow x0y0 + x1y1$ \\ +14. $t1 \leftarrow x0 - t1$ \\ +\\ +Calculate the final product. \\ +15. $t1 \leftarrow t1 \cdot \beta^B$ (\textit{hint: use mp\_lshd}) \\ +16. $x1y1 \leftarrow x1y1 \cdot \beta^{2B}$ \\ +17. $t1 \leftarrow x0y0 + t1$ \\ +18. $c \leftarrow t1 + x1y1$ \\ +19. Clear all of the temporary variables. \\ +20. Return(\textit{MP\_OKAY}).\\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_karatsuba\_mul} +\end{figure} + +\textbf{Algorithm mp\_karatsuba\_mul.} + + +\section{Squaring} +\subsection{The Baseline Squaring Algorithm} +\subsection{Faster Squaring by the ``Comba'' Method} +\subsection{Karatsuba Squaring} +\section{Tuning Algorithms} +\subsection{How to Tune Karatsuba Algorithms} + +\chapter{Modular Reductions} +\section{Basics of Modular Reduction} +\section{The Barrett Reduction} +\section{The Montgomery Reduction} +\subsection{Faster ``Comba'' Montgomery Reduction} +\subsection{Example Montgomery Algorithms} +\section{The Diminished Radix Algorithm} +\section{Algorithm Comparison} + +\chapter{Exponentiation} +\section{Single Digit Exponentiation} +\section{Modular Exponentiation} +\subsection{General Case} +\subsection{Odd or Diminished Radix Moduli} +\section{Quick Power of Two} + +\chapter{Higher Level Algorithms} +\section{Integer Division with Remainder} +\section{Single Digit Helpers} +\subsection{Single Digit Addition} +\subsection{Single Digit Subtraction} +\subsection{Single Digit Multiplication} +\subsection{Single Digit Division} +\subsection{Single Digit Modulo} +\subsection{Single Digit Root Extraction} +\section{Random Number Generation} +\section{Formatted Output} +\subsection{Getting The Output Size} +\subsection{Generating Radix-n Output} +\subsection{Reading Radix-n Input} +\section{Unformatted Output} +\subsection{Getting The Output Size} +\subsection{Generating Output} +\subsection{Reading Input} + +\chapter{Number Theoretic Algorithms} +\section{Greatest Common Divisor} +\section{Least Common Multiple} +\section{Jacobi Symbol Computation} +\section{Modular Inverse} +\subsection{General Case} +\subsection{Odd Moduli} +\section{Primality Tests} +\subsection{Trial Division} +\subsection{The Fermat Test} +\subsection{The Miller-Rabin Test} +\subsection{Primality Test in a Bottle} +\subsection{The Next Prime} +\section{Root Extraction} + +\backmatter +\appendix +\begin{thebibliography}{ABCDEF} +\bibitem[1]{TAOCPV2} +Donald Knuth, \textit{The Art of Computer Programming}, Third Edition, Volume Two, Seminumerical Algorithms, Addison-Wesley, 1998 + +\bibitem[2]{HAC} +A. Menezes, P. van Oorschot, S. Vanstone, \textit{Handbook of Applied Cryptography}, CRC Press, 1996 + +\bibitem[3]{ROSE} +Michael Rosing, \textit{Implementing Elliptic Curve Cryptography}, Manning Publications, 1999 + +\bibitem[4]{COMBA} +Paul G. Comba, \textit{Exponentiation Cryptosystems on the IBM PC}. IBM Systems Journal 29(4): 526-538 (1990) + +\bibitem[5]{KARA} +A. Karatsuba, Doklay Akad. Nauk SSSR 145 (1962), pp.293-294 + +\bibitem[6]{KARAP} +Andre Weimerskirch and Christof Paar, \textit{Generalizations of the Karatsuba Algorithm for Polynomial Multiplication}, Submitted to Design, Codes and Cryptography, March 2002 + +\end{thebibliography} + +\input{tommath.ind} + +\chapter{Appendix} +\subsection*{Appendix A -- Source Listing of tommath.h} + +The following is the source listing of the header file ``tommath.h'' for the LibTomMath project. It contains many of +the definitions used throughout the code such as \textbf{mp\_int}, \textbf{MP\_PREC} and so on. The header is +presented here for completeness. + +LIST,tommath.h + +\end{document} \ No newline at end of file diff --git a/tommath.tex b/tommath.tex new file mode 100644 index 0000000..ae4cb61 --- /dev/null +++ b/tommath.tex @@ -0,0 +1,4195 @@ +\documentclass[b5paper]{book} +\usepackage{makeidx} +\usepackage{amssymb} +\usepackage{color} +\usepackage{alltt} +\usepackage{graphicx} +\usepackage{layout} +\def\union{\cup} +\def\intersect{\cap} +\def\getsrandom{\stackrel{\rm R}{\gets}} +\def\cross{\times} +\def\cat{\hspace{0.5em} \| \hspace{0.5em}} +\def\catn{$\|$} +\def\divides{\hspace{0.3em} | \hspace{0.3em}} +\def\nequiv{\not\equiv} +\def\approx{\raisebox{0.2ex}{\mbox{\small $\sim$}}} +\def\lcm{{\rm lcm}} +\def\gcd{{\rm gcd}} +\def\log{{\rm log}} +\def\ord{{\rm ord}} +\def\abs{{\mathit abs}} +\def\rep{{\mathit rep}} +\def\mod{{\mathit\ mod\ }} +\renewcommand{\pmod}[1]{\ ({\rm mod\ }{#1})} +\newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} +\newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} +\def\Or{{\rm\ or\ }} +\def\And{{\rm\ and\ }} +\def\iff{\hspace{1em}\Longleftrightarrow\hspace{1em}} +\def\implies{\Rightarrow} +\def\undefined{{\rm ``undefined"}} +\def\Proof{\vspace{1ex}\noindent {\bf Proof:}\hspace{1em}} +\let\oldphi\phi +\def\phi{\varphi} +\def\Pr{{\rm Pr}} +\newcommand{\str}[1]{{\mathbf{#1}}} +\def\F{{\mathbb F}} +\def\N{{\mathbb N}} +\def\Z{{\mathbb Z}} +\def\R{{\mathbb R}} +\def\C{{\mathbb C}} +\def\Q{{\mathbb Q}} +\definecolor{DGray}{gray}{0.5} +\newcommand{\url}[1]{\mbox{$<${#1}$>$}} +\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}} +\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} +\def\gap{\vspace{0.5ex}} +\makeindex +\begin{document} +\frontmatter +\pagestyle{empty} +\title{Multiple-Precision Integer Arithmetic, \\ A Case Study Involving the LibTomMath Project \\ - DRAFT - } +\author{\mbox{ +%\begin{small} +\begin{tabular}{c} +Tom St Denis \\ +Algonquin College \\ +\\ +Mads Rasmussen \\ +Open Communications Security \\ +\\ +Gregory Rose \\ +Qualcomm \\ +\end{tabular} +%\end{small} +} +} +\maketitle +This text in its entirety is copyrighted \copyright{}2003 by Tom St Denis. It may not be redistributed +electronically or otherwise without the sole permission of the author. The text is freely re distributable as long as +it is packaged along with the LibTomMath project in a non-commercial project. Contact the +author for other redistribution rights. + +This text corresponds to the v0.17 release of the LibTomMath project. + +\begin{alltt} +Tom St Denis +111 Banning Rd +Ottawa, Ontario +K2L 1C3 +Canada + +Phone: 1-613-836-3160 +Email: tomstdenis@iahu.ca +\end{alltt} + +This text is formatted to the international B5 paper size of 176mm wide by 250mm tall using the \LaTeX{} +{\em book} macro package and the Perl {\em booker} package. + +\tableofcontents +\listoffigures +\chapter*{Preface} +Blah. + +\mainmatter +\pagestyle{headings} +\chapter{Introduction} +\section{Multiple Precision Arithmetic} +\subsection{The Need for Multiple Precision Arithmetic} +The most prevalent use for multiple precision arithmetic (\textit{often referred to as bignum math}) is within public +key cryptography. Algorithms such as RSA, Diffie-Hellman and Elliptic Curve Cryptography require large integers in order to +resist known cryptanalytic attacks. Typical modern programming languages such as C and Java only provide small +single-precision data types which are incapable of precisely representing integers which are often hundreds of bits long. + +For example, consider multiplying $1,234,567$ by $9,876,543$ in C with an ``unsigned long'' data type. With an +x86 machine the result is $4,136,875,833$ while the true result is $12,193,254,061,881$. The original inputs +were approximately $21$ and $24$ bits respectively. If the C language cannot multiply two relatively small values +together precisely how does anyone expect it to multiply two values which are considerably larger? + +Most advancements in fast multiple precision arithmetic stems from the desire for faster cryptographic primitives. However, cryptography +is not the only field of study that can benefit fast large integer routines. Another auxiliary use for multiple precision integers is +high precision floating point data types. The basic IEEE standard floating point type is made up of an integer mantissa $q$ and an exponent $e$. +Numbers are given in the form $n = q \cdot b^e$ where $b = 2$ is convention. Since IEEE is meant to be implemented in +hardware the precision of the mantissa is often fairly small (\textit{roughly 23 bits}). Since the mantissa is merely an +integer a large multiple precision integer could be used. In effect very high precision floating point arithmetic +could be performed. This would be useful where scientific applications must minimize the total output error over long simulations. + +\subsection{Multiple Precision Arithmetic} +\index{multiple precision} +Multiple precision arithmetic attempts to the solve the shortcomings of single precision data types such as those from +the C and Java programming languages. In essence multiple precision arithmetic is a set of operations that can be +performed on members of an algebraic group whose precision is not fixed. The algorithms when implemented to be multiple +precision can allow a developer to work with any practical precision required. + +Typically the arithmetic is performed over the ring of integers denoted by a $\Z$ and referred to casually as ``bignum'' +routines. However, it is possible to have rings of polynomials as well typically denoted by $\Z/p\Z \left [ X \right ]$ +which could have variable precision (\textit{or degree}). This text will discuss implementation of the former, however, +implementing polynomial basis routines should be relatively easy after reading this text. + +\subsection{Benefits of Multiple Precision Arithmetic} +\index{precision} \index{accuracy} +Precision is defined loosely as the proximity to the real value a given representation is. Accuracy is defined as the +reproducibility of the result. For example, the calculation $1/3 = 0.25$ is imprecise but can be accurate provided +it is reproducible. + +The benefit of multiple precision representations over single precision representations is that +often no precision is lost while representing the result of an operation which requires excess precision. For example, +the multiplication of two $n$-bit integers requires at least $2n$ bits to represent the result. A multiple precision +system would augment the precision of the destination to accomodate the result while a single precision system would +truncate excess bits to maintain a fixed level of precision. + +Multiple precision representations allow for the precision to be very high (\textit{if not exacting}) but at a cost of +modest computer resources. The only reasonable case where a multiple precision system will lose precision is when +emulating a floating point data type. However, with multiple precision integer arithmetic no precision is lost. + +\subsection{Basis of Operations} +At the heart of all multiple precision integer operations are the ``long-hand'' algorithms we all learnt as children +in grade school. For example, to multiply $1,234$ by $981$ the student is not taught to memorize the times table for +$1,234$ instead they are taught how to long-multiply. That is to multiply each column using simple single digit +multiplications and add the resulting products by column. The representation that most are familiar with is known as +decimal or formally as radix-10. A radix-$n$ representation simply means there are $n$ possible values per digit. +For example, binary would be a radix-2 representation. + +In essence computer based multiple precision arithmetic is very much the same. The most notable difference is the usage +of a binary friendly radix. That is to use a radix of the form $2^k$ where $k$ is typically the size of a machine +register. Also occasionally more optimal algorithms are used to perform certain operations such as multiplication and +squaring instead of traditional long-hand algorithms. + +\section{Purpose of This Text} +The purpose of this text is to instruct the reader regarding how to implement multiple precision algorithms. That is +to not only explain the core theoretical algorithms but also the various ``house keeping'' tasks that are neglected by +authors of other texts on the subject. Texts such as Knuths' ``The Art of Computer Programming, vol 2.'' and the +Handbook of Applied Cryptography (\textit{HAC}) give considerably detailed explanations of the theoretical aspects of +the algorithms and very little regarding the practical aspects. + +That is how an algorithm is explained and how it is actually implemented are two very different +realities. For example, algorithm 14.7 on page 594 of HAC lists a relatively simple algorithm for performing multiple +precision integer addition. However, what the description lacks is any discussion concerning the fact that the two +integer inputs may be of differing magnitudes. Similarly the division routine (\textit{Algorithm 14.20, pp. 598}) +does not discuss how to handle sign or handle the dividends decreasing magnitude in the main loop (\textit{Step \#3}). + +As well as the numerous practical oversights both of the texts do not discuss several key optimal algorithms required +such as ``Comba'' and Karatsuba multipliers and fast modular inversion. These optimal algorithms are considerably +vital to achieve any form of useful performance in non-trivial applications. + +To solve this problem the focus of this text is on the practical aspects of implementing the algorithms that +constitute a multiple precision integer package with light cursory discussions on the theoretical aspects. As a case +study the ``LibTomMath''\footnote{Available freely at http://math.libtomcrypt.org} package is used to demonstrate +algorithms with implementations that have been field tested and work very well. + +\section{Discussion and Notation} +\subsection{Notation} +A multiple precision integer of $n$-digits shall be denoted as $x = (x_n ... x_1 x_0)_{ \beta }$ to be the +multiple precision notation for the integer $x \equiv \sum_{i=0}^{n} x_i\beta^i$. The elements of the array $x$ are +said to be the radix $\beta$ digits of the integer. For example, $x = (15,0,7)_{\beta}$ would represent the +integer $15\cdot\beta^2 + 0\cdot\beta^1 + 7\cdot\beta^0$. + +A ``mp\_int'' shall refer to a composite structure which contains the digits of the integer as well as auxilary data +required to manipulate the data. These additional members are discussed in chapter three. For the purposes of this text +a ``multiple precision integer'' and a ``mp\_int'' are synonymous. + +\index{single-precision} \index{double-precision} \index{mp\_digit} \index{mp\_word} +For the purposes of this text a single-precision variable must be able to represent integers in the range $0 \le x < 2 \beta$ while +a double-precision variable must be able to represent integers in the range $0 \le x < 2 \beta^2$. Within the source code that will be +presented the data type \textbf{mp\_digit} will represent a single-precision type while \textbf{mp\_word} will represent a +double-precision type. In several algorithms (\textit{notably the Comba routines}) temporary results +will be stored in a double-precision arrays. For the purposes of this text $x_j$ will refer to the +$j$'th digit of a single-precision array and $\hat x_j$ will refer to the $j$'th digit of a double-precision +array. + +\subsection{Work Effort} +\index{big-O} +To measure the efficiency of various algorithms a modified big-O notation is used. In this system all +single precision operations are considered to have the same cost\footnote{Except where explicitly noted.}. +That is a single precision addition, multiplication and division are assumed to take the same time to +complete. While this is generally not true in practice it will simplify the discussions considerably. + +Some algorithms have slight advantages over others which is why some constants will not be removed in +the notation. For example, a normal multiplication requires $O(n^2)$ work while a squaring requires +$O({{n^2 + n}\over 2})$ work. In standard big-O notation these would be said to be equivalent. However, in the +context of the this text the magnitude of the inputs will not approach an infinite size. This means the conventional limit +notation wisdom does not apply to the cancellation of constants. + +Throughout the discussions various ``work levels'' will be discussed. These levels are the $O(1)$, +$O(n)$, $O(n^2)$, ..., $O(n^k)$ work efforts. For example, operations at the $O(n^k)$ ``level'' are said to be +executed more frequently than operations at the $O(n^m)$ ``level'' when $k > m$. Obviously most optimizations will pay +off the most at the higher levels since they represent the bulk of the effort required. + +\section{Exercises} +Within the more advanced chapters a section will be set aside to give the reader some challenging exercises. These exercises are not +designed to be prize winning problems yet instead to be thought provoking. Wherever possible the problems are foreward minded stating +problems that will be answered in subsequent chapters. The reader is encouraged to finish the exercises as they appear to get a +better understanding of the subject material. + +Similar to the exercises of \cite{TAOCPV2} as explained on pp.\textit{ix} these exercises are given a scoring system. However, unlike +\cite{TAOCPV2} the problems do not get nearly as hard as often. The scoring of these exercises ranges from one (\textit{the easiest}) to +five (\textit{the hardest}). The following table sumarizes the scoring. + +\vspace{5mm} +\begin{tabular}{cl} +$\left [ 1 \right ]$ & An easy problem that should only take the reader a manner of \\ + & minutes to solve. Usually does not involve much computer time. \\ + & \\ +$\left [ 2 \right ]$ & An easy problem that involves a marginal amount of computer \\ + & time usage. Usually requires a program to be written to \\ + & solve the problem. \\ + & \\ +$\left [ 3 \right ]$ & A moderately hard problem that requires a non-trivial amount \\ + & of work. Usually involves trivial research and development of \\ + & new theory from the perspective of a student. \\ + & \\ +$\left [ 4 \right ]$ & A moderately hard problem that involves a non-trivial amount \\ + & of work and research. The solution to which will demonstrate \\ + & a higher mastery of the subject matter. \\ + & \\ +$\left [ 5 \right ]$ & A hard problem that involves concepts that are non-trivial. \\ + & Solutions to these problems will demonstrate a complete mastery \\ + & of the given subject. \\ + & \\ +\end{tabular} + +Essentially problems at the first level are meant to be simple questions that the reader can answer quickly without programming a solution or +devising new theory. These problems are quick tests to see if the material is understood. Problems at the second level are also +designed to be easy but will require a program or algorithm to be implemented to arrive at the answer. + +Problems at the third level are meant to be a bit more difficult. Often the answer is fairly obvious but arriving at an exacting solution +requires some thought and skill. These problems will almost always involve devising a new algorithm or implementing a variation of +another algorithm. + +Problems at the fourth level are meant to be even more difficult as well as involve some research. The reader will most likely not know +the answer right away nor will this text provide the exact details of the answer (\textit{or at least not until a subsequent chapter}). Problems +at the fifth level are meant to be the hardest problems relative to all the other problems in the chapter. People who can correctly +answer fifth level problems have a mastery of the subject matter at hand. + +Often problems will be tied together. The purpose of this is to start a chain of thought that will be discussed in future chapters. The reader +is encouraged to answer the follow-up problems and try to draw the relevence of problems. + +\chapter{Introduction to LibTomMath} + +\section{What is the LibTomMath?} +LibTomMath is a free and open source multiple precision number theoretic library written in portable ISO C +source code. By portable it is meant that the library does not contain any code that is platform dependent or otherwise +problematic to use on any given platform. The library has been successfully tested under numerous operating systems +including Solaris, MacOS, Windows, Linux, PalmOS and on standalone hardware such as the Gameboy Advance. The +library is designed to contain enough functionality to be able to develop number theoretic applications such as public +key cryptosystems. + +\section{Goals of the LibTomMath} + +Even though the library is written entirely in portable ISO C considerable care has been taken to +optimize the algorithm implementations within the library. Specifically the code has been written to work well with +the GNU C Compiler (\textit{GCC}) on both x86 and ARMv4 processors. Wherever possible optimal +algorithms (\textit{such as Karatsuba multiplication, sliding window exponentiation and Montgomery reduction.}) have +been provided to make the library as efficient as possible. Even with the optimal and sometimes specialized +algorithms that have been included the API has been kept as simple as possible. Often generic place holder routines +will make use of specialized algorithms automatically without the developers attention. One such example +is the generic multiplication algorithm \textbf{mp\_mul()} which will automatically use Karatsuba multiplication if the +inputs are of a specific size. + +Making LibTomMath as efficient as possible is not the only goal of the LibTomMath project. Ideally the library should +be source compatible with another popular library which makes it more attractive for developers to use. In this case the +MPI library was used as a API template for all the basic functions. + +The project is also meant to act as a learning tool for students. The logic being that no easy to follow ``bignum'' +library exists which can be used to teach computer science students how to perform fast and reliable multiple precision +arithmetic. To this end the source code has been given quite a few comments and algorithm discussion points. Often +where applicable routines have more comments than lines of code. + +\section{Choice of LibTomMath} +LibTomMath was chosen as the case study of this text not only because the author of both projects is one and the same but +for more worthy reasons. Other libraries such as GMP, MPI, LIP and OpenSSL have multiple precision +integer arithmetic routines but would not be ideal for this text for numerous reasons as will be explained in the +following sub-sections. + +\subsection{Code Base} +The LibTomMath code base is all portable ISO C source code. This means that there are no platform dependent conditional +segments of code littered throughout the source. This clean and uncluttered approach to the library means that a +developer can more readily ascertain the true intent of a given section of source code without trying to keep track of +what conditional code will be used. + +The code base of LibTomMath is also exceptionally well organized. Each function is in its own separate source code file +which allows the reader to find a given function very fast. When compiled with GCC for the x86 processor the entire +library is a mere 87,760 bytes (\textit{$116,182$ bytes for ARMv4 processors}). This includes every single function +LibTomMath provides from basic arithmetic to various number theoretic functions such as modular exponentiation, various +reduction algorithms and Jacobi symbol computation. + +By comparison MPI which has fewer number theoretic functions than LibTomMath compiled with the same conditions is +45,429 bytes (\textit{$54,536$ for ARMv4}). GMP which has rather large collection of functions with the default +configuration on an x86 Athlon is 2,950,688 bytes. Note that while LibTomMath has fewer functions than GMP it has been +been used as the sole basis for several public key cryptosystems without having to seek additional outside functions +to supplement the library. + +\subsection{API Simplicity} +LibTomMath is designed after the MPI library and shares the API design. Quite often programs that use MPI will build +with LibTomMath without change. The function names are relatively straight forward as to what they perform. Almost all of the +functions except for a few minor exceptions which as will be discussed are for good reasons share the same parameter passing +convention. The learning curve is fairly shallow with the API provided which is an extremely valuable benefit for the +student and developer alike. + +The LIP library is an example of a library with an API that is awkward to work with. LIP uses function names that are often ``compressed'' to +illegible short hand. LibTomMath does not share this fault. + +\subsection{Optimizations} +While LibTomMath is certainly not the fastest library (\textit{GMP often beats LibTomMath by a factor of two}) it does +feature a set of optimal algorithms for tasks ranging from modular reduction to squaring. GMP and LIP also feature +such optimizations while MPI only uses baseline algorithms with no optimizations. + +LibTomMath is almost always a magnitude faster than the MPI library at computationally expensive tasks such as modular +exponentiation. In the grand scheme of ``bignum'' libraries LibTomMath is faster than the average library and usually +slower than the best libraries such as GMP and OpenSSL by a small factor. + +\subsection{Portability and Stability} +LibTomMath will build ``out of the box'' on any platform equipped with a modern version of the GNU C Compiler +(\textit{GCC}). This means that without changes the library will build without configuration or setting up any +variables. LIP and MPI will build ``out of the box'' as well but have numerous known bugs. Most notably the author of +MPI is not working on his library anymore. + +GMP requires a configuration script to run and will not build out of the box. GMP and LibTomMath are still in active +development and are very stable across a variety of platforms. + +\subsection{Choice} +LibTomMath is a relatively compact, well documented, highly optimized and portable library which seems only natural for +the case study of this text. Various source files from the LibTomMath project will be included within the text. However, the +reader is encouraged to download their own copy of the library to actually be able to work with the library. + +\chapter{Getting Started} +\section{Library Basics} +To get the ``ball rolling'' so to speak a primitive data type and a series of primitive algorithms must be established. First a data +type that will hold the information required to maintain a multiple precision integer must be designed. With this basic data type of a series +of low level algorithms for initializing, clearing, growing and clamping integers can be developed to form the basis of the entire +package of algorithms. + +\section{The mp\_int structure} +First the data type for storing multiple precision integers must be designed. This data type must be able to hold information to +maintain an array of digits, how many are actually used in the representation and the sign. The ISO C standard does not provide for +any such data type but it does provide for making composite data types known as structures. The following is the structure definition +used within LibTomMath. + +\index{mp\_int} +\begin{verbatim} +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; +\end{verbatim} + +The \textbf{used} parameter denotes how many digits of the array \textbf{dp} are actually being used. The array +\textbf{dp} holds the digits that represent the integer desired. The \textbf{alloc} parameter denotes how +many digits are available in the array to use by functions before it has to increase in size. When the \textbf{used} count +of a result would exceed the \textbf{alloc} count all LibTomMath routines will automatically increase the size of the +array to accommodate the precision of the result. The \textbf{sign} parameter denotes the sign as either zero/positive +(\textbf{MP\_ZPOS}) or negative (\textbf{MP\_NEG}). + +\section{Argument Passing} +A convention of arugment passing must be adopted early on in the development of any library. Making the function prototypes +consistent will help eliminate many headaches in the future as the library grows to significant complexity. In LibTomMath the multiple precision +integer functions accept parameters from left to right as pointers to mp\_int structures. That means that the source operands are +placed on the left and the destination on the right. Consider the following examples. + +\begin{verbatim} + mp_mul(&a, &b, &c); /* c = a * b */ + mp_add(&a, &b, &a); /* a = a + b */ + mp_sqr(&a, &b); /* b = a * a */ +\end{verbatim} + +The left to right order is a fairly natural way to implement the functions since it lets the developer read aloud the +functions and make sense of them. For example, the first function would read ``multiply a and b and store in c''. + +Certain libraries (\textit{LIP by Lenstra for instance}) accept parameters the other way around. That is the destination +on the left and arguments on the right. In truth it is entirely a matter of preference. + +Another very useful design consideration is whether to allow argument sources to also be a destination. For example, the +second example (\textit{mp\_add}) adds $a$ to $b$ and stores in $a$. This is an important feature to implement since it +allows the higher up functions to cut down on the number of variables. However, to implement this feature specific +care has to be given to ensure the destination is not written before the source is fully read. + +\section{Return Values} +A well implemented library, no matter what its purpose, should trap as many runtime errors as possible and return them to the +caller. By catching runtime errors a library can be guaranteed to prevent undefined behaviour within reason. In a multiple precision +library the only errors that are bound to occur are related to inappropriate inputs (\textit{division by zero for instance}) or +memory allocation errors. + +In LibTomMath any function that can cause a runtime error will return an error as an \textbf{int} data type with one of the +following values. + +\index{MP\_OKAY} \index{MP\_VAL} \index{MP\_MEM} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Value} & \textbf{Meaning} \\ +\hline \textbf{MP\_OKAY} & The function was successful \\ +\hline \textbf{MP\_VAL} & One of the input value(s) was invalid \\ +\hline \textbf{MP\_MEM} & The function ran out of heap memory \\ +\hline +\end{tabular} +\end{center} + +When an error is detected within a function it should free any memory they allocated and return as soon as possible. The goal +is to leave the system in the same state the system was when the function was called. Error checking with this style of API is fairly simple. + +\begin{verbatim} + int err; + if ((err = mp_add(&a, &b, &c)) != MP_OKAY) { + printf("Error: %d\n", err); + exit(EXIT_FAILURE); + } +\end{verbatim} + +The GMP library uses C style \textit{signals} to flag errors which is of questionable use. Not all errors are fatal +and it is not ideal to force developers to have signal handlers for such cases. + +\section{Initialization and Clearing} +The logical starting point when actually writing multiple precision integer functions is the initialization and +clearing of the integers. These two functions will be used by far the most throughout the algorithms whenever +temporary integers are required. + +Given the basic mp\_int structure an initialization routine must first allocate memory to hold the digits of +the integer. Often it is optimal to allocate a sufficiently large pre-set number of digits even considering +the initial integer will represent zero. If only a single digit were allocated quite a few re-allocations +would occur for the majority of inputs. There exists a tradeoff between how many default digits to allocate +and how many re-allocations are tolerable. + +If the memory for the digits has been successfully allocated then the rest of the members of the structure must +be initialized. Since the initial state is to represent a zero integer the digits allocated must all be zeroed. The +\textbf{used} count set to zero and \textbf{sign} set to \textbf{MP\_ZPOS}. + +\subsection{Initializing an mp\_int} +To initialize an mp\_int the mp\_init algorithm shall be used. The purpose of this algorithm is to allocate +the memory required and initialize the integer to a default representation of zero. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Allocate memory for the digits and set to a zero state. \\ +\hline \\ +1. Allocate memory for \textbf{MP\_PREC} digits. \\ +2. If the allocation failed then return(\textit{MP\_MEM}) \\ +3. for $n$ from $0$ to $MP\_PREC - 1$ do \\ +\hspace{3mm}3.1 $a_n \leftarrow 0$\\ +4. $a.sign \leftarrow MP\_ZPOS$\\ +5. $a.used \leftarrow 0$\\ +6. $a.alloc \leftarrow MP\_PREC$\\ +7. Return(\textit{MP\_OKAY})\\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init} +\end{figure} + +\textbf{Algorithm mp\_init.} +The \textbf{MP\_PREC} variable is a simple constant used to dictate minimal precision of allocated integers. It is ideally at least equal to $32$ but +can be any reasonable power of two. Step one and two allocate the memory and account for it. If the allocation fails the algorithm returns +immediately to signal the failure. Step three will ensure that all the digits are in the default state of zero. Finally steps +four through six set the default settings of the \textbf{sign}, \textbf{used} and \textbf{alloc} members of the mp\_int structure. + +\index{bn\_mp\_init.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_init.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* init a new bigint */ +018 int +019 mp_init (mp_int * a) +020 \{ +021 /* allocate ram required and clear it */ +022 a->dp = OPT_CAST calloc (sizeof (mp_digit), MP_PREC); +023 if (a->dp == NULL) \{ +024 return MP_MEM; +025 \} +026 +027 /* set the used to zero, allocated digit to the default precision +028 * and sign to positive */ +029 a->used = 0; +030 a->alloc = MP_PREC; +031 a->sign = MP_ZPOS; +032 +033 return MP_OKAY; +034 \} +\end{alltt} +\end{small} + +The \textbf{OPT\_CAST} type cast on line 22 is designed to allow C++ compilers to build the code out of +the box. Microsoft C V5.00 is known to cause problems without the cast. Also note that if the memory +allocation fails the other members of the mp\_int will be in an undefined state. The code from +line 29 to line 31 sets the default state for a mp\_int which is zero, positive and no used digits. + +\subsection{Clearing an mp\_int} +When an mp\_int is no longer required the memory allocated for it can be cleared from the heap with +the mp\_clear algorithm. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_clear}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. The memory for $a$ is cleared. \\ +\hline \\ +1. If $a$ has been previously freed then return(\textit{MP\_OKAY}). \\ +2. Free the digits of $a$ and mark $a$ as freed. \\ +3. $a.used \leftarrow 0$ \\ +4. $a.alloc \leftarrow 0$ \\ +5. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_clear} +\end{figure} + +\textbf{Algorithm mp\_clear.} +In steps one and two the memory for the digits are only free'd if they had not been previously released before. +This is more of concern for the implementation since it is used to prevent ``double-free'' errors. It also helps catch +code errors where mp\_ints are used after being cleared. Simiarly steps three and four set the +\textbf{used} and \textbf{alloc} to known values which would be easy to spot during debugging. For example, if an mp\_int is expected +to be non-zero and its \textbf{used} member observed to be zero (\textit{due to being cleared}) then an obvious bug in the code has been +spotted. + +\index{bn\_mp\_clear.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_clear.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* clear one (frees) */ +018 void +019 mp_clear (mp_int * a) +020 \{ +021 if (a->dp != NULL) \{ +022 +023 /* first zero the digits */ +024 memset (a->dp, 0, sizeof (mp_digit) * a->used); +025 +026 /* free ram */ +027 free (a->dp); +028 +029 /* reset members to make debugging easier */ +030 a->dp = NULL; +031 a->alloc = a->used = 0; +032 \} +033 \} +\end{alltt} +\end{small} + +The \textbf{if} statement on line 21 prevents the heap from being corrupted if a user double-frees an +mp\_int. For example, a trivial case of this bug would be as follows. + +\begin{verbatim} +mp_int a; +mp_init(&a); +mp_clear(&a); +mp_clear(&a); +\end{verbatim} + +Without that check the code would try to free the memory allocated for the digits twice which will cause most standard C +libraries to cause a fault. Also by setting the pointer to \textbf{NULL} it helps debug code that may inadvertently +free the mp\_int before it is truly not needed. The allocated digits are set to zero before being freed on line 24. +This is ideal for cryptographic situations where the mp\_int is a secret parameter. + +The following snippet is an example of using both the init and clear functions. + +\begin{small} +\begin{verbatim} +#include +#include +#include +int main(void) +{ + mp_int num; + int err; + + /* init the bignum */ + if ((err = mp_init(&num)) != MP_OKAY) { + printf("Error: %d\n", err); + return EXIT_FAILURE; + } + + /* do work with it ... */ + + /* clear up */ + mp_clear(&num); + + return EXIT_SUCCESS; +} +\end{verbatim} +\end{small} + +\section{Other Initialization Routines} + +It is often helpful to have specialized initialization algorithms to simplify the design of other algorithms. For example, an +initialization followed by a copy is a common operation when temporary copies of integers are required. It is quite +beneficial to have a series of simple helper functions available. + +\subsection{Initializing Variable Sized mp\_int Structures} +Occasionally the number of digits required will be known in advance of an initialization. In these +cases the mp\_init\_size algorithm can be of use. The purpose of this algorithm is similar to mp\_init except that +it will allocate \textit{at least} a specified number of digits. This is ideal to prevent re-allocations when the +input size is known. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init\_size}. \\ +\textbf{Input}. An mp\_int $a$ and the requested number of digits $b$\\ +\textbf{Output}. $a$ is initialized to hold at least $b$ digits. \\ +\hline \\ +1. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ +2. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ +3. Allocate $v$ digits. \\ +4. If the allocation failed then return(\textit{MP\_MEM}). \\ +5. for $n$ from $0$ to $v - 1$ do \\ +\hspace{3mm}5.1 $a_n \leftarrow 0$ \\ +6. $a.sign \leftarrow MP\_ZPOS$\\ +7. $a.used \leftarrow 0$\\ +8. $a.alloc \leftarrow v$\\ +9. Return(\textit{MP\_OKAY})\\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init\_size} +\end{figure} + +\textbf{Algorithm mp\_init\_size.} +The value of $v$ is calculated to be at least the requested amount of digits $b$ plus additional padding. The padding is calculated +to be at least \textbf{MP\_PREC} digits plus enough digits to make the digit count a multiple of \textbf{MP\_PREC}. This padding is used to +prevent trivial allocations from becomming a bottleneck in the rest of the algorithms that depend on this. + +\index{bn\_mp\_init\_size.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_init\_size.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* init a mp_init and grow it to a given size */ +018 int +019 mp_init_size (mp_int * a, int size) +020 \{ +021 +022 /* pad size so there are always extra digits */ +023 size += (MP_PREC * 2) - (size & (MP_PREC - 1)); +024 +025 /* alloc mem */ +026 a->dp = OPT_CAST calloc (sizeof (mp_digit), size); +027 if (a->dp == NULL) \{ +028 return MP_MEM; +029 \} +030 a->used = 0; +031 a->alloc = size; +032 a->sign = MP_ZPOS; +033 +034 return MP_OKAY; +035 \} +\end{alltt} +\end{small} + +Line 23 will ensure that the number of digits actually allocated is padded up to the next multiple of +\textbf{MP\_PREC} plus an additional \textbf{MP\_PREC}. This ensures that the number of allocated digit is +always greater than the amount requested. As a result it prevents many trivial memory allocations. The value of +\textbf{MP\_PREC} is defined in ``tommath.h'' and must be a power of two. + +\subsection{Creating a Clone} +Another common sequence of operations is to make a local temporary copy of an argument. To initialize then copy a mp\_int will be known as +creating a clone. This is useful within functions that need to modify an integer argument but do not wish to actually modify the original copy. +The mp\_init\_copy algorithm will perform this very task. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init\_copy}. \\ +\textbf{Input}. An mp\_int $a$ and $b$\\ +\textbf{Output}. $a$ is initialized to be a copy of $b$. \\ +\hline \\ +1. Init $a$. (\textit{hint: use mp\_init}) \\ +2. If the init of $a$ was unsuccessful return(\textit{MP\_MEM}) \\ +3. Copy $b$ to $a$. (\textit{hint: use mp\_copy}) \\ +4. Return the status of the copy operation. \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init\_copy} +\end{figure} + +\textbf{Algorithm mp\_init\_copy.} +This algorithm will initialize a mp\_int variable and copy another previously initialized mp\_int variable into it. The algorithm will +detect when the initialization fails and returns the error to the calling algorithm. As such this algorithm will perform two operations +in one step. + +\index{bn\_mp\_init\_copy.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_init\_copy.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* creates "a" then copies b into it */ +018 int +019 mp_init_copy (mp_int * a, mp_int * b) +020 \{ +021 int res; +022 +023 if ((res = mp_init (a)) != MP_OKAY) \{ +024 return res; +025 \} +026 return mp_copy (b, a); +027 \} +\end{alltt} +\end{small} + +This will initialize \textbf{a} and make it a verbatim copy of the contents of \textbf{b}. Note that +\textbf{a} will have its own memory allocated which means that \textbf{b} may be cleared after the call +and \textbf{a} will be left intact. + +\subsection{Multiple Integer Initializations} +Occasionally a function will require a series of mp\_int data types to be made available. The mp\_init\_multi algorithm +is provided to simplify such cases. The purpose of this algorithm is to initialize a variable length array of mp\_int +structures at once. As a result algorithms that require multiple integers only has to use +one algorithm to initialize all the mp\_int variables. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_init\_multi}. \\ +\textbf{Input}. Variable length array of mp\_int variables of length $k$. \\ +\textbf{Output}. The array is initialized such that each each mp\_int is ready to use. \\ +\hline \\ +1. for $n$ from 0 to $k - 1$ do \\ +\hspace{+3mm}1.1. Initialize the $n$'th mp\_int (\textit{hint: use mp\_init}) \\ +\hspace{+3mm}1.2. If initialization failed then do \\ +\hspace{+6mm}1.2.1. for $j$ from $0$ to $n$ do \\ +\hspace{+9mm}1.2.1.1. Free the $j$'th mp\_int (\textit{hint: use mp\_clear}) \\ +\hspace{+6mm}1.2.2. Return(\textit{MP\_MEM}) \\ +2. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_init\_multi} +\end{figure} + +\textbf{Algorithm mp\_init\_multi.} +The algorithm will initialize the array of mp\_int variables one at a time. As soon as an runtime error is detected (\textit{step 1.2}) all of +the previously initialized variables are cleared. The goal is an ``all or nothing'' initialization which allows for quick recovery from runtime +errors. + +\subsection{Multiple Integer Clearing} +Similarly to clear a variable length list of mp\_int structures the mp\_clear\_multi algorithm will be used. + +\index{bn\_mp\_multi.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_multi.c +\vspace{-3mm} +\begin{alltt} +016 #include +017 +018 int mp_init_multi(mp_int *mp, ...) +019 \{ +020 mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ +021 int n = 0; /* Number of ok inits */ +022 mp_int* cur_arg = mp; +023 va_list args; +024 +025 va_start(args, mp); /* init args to next argument from caller */ +026 while (cur_arg != NULL) \{ +027 if (mp_init(cur_arg) != MP_OKAY) \{ +028 /* Oops - error! Back-track and mp_clear what we already +029 succeeded in init-ing, then return error. +030 */ +031 va_list clean_args; +032 +033 /* end the current list */ +034 va_end(args); +035 +036 /* now start cleaning up */ +037 cur_arg = mp; +038 va_start(clean_args, mp); +039 while (n--) \{ +040 mp_clear(cur_arg); +041 cur_arg = va_arg(clean_args, mp_int*); +042 \} +043 va_end(clean_args); +044 res = MP_MEM; +045 break; +046 \} +047 n++; +048 cur_arg = va_arg(args, mp_int*); +049 \} +050 va_end(args); +051 return res; /* Assumed ok, if error flagged above. */ +052 \} +053 +054 void mp_clear_multi(mp_int *mp, ...) +055 \{ +056 mp_int* next_mp = mp; +057 va_list args; +058 va_start(args, mp); +059 while (next_mp != NULL) \{ +060 mp_clear(next_mp); +061 next_mp = va_arg(args, mp_int*); +062 \} +063 va_end(args); +064 \} +\end{alltt} +\end{small} + +Consider the following snippet which demonstrates how to use both routines. +\begin{small} +\begin{verbatim} +#include +#include +#include +int main(void) +{ + mp_int num1, num2, num3; + int err; + + if ((err = mp_init_multi(&num1, &num2, &num3, NULL)) !- MP_OKAY) { + printf("Error: %d\n", err); + return EXIT_FAILURE; + } + + /* at this point num1/num2/num3 are ready */ + + /* free them */ + mp_clear_multi(&num1, &num2, &num3, NULL); + + return EXIT_SUCCESS; +} +\end{verbatim} +\end{small} + +\section{Maintenance} +A small useful collection of mp\_int maintenance functions will also prove useful. + +\subsection{Augmenting Integer Precision} +When storing a value in an mp\_int sufficient digits must be available to accomodate the entire value without +loss of precision. Quite often the size of the array given by the \textbf{alloc} member is large enough to simply +increase the \textbf{used} digit count. However, when the size of the array is too small it must be re-sized +appropriately to accomodate the result. The mp\_grow algorithm will provide this functionality. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_grow}. \\ +\textbf{Input}. An mp\_int $a$ and an integer $b$. \\ +\textbf{Output}. $a$ is expanded to accomodate $b$ digits. \\ +\hline \\ +1. if $a.alloc \ge b$ then return(\textit{MP\_OKAY}) \\ +2. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ +3. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ +4. Re-Allocate the array of digits $a$ to size $v$ \\ +5. If the allocation failed then return(\textit{MP\_MEM}). \\ +6. for n from a.alloc to $v - 1$ do \\ +\hspace{+3mm}6.1 $a_n \leftarrow 0$ \\ +7. $a.alloc \leftarrow v$ \\ +8. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_grow} +\end{figure} + +\textbf{Algorithm mp\_grow.} +Step one will prevent a re-allocation from being performed if it was not required. This is useful to prevent mp\_ints +from growing excessively in code that erroneously calls mp\_grow. Similar to mp\_init\_size the requested digit count +is padded to provide more digits than requested. + +In step four it is assumed that the reallocation leaves the lower $a.alloc$ digits intact. Much akin to how the +\textit{realloc} function from the standard C library works. Since the newly allocated digits are assumed to contain +undefined values they are also initially zeroed. + +\index{bn\_mp\_grow.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_grow.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* grow as required */ +018 int +019 mp_grow (mp_int * a, int size) +020 \{ +021 int i; +022 +023 /* if the alloc size is smaller alloc more ram */ +024 if (a->alloc < size) \{ +025 /* ensure there are always at least MP_PREC digits extra on top */ +026 size += (MP_PREC * 2) - (size & (MP_PREC - 1)); +027 +028 a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * size); +029 if (a->dp == NULL) \{ +030 return MP_MEM; +031 \} +032 +033 /* zero excess digits */ +034 i = a->alloc; +035 a->alloc = size; +036 for (; i < a->alloc; i++) \{ +037 a->dp[i] = 0; +038 \} +039 \} +040 return MP_OKAY; +041 \} +\end{alltt} +\end{small} + +The first step is to see if we actually need to perform a re-allocation at all. This is tested for on line +24. Similar to mp\_init\_size the same code on line 26 was used to resize the +digits requested. A simple for loop from line 34 to line 38 will zero all digits that were above the +old \textbf{alloc} limit to make sure the integer is in a known state. + +\subsection{Clamping Excess Digits} +When a function anticipates a result will be $n$ digits it is simpler to assume this is true within the body of +the function. For example, a multiplication of a $i$ digit number by a $j$ digit produces a result of at most +$i + j + 1$ digits. It is entirely possible that the result is $i + j$ though, with no final carry into the last +position. However, suppose the destination had to be first expanded (\textit{via mp\_grow}) to accomodate $i + j$ +digits than further expanded to accomodate the final carry. That would be a considerable waste of time since heap +operations are relatively slow. + +The ideal solution is to always assume the result is $i + j + 1$ and fix up the \textbf{used} count after the function +terminates. This way a single heap operation (\textit{at most}) is required. However, if the result was not checked +there would be an excess high order zero digit. + +For example, suppose the product of two integers was $x_n = (0x_{n-1}x_{n-2}...x_0)_{\beta}$. The leading zero digit +will not contribute to the precision of the result. In fact, through subsequent operations more leading zero digits would +accumulate to the point the size of the integer would be prohibitive. As a result even though the precision is very +low the representation is excessively large. + +The mp\_clamp algorithm is designed to solve this very problem. It will trim leading zeros by decrementing the +\textbf{used} count until a non-zero leading digit is found. Also in this system, zero is considered to be a positive +number which means that if the \textbf{used} count is decremented to zero the sign must be set to \textbf{MP\_ZPOS}. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_clamp}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Any excess leading zero digits of $a$ are removed \\ +\hline \\ +1. while $a.used > 0$ and $a_{a.used - 1} = 0$ do \\ +\hspace{+3mm}1.1 $a.used \leftarrow a.used - 1$ \\ +2. if $a.used = 0$ then do \\ +\hspace{+3mm}2.1 $a.sign \leftarrow MP\_ZPOS$ \\ +\hline \\ +\end{tabular} +\end{center} +\caption{Algorithm mp\_clamp} +\end{figure} + +\textbf{Algorithm mp\_clamp.} +As can be expected this algorithm is very simple. The loop on step one is indended to be iterate only once or twice at +the most. For example, for cases where there is not a carry to fill the last position. Step two fixes the sign for +when all of the digits are zero to ensure that the mp\_int is valid at all times. + +\index{bn\_mp\_clamp.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_clamp.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* trim unused digits +018 * +019 * This is used to ensure that leading zero digits are +020 * trimed and the leading "used" digit will be non-zero +021 * Typically very fast. Also fixes the sign if there +022 * are no more leading digits +023 */ +024 void +025 mp_clamp (mp_int * a) +026 \{ +027 while (a->used > 0 && a->dp[a->used - 1] == 0) \{ +028 --(a->used); +029 \} +030 if (a->used == 0) \{ +031 a->sign = MP_ZPOS; +032 \} +033 \} +\end{alltt} +\end{small} + +Note on line 27 how to test for the \textbf{used} count is made on the left of the \&\& operator. In the C programming +language the terms to \&\& are evaluated left to right with a boolean short-circuit if any condition fails. This is +important since if the \textbf{used} is zero the test on the right would fetch below the array. That is obviously +undesirable. The parenthesis on line 28 is used to make sure the \textbf{used} count is decremented and not +the pointer ``a''. + +\section*{Exercises} +\begin{tabular}{cl} +$\left [ 1 \right ]$ & Discuss the relevance of the \textbf{used} member of the mp\_int structure. \\ + & \\ +$\left [ 1 \right ]$ & Discuss the consequences of not using padding when performing allocations. \\ + & \\ +$\left [ 2 \right ]$ & Estimate an ideal value for \textbf{MP\_PREC} when performing 1024-bit RSA \\ + & encryption when $\beta = 2^{28}$. \\ + & \\ +$\left [ 1 \right ]$ & Discuss the relevance of the algorithm mp\_clamp. What does it prevent? \\ + & \\ +$\left [ 1 \right ]$ & Give an example of when the algorithm mp\_init\_copy might be useful. \\ + & \\ +\end{tabular} + + +\chapter{Basic Operations} +\section{Copying an Integer} +After the various house-keeping routines are in place, simpl algorithms can be designed to take advantage of them. Being able +to make a verbatim copy of an integer is a very useful function to have. To copy an integer the mp\_copy algorithm will be used. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_copy}. \\ +\textbf{Input}. An mp\_int $a$ and $b$. \\ +\textbf{Output}. Store a copy of $a$ in $b$. \\ +\hline \\ +1. Check if $a$ and $b$ point to the same location in memory. \\ +2. If true then return(\textit{MP\_OKAY}). \\ +3. If $b.alloc < a.used$ then grow $b$ to $a.used$ digits. (\textit{hint: use mp\_grow}) \\ +4. If failed to grow then return(\textit{MP\_MEM}). \\ +5. for $n$ from 0 to $a.used - 1$ do \\ +\hspace{3mm}5.1 $b_{n} \leftarrow a_{n}$ \\ +6. if $a.used < b.used - 1$ then \\ +\hspace{3mm}6.1. for $n$ from $a.used$ to $b.used - 1$ do \\ +\hspace{6mm}6.1.1 $b_{n} \leftarrow 0$ \\ +7. $b.used \leftarrow a.used$ \\ +8. $b.sign \leftarrow a.sign$ \\ +9. return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_copy} +\end{figure} + +\textbf{Algorithm mp\_copy.} +Step 1 and 2 make sure that the two mp\_ints are unique. This allows the user to call the copy function with +potentially the same input and not waste time. Step 3 and 4 ensure that the destination is large enough to +hold a copy of the input $a$. Note that the \textbf{used} member of $b$ may be smaller than the \textbf{used} +member of $a$ but a memory re-allocation is only required if the \textbf{alloc} member of $b$ is smaller. This +prevents trivial memory reallocations. + +Step 5 copies the digits from $a$ to $b$ while step 6 ensures that if initially $\vert b \vert > \vert a \vert$, +the leading digits of $b$ will be zeroed. Finally steps 7 and 8 copies the \textbf{used} and \textbf{sign} members over +which completes the copy operation. + +\index{bn\_mp\_copy.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_copy.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* copy, b = a */ +018 int +019 mp_copy (mp_int * a, mp_int * b) +020 \{ +021 int res, n; +022 +023 /* if dst == src do nothing */ +024 if (a == b || a->dp == b->dp) \{ +025 return MP_OKAY; +026 \} +027 +028 /* grow dest */ +029 if ((res = mp_grow (b, a->used)) != MP_OKAY) \{ +030 return res; +031 \} +032 +033 /* zero b and copy the parameters over */ +034 \{ +035 register mp_digit *tmpa, *tmpb; +036 +037 /* pointer aliases */ +038 tmpa = a->dp; +039 tmpb = b->dp; +040 +041 /* copy all the digits */ +042 for (n = 0; n < a->used; n++) \{ +043 *tmpb++ = *tmpa++; +044 \} +045 +046 /* clear high digits */ +047 for (; n < b->used; n++) \{ +048 *tmpb++ = 0; +049 \} +050 \} +051 b->used = a->used; +052 b->sign = a->sign; +053 return MP_OKAY; +054 \} +\end{alltt} +\end{small} + +Source lines 23-31 do the initial house keeping. That is to see if the input is unique and if so to +make sure there is enough room. If not enough space is available it returns the error and leaves the destination variable +intact. + +The inner loop of the copy operation is contained between lines 34 and 50. Many LibTomMath routines are designed with this source code style +in mind, making aliases to shorten lengthy pointers (\textit{see line 38 and 39}) for rapid to use. Also the +use of nested braces creates a simple way to denote various portions of code that reside on various work levels. Here, the copy loop is at the +$O(n)$ level. + +\section{Zeroing an Integer} +Reseting an mp\_int to the default state is a common step in many algorithms. The mp\_zero algorithm will be the algorithm used to +perform this task. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_zero}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Zero the contents of $a$ \\ +\hline \\ +1. $a.used \leftarrow 0$ \\ +2. $a.sign \leftarrow$ MP\_ZPOS \\ +3. for $n$ from 0 to $a.alloc - 1$ do \\ +\hspace{3mm}3.1 $a_n \leftarrow 0$ \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_zero} +\end{figure} + +\textbf{Algorithm mp\_zero.} +This algorithm simply resets a mp\_int to the default state. + +\index{bn\_mp\_zero.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_zero.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* set to zero */ +018 void +019 mp_zero (mp_int * a) +020 \{ +021 a->sign = MP_ZPOS; +022 a->used = 0; +023 memset (a->dp, 0, sizeof (mp_digit) * a->alloc); +024 \} +\end{alltt} +\end{small} + +After the function is completed, all of the digits are zeroed, the \textbf{used} count is zeroed and the +\textbf{sign} variable is set to \textbf{MP\_ZPOS}. + +\section{Sign Manipulation} +\subsection{Absolute Value} +With the mp\_int representation of an integer, calculating the absolute value is trivial. The mp\_abs algorithm will compute +the absolute value of an mp\_int. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_abs}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Computes $b = \vert a \vert$ \\ +\hline \\ +1. Copy $a$ to $b$. (\textit{hint: use mp\_copy}) \\ +2. If the copy failed return(\textit{MP\_MEM}). \\ +3. $b.sign \leftarrow MP\_ZPOS$ \\ +4. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_abs} +\end{figure} + +\textbf{Algorithm mp\_abs.} +This algorithm computes the absolute of an mp\_int input. As can be expected the algorithm is very trivial. + +\index{bn\_mp\_abs.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_abs.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* b = |a| +018 * +019 * Simple function copies the input and fixes the sign to positive +020 */ +021 int +022 mp_abs (mp_int * a, mp_int * b) +023 \{ +024 int res; +025 if ((res = mp_copy (a, b)) != MP_OKAY) \{ +026 return res; +027 \} +028 b->sign = MP_ZPOS; +029 return MP_OKAY; +030 \} +\end{alltt} +\end{small} + +\subsection{Integer Negation} +With the mp\_int representation of an integer, calculating the negation is also trivial. The mp\_neg algorithm will compute +the negative of an mp\_int input. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_neg}. \\ +\textbf{Input}. An mp\_int $a$ \\ +\textbf{Output}. Computes $b = -a$ \\ +\hline \\ +1. Copy $a$ to $b$. (\textit{hint: use mp\_copy}) \\ +2. If the copy failed return(\textit{MP\_MEM}). \\ +3. If $a.sign = MP\_ZPOS$ then do \\ +\hspace{3mm}3.1 $b.sign = MP\_NEG$. \\ +4. else do \\ +\hspace{3mm}4.1 $b.sign = MP\_ZPOS$. \\ +5. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_neg} +\end{figure} + +\textbf{Algorithm mp\_neg.} +This algorithm computes the negation of an input. + +\index{bn\_mp\_neg.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_neg.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* b = -a */ +018 int +019 mp_neg (mp_int * a, mp_int * b) +020 \{ +021 int res; +022 if ((res = mp_copy (a, b)) != MP_OKAY) \{ +023 return res; +024 \} +025 b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; +026 return MP_OKAY; +027 \} +\end{alltt} +\end{small} + +\section{Small Constants} +\subsection{Setting Small Constants} +Often a mp\_int must be set to a relatively small value such as $1$ or $2$. For these cases the mp\_set algorithm is useful. + +\newpage\begin{figure} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_set}. \\ +\textbf{Input}. An mp\_int $a$ and a digit $b$ \\ +\textbf{Output}. Make $a$ equivalent to $b$ \\ +\hline \\ +1. Zero $a$ (\textit{hint: use mp\_zero}). \\ +2. $a_0 \leftarrow b \mbox{ (mod }\beta\mbox{)}$ \\ +3. $a.used \leftarrow \left \lbrace \begin{array}{ll} + 1 & \mbox{if }a_0 > 0 \\ + 0 & \mbox{if }a_0 = 0 + \end{array} \right .$ \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_set} +\end{figure} + +\textbf{Algorithm mp\_set.} +This algorithm sets a mp\_int to a small single digit value. Step number 1 ensures that the integer is reset to the default state. The +single digit is set (\textit{modulo $\beta$}) and the \textbf{used} count is adjusted accordingly. + +\index{bn\_mp\_set.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_set.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* set to a digit */ +018 void +019 mp_set (mp_int * a, mp_digit b) +020 \{ +021 mp_zero (a); +022 a->dp[0] = b & MP_MASK; +023 a->used = (a->dp[0] != 0) ? 1 : 0; +024 \} +\end{alltt} +\end{small} + +Line 21 calls mp\_zero() to clear the mp\_int and reset the sign. Line 22 actually copies digit +into the least significant location. Note the usage of a new constant \textbf{MP\_MASK}. This constant is used to quickly +reduce an integer modulo $\beta$. Since $\beta = 2^k$ it suffices to perform a binary AND with $MP\_MASK = 2^k - 1$ to perform +the reduction. Finally line 23 will set the \textbf{used} member with respect to the digit actually set. This function +will always make the integer positive. + +One important limitation of this function is that it will only set one digit. The size of a digit is not fixed, meaning source that uses +this function should take that into account. The define \textbf{DIGIT\_BIT} in ``tommath.h'' +defines how many bits per digit are available. Generally at least seven bits are guaranteed to be available per +digit. This means that trivially small constants can be set using this function. + +\subsection{Setting Large Constants} +To overcome the limitations of the mp\_set algorithm the mp\_set\_int algorithm is provided. It accepts a ``long'' +data type as input and will always treat it as a 32-bit integer. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_set\_int}. \\ +\textbf{Input}. An mp\_int $a$ and a ``long'' integer $b$ \\ +\textbf{Output}. Make $a$ equivalent to $b$ \\ +\hline \\ +1. Zero $a$ (\textit{hint: use mp\_zero}) \\ +2. for $n$ from 0 to 7 do \\ +\hspace{3mm}2.1 $a \leftarrow a \cdot 16$ (\textit{hint: use mp\_mul2d}) \\ +\hspace{3mm}2.2 $u \leftarrow \lfloor b / 2^{4(7 - n)} \rfloor \mbox{ (mod }16\mbox{)}$\\ +\hspace{3mm}2.3 $a_0 \leftarrow a_0 + u$ \\ +\hspace{3mm}2.4 $a.used \leftarrow a.used + \lfloor 32 / lg(\beta) \rfloor + 1$ \\ +3. Clamp excess used digits (\textit{hint: use mp\_clamp}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_set\_int} +\end{figure} + +\textbf{Algorithm mp\_set\_int.} +The algorithm performs eight iterations of a simple loop where in each iteration four bits from the source are added to the +mp\_int. Step 2.1 will multiply the current result by sixteen making room for four more bits. In step 2.2 the +next four bits from the source are extracted. The four bits are added to the mp\_int and the \textbf{used} digit count is +incremented. The \textbf{used} digit counter is incremented since if any of the leading digits were zero the mp\_int would have +zero digits used and the newly added four bits would be ignored. + +Excess zero digits are trimmed in steps 2.1 and 3 by using higher level algorithms mp\_mul2d and mp\_clamp. + +\index{bn\_mp\_set\_int.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_set\_int.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* set a 32-bit const */ +018 int +019 mp_set_int (mp_int * a, unsigned int b) +020 \{ +021 int x, res; +022 +023 mp_zero (a); +024 /* set four bits at a time */ +025 for (x = 0; x < 8; x++) \{ +026 /* shift the number up four bits */ +027 if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) \{ +028 return res; +029 \} +030 +031 /* OR in the top four bits of the source */ +032 a->dp[0] |= (b >> 28) & 15; +033 +034 /* shift the source up to the next four bits */ +035 b <<= 4; +036 +037 /* ensure that digits are not clamped off */ +038 a->used += 32 / DIGIT_BIT + 2; +039 \} +040 mp_clamp (a); +041 return MP_OKAY; +042 \} +\end{alltt} +\end{small} + +This function sets four bits of the number at a time to handle all practical \textbf{DIGIT\_BIT} sizes. The weird +addition on line 38 ensures that the newly added in bits are added to the number of digits. While it may not +seem obvious as to why the digit counter does not grow exceedingly large it is because of the shift on line 27 +as well as the call to mp\_clamp() on line 40. Both functions will clamp excess leading digits which keeps +the number of used digits low. + +\section{Comparisons} +\subsection{Unsigned Comparisions} +Comparing a multiple precision integer is performed with the exact same algorithm used to compare two decimal numbers. For example, +to compare $1,234$ to $1,264$ the digits are extracted by their positions. That is we compare $1 \cdot 10^3 + 2 \cdot 10^2 + 3 \cdot 10^1 + 4 \cdot 10^0$ +to $1 \cdot 10^3 + 2 \cdot 10^2 + 6 \cdot 10^1 + 4 \cdot 10^0$ by comparing single digits at a time starting with the highest magnitude +positions. If any leading digit of one integer is greater than a digit in the same position of another integer then obviously it must be greater. + +The first comparision routine that will be developed is the unsigned magnitude compare which will perform a comparison based on the digits of two +mp\_int variables alone. It will ignore the sign of the two inputs. Such a function is useful when an absolute comparison is required or if the +signs are known to agree in advance. + +To facilitate working with the results of the comparison functions three constants are required. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{|r|l|} +\hline \textbf{Constant} & \textbf{Meaning} \\ +\hline \textbf{MP\_GT} & Greater Than \\ +\hline \textbf{MP\_EQ} & Equal To \\ +\hline \textbf{MP\_LT} & Less Than \\ +\hline +\end{tabular} +\end{center} +\caption{Comparison Return Codes} +\end{figure} + +\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_cmp\_mag}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$. \\ +\textbf{Output}. Unsigned comparison results ($a$ to the left of $b$). \\ +\hline \\ +1. If $a.used > b.used$ then return(\textit{MP\_GT}) \\ +2. If $a.used < b.used$ then return(\textit{MP\_LT}) \\ +3. for n from $a.used - 1$ to 0 do \\ +\hspace{+3mm}3.1 if $a_n > b_n$ then return(\textit{MP\_GT}) \\ +\hspace{+3mm}3.2 if $a_n < b_n$ then return(\textit{MP\_LT}) \\ +4. Return(\textit{MP\_EQ}) \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_cmp\_mag} +\end{figure} + +\textbf{Algorithm mp\_cmp\_mag.} +By saying ``$a$ to the left of $b$'' it is meant that the comparison is with respect to $a$, that is if $a$ is greater than $b$ it will return +\textbf{MP\_GT} and similar with respect to when $a = b$ and $a < b$. The first two steps compare the number of digits used in both $a$ and $b$. +Obviously if the digit counts differ there would be an imaginary zero digit in the smaller number where the leading digit of the larger number is. +If both have the same number of digits than the actual digits themselves must be compared starting at the leading digit. + +By step three both inputs must have the same number of digits so its safe to start from either $a.used - 1$ or $b.used - 1$ and count down to +the zero'th digit. If after all of the digits have been compared and no difference found the algorithm simply returns \textbf{MP\_EQ}. + +\index{bn\_mp\_cmp\_mag.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_cmp\_mag.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* compare maginitude of two ints (unsigned) */ +018 int +019 mp_cmp_mag (mp_int * a, mp_int * b) +020 \{ +021 int n; +022 +023 /* compare based on # of non-zero digits */ +024 if (a->used > b->used) \{ +025 return MP_GT; +026 \} +027 +028 if (a->used < b->used) \{ +029 return MP_LT; +030 \} +031 +032 /* compare based on digits */ +033 for (n = a->used - 1; n >= 0; n--) \{ +034 if (a->dp[n] > b->dp[n]) \{ +035 return MP_GT; +036 \} +037 +038 if (a->dp[n] < b->dp[n]) \{ +039 return MP_LT; +040 \} +041 \} +042 return MP_EQ; +043 \} +\end{alltt} +\end{small} + +The two if statements on lines 24 and 28 compare the number of digits in the two inputs. These two are performed before all of the digits +are compared since it is a very cheap test to perform and can potentially save considerable time. The implementation given is also not valid +without those two statements. $b.alloc$ may be smaller than $a.used$, meaning that undefined values will be read from $b$ passed the end of the +array of digits. + +\subsection{Signed Comparisons} +Comparing with sign considerations is also fairly critical in several routines (\textit{division for example}). Based on an unsigned magnitude +comparison a trivial signed comparison algorithm can be written. + +\newpage\begin{figure}[here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_cmp}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. Signed Comparison Results ($a$ to the left of $b$) \\ +\hline \\ +1. if $a.sign = MP\_NEG$ and $b.sign = MP\_ZPOS$ then return(\textit{MP\_LT}) \\ +2. if $a.sign = MP\_ZPOS$ and $b.sign = MP\_NEG$ then return(\textit{MP\_GT}) \\ +3. if $a.sign = MP\_NEG$ then \\ +\hspace{+3mm}3.1 Return the unsigned comparison of $b$ and $a$ (\textit{hint: use mp\_cmp\_mag}) \\ +4 Otherwise \\ +\hspace{+3mm}4.1 Return the unsigned comparison of $a$ and $b$ \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_cmp} +\end{figure} + +\textbf{Algorithm mp\_cmp.} +The first two steps compare the signs of the two inputs. If the signs do not agree then it can return right away with the appropriate +comparison code. When the signs are equal the digits of the inputs must be compared to determine the correct result. In step +three the unsigned comparision flips the order of the arguments since they are both negative. For instance, if $-a > -b$ then +$\vert a \vert < \vert b \vert$. Step number four will compare the two when they are both positive. + +\index{bn\_mp\_cmp.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_cmp.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* compare two ints (signed)*/ +018 int +019 mp_cmp (mp_int * a, mp_int * b) +020 \{ +021 /* compare based on sign */ +022 if (a->sign == MP_NEG && b->sign == MP_ZPOS) \{ +023 return MP_LT; +024 \} +025 +026 if (a->sign == MP_ZPOS && b->sign == MP_NEG) \{ +027 return MP_GT; +028 \} +029 +030 /* compare digits */ +031 if (a->sign == MP_NEG) \{ +032 /* if negative compare opposite direction */ +033 return mp_cmp_mag(b, a); +034 \} else \{ +035 return mp_cmp_mag(a, b); +036 \} +037 \} +\end{alltt} +\end{small} + +The two if statements on lines 22 and 26 perform the initial sign comparison. If the signs are not the equal then which ever +has the positive sign is larger. At line 31, the inputs are compared based on magnitudes. If the signs were both negative then +the unsigned comparison is performed in the opposite direction (\textit{line 33}). Otherwise, the signs are assumed to +be both positive and a forward direction unsigned comparison is performed. + +\section*{Exercises} +\begin{tabular}{cl} +$\left [ 2 \right ]$ & Modify algorithm mp\_set\_int to accept as input a variable length array of bits. \\ + & \\ +$\left [ 3 \right ]$ & Give the probability that algorithm mp\_cmp\_mag will have to compare $k$ digits \\ + & of two random digits (of equal magnitude) before a difference is found. \\ + & \\ +$\left [ 1 \right ]$ & Suggest a simple method to speed up the implementation of mp\_cmp\_mag based \\ + & on the observations made in the previous problem. \\ + & +\end{tabular} + +\chapter{Basic Arithmetic} +\section{Building Blocks} +At this point algorithms for initialization, de-initialization, zeroing, copying, comparing and setting small constants have been +established. The next logical set of algorithms to develop are the addition, subtraction and digit movement algorithms. These +algorithms make use of the lower level algorithms and are the cruicial building block for the multipliers. It is very important that these +algorithms are highly optimized. On their own they are simple $O(n)$ algorithms but they can be called from higher level algorithms +which easily places them at $O(n^2)$ or even $O(n^3)$ work levels. + +All nine algorithms within this chapter make use of the logical bit shift operations denoted by $<<$ and $>>$ for left and right +logical shifts respectively. A logical shift is analogous to sliding the decimal point of radix-10 representations. For example, the real +number $0.9345$ is equivalent to $93.45\%$ which is found by sliding the the decimal two places to the right (\textit{multiplying by $10^2$}). +Mathematically a logical shift is equivalent to a division or multiplication by a power of two. +For example, $a << k = a \cdot 2^k$ while $a >> k = \lfloor a/2^k \rfloor$. + +One significant difference between a logical shift and the way decimals are shifted is that digits below the zero'th position are removed +from the number. For example, consider $1101_2 >> 1$ using decimal notation this would produce $110.1_2$. However, with a logical shift the +result is $110_2$. + +\section{Addition and Subtraction} +In normal fixed precision arithmetic negative numbers are easily represented by subtraction from the modulus. For example, with 32-bit integers +$a - b\mbox{ (mod }2^{32}\mbox{)}$ is the same as $a + (2^{32} - b) \mbox{ (mod }2^{32}\mbox{)}$ since $2^{32} \equiv 0 \mbox{ (mod }2^{32}\mbox{)}$. +As a result subtraction can be performed with a trivial series of logical operations and an addition. + +However, in multiple precision arithmetic negative numbers are not represented in the same way. Instead a sign flag is used to keep track of the +sign of the integer. As a result signed addition and subtraction are actually implemented as conditional usage of lower level addition or +subtraction algorithms with the sign fixed up appropriately. + +The lower level algorithms will add or subtract integers without regard to the sign flag. That is they will add or subtract the magnitude of +the integers respectively. + +\subsection{Low Level Addition} +An unsigned addition of multiple precision integers is performed with the same long-hand algorithm used to add decimal numbers. That is to add the +trailing digits first and propagate the resulting carry upwards. Since this is a lower level algorithm the name will have a ``s\_'' prefix. +Historically that convention stems from the MPI library where ``s\_'' stood for static functions that were hidden from the developer entirely. + +\newpage +\begin{figure}[!here] +\begin{center} +\begin{small} +\begin{tabular}{l} +\hline Algorithm \textbf{s\_mp\_add}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. The unsigned addition $c = \vert a \vert + \vert b \vert$. \\ +\hline \\ +1. if $a.used > b.used$ then \\ +\hspace{+3mm}1.1 $min \leftarrow b.used$ \\ +\hspace{+3mm}1.2 $max \leftarrow a.used$ \\ +\hspace{+3mm}1.3 $x \leftarrow a$ \\ +2. else \\ +\hspace{+3mm}2.1 $min \leftarrow a.used$ \\ +\hspace{+3mm}2.2 $max \leftarrow b.used$ \\ +\hspace{+3mm}2.3 $x \leftarrow b$ \\ +3. If $c.alloc < max + 1$ then grow $c$ to hold at least $max + 1$ digits (\textit{hint: use mp\_grow}) \\ +4. If failed to grow $c$ return(\textit{MP\_MEM}) \\ +5. $oldused \leftarrow c.used$ \\ +6. $c.used \leftarrow max + 1$ \\ +7. $u \leftarrow 0$ \\ +8. for $n$ from $0$ to $min - 1$ do \\ +\hspace{+3mm}8.1 $c_n \leftarrow a_n + b_n + u$ \\ +\hspace{+3mm}8.2 $u \leftarrow c_n >> lg(\beta)$ \\ +\hspace{+3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +9. if $min \ne max$ then do \\ +\hspace{+3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ +\hspace{+6mm}9.1.1 $c_n \leftarrow x_n + u$ \\ +\hspace{+6mm}9.1.2 $u \leftarrow c_n >> lg(\beta)$ \\ +\hspace{+6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +10. $c_{max} \leftarrow u$ \\ +11. if $olduse > max$ then \\ +\hspace{+3mm}11.1 for $n$ from $max + 1$ to $olduse - 1$ do \\ +\hspace{+6mm}11.1.1 $c_n \leftarrow 0$ \\ +12. Clamp excess digits in $c$. (\textit{hint: use mp\_clamp}) \\ +13. Return(\textit{MP\_OKAY}) \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Algorithm s\_mp\_add} +\end{figure} + +\textbf{Algorithm s\_mp\_add.} +This algorithm is loosely based on algorithm 14.7 of \cite[pp. 594]{HAC} but has been extended to allow the inputs to have different magnitudes. +Coincidentally the description of algorithm A in \cite[pp. 266]{TAOCPV2} shares the same flaw as that from \cite{HAC}. Even the MIX pseudo +machine code presented \cite[pp. 266-267]{TAOCPV2} is incapable of handling inputs which are of different magnitudes. + +Steps 1 and 2 will sort the two inputs based on their \textbf{used} digit count. This allows the inputs to have varying magnitudes which not +only makes it more efficient than the trivial algorithm presented in the other references but more flexible. The variable $min$ is given the lowest +digit count while $max$ is given the highest digit count. If both inputs have the same \textbf{used} digit count both $min$ and $max$ are +set to the same. The variable $x$ is an \textit{alias} for the largest input and not meant to be a copy of it. After the inputs are sorted steps +3 and 4 will ensure that the destination $c$ can accommodate the result. The old \textbf{used} count from $c$ is copied to $oldused$ and the +new count is set to $max + 1$. + +At step 7 the carry variable $u$ is set to zero and the first leg of the addition loop can begin. The first step of the loop (\textit{8.1}) adds +digits from the two inputs together along with the carry variable $u$. The following step extracts the carry bit by shifting the result of the +preceding step right $lg(\beta)$ positions. The shift to extract the carry is similar to how carry extraction works with decimal addition. + +Consider adding $77$ to $65$, the first addition of the first column is $7 + 5$ which produces the result $12$. The trailing digit of the result +is $2 \equiv 12 \mbox{ (mod }10\mbox{)}$ and the carry is found by dividing (\textit{and ignoring the remainder}) $12$ by the radix or in this case $10$. The +division and multiplication of $10$ is simply a logical shift right or left respectively of the digits. In otherwords the carry can be extracted +by shifting one digit to the right. + +Note that $lg()$ is simply the base two logarithm such that $lg(2^k) = k$. This implies that $lg(\beta)$ is the number of bits in a radix-$\beta$ +digit. Therefore, a logical shift right of the single digit by $lg(\beta)$ will extract the carry. The final step of the loop reduces the digit +modulo the radix $\beta$ to ensure it is in range. + +After step 8 the smallest input (\textit{or both if they are the same magnitude}) has been exhausted. Step 9 decides whether +the inputs were of equal magnitude. If not than another loop similar to that in step 8 must be executed. The loop at step +number 9.1 differs from the previous loop since it only adds the mp\_int $x$ along with the carry. + +Step 10 finishes the addition phase by copying the final carry to the highest location in the result $c_{max}$. Step 11 ensures that +leading digits that were originally present in $c$ are cleared. Finally excess leading digits are clamped and the algorithm returns success. + +\index{bn\_s\_mp\_add.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_add.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* low level addition, based on HAC pp.594, Algorithm 14.7 */ +018 int +019 s_mp_add (mp_int * a, mp_int * b, mp_int * c) +020 \{ +021 mp_int *x; +022 int olduse, res, min, max; +023 +024 /* find sizes, we let |a| <= |b| which means we have to sort +025 * them. "x" will point to the input with the most digits +026 */ +027 if (a->used > b->used) \{ +028 min = b->used; +029 max = a->used; +030 x = a; +031 \} else \{ +032 min = a->used; +033 max = b->used; +034 x = b; +035 \} +036 +037 /* init result */ +038 if (c->alloc < max + 1) \{ +039 if ((res = mp_grow (c, max + 1)) != MP_OKAY) \{ +040 return res; +041 \} +042 \} +043 +044 /* get old used digit count and set new one */ +045 olduse = c->used; +046 c->used = max + 1; +047 +048 /* set the carry to zero */ +049 \{ +050 register mp_digit u, *tmpa, *tmpb, *tmpc; +051 register int i; +052 +053 /* alias for digit pointers */ +054 +055 /* first input */ +056 tmpa = a->dp; +057 +058 /* second input */ +059 tmpb = b->dp; +060 +061 /* destination */ +062 tmpc = c->dp; +063 +064 /* zero the carry */ +065 u = 0; +066 for (i = 0; i < min; i++) \{ +067 /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ +068 *tmpc = *tmpa++ + *tmpb++ + u; +069 +070 /* U = carry bit of T[i] */ +071 u = *tmpc >> ((mp_digit)DIGIT_BIT); +072 +073 /* take away carry bit from T[i] */ +074 *tmpc++ &= MP_MASK; +075 \} +076 +077 /* now copy higher words if any, that is in A+B +078 * if A or B has more digits add those in +079 */ +080 if (min != max) \{ +081 for (; i < max; i++) \{ +082 /* T[i] = X[i] + U */ +083 *tmpc = x->dp[i] + u; +084 +085 /* U = carry bit of T[i] */ +086 u = *tmpc >> ((mp_digit)DIGIT_BIT); +087 +088 /* take away carry bit from T[i] */ +089 *tmpc++ &= MP_MASK; +090 \} +091 \} +092 +093 /* add carry */ +094 *tmpc++ = u; +095 +096 /* clear digits above oldused */ +097 for (i = c->used; i < olduse; i++) \{ +098 *tmpc++ = 0; +099 \} +100 \} +101 +102 mp_clamp (c); +103 return MP_OKAY; +104 \} +\end{alltt} +\end{small} + +Lines 27 to 35 perform the initial sorting of the inputs and determine the $min$ and $max$ variables. Note that $x$ is pointer to a +mp\_int assigned to the largest input, in effect it is a local alias. Lines 37 to 42 ensure that the destination is grown to +accomodate the result of the addition. + +Similar to the implementation of mp\_copy this function uses the braced code and local aliases coding style. The three aliases on +lines 56, 59 and 62 are the for the two inputs and destination respectively. These aliases are used to ensure the +compiler does not have to dereference $a$, $b$ or $c$ (respectively) to access the digits of the respective mp\_int. + +The initial carry $u$ is cleared on line 65, note that $u$ is of type mp\_digit which ensures type compatibility within the +implementation. The initial addition loop begins on line 66 and ends on line 75. Similarly the conditional addition loop +begins on line 81 and ends on line 90. The addition is finished with the final carry being stored in $tmpc$ on line 94. +Note the ``++'' operator on the same line. After line 94 $tmpc$ will point to the $c.used$'th digit of the mp\_int $c$. This is useful +for the next loop on lines 97 to 99 which set any old upper digits to zero. + +\subsection{Low Level Subtraction} +The low level unsigned subtraction algorithm is very similar to the low level unsigned addition algorithm. The principle difference is that the +unsigned subtraction algorithm requires the result to be positive. That is when computing $a - b$ the condition $\vert a \vert \ge \vert b\vert$ must +be met for this algorithm to function properly. Keep in mind this low level algorithm is not meant to be used in higher level algorithms directly. +This algorithm as will be shown can be used to create functional signed addition and subtraction algorithms. + + +For this algorithm a new variable is required to make the description simpler. Recall from section 1.3.1 that a mp\_digit must be able to represent +the range $0 \le x < 2\beta$. It is allowable that a mp\_digit represent a larger range of values. For this algorithm we will assume that +the variable $\gamma$ represents the number of bits available in a mp\_digit (\textit{this implies $2^{\gamma} > \beta$}). + +\newpage\begin{figure}[!here] +\begin{center} +\begin{small} +\begin{tabular}{l} +\hline Algorithm \textbf{s\_mp\_sub}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ ($\vert a \vert \ge \vert b \vert$) \\ +\textbf{Output}. The unsigned subtraction $c = \vert a \vert - \vert b \vert$. \\ +\hline \\ +1. $min \leftarrow b.used$ \\ +2. $max \leftarrow a.used$ \\ +3. If $c.alloc < max$ then grow $c$ to hold at least $max$ digits. (\textit{hint: use mp\_grow}) \\ +4. If the reallocation failed return(\textit{MP\_MEM}). \\ +5. $oldused \leftarrow c.used$ \\ +6. $c.used \leftarrow max$ \\ +7. $u \leftarrow 0$ \\ +8. for $n$ from $0$ to $min - 1$ do \\ +\hspace{3mm}8.1 $c_n \leftarrow a_n - b_n - u$ \\ +\hspace{3mm}8.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ +\hspace{3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +9. if $min < max$ then do \\ +\hspace{3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ +\hspace{6mm}9.1.1 $c_n \leftarrow a_n - u$ \\ +\hspace{6mm}9.1.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ +\hspace{6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ +10. if $oldused > max$ then do \\ +\hspace{3mm}10.1 for $n$ from $max$ to $oldused - 1$ do \\ +\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ +11. Clamp excess digits of $c$. (\textit{hint: use mp\_clamp}). \\ +12. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Algorithm s\_mp\_sub} +\end{figure} + +\textbf{Algorithm s\_mp\_sub.} +This algorithm performs the unsigned subtraction of two mp\_int variables under the restriction that the result must be positive. That is when +passing variables $a$ and $b$ the condition that $\vert a \vert \ge \vert b \vert$ must be met for the algorithm to function correctly. This +algorithm is loosely based on algorithm 14.9 \cite[pp. 595]{HAC} and is similar to algorithm S in \cite[pp. 267]{TAOCPV2} as well. As was the case +of the algorithm s\_mp\_add both other references lack discussion concerning various practical details such as when the inputs differ in magnitude. + +The initial sorting of the inputs is trivial in this algorithm since $a$ is guaranteed to have at least the same magnitude of $b$. Steps 1 and 2 +set the $min$ and $max$ variables. Unlike the addition routine there is guaranteed to be no carry which means that the final result can be at +most $max$ digits in length as oppose to $max + 1$. Similar to the addition algorithm the \textbf{used} count of $c$ is copied locally and +set to the maximal count for the operation. + +The subtraction loop that begins on step 8 is essentially the same as the addition loop of algorithm s\_mp\_add except single precision +subtraction is used instead. Note the use of the $\gamma$ variable to extract the carry within the subtraction loops. Under the assumption +that two's complement single precision arithmetic is used this will successfully extract the carry. + +For example, consider subtracting $0101_2$ from +$0100_2$ where $\gamma = 4$. The least significant bit will force a carry upwards to the third bit which will be set to zero after the borrow. After +the very first bit has been subtracted $4 - 1 \equiv 0011_2$ will remain, When the third bit of $0101_2$ is subtracted from the result it will cause +another carry. In this case though the carry will be forced to propagate all the way to the most significant bit. + +Recall that $\beta < 2^{\gamma}$. This means that if a carry does occur it will propagate all the way to the most significant bit. Therefore a single +logical shift right by $\gamma - 1$ positions is sufficient to extract the carry. This method of carry extraction may seem awkward but the reason for +it becomes apparent when the implementation is discussed. + +If $b$ has a smaller magnitude than $a$ then step 9 will force the carry and copy operation to propagate through the larger input $a$ into $c$. Step +10 will ensure that any leading digits of $c$ above the $max$'th position are zeroed. + +\index{bn\_s\_mp\_sub.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_sub.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +018 int +019 s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +020 \{ +021 int olduse, res, min, max; +022 +023 /* find sizes */ +024 min = b->used; +025 max = a->used; +026 +027 /* init result */ +028 if (c->alloc < max) \{ +029 if ((res = mp_grow (c, max)) != MP_OKAY) \{ +030 return res; +031 \} +032 \} +033 olduse = c->used; +034 c->used = max; +035 +036 /* sub digits from lower part */ +037 \{ +038 register mp_digit u, *tmpa, *tmpb, *tmpc; +039 register int i; +040 +041 /* alias for digit pointers */ +042 tmpa = a->dp; +043 tmpb = b->dp; +044 tmpc = c->dp; +045 +046 /* set carry to zero */ +047 u = 0; +048 for (i = 0; i < min; i++) \{ +049 /* T[i] = A[i] - B[i] - U */ +050 *tmpc = *tmpa++ - *tmpb++ - u; +051 +052 /* U = carry bit of T[i] +053 * Note this saves performing an AND operation since +054 * if a carry does occur it will propagate all the way to the +055 * MSB. As a result a single shift is required to get the carry +056 */ +057 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); +058 +059 /* Clear carry from T[i] */ +060 *tmpc++ &= MP_MASK; +061 \} +062 +063 /* now copy higher words if any, e.g. if A has more digits than B */ +064 for (; i < max; i++) \{ +065 /* T[i] = A[i] - U */ +066 *tmpc = *tmpa++ - u; +067 +068 /* U = carry bit of T[i] */ +069 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); +070 +071 /* Clear carry from T[i] */ +072 *tmpc++ &= MP_MASK; +073 \} +074 +075 /* clear digits above used (since we may not have grown result above) */ + +076 for (i = c->used; i < olduse; i++) \{ +077 *tmpc++ = 0; +078 \} +079 \} +080 +081 mp_clamp (c); +082 return MP_OKAY; +083 \} +\end{alltt} +\end{small} + +Line 24 and 25 perform the initial hardcoded sorting. In reality they are only aliases and are only used to make the source easier to +read. Again the pointer alias optimization is used within this algorithm. Lines 42, 43 and 44 initialize the aliases for +$a$, $b$ and $c$ respectively. + +The first subtraction loop occurs on lines 47 through 61. The theory behind the subtraction loop is exactly the same as that for +the addition loop. As remarked earlier there is an implementation reason for using the ``awkward'' method of extracting the carry +(\textit{see line 57}). The traditional method for extracting the carry would be to shift by $lg(\beta)$ positions and logically AND +the least significant bit. The AND operation is required because all of the bits above the $\lg(\beta)$'th bit will be set to one after a carry +occurs from subtraction. This carry extraction requires two relatively cheap operations to extract the carry. The other method is to simply +shift the most significant bit to the least significant bit thus extracting the carry with a single cheap operation. This optimization only works on +twos compliment machines which is a safe assumption to make. + +If $a$ has a higher magnitude than $b$ an additional loop (\textit{see lines 64 through 73}) is required to propagate the carry through +$a$ and copy the result to $c$. + +\subsection{High Level Addition} +Now that both lower level addition and subtraction algorithms have been established an effective high level signed addition algorithm can be +established. This high level addition algorithm will be what other algorithms and developers will use to perform addition of mp\_int data +types. + +Recall from section 5.2 that an mp\_int represents an integer with an unsigned mantissa (\textit{the array of digits}) and a \textbf{sign} +flag. A high level addition is actually performed as a series of eight seperate cases which can be optimized down to three unique cases. + +\newpage\begin{figure}[!here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_add}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. The signed addition $c = a + b$. \\ +\hline \\ +1. if $a.sign = b.sign$ then do \\ +\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ +\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{hint: use s\_mp\_add})\\ +2. else do \\ +\hspace{3mm}2.1 if $\vert a \vert < \vert b \vert$ then do (\textit{hint: use mp\_cmp\_mag}) \\ +\hspace{6mm}2.1.1 $c.sign \leftarrow b.sign$ \\ +\hspace{6mm}2.1.2 $c \leftarrow \vert b \vert - \vert a \vert$ (\textit{hint: use s\_mp\_sub}) \\ +\hspace{3mm}2.2 else do \\ +\hspace{6mm}2.2.1 $c.sign \leftarrow a.sign$ \\ +\hspace{6mm}2.2.2 $c \leftarrow \vert a \vert - \vert b \vert$ \\ +3. If any of the lower level operations failed return(\textit{MP\_MEM}) \\ +4. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_add} +\end{figure} + +\textbf{Algorithm mp\_add.} +This algorithm performs the signed addition of two mp\_int variables. There is no reference algorithm to draw upon from either \cite{TAOCPV2} or +\cite{HAC} since they both only provide unsigned operations. The algorithm is fairly straightforward but restricted since subtraction can only +produce positive results. Consider the following chart of possible inputs. + +\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|c|c|} +\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert > \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ +\hline $+$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $+$ & $+$ & No & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $-$ & No & $c = a + b$ & $a.sign$ \\ +\hline &&&&\\ + +\hline $+$ & $-$ & No & $c = b - a$ & $b.sign$ \\ +\hline $-$ & $+$ & No & $c = b - a$ & $b.sign$ \\ + +\hline &&&&\\ + +\hline $+$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ +\hline $-$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ + +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Addition Guide Chart} +\end{figure} + +The chart lists all of the eight possible input combinations and is sorted to show that only three specific cases need to be handled. The +return code of the unsigned operations at step 1.2, 2.1.2 and 2.2.2 are forwarded to step 3 to check for errors. This simpliies the description +of the algorithm considerably and best follows how the implementation actually was achieved. + +Also note how the \textbf{sign} is set before the unsigned addition or subtraction is performed. Recall from the descriptions of algorithms +s\_mp\_add and s\_mp\_sub that the mp\_clamp function is used at the end to trim excess digits. The mp\_clamp algorithm will set the \textbf{sign} +to \textbf{MP\_ZPOS} when the \textbf{used} digit count reaches zero. + +For example, consider performing $-a + a$ with algorithm mp\_add. By the description of the algorithm the sign is set to \textbf{MP\_NEG} which would +produce a result of $-0$. However, since the sign is set first then the unsigned addition is performed the subsequent usage of algorithm mp\_clamp +within algorithm s\_mp\_add will force $-0$ to become $0$. + +\index{bn\_mp\_add.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_add.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* high level addition (handles signs) */ +018 int +019 mp_add (mp_int * a, mp_int * b, mp_int * c) +020 \{ +021 int sa, sb, res; +022 +023 /* get sign of both inputs */ +024 sa = a->sign; +025 sb = b->sign; +026 +027 /* handle two cases, not four */ +028 if (sa == sb) \{ +029 /* both positive or both negative */ +030 /* add their magnitudes, copy the sign */ +031 c->sign = sa; +032 res = s_mp_add (a, b, c); +033 \} else \{ +034 /* one positive, the other negative */ +035 /* subtract the one with the greater magnitude from */ +036 /* the one of the lesser magnitude. The result gets */ +037 /* the sign of the one with the greater magnitude. */ +038 if (mp_cmp_mag (a, b) == MP_LT) \{ +039 c->sign = sb; +040 res = s_mp_sub (b, a, c); +041 \} else \{ +042 c->sign = sa; +043 res = s_mp_sub (a, b, c); +044 \} +045 \} +046 return res; +047 \} +048 +\end{alltt} +\end{small} + +The source code follows the algorithm fairly closely. The most notable new source code addition is the usage of the $res$ integer variable which +is used to pass result of the unsigned operations forward. Unlike in the algorithm, the variable $res$ is merely returned as is without +explicitly checking it and returning the constant \textbf{MP\_OKAY}. The observation is this algorithm will succeed or fail only if the lower +level functions do so. Returning their return code is sufficient. + +\subsection{High Level Subtraction} +The high level signed subtraction algorithm is essentially the same as the high level signed addition algorithm. + +\begin{figure}[!here] +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_sub}. \\ +\textbf{Input}. Two mp\_ints $a$ and $b$ \\ +\textbf{Output}. The signed subtraction $c = a - b$. \\ +\hline \\ +1. if $a.sign \ne b.sign$ then do \\ +\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ +\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{hint: use s\_mp\_add}) \\ +2. else do \\ +\hspace{3mm}2.1 if $\vert a \vert \ge \vert b \vert$ then do (\textit{hint: use mp\_cmp\_mag}) \\ +\hspace{6mm}2.1.1 $c.sign \leftarrow a.sign$ \\ +\hspace{6mm}2.1.2 $c \leftarrow \vert a \vert - \vert b \vert$ (\textit{hint: use s\_mp\_sub}) \\ +\hspace{3mm}2.2 else do \\ +\hspace{6mm}2.2.1 $c.sign \leftarrow \left \lbrace \begin{array}{ll} + MP\_ZPOS & \mbox{if }a.sign = MP\_NEG \\ + MP\_NEG & \mbox{otherwise} \\ + \end{array} \right .$ \\ +\hspace{6mm}2.2.2 $c \leftarrow \vert b \vert - \vert a \vert$ \\ +3. If any of the lower level operations failed return(\textit{MP\_MEM}). \\ +4. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\caption{Algorithm mp\_sub} +\end{figure} + +\textbf{Algorithm mp\_sub.} +This algorithm performs the signed subtraction of two inputs. Similar to algorithm mp\_add there is no reference in either \cite{TAOCPV2} or +\cite{HAC}. Also this algorithm is restricted by algorithm s\_mp\_sub. The following chart lists the eight possible inputs and +the operations required. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|c|c|} +\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert \ge \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ +\hline $+$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $+$ & $-$ & No & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ +\hline $-$ & $+$ & No & $c = a + b$ & $a.sign$ \\ +\hline &&&& \\ +\hline $+$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ +\hline $-$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ +\hline &&&& \\ +\hline $+$ & $+$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ +\hline $-$ & $-$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Subtraction Guide Chart} +\end{figure} + +Similar to the case of algorithm mp\_add the \textbf{sign} is set first before the unsigned addition or subtraction. That is to prevent the +algorithm from producing $-a - -a = -0$ as a result. + +\index{bn\_mp\_sub.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_sub.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* high level subtraction (handles signs) */ +018 int +019 mp_sub (mp_int * a, mp_int * b, mp_int * c) +020 \{ +021 int sa, sb, res; +022 +023 sa = a->sign; +024 sb = b->sign; +025 +026 if (sa != sb) \{ +027 /* subtract a negative from a positive, OR */ +028 /* subtract a positive from a negative. */ +029 /* In either case, ADD their magnitudes, */ +030 /* and use the sign of the first number. */ +031 c->sign = sa; +032 res = s_mp_add (a, b, c); +033 \} else \{ +034 /* subtract a positive from a positive, OR */ +035 /* subtract a negative from a negative. */ +036 /* First, take the difference between their */ +037 /* magnitudes, then... */ +038 if (mp_cmp_mag (a, b) != MP_LT) \{ +039 /* Copy the sign from the first */ +040 c->sign = sa; +041 /* The first has a larger or equal magnitude */ +042 res = s_mp_sub (a, b, c); +043 \} else \{ +044 /* The result has the *opposite* sign from */ +045 /* the first number. */ +046 c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; +047 /* The second has a larger magnitude */ +048 res = s_mp_sub (b, a, c); +049 \} +050 \} +051 return res; +052 \} +053 +\end{alltt} +\end{small} + +Much like the implementation of algorithm mp\_add the variable $res$ is used to catch the return code of the unsigned addition or subtraction operations +and forward it to the end of the function. On line 38 the ``not equal to'' \textbf{MP\_LT} expression is used to emulate a +``greater than or equal to'' comparison. + +\section{Bit and Digit Shifting} +It is quite common to think of a multiple precision integer as a polynomial in $x$, that is $y = f(\beta)$ where $f(x) = \sum_{i=0}^{n-1} a_i x^i$. +This notation arises within discussion of Montgomery and Diminished Radix Reduction as well as Karatsuba multiplication and squaring. + +In order to facilitate operations on polynomials in $x$ as above a series of simple ``digit'' algorithms have to be established. That is to shift +the digits left or right as well to shift individual bits of the digits left and right. It is important to note that not all ``shift'' operations +are on radix-$\beta$ digits. + +\subsection{Multiplication by Two} + +In a binary system where the radix is a power of two multiplication by two not only arises often in other algorithms it is a fairly efficient +operation to perform. A single precision logical shift left is sufficient to multiply a single digit by two. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_mul\_2}. \\ +\textbf{Input}. One mp\_int $a$ \\ +\textbf{Output}. $b = 2a$. \\ +\hline \\ +1. If $b.alloc < a.used + 1$ then grow $b$ to hold $a.used + 1$ digits. (\textit{hint: use mp\_grow}) \\ +2. If the reallocation failed return(\textit{MP\_MEM}). \\ +3. $oldused \leftarrow b.used$ \\ +4. $b.used \leftarrow a.used$ \\ +5. $r \leftarrow 0$ \\ +6. for $n$ from 0 to $a.used - 1$ do \\ +\hspace{3mm}6.1 $rr \leftarrow a_n >> (lg(\beta) - 1)$ \\ +\hspace{3mm}6.2 $b_n \leftarrow (a_n << 1) + r \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{3mm}6.3 $r \leftarrow rr$ \\ +7. If $r \ne 0$ then do \\ +\hspace{3mm}7.1 $b_{a.used} = 1$ \\ +\hspace{3mm}7.2 $b.used \leftarrow b.used + 1$ \\ +8. If $b.used < oldused - 1$ then do \\ +\hspace{3mm}8.1 for $n$ from $b.used$ to $oldused - 1$ do \\ +\hspace{6mm}8.1.1 $b_n \leftarrow 0$ \\ +9. $b.sign \leftarrow a.sign$ \\ +10. Return(\textit{MP\_OKAY}).\\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_mul\_2} +\end{figure} + +\textbf{Algorithm mp\_mul\_2.} +This algorithm will quickly multiply a mp\_int by two provided $\beta$ is a power of two. Neither \cite{TAOCPV2} nor \cite{HAC} describe such +an algorithm despite the fact it arises often in other algorithms. The algorithm is setup much like the lower level algorithm s\_mp\_add since +it is for all intents and purposes equivalent to the operation $b = \vert a \vert + \vert a \vert$. + +Step 1 and 2 grow the input as required to accomodate the maximum number of \textbf{used} digits in the result. The initial \textbf{used} count +is set to $a.used$ at step 4. Only if there is a final carry will the \textbf{used} count require adjustment. + +Step 6 is an optimization implementation of the addition loop for this specific case. That is since the two values being added together +are the same there is no need to perform two reads from the digits of $a$. Step 6.1 performs a single precision shift on the current digit $a_n$ to +obtain what will be the carry for the next iteration. Step 6.2 calculates the $n$'th digit of the result as single precision shift of $a_n$ plus +the previous carry. Recall from section 5.1 that $a_n << 1$ is equivalent to $a_n \cdot 2$. An iteration of the addition loop is finished with +forwarding the carry to the next iteration. + +Step 7 takes care of any final carry by setting the $a.used$'th digit of the result to one and augmenting the \textbf{used} count. Step 8 clears +any original leading digits of $b$. + +\index{bn\_mp\_mul\_2.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_mul\_2.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* b = a*2 */ +018 int +019 mp_mul_2 (mp_int * a, mp_int * b) +020 \{ +021 int x, res, oldused; +022 +023 /* grow to accomodate result */ +024 if (b->alloc < a->used + 1) \{ +025 if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) \{ +026 return res; +027 \} +028 \} +029 +030 oldused = b->used; +031 b->used = a->used; +032 +033 \{ +034 register mp_digit r, rr, *tmpa, *tmpb; +035 +036 /* alias for source */ +037 tmpa = a->dp; +038 +039 /* alias for dest */ +040 tmpb = b->dp; +041 +042 /* carry */ +043 r = 0; +044 for (x = 0; x < a->used; x++) \{ +045 +046 /* get what will be the *next* carry bit from the +047 * MSB of the current digit +048 */ +049 rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); +050 +051 /* now shift up this digit, add in the carry [from the previous] */ +052 *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; +053 +054 /* copy the carry that would be from the source +055 * digit into the next iteration +056 */ +057 r = rr; +058 \} +059 +060 /* new leading digit? */ +061 if (r != 0) \{ +062 /* add a MSB which is always 1 at this point */ +063 *tmpb = 1; +064 ++b->used; +065 \} +066 +067 /* now zero any excess digits on the destination +068 * that we didn't write to +069 */ +070 tmpb = b->dp + b->used; +071 for (x = b->used; x < oldused; x++) \{ +072 *tmpb++ = 0; +073 \} +074 \} +075 b->sign = a->sign; +076 return MP_OKAY; +077 \} +\end{alltt} +\end{small} + +This implementation is essentially an optimized implementation of s\_mp\_add for the case of doubling an input. The only noteworthy difference +is the use of the logical shift operator on line 52 to perform a single precision doubling. + +\subsection{Division by Two} +A division by two can just as easily be accomplished with a logical shift right as multiplication by two can be with a logical shift left. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_div\_2}. \\ +\textbf{Input}. One mp\_int $a$ \\ +\textbf{Output}. $b = a/2$. \\ +\hline \\ +1. If $b.alloc < a.used$ then grow $b$ to hold $a.used$ digits. (\textit{hint: use mp\_grow}) \\ +2. If the reallocation failed return(\textit{MP\_MEM}). \\ +3. $oldused \leftarrow b.used$ \\ +4. $b.used \leftarrow a.used$ \\ +5. $r \leftarrow 0$ \\ +6. for $n$ from $b.used - 1$ to $0$ do \\ +\hspace{3mm}6.1 $rr \leftarrow a_n \mbox{ (mod }2\mbox{)}$\\ +\hspace{3mm}6.2 $b_n \leftarrow (a_n >> 1) + (r << (lg(\beta) - 1)) \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{3mm}6.3 $r \leftarrow rr$ \\ +7. If $b.used < oldused - 1$ then do \\ +\hspace{3mm}7.1 for $n$ from $b.used$ to $oldused - 1$ do \\ +\hspace{6mm}7.1.1 $b_n \leftarrow 0$ \\ +8. $b.sign \leftarrow a.sign$ \\ +9. Return(\textit{MP\_OKAY}).\\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_div\_2} +\end{figure} + +\textbf{Algorithm mp\_div\_2.} +This algorithm will divide an mp\_int by two using logical shifts to the right. Like mp\_mul\_2 it uses a modified low level addition +core as the basis of the algorithm. Unlike mp\_mul\_2 the shift operations work from the leading digit to the trailing digit. The algorithm +could be written to work from the trailing digit to the leading digit however, it would have to stop one short of $a.used - 1$ digits to prevent +reading passed the end of the array of digits. + +Essentially the loop at step 6 is similar to that of mp\_mul\_2 except the logical shifts go in the opposite direction and the carry is at the +least significant bit not the most significant bit. + +\index{bn\_mp\_div\_2.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_div\_2.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* b = a/2 */ +018 int +019 mp_div_2 (mp_int * a, mp_int * b) +020 \{ +021 int x, res, oldused; +022 +023 /* copy */ +024 if (b->alloc < a->used) \{ +025 if ((res = mp_grow (b, a->used)) != MP_OKAY) \{ +026 return res; +027 \} +028 \} +029 +030 oldused = b->used; +031 b->used = a->used; +032 \{ +033 register mp_digit r, rr, *tmpa, *tmpb; +034 +035 /* source alias */ +036 tmpa = a->dp + b->used - 1; +037 +038 /* dest alias */ +039 tmpb = b->dp + b->used - 1; +040 +041 /* carry */ +042 r = 0; +043 for (x = b->used - 1; x >= 0; x--) \{ +044 /* get the carry for the next iteration */ +045 rr = *tmpa & 1; +046 +047 /* shift the current digit, add in carry and store */ +048 *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); +049 +050 /* forward carry to next iteration */ +051 r = rr; +052 \} +053 +054 /* zero excess digits */ +055 tmpb = b->dp + b->used; +056 for (x = b->used; x < oldused; x++) \{ +057 *tmpb++ = 0; +058 \} +059 \} +060 b->sign = a->sign; +061 mp_clamp (b); +062 return MP_OKAY; +063 \} +\end{alltt} +\end{small} + +\section{Polynomial Basis Operations} +Recall from section 5.3 that any integer can be represented as a polynomial in $x$ as $y = f(\beta)$. Such a representation is also known as +the polynomial basis \cite[pp. 48]{ROSE}. Given such a notation a multiplication or division by $x$ amounts to shifting whole digits a single +place. The need for such operations arises in several other higher level algorithms such as Barrett and Montgomery reduction, integer +division and Karatsuba multiplication. + +Converting from an array of digits to polynomial basis is very simple. Consider the integer $y \equiv (a_2, a_1, a_0)_{\beta}$ and recall that +$y = \sum_{i=0}^{2} a_i \beta^i$. Simply replace $\beta$ with $x$ and the expression is in polynomial basis. For example, $f(x) = 8x + 9$ is the +polynomial basis representation for $89$ using radix ten. That is, $f(10) = 8(10) + 9 = 89$. + +\subsection{Multiplication by $x$} + +Given a polynomial in $x$ such as $f(x) = a_n x^n + a_{n-1} x^{n-1} + ... + a_0$ multiplying by $x$ amounts to shifting the coefficients up one +degree. In this case $f(x) \cdot x = a_n x^{n+1} + a_{n-1} x^n + ... + a_0 x$. From a scalar basis point of view multiplying by $x$ is equivalent to +multiplying by the integer $\beta$. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_lshd}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $a \leftarrow a \cdot \beta^b$ (Multiply by $x^b$). \\ +\hline \\ +1. If $b \le 0$ then return(\textit{MP\_OKAY}). \\ +2. If $a.alloc < a.used + b$ then grow $a$ to at least $a.used + b$ digits. (\textit{hint: use mp\_grow}). \\ +3. If the reallocation failed return(\textit{MP\_MEM}). \\ +4. $a.used \leftarrow a.used + b$ \\ +5. $i \leftarrow a.used - 1$ \\ +6. $j \leftarrow a.used - 1 - b$ \\ +7. for $n$ from $a.used - 1$ to $b$ do \\ +\hspace{3mm}7.1 $a_{i} \leftarrow a_{j}$ \\ +\hspace{3mm}7.2 $i \leftarrow i - 1$ \\ +\hspace{3mm}7.3 $j \leftarrow j - 1$ \\ +8. for $n$ from 0 to $b - 1$ do \\ +\hspace{3mm}8.1 $a_n \leftarrow 0$ \\ +9. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_lshd} +\end{figure} + +\textbf{Algorithm mp\_lshd.} +This algorithm multiplies an mp\_int by the $b$'th power of $x$. This is equivalent to multiplying by $\beta^b$. The algorithm differs +from the other algorithms presented so far as it performs the operation in place instead storing the result in a seperate location. The algorithm +will return success immediately if $b \le 0$ since the rest of algorithm is only valid when $b > 0$. + +First the destination $a$ is grown as required to accomodate the result. The counters $i$ and $j$ are used to form a \textit{sliding window} over +the digits of $a$ of length $b$. The head of the sliding window is at $i$ (\textit{the leading digit}) and the tail at $j$ (\textit{the trailing digit}). +The loop on step 7 copies the digit from the tail to the head. In each iteration the window is moved down one digit. The last loop on +step 8 sets the lower $b$ digits to zero. + +\newpage +\begin{center} +\begin{figure}[here] +\includegraphics{pics/sliding_window.ps} +\caption{Sliding Window Movement} +\end{figure} +\end{center} + +\index{bn\_mp\_lshd.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_lshd.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* shift left a certain amount of digits */ +018 int +019 mp_lshd (mp_int * a, int b) +020 \{ +021 int x, res; +022 +023 /* if its less than zero return */ +024 if (b <= 0) \{ +025 return MP_OKAY; +026 \} +027 +028 /* grow to fit the new digits */ +029 if (a->alloc < a->used + b) \{ +030 if ((res = mp_grow (a, a->used + b)) != MP_OKAY) \{ +031 return res; +032 \} +033 \} +034 +035 \{ +036 register mp_digit *tmpa, *tmpaa; +037 +038 /* increment the used by the shift amount than copy upwards */ +039 a->used += b; +040 +041 /* top */ +042 tmpa = a->dp + a->used - 1; +043 +044 /* base */ +045 tmpaa = a->dp + a->used - 1 - b; +046 +047 /* much like mp_rshd this is implemented using a sliding window +048 * except the window goes the otherway around. Copying from +049 * the bottom to the top. see bn_mp_rshd.c for more info. +050 */ +051 for (x = a->used - 1; x >= b; x--) \{ +052 *tmpa-- = *tmpaa--; +053 \} +054 +055 /* zero the lower digits */ +056 tmpa = a->dp; +057 for (x = 0; x < b; x++) \{ +058 *tmpa++ = 0; +059 \} +060 \} +061 return MP_OKAY; +062 \} +\end{alltt} +\end{small} + +The if statement on line 24 ensures that the $b$ variable is greater than zero. The \textbf{used} count is incremented by $b$ before +the copy loop begins. This elminates the need for an additional variable in the for loop. The variable $tmpa$ on line 42 is an alias +for the leading digit while $tmpaa$ on line 45 is an alias for the trailing edge. The aliases form a window of exactly $b$ digits +over the input. + +\subsection{Division by $x$} + +Division by powers of $x$ is easily achieved by shifting the digits right and removing any that will end up to the right of the zero'th digit. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_rshd}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $a \leftarrow a / \beta^b$ (Divide by $x^b$). \\ +\hline \\ +1. If $b \le 0$ then return. \\ +2. If $a.used \le b$ then do \\ +\hspace{3mm}2.1 Zero $a$. (\textit{hint: use mp\_zero}). \\ +\hspace{3mm}2.2 Return. \\ +3. $i \leftarrow 0$ \\ +4. $j \leftarrow b$ \\ +5. for $n$ from 0 to $a.used - b - 1$ do \\ +\hspace{3mm}5.1 $a_i \leftarrow a_j$ \\ +\hspace{3mm}5.2 $i \leftarrow i + 1$ \\ +\hspace{3mm}5.3 $j \leftarrow j + 1$ \\ +6. for $n$ from $a.used - b$ to $a.used - 1$ do \\ +\hspace{3mm}6.1 $a_n \leftarrow 0$ \\ +7. Clamp excess digits. (\textit{hint: use mp\_clamp}). \\ +8. Return. \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_rshd} +\end{figure} + +\textbf{Algorithm mp\_rshd.} +This algorithm divides the input in place by the $b$'th power of $x$. It is analogous to dividing by a $\beta^b$ but much quicker since +it does not require single precision division. This algorithm does not actually return an error code as it cannot fail. + +If the input $b$ is less than one the algorithm quickly returns without performing any work. If the \textbf{used} count is less than or equal +to the shift count $b$ then it will simply zero the input and return. + +After the trivial cases of inputs have been handled the sliding window is setup. Much like the case of algorithm mp\_lshd a sliding window that +is $b$ digits wide is used to copy the digits. Unlike mp\_lshd the window slides in the opposite direction from the trailing to the leading digit. +Also the digits are copied from the leading to the trailing edge. + +Once the window copy is complete the upper digits must be zeroed. Finally algorithm mp\_clamp is used to trim excess digits. + +\index{bn\_mp\_rshd.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_rshd.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* shift right a certain amount of digits */ +018 void +019 mp_rshd (mp_int * a, int b) +020 \{ +021 int x; +022 +023 /* if b <= 0 then ignore it */ +024 if (b <= 0) \{ +025 return; +026 \} +027 +028 /* if b > used then simply zero it and return */ +029 if (a->used <= b) \{ +030 mp_zero (a); +031 return; +032 \} +033 +034 \{ +035 register mp_digit *tmpa, *tmpaa; +036 +037 /* shift the digits down */ +038 +039 /* base */ +040 tmpa = a->dp; +041 +042 /* offset into digits */ +043 tmpaa = a->dp + b; +044 +045 /* this is implemented as a sliding window where +046 * the window is b-digits long and digits from +047 * the top of the window are copied to the bottom +048 * +049 * e.g. +050 +051 b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> +052 /\symbol{92} | ----> +053 \symbol{92}-------------------/ ----> +054 */ +055 for (x = 0; x < (a->used - b); x++) \{ +056 *tmpa++ = *tmpaa++; +057 \} +058 +059 /* zero the top digits */ +060 for (; x < a->used; x++) \{ +061 *tmpa++ = 0; +062 \} +063 \} +064 mp_clamp (a); +065 \} +\end{alltt} +\end{small} + +The only noteworthy element of this routine is the lack of a return type. This function cannot fail and as such it is more optimal to not +return anything. + +\section{Powers of Two} + +Now that algorithms for moving single bits as well as whole digits exist algorithms for moving the ``in between'' distances are required. For +example, to quickly multiply by $2^k$ for any $k$ without using a full multiplier algorithm would prove useful. Instead of performing single +shifts $k$ times to achieve a multiplication by $2^{\pm k}$ a mixture of whole digit shifting and partial digit shifting is employed. + +\subsection{Multiplication by Power of Two} + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_mul\_2d}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $c \leftarrow a \cdot 2^b$. \\ +\hline \\ +1. $c \leftarrow a$. (\textit{hint: use mp\_copy}) \\ +2. If $c.alloc < c.used + \lfloor b / lg(\beta) \rfloor + 2$ then grow $c$ accordingly. \\ +3. If the reallocation failed return(\textit{MP\_MEM}). \\ +4. If $b \ge lg(\beta)$ then \\ +\hspace{3mm}4.1 $c \leftarrow c \cdot \beta^{\lfloor b / lg(\beta) \rfloor}$ (\textit{hint: use mp\_lshd}). \\ +\hspace{3mm}4.2 If step 4.1 failed return(\textit{MP\_MEM}). \\ +5. $d \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ +6. If $d \ne 0$ then do \\ +\hspace{3mm}6.1 $mask \leftarrow 2^d$ \\ +\hspace{3mm}6.2 $r \leftarrow 0$ \\ +\hspace{3mm}6.3 for $n$ from $0$ to $c.used - 1$ do \\ +\hspace{6mm}6.3.1 $rr \leftarrow c_n >> (lg(\beta) - d) \mbox{ (mod }mask\mbox{)}$ \\ +\hspace{6mm}6.3.2 $c_n \leftarrow (c_n << d) + r \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ +\hspace{3mm}6.4 If $r > 0$ then do \\ +\hspace{6mm}6.4.1 $c_{c.used} \leftarrow r$ \\ +\hspace{6mm}6.4.2 $c.used \leftarrow c.used + 1$ \\ +7. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_mul\_2d} +\end{figure} + +\textbf{Algorithm mp\_mul\_2d.} +This algorithm multiplies $a$ by $2^b$ and stores the result in $c$. The algorithm uses algorithm mp\_lshd and a derivative of algorithm mp\_mul\_2 to +quickly compute the product. + +First the algorithm will multiply $a$ by $x^{\lfloor b / lg(\beta) \rfloor}$ which will ensure that the remainder multiplicand is less than +$\beta$. For example, if $b = 37$ and $\beta = 2^{28}$ then this step will multiply by $x$ leaving a multiplication by $2^{37 - 28} = 2^{9}$ +left. + +The logarithm of the residue is calculated on step 5. If it is non-zero a modified shift loop is used to calculate the remaining product. +Essentially the loop is a generic version of algorith mp\_mul2 designed to handle any shift count in the range $1 \le x < lg(\beta)$. The $mask$ +variable is used to extract the upper $d$ bits to form the carry for the next iteration. + +This algorithm is loosely measured as a $O(2n)$ algorithm which means that if the input is $n$-digits that it takes $2n$ ``time'' to +complete. It is possible to optimize this algorithm down to a $O(n)$ algorithm at a cost of making the algorithm slightly harder to follow. + +\index{bn\_mp\_mul\_2d.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_mul\_2d.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* NOTE: This routine requires updating. For instance the c->used = c->all + oc bit +018 is wrong. We should just shift c->used digits then set the carry as c->d + p[c->used] = carry +019 +020 To be fixed for LTM 0.18 +021 */ +022 +023 /* shift left by a certain bit count */ +024 int +025 mp_mul_2d (mp_int * a, int b, mp_int * c) +026 \{ +027 mp_digit d; +028 int res; +029 +030 /* copy */ +031 if (a != c) \{ +032 if ((res = mp_copy (a, c)) != MP_OKAY) \{ +033 return res; +034 \} +035 \} +036 +037 if (c->alloc < (int)(c->used + b/DIGIT_BIT + 2)) \{ +038 if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 2)) != MP_OKAY) \{ +039 return res; +040 \} +041 \} +042 +043 /* shift by as many digits in the bit count */ +044 if (b >= (int)DIGIT_BIT) \{ +045 if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) \{ +046 return res; +047 \} +048 \} +049 c->used = c->alloc; +050 +051 /* shift any bit count < DIGIT_BIT */ +052 d = (mp_digit) (b % DIGIT_BIT); +053 if (d != 0) \{ +054 register mp_digit *tmpc, mask, r, rr; +055 register int x; +056 +057 /* bitmask for carries */ +058 mask = (((mp_digit)1) << d) - 1; +059 +060 /* alias */ +061 tmpc = c->dp; +062 +063 /* carry */ +064 r = 0; +065 for (x = 0; x < c->used; x++) \{ +066 /* get the higher bits of the current word */ +067 rr = (*tmpc >> (DIGIT_BIT - d)) & mask; +068 +069 /* shift the current word and OR in the carry */ +070 *tmpc = ((*tmpc << d) | r) & MP_MASK; +071 ++tmpc; +072 +073 /* set the carry to the carry bits of the current word */ +074 r = rr; +075 \} +076 \} +077 mp_clamp (c); +078 return MP_OKAY; +079 \} +\end{alltt} +\end{small} + +Notes to be revised when code is updated. -- Tom + +\subsection{Division by Power of Two} + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_div\_2d}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $c \leftarrow \lfloor a / 2^b \rfloor, d \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ +\hline \\ +1. If $b \le 0$ then do \\ +\hspace{3mm}1.1 $c \leftarrow a$ (\textit{hint: use mp\_copy}) \\ +\hspace{3mm}1.2 $d \leftarrow 0$ (\textit{hint: use mp\_zero}) \\ +\hspace{3mm}1.3 Return(\textit{MP\_OKAY}). \\ +2. $c \leftarrow a$ \\ +3. $d \leftarrow a \mbox{ (mod }2^b\mbox{)}$ (\textit{hint: use mp\_mod\_2d}) \\ +4. If $b \ge lg(\beta)$ then do \\ +\hspace{3mm}4.1 $c \leftarrow \lfloor c/\beta^{\lfloor b/lg(\beta) \rfloor} \rfloor$ (\textit{hint: use mp\_rshd}). \\ +5. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ +6. If $k \ne 0$ then do \\ +\hspace{3mm}6.1 $mask \leftarrow 2^k$ \\ +\hspace{3mm}6.2 $r \leftarrow 0$ \\ +\hspace{3mm}6.3 for $n$ from $c.used - 1$ to $0$ do \\ +\hspace{6mm}6.3.1 $rr \leftarrow c_n \mbox{ (mod }mask\mbox{)}$ \\ +\hspace{6mm}6.3.2 $c_n \leftarrow (c_n >> k) + (r << (lg(\beta) - k))$ \\ +\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ +7. Clamp excess digits of $c$. (\textit{hint: use mp\_clamp}) \\ +8. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_div\_2d} +\end{figure} + +\textbf{Algorithm mp\_div\_2d.} +This algorithm will divide an input $a$ by $2^b$ and produce the quotient and remainder. The algorithm is designed much like algorithm +mp\_mul\_2d by first using whole digit shifts then single precision shifts. This algorithm will also produce the remainder of the division +by using algorithm mp\_mod\_2d. + +\index{bn\_mp\_div\_2d.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_div\_2d.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* shift right by a certain bit count (store quotient in c, remainder in d) + */ +018 int +019 mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +020 \{ +021 mp_digit D, r, rr; +022 int x, res; +023 mp_int t; +024 +025 +026 /* if the shift count is <= 0 then we do no work */ +027 if (b <= 0) \{ +028 res = mp_copy (a, c); +029 if (d != NULL) \{ +030 mp_zero (d); +031 \} +032 return res; +033 \} +034 +035 if ((res = mp_init (&t)) != MP_OKAY) \{ +036 return res; +037 \} +038 +039 /* get the remainder */ +040 if (d != NULL) \{ +041 if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) \{ +042 mp_clear (&t); +043 return res; +044 \} +045 \} +046 +047 /* copy */ +048 if ((res = mp_copy (a, c)) != MP_OKAY) \{ +049 mp_clear (&t); +050 return res; +051 \} +052 +053 /* shift by as many digits in the bit count */ +054 if (b >= (int)DIGIT_BIT) \{ +055 mp_rshd (c, b / DIGIT_BIT); +056 \} +057 +058 /* shift any bit count < DIGIT_BIT */ +059 D = (mp_digit) (b % DIGIT_BIT); +060 if (D != 0) \{ +061 register mp_digit *tmpc, mask; +062 +063 /* mask */ +064 mask = (((mp_digit)1) << D) - 1; +065 +066 /* alias */ +067 tmpc = c->dp + (c->used - 1); +068 +069 /* carry */ +070 r = 0; +071 for (x = c->used - 1; x >= 0; x--) \{ +072 /* get the lower bits of this word in a temp */ +073 rr = *tmpc & mask; +074 +075 /* shift the current word and mix in the carry bits from the previous + word */ +076 *tmpc = (*tmpc >> D) | (r << (DIGIT_BIT - D)); +077 --tmpc; +078 +079 /* set the carry to the carry bits of the current word found above */ +080 r = rr; +081 \} +082 \} +083 mp_clamp (c); +084 res = MP_OKAY; +085 if (d != NULL) \{ +086 mp_exch (&t, d); +087 \} +088 mp_clear (&t); +089 return MP_OKAY; +090 \} +\end{alltt} +\end{small} + +The implementation of algorithm mp\_div\_2d is slightly different than the algorithm specifies. The remainder $d$ may be optionally +ignored by passing \textbf{NULL} as the pointer to the mp\_int variable. The temporary mp\_int variable $t$ is used to hold the +result of the remainder operation until the end. This allows $d = a$ to be true without overwriting the input before they are no longer required. + +The remainder of the source code is essentially the same as the source code for mp\_mul\_2d. (-- Fix this paragraph up later, Tom). + +\subsection{Remainder of Division by Power of Two} + +The last algorithm in the series of polynomial basis power of two algorithms is calculating the remainder of division by $2^b$. This +algorithm benefits from the fact that in twos complement arithmetic $a \mbox{ (mod }2^b\mbox{)}$ is the same as $a$ AND $2^b - 1$. + +\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_mod\_2d}. \\ +\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ +\textbf{Output}. $c \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ +\hline \\ +1. If $b \le 0$ then do \\ +\hspace{3mm}1.1 $c \leftarrow 0$ (\textit{hint: use mp\_zero}) \\ +\hspace{3mm}1.2 Return(\textit{MP\_OKAY}). \\ +2. If $b > a.used \cdot lg(\beta)$ then do \\ +\hspace{3mm}2.1 $c \leftarrow a$ (\textit{hint: use mp\_copy}) \\ +\hspace{3mm}2.2 Return the result of step 2.1. \\ +3. $c \leftarrow a$ \\ +4. If step 3 failed return(\textit{MP\_MEM}). \\ +5. for $n$ from $\lceil b / lg(\beta) \rceil$ to $c.used$ do \\ +\hspace{3mm}5.1 $c_n \leftarrow 0$ \\ +6. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ +7. $c_{\lfloor b / lg(\beta) \rfloor} \leftarrow c_{\lfloor b / lg(\beta) \rfloor} \mbox{ (mod }2^{k}\mbox{)}$. \\ +8. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_mod\_2d} +\end{figure} + +\textbf{Algorithm mp\_mod\_2d.} +This algorithm will quickly calculate the value of $a \mbox{ (mod }2^b\mbox{)}$. First if $b$ is less than or equal to zero the +result is set to zero. If $b$ is greater than the number of bits in $a$ then it simply copies $a$ to $c$ and returns. Otherwise, $a$ +is copied to $b$, leading digits are removed and the remaining leading digit is trimed to the exact bit count. + +\index{bn\_mp\_mod\_2d.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_mp\_mod\_2d.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* calc a value mod 2\b */ +018 int +019 mp_mod_2d (mp_int * a, int b, mp_int * c) +020 \{ +021 int x, res; +022 +023 +024 /* if b is <= 0 then zero the int */ +025 if (b <= 0) \{ +026 mp_zero (c); +027 return MP_OKAY; +028 \} +029 +030 /* if the modulus is larger than the value than return */ +031 if (b > (int) (a->used * DIGIT_BIT)) \{ +032 res = mp_copy (a, c); +033 return res; +034 \} +035 +036 /* copy */ +037 if ((res = mp_copy (a, c)) != MP_OKAY) \{ +038 return res; +039 \} +040 +041 /* zero digits above the last digit of the modulus */ +042 for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x+ + +) \{ +043 c->dp[x] = 0; +044 \} +045 /* clear the digit that is not completely outside/inside the modulus */ +046 c->dp[b / DIGIT_BIT] &= +047 (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digi + t) 1)); +048 mp_clamp (c); +049 return MP_OKAY; +050 \} +\end{alltt} +\end{small} + +-- Add comments later, Tom. + +\section*{Exercises} +\begin{tabular}{cl} +$\left [ 3 \right ] $ & Devise an algorithm that performs $a \cdot 2^b$ for generic values of $b$ \\ + & in $O(n)$ time. \\ + &\\ +$\left [ 3 \right ] $ & Devise an efficient algorithm to multiply by small low hamming \\ + & weight values such as $3$, $5$ and $9$. Extend it to handle all values \\ + & upto $64$ with a hamming weight less than three. \\ + &\\ +$\left [ 2 \right ] $ & Modify the preceding algorithm to handle values of the form \\ + & $2^k - 1$ as well. \\ + &\\ +$\left [ 3 \right ] $ & Using only algorithms mp\_mul\_2, mp\_div\_2 and mp\_add create an \\ + & algorithm to multiply two integers in roughly $O(2n^2)$ time for \\ + & any $n$-bit input. Note that the time of addition is ignored in the \\ + & calculation. \\ + & \\ +$\left [ 5 \right ] $ & Improve the previous algorithm to have a working time of at most \\ + & $O \left (2^{(k-1)}n + \left ({2n^2 \over k} \right ) \right )$ for an appropriate choice of $k$. Again ignore \\ + & the cost of addition. \\ + & \\ +$\left [ 1 \right ] $ & There exists an improvement on the previous algorithm to \\ + & slightly reduce the number of additions required. Modify the \\ + & previous algorithm to include this improvement. \\ + & \\ +$\left [ 2 \right ] $ & Devise a chart to find optimal values of $k$ for the previous problem \\ + & for $n = 64 \ldots 1024$ in steps of $64$. \\ + & \\ +$\left [ 2 \right ] $ & Using only algorithms mp\_abs and mp\_sub devise another method for \\ + & calculating the result of a signed comparison. \\ + & +\end{tabular} + +\chapter{Multiplication and Squaring} +\section{The Multipliers} +For most number theoretic systems including public key cryptographic algorithms the set of algorithms collectively known as the +``multipliers'' form the most important subset of algorithms of any multiple precision integer package. The set of multipliers +include multiplication, squaring and modular reduction algorithms. + +The importance of these algorithms is driven by the fact that most popular public key algorithms are based on modular +exponentiation. That is performing $d \equiv a^b \mbox{ (mod }c\mbox{)}$ for some arbitrary choice of $a$, $b$, $c$ and $d$. Roughly +speaking the a modular exponentiation will spend about 40\% of the time in modular reductions, 35\% of the time in squaring and 25\% of +the time in multiplications. Only a small trivial amount of time is spent on lower level algorithms such as mp\_clamp, mp\_init, etc... + +This chapter will discuss only two of the multipliers algorithms, multiplication and squaring. As will be discussed shortly very efficient +multiplier algorithms are not always straightforward and deserve a lot of attention. + +\section{Multiplication} +\subsection{The Baseline Multiplication} +\index{baseline multiplication} +Computing the product of two integers in software can be achieved using a trivial adaptation of the standard $O(n^2)$ long-hand multiplication +algorithm school children are taught. The ``baseline multiplication'' algorithm is designed to act as the ``catch-all'' algorithm only called +when the faster algorithms cannot be used. This algorithm does not use any particularly interesting optimizations. + +The first algorithm to review is the unsigned multiplication algorithm from which a signed multiplication algorithm can be established. One important +facet of this algorithm to note is that it has been modified to only produce a certain amount of output digits as resolution. Recall that for +a $n$ and $m$ digit input the product will be at most $n + m + 1$ digits. Therefore, this algorithm can be reduced to a full multiplier by +telling it to produce $n + m + 1$ digits. + +Recall from sub-section 5.2.2 the definition of $\gamma$ as the number of bits in the type \textbf{mp\_digit}. We shall now extend this variable set to +include $\alpha$ which shall represent the number of bits in the type \textbf{mp\_word}. This implies that $2^{\alpha} > 2 \cdot \beta^2$. The +constant $\delta = 2^{\alpha - 2lg(\beta)}$ will represent the maximal weight of any column in a product (\textit{see sub-section 6.2.2 for more information}). + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{s\_mp\_mul\_digs}. \\ +\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ +\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ +\hline \\ +1. If min$(a.used, b.used) < \delta$ then do \\ +\hspace{3mm}1.1 Calculate $c = \vert a \vert \cdot \vert b \vert$ by the Comba method. \\ +\hspace{3mm}1.2 Return the result of step 1.1 \\ +\\ +Allocate and initialize a temporary mp\_int. \\ +2. Init $t$ to be of size $digs$ \\ +3. If step 2 failed return(\textit{MP\_MEM}). \\ +4. $t.used \leftarrow digs$ \\ +\\ +Compute the product. \\ +5. for $ix$ from $0$ to $a.used - 1$ do \\ +\hspace{3mm}5.1 $u \leftarrow 0$ \\ +\hspace{3mm}5.2 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ +\hspace{3mm}5.3 If $pb < 1$ then goto step 6. \\ +\hspace{3mm}5.4 for $iy$ from $0$ to $pb - 1$ do \\ +\hspace{6mm}5.4.1 $\hat r \leftarrow t_{iy + ix} + a_{ix} \cdot b_{iy} + u$ \\ +\hspace{6mm}5.4.2 $t_{iy + ix} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ +\hspace{6mm}5.4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ +\hspace{3mm}5.5 if $ix + iy < digs$ then do \\ +\hspace{6mm}5.5.1 $t_{ix + pb} \leftarrow u$ \\ +6. Clamp excess digits of $t$. \\ +7. Swap $c$ with $t$ \\ +8. Clear $t$ \\ +9. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm s\_mp\_mul\_digs} +\end{figure} + +\textbf{Algorithm s\_mp\_mul\_digs.} +This algorithm computes the unsigned product of two inputs $a$ and $c$ limited to an output precision of $digs$ digits. While it may seem +a bit awkward to modify the function from its simple $O(n^2)$ description the usefulness of partial multipliers will arise in a future +algorithm. The algorithm is loosely based on algorithm 14.12 from \cite[pp. 595]{HAC} and is similar to Algorithm M \cite[pp. 268]{TAOCPV2}. The +algorithm differs from those cited references because it can produce a variable output precision regardless of the precision of the inputs. + +The first thing this algorithm checks for is whether a Comba multiplier can be used instead. That is if the minimal digit count of either +input is less than $\delta$ the Comba method is used. After the Comba method is ruled out the baseline algorithm begins. A +temporary mp\_int variable $t$ is used to hold the intermediate result of the product. This allows the algorithm to be used to +compute products when either $a = c$ or $b = c$ without overwriting the inputs. + +All of step 5 is the infamous $O(n^2)$ multiplication loop slightly modified to only produce upto $digs$ digits of output. The $pb$ variable +is given the count of digits to read from $b$ inside the nested loop. If $pb < 0$ then no more output digits can be produced and the algorithm +will exit the loop. The best way to think of the loops are as a series of $pb \times 1$ multiplication. That is, in each pass of the +innermost loop $a_{ix}$ is multiplied against $b$ and the result is added (\textit{with an appropriate shift}) to $t$. + +For example, consider multiplying $576$ by $241$. That is equivalent to computing $10^0(1)(576) + 10^1(4)(576) + 10^2(2)(576)$ which is best +visualized as the following table. + +\begin{figure}[here] +\begin{center} +\begin{tabular}{|c|c|c|c|c|c|c|} +\hline && & 5 & 7 & 6 & \\ +\hline $\times$&& & 2 & 4 & 1 & \\ +\hline &&&&&&\\ + && & 5 & 7 & 6 & $10^0(1)(576)$ \\ + &2 & 3 & 0 & 4 & 0 & $10^1(4)(576)$ \\ + 1 & 1 & 5 & 2 & 0 & 0 & $10^2(2)(576)$ \\ +\hline +\end{tabular} +\end{center} +\caption{Long-Hand Multiplication Diagram} +\end{figure} + +Each row of the product is added to the result after being shifted to the left (\textit{multiplied by a power of the radix}) by the appropriate +count. That is in pass $ix$ of the inner loop the product is added starting at the $ix$'th digit of the reult. + +Step 5.4.1 introduces the hat symbol (\textit{e.g. $\hat x$}) which represents a double precision variable. The multiplication on that step +is assumed to be a double wide output single precision multiplication. That is, two single precision variables are multiplied to produce a +double precision result. The step is somewhat optimized from a long-hand multiplication algorithm because the carry from the addition in step +5.4.1 is forwarded through the nested loop. If the carry was ignored it would overflow the single precision digit $t_{ix+iy}$ and the result +would be lost. + +At step 5.5 the nested loop is finished and any carry that was left over should be forwarded. That is provided $ix + iy < digs$ otherwise the +carry is ignored since it will not be part of the result anyways. + +\index{bn\_s\_mp\_mul\_digs.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_mul\_digs.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* multiplies |a| * |b| and only computes upto digs digits of result +018 * HAC pp. 595, Algorithm 14.12 Modified so you can control how +019 * many digits of output are created. +020 */ +021 int +022 s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +023 \{ +024 mp_int t; +025 int res, pa, pb, ix, iy; +026 mp_digit u; +027 mp_word r; +028 mp_digit tmpx, *tmpt, *tmpy; +029 +030 /* can we use the fast multiplier? */ +031 if (((digs) < MP_WARRAY) && +032 MIN (a->used, b->used) < +033 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) \{ +034 return fast_s_mp_mul_digs (a, b, c, digs); +035 \} +036 +037 if ((res = mp_init_size (&t, digs)) != MP_OKAY) \{ +038 return res; +039 \} +040 t.used = digs; +041 +042 /* compute the digits of the product directly */ +043 pa = a->used; +044 for (ix = 0; ix < pa; ix++) \{ +045 /* set the carry to zero */ +046 u = 0; +047 +048 /* limit ourselves to making digs digits of output */ +049 pb = MIN (b->used, digs - ix); +050 +051 /* setup some aliases */ +052 /* copy of the digit from a used within the nested loop */ +053 tmpx = a->dp[ix]; +054 +055 /* an alias for the destination shifted ix places */ +056 tmpt = t.dp + ix; +057 +058 /* an alias for the digits of b */ +059 tmpy = b->dp; +060 +061 /* compute the columns of the output and propagate the carry */ +062 for (iy = 0; iy < pb; iy++) \{ +063 /* compute the column as a mp_word */ +064 r = ((mp_word) *tmpt) + +065 ((mp_word) tmpx) * ((mp_word) * tmpy++) + +066 ((mp_word) u); +067 +068 /* the new column is the lower part of the result */ +069 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); +070 +071 /* get the carry word from the result */ +072 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); +073 \} +074 /* set carry if it is placed below digs */ +075 if (ix + iy < digs) \{ +076 *tmpt = u; +077 \} +078 \} +079 +080 mp_clamp (&t); +081 mp_exch (&t, c); +082 +083 mp_clear (&t); +084 return MP_OKAY; +085 \} +\end{alltt} +\end{small} + +Lines 31 to 35 determine if the Comba method can be used first. The conditions for using the Comba routine are that min$(a.used, b.used) < \delta$ and +the number of digits of output is less than \textbf{MP\_WARRAY}. This new constant is used to control the stack usage in the Comba routines. By +default it is set to $\delta$ but can be reduced when memory is at a premium. + +Of particular importance is the calculation of the $ix+iy$'th column on lines 64, 65 and 66. Note how all of the +variables are cast to the type \textbf{mp\_word}. That is to ensure that double precision operations are used instead of single precision. The +multiplication on line 65 is a bit of a GCC optimization. On the outset it looks like the compiler will have to use a double precision +multiplication to produce the result required. Such an operation would be horribly slow on most processors and drag this to a crawl. However, +GCC is smart enough to realize that double wide output single precision multipliers can be used. For example, the instruction ``MUL'' on the +x86 processor can multiply two 32-bit values and produce a 64-bit result. + +\subsection{Faster Multiplication by the ``Comba'' Method} + +One of the huge drawbacks of the ``baseline'' algorithms is that at the $O(n^2)$ level the carry must be computed and propagated upwards. This +makes the nested loop very sequential and hard to unroll and implement in parallel. The ``Comba'' method is named after little known +(\textit{in cryptographic venues}) Paul G. Comba where in \cite{COMBA} a method of implementing fast multipliers that do not require nested +carry fixup operations was presented. + +At the heart of algorithm is once again the long-hand algorithm for multiplication. Except in this case a slight twist is placed on how +the columns of the result are produced. In the standard long-hand algorithm rows of products are produced then added together to form the +final result. In the baseline algorithm the columns are added together to get the result instantaneously. + +In the Comba algorithm however, the columns of the result are produced entirely independently of each other. That is at the $O(n^2)$ level a +simple multiplication and addition step is performed. Or more succintly that + +\begin{equation} +x_n = \sum_{i+j = n} a_ib_j +\end{equation} + +Where $x_n$ is the $n'th$ column of the output vector. To see how this works consider once again multiplying $576$ by $241$. + +\begin{figure}[here] +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|c|c|c|} + \hline & & 5 & 7 & 6 & First Input\\ + \hline $\times$ & & 2 & 4 & 1 & Second Input\\ +\hline & & $1 \cdot 5 = 5$ & $1 \cdot 7 = 7$ & $1 \cdot 6 = 6$ & First pass \\ + & $4 \cdot 5 = 20$ & $4 \cdot 7+5=33$ & $4 \cdot 6+7=31$ & 6 & Second pass \\ + $2 \cdot 5 = 10$ & $2 \cdot 7 + 20 = 34$ & $2 \cdot 6+33=45$ & 31 & 6 & Third pass \\ +\hline 10 & 34 & 45 & 31 & 6 & Final Result \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Comba Multiplication Diagram} +\end{figure} + +At this point the vector $x = \left < 10, 34, 45, 31, 6 \right >$ is the result of the first step of the Comba multipler. +Now the columns must be fixed by propagating the carry upwards. The following trivial algorithm will accomplish this. + +\begin{enumerate} + \item for $n$ from 0 to $k - 1$ do + \item \hspace{3mm} $x_{n+1} \leftarrow x_{n+1} + \lfloor x_{n}/\beta \rfloor$ + \item \hspace{3mm} $x_{n} \leftarrow x_{n} \mbox{ (mod }\beta\mbox{)}$ +\end{enumerate} + +With that algorithm and $k = 5$ and $\beta = 10$ the following vector is produced $y = \left < 1, 3, 8, 8, 1, 6 \right >$. In this case +$241 \cdot 576$ is in fact $138816$ and the procedure succeeded. If the algorithm is correct and as will be demonstrated shortly more +efficient than the baseline algorithm why not simply always use this algorithm? + +\subsubsection{Column Weight.} +At the nested $O(n^2)$ level the Comba method adds the product of two single precision variables to a each column of the output +independently. A serious obstacle is if the carry is lost due to lack of precision before the algorithm has a chance to fix +the carries. For example, in the multiplication of two three-digit numbers the third column of output will be the sum of +three single precision multiplications. If the precision of the accumulator for the output digits is less then $3 \cdot (\beta - 1)^2$ then +an overflow can occur and the carry information will be lost. For any $m$ and $n$ digit input the maximal weight of any column is +min$(m, n)$ which is fairly obvious. + +The maximal number of terms in any column of a product is known as the ``column weight'' and strictly governs when the algorithm can be used. Recall +from earlier that a double precision type has $\alpha$ bits of resolution and a single precision digit has $lg(\beta)$ bits of precision. Given these +two quantities we may not violate the following + +\begin{equation} +k \cdot \left (\beta - 1 \right )^2 < 2^{\alpha} +\end{equation} + +Which reduces to + +\begin{equation} +k \cdot \left ( \beta^2 - 2\beta + 1 \right ) < 2^{\alpha} +\end{equation} + +Let $\rho = lg(\beta)$ represent the number of bits in a single precision digit. By further re-arrangement of the equation the final solution is +found. + +\begin{equation} +k \cdot \left (2^{2\rho} - 2^{\rho + 1} + 1 \right ) < 2^{\alpha} +\end{equation} + +The defaults for LibTomMath are $\beta = 2^{28}, \alpha = 2^{64}$ which simplies to $72057593501057025 \cdot k < 2^{64}$ which when divided out +result in $k < 257$. This implies that the smallest input may not have more than $256$ digits if the Comba method is to be used in +this configuration. This is quite satisfactory for most applications since $256$ digits would be allow for numbers in the range of $2^{7168}$ +which is much larger than the typical $2^{100}$ to $2^{4000}$ range most public key cryptographic algorithms use. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{fast\_s\_mp\_mul\_digs}. \\ +\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ +\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ +\hline \\ +Place an array of \textbf{MP\_WARRAY} double precision digits named $\hat W$ on the stack. \\ +1. If $c.alloc < digs$ then grow $c$ to $digs$ digits. (\textit{hint: use mp\_grow}) \\ +2. If step 1 failed return(\textit{MP\_MEM}).\\ +\\ +Zero the temporary array $\hat W$. \\ +3. for $n$ from $0$ to $digs - 1$ do \\ +\hspace{3mm}3.1 $\hat W_n \leftarrow 0$ \\ +\\ +Compute the columns. \\ +4. for $ix$ from $0$ to $a.used - 1$ do \\ +\hspace{3mm}4.1 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ +\hspace{3mm}4.2 If $pb < 1$ then goto step 5. \\ +\hspace{3mm}4.3 for $iy$ from $0$ to $pb - 1$ do \\ +\hspace{6mm}4.3.1 $\hat W_{ix+iy} \leftarrow \hat W_{ix+iy} + a_{ix}b_{iy}$ \\ +\\ +Propagate the carries upwards. \\ +5. $oldused \leftarrow c.used$ \\ +6. $c.used \leftarrow digs$ \\ +7. If $digs > 1$ then do \\ +\hspace{3mm}7.1. for $ix$ from $1$ to $digs - 1$ do \\ +\hspace{6mm}7.1.1 $\hat W_{ix} \leftarrow \hat W_{ix} + \lfloor \hat W_{ix-1} / \beta \rfloor$ \\ +\hspace{6mm}7.1.2 $c_{ix - 1} \leftarrow \hat W_{ix - 1} \mbox{ (mod }\beta\mbox{)}$ \\ +8. else do \\ +\hspace{3mm}8.1 $ix \leftarrow 0$ \\ +9. $c_{ix} \leftarrow \hat W_{ix} \mbox{ (mod }\beta\mbox{)}$ \\ +\\ +Zero excess digits. \\ +10. If $digs < oldused$ then do \\ +\hspace{3mm}10.1 for $n$ from $digs$ to $oldused - 1$ do \\ +\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ +11. Clamp excessive digits of $c$. (\textit{hint: use mp\_clamp}) \\ +12. Return(\textit{MP\_OKAY}). \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm fast\_s\_mp\_mul\_digs} +\end{figure} + +\textbf{Algorithm fast\_s\_mp\_mul\_digs.} +This algorithm performs the unsigned multiplication of $a$ and $b$ using the Comba method limited to $digs$ digits of precision. The algorithm +essentially peforms the same calculation as algorithm s\_mp\_mul\_digs but much faster. + +The array $\hat W$ is meant to be on the stack when the algorithm is used. The size of the array does not change which is ideal. Note also that +unlike algorithm s\_mp\_mul\_digs no temporary mp\_int is required since the result is calculated in place in $\hat W$. + +The $O(n^2)$ loop on step four is where the Comba method starts to show through. First there is no carry variable in the loop. Second the +double precision multiply and add step does not have a carry fixup of any sort. In fact the nested loop is very simple and can be implemented +in parallel. + +What makes the Comba method so attractive is that the carry propagation only takes place outside the $O(n^2)$ nested loop. For example, if the +cost in terms of time of a multiply and add is $p$ and the cost of a carry propagation is $q$ then a baseline multiplication would require +$O \left ((p + q)n^2 \right )$ time to multiply two $n$-digit numbers. The Comba method only requires $pn^2 + qn$ time, however, in practice +the speed increase is actually much more. With $O(n)$ space the algorithm can be reduced to $O(pn + qn)$ time by implementing the $n$ multiply +and add operations in the nested loop in parallel. + +The carry propagation loop on step 7 is fairly straightforward. It could have been written phased the other direction, that is, to assign +to $c_{ix}$ instead of $c_{ix-1}$ in each iteration. However, it would still require pre-caution to make sure that $\hat W_{ix+1}$ is not beyond +the \textbf{MP\_WARRAY} words set aside. + +\index{bn\_fast\_s\_mp\_mul\_digs.c} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: bn\_fast\_s\_mp\_mul\_digs.c +\vspace{-3mm} +\begin{alltt} +016 +017 /* Fast (comba) multiplier +018 * +019 * This is the fast column-array [comba] multiplier. It is +020 * designed to compute the columns of the product first +021 * then handle the carries afterwards. This has the effect +022 * of making the nested loops that compute the columns very +023 * simple and schedulable on super-scalar processors. +024 * +025 * This has been modified to produce a variable number of +026 * digits of output so if say only a half-product is required +027 * you don't have to compute the upper half (a feature +028 * required for fast Barrett reduction). +029 * +030 * Based on Algorithm 14.12 on pp.595 of HAC. +031 * +032 */ +033 int +034 fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +035 \{ +036 int olduse, res, pa, ix; +037 mp_word W[MP_WARRAY]; +038 +039 /* grow the destination as required */ +040 if (c->alloc < digs) \{ +041 if ((res = mp_grow (c, digs)) != MP_OKAY) \{ +042 return res; +043 \} +044 \} +045 +046 /* clear temp buf (the columns) */ +047 memset (W, 0, sizeof (mp_word) * digs); +048 +049 /* calculate the columns */ +050 pa = a->used; +051 for (ix = 0; ix < pa; ix++) \{ +052 /* this multiplier has been modified to allow you to +053 * control how many digits of output are produced. +054 * So at most we want to make upto "digs" digits of output. +055 * +056 * this adds products to distinct columns (at ix+iy) of W +057 * note that each step through the loop is not dependent on +058 * the previous which means the compiler can easily unroll +059 * the loop without scheduling problems +060 */ +061 \{ +062 register mp_digit tmpx, *tmpy; +063 register mp_word *_W; +064 register int iy, pb; +065 +066 /* alias for the the word on the left e.g. A[ix] * A[iy] */ +067 tmpx = a->dp[ix]; +068 +069 /* alias for the right side */ +070 tmpy = b->dp; +071 +072 /* alias for the columns, each step through the loop adds a new +073 term to each column +074 */ +075 _W = W + ix; +076 +077 /* the number of digits is limited by their placement. E.g. +078 we avoid multiplying digits that will end up above the # of +079 digits of precision requested +080 */ +081 pb = MIN (b->used, digs - ix); +082 +083 for (iy = 0; iy < pb; iy++) \{ +084 *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); +085 \} +086 \} +087 +088 \} +089 +090 /* setup dest */ +091 olduse = c->used; +092 c->used = digs; +093 +094 \{ +095 register mp_digit *tmpc; +096 +097 /* At this point W[] contains the sums of each column. To get the +098 * correct result we must take the extra bits from each column and +099 * carry them down +100 * +101 * Note that while this adds extra code to the multiplier it +102 * saves time since the carry propagation is removed from the +103 * above nested loop.This has the effect of reducing the work +104 * from N*(N+N*c)==N**2 + c*N**2 to N**2 + N*c where c is the +105 * cost of the shifting. On very small numbers this is slower +106 * but on most cryptographic size numbers it is faster. +107 */ +108 tmpc = c->dp; +109 for (ix = 1; ix < digs; ix++) \{ +110 W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); +111 *tmpc++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); +112 \} +113 *tmpc++ = (mp_digit) (W[digs - 1] & ((mp_word) MP_MASK)); +114 +115 /* clear unused */ +116 for (; ix < olduse; ix++) \{ +117 *tmpc++ = 0; +118 \} +119 \} +120 +121 mp_clamp (c); +122 return MP_OKAY; +123 \} +\end{alltt} +\end{small} + +The memset on line 47 clears the initial $\hat W$ array to zero in a single step. Like the slower baseline multiplication +implementation a series of aliases (\textit{lines 67, 70 and 75}) are used to simplify the inner $O(n^2)$ loop. +In this case a new alias $\_\hat W$ has been added which refers to the double precision columns offset by $ix$ in each pass. + +The inner loop on line 84 is where the algorithm will spend the majority of the time. Which is why it has been stripped to the +bones of any extra baggage\footnote{Hence the pointer aliases.}. On x86 processors the multiply and add amounts to at the very least five +instructions (\textit{two loads, two additions, one multiply}) while on the ARMv4 processors it amounts to only three (\textit{one load, one store, +one multiply-add}). On both the x86 and ARMv4 processors GCC v3.2 does a very good job at unrolling the loop and scheduling it so there +are very few dependency stalls. + +In theory the difference between the baseline and comba algorithms is a mere $O(qn)$ time difference. However, in the $O(n^2)$ nested loop of the +baseline method there are dependency stalls as the algorithm must wait for the multiplier to finish before propagating the carry to the next +digit. As a result fewer of the often multiple execution units\footnote{The AMD Athlon has three execution units and the Intel P4 has four.} can +be simultaneously used. + +\subsection{Multiplication at New Bounds by Karatsuba Method} +So far two methods of multiplication have been presented. Both of the algorithms require asymptotically $O(n^2)$ time to multiply two $n$-digit +numbers together. While the Comba method is much faster than the baseline algorithm it still requires far too much time to multiply +large inputs together. In fact it was not until \cite{KARA} in 1962 that a faster algorithm had been proposed at all. + +The idea behind Karatsubas method is that an input can be represented in polynomial basis as two halves then multiplied. For example, if +$f(x) = ax + b$ and $g(x) = cx + b$ then the product of the two polynomials $h(x) = f(x)g(x)$ will allow $h(\beta) = (f(\beta))(g(\beta))$. + +So how does this help? First expand the product $h(x)$. + +\begin{center} +\begin{tabular}{rcl} +$h(x)$ & $=$ & $f(x)g(x)$ \\ + & $=$ & $(ax + b)(cx + d)$ \\ + & $=$ & $acx^2 + adx + bcx + bd$ \\ +\end{tabular} +\end{center} + +The next equation is a bit of genius on the part of Karatsuba. He proved that the previous equation is equivalent to + +\begin{equation} +h(x) = acx^2 + ((a - c)(b - d) + bd + ac)x + bd +\end{equation} + +Essentially the proof lies in some fairly light algebraic number theory (\textit{see \cite{KARAP} for details}) that is not important for +the discussion. At first glance it appears that the Karatsuba method is actually harder than the straight $O(n^2)$ approach. +However, further investigation will prove otherwise. + +The first important observation is that both $f(x)$ and $g(x)$ are the polynomial basis representation of two-digit numbers. This means that +$\left < a, b, c, d \right >$ are single digit values. Using either the baseline or straight polynomial multiplication the old method requires +$O \left (4(n/2)^2 \right ) = O(n^2)$ single precision multiplications. Looking closer at Karatsubas equation there are only three unique multiplications +required which are $ac$, $bd$ and $(a - c)(b - d)$. As a result only $O \left (3 \cdot (n/2)^2 \right ) = O \left ( {3 \over 4}n^2 \right )$ +multiplications are required. + +So far the algorithm has been discussed from the point of view of ``two-digit'' numbers. However, there is no reason why two digits implies a range of +$\beta^2$. It could just as easily represent a range of $\left (\beta^k \right)^2$ as well. For example, the polynomial +$f(x) = a_3x^3 + a_2x^2 + a_1x + a_0$ could also be written as $f'(x) = a'_1x + a'_0$ where $f(\beta) = f'(\beta^2)$. Fortunately representing an +integer which is already in an array of radix-$\beta$ digits in polynomial basis in terms of a power of $\beta$ is very simple. + +\subsubsection{Recursion} +The Karatsuba multiplication algorithm can be applied to practically any size of input. Therefore, it is possible that the Karatsuba method itself +be used for the three multiplications required. For example, when multiplying two four-digit numbers there will be three multiplications of two-digit +numbers. In this case the smaller multiplication requires $p(n) = {3 \over 4}n^2$ time to complete while the larger multiplication requires +$q(n) = 3 \cdot p(n/2)$ multiplications. + +By expanding $q(n)$ the following equation is achieved. + +\begin{center} +\begin{tabular}{rcl} +$q(n)$ & $=$ & $3 \cdot p(n/2)$ \\ + & $=$ & $3 \cdot (3 \cdot ((n/2)/2)^2)$ \\ + & $=$ & $9 \cdot (n/4)^2$ \\ + & $=$ & ${9 \over 16}n^2$ \\ +\end{tabular} +\end{center} + +The generic expression for the multiplicand is simply $\left ( {3 \over 4} \right )^k$ for $k \ge 1$ recurisions. The maximal number of recursions +is approximately $lg(n)$. Putting this all in terms of a base $n$ logarithm the asymptotic running time can be deduced. + +\begin{center} +\begin{tabular}{rcl} +$lg_n \left ( \left ( {3 \over 4} \right )^{lg_2 n} \cdot n^2 \right )$ & $=$ & $lg_2 n \cdot lg_n \left ( { 3 \over 4 } \right ) + 2$ \\ + & $=$ & $\left ( {log N \over log 2} \right ) \cdot \left ( {log \left ( {3 \over 4} \right ) \over log N } \right ) + 2$ \\ + & $=$ & ${ log 3 - log 2^2 + 2 \cdot log 2} \over log 2$ \\ + & $=$ & $log 3 \over log 2$ \\ +\end{tabular} +\end{center} + +Which leads to a running time of $O \left ( n^{lg(3)} \right )$ which is approximately $O(n^{1.584})$. This can lead to +impressive savings with fairly moderate sized numbers. For example, when multiplying two 128-digit numbers the Karatsuba +method saves $14,197$ (\textit{or $86\%$ of the total}) single precision multiplications. + +The immediate question becomes why not simply use Karatsuba multiplication all the time and forget about the baseline and Comba algorithms? + +\subsubsection{Overhead} +While the Karatsuba method saves on the number of single precision multiplications required this savings is not entirely free. The product +of three half size products must be stored somewhere as well as four additions and two subtractions performed. These operations incur sufficient +overhead that often for fairly trivial sized inputs the Karatsuba method is slower. + +\index{cutoff point} +The \textit{cutoff point} for Karatsuba multiplication is the point at which the Karatsuba multiplication and baseline (\textit{or Comba}) meet. +For the purposes of this discussion call this value $x$. For any input with $n$ digits such that $n < x$ Karatsuba multiplication will be slower +and for $n > x$ it will be faster. Often the break between the two algorithms is not so clean cut in reality. The cleaner the cut the more +efficient multiplication will be which is why tuning the multiplication is a very important process. For example, a properly tuned Karatsuba +multiplication algorithm can multiply two $4,096$ bit numbers up to five times faster on an Athlon processor compared to the standard baseline +algorithm. + +The exact placement of the value of $x$ depends on several key factors. The cost of allocating storage for the temporary variables, the cost of +performing the additions and most importantly the cost of performing a single precision multiplication. With a processor where single precision +multiplication is fast\footnote{The AMD Athlon for instance has a six cycle multiplier compared to the Intel P4 which has a 15 cycle multiplier.} the +cutoff point will move upwards. Similarly with a slower processor the cutoff point will move downwards. + +\newpage\begin{figure}[!here] +\begin{small} +\begin{center} +\begin{tabular}{l} +\hline Algorithm \textbf{mp\_karatsuba\_mul}. \\ +\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ +\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert$ \\ +\hline \\ +1. $B \leftarrow \mbox{min}(a.used, b.used)/2$ \\ +2. Init the following mp\_int variables: $x0$, $x1$, $y0$, $y1$, $t1$, $x0y0$, $x1y1$.\\ +3. If step 2 failed then return(\textit{MP\_MEM}). \\ +\\ +Split the input. e.g. $a = x1 \cdot \beta^B + x0$ \\ +4. $x0 \leftarrow a \mbox{ (mod }\beta^B\mbox{)}$ (\textit{hint: use mp\_mod\_2d}) \\ +5. $y0 \leftarrow b \mbox{ (mod }\beta^B\mbox{)}$ \\ +6. $x1 \leftarrow \lfloor a / \beta^B \rfloor$ (\textit{hint: use mp\_rshd}) \\ +7. $y1 \leftarrow \lfloor b / \beta^B \rfloor$ \\ +\\ +Calculate the three products. \\ +8. $x0y0 \leftarrow x0 \cdot y0$ (\textit{hint: use mp\_mul}) \\ +9. $x1y1 \leftarrow x1 \cdot y1$ \\ +10. $t1 \leftarrow x1 - x0$ (\textit{hint: use mp\_sub}) \\ +11. $x0 \leftarrow y1 - y0$ \\ +12. $t1 \leftarrow t1 \cdot x0$ \\ +\\ +Calculate the middle term. \\ +13. $x0 \leftarrow x0y0 + x1y1$ \\ +14. $t1 \leftarrow x0 - t1$ \\ +\\ +Calculate the final product. \\ +15. $t1 \leftarrow t1 \cdot \beta^B$ (\textit{hint: use mp\_lshd}) \\ +16. $x1y1 \leftarrow x1y1 \cdot \beta^{2B}$ \\ +17. $t1 \leftarrow x0y0 + t1$ \\ +18. $c \leftarrow t1 + x1y1$ \\ +19. Clear all of the temporary variables. \\ +20. Return(\textit{MP\_OKAY}).\\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{Algorithm mp\_karatsuba\_mul} +\end{figure} + +\textbf{Algorithm mp\_karatsuba\_mul.} + + +\section{Squaring} +\subsection{The Baseline Squaring Algorithm} +\subsection{Faster Squaring by the ``Comba'' Method} +\subsection{Karatsuba Squaring} +\section{Tuning Algorithms} +\subsection{How to Tune Karatsuba Algorithms} + +\chapter{Modular Reductions} +\section{Basics of Modular Reduction} +\section{The Barrett Reduction} +\section{The Montgomery Reduction} +\subsection{Faster ``Comba'' Montgomery Reduction} +\subsection{Example Montgomery Algorithms} +\section{The Diminished Radix Algorithm} +\section{Algorithm Comparison} + +\chapter{Exponentiation} +\section{Single Digit Exponentiation} +\section{Modular Exponentiation} +\subsection{General Case} +\subsection{Odd or Diminished Radix Moduli} +\section{Quick Power of Two} + +\chapter{Higher Level Algorithms} +\section{Integer Division with Remainder} +\section{Single Digit Helpers} +\subsection{Single Digit Addition} +\subsection{Single Digit Subtraction} +\subsection{Single Digit Multiplication} +\subsection{Single Digit Division} +\subsection{Single Digit Modulo} +\subsection{Single Digit Root Extraction} +\section{Random Number Generation} +\section{Formatted Output} +\subsection{Getting The Output Size} +\subsection{Generating Radix-n Output} +\subsection{Reading Radix-n Input} +\section{Unformatted Output} +\subsection{Getting The Output Size} +\subsection{Generating Output} +\subsection{Reading Input} + +\chapter{Number Theoretic Algorithms} +\section{Greatest Common Divisor} +\section{Least Common Multiple} +\section{Jacobi Symbol Computation} +\section{Modular Inverse} +\subsection{General Case} +\subsection{Odd Moduli} +\section{Primality Tests} +\subsection{Trial Division} +\subsection{The Fermat Test} +\subsection{The Miller-Rabin Test} +\subsection{Primality Test in a Bottle} +\subsection{The Next Prime} +\section{Root Extraction} + +\backmatter +\appendix +\begin{thebibliography}{ABCDEF} +\bibitem[1]{TAOCPV2} +Donald Knuth, \textit{The Art of Computer Programming}, Third Edition, Volume Two, Seminumerical Algorithms, Addison-Wesley, 1998 + +\bibitem[2]{HAC} +A. Menezes, P. van Oorschot, S. Vanstone, \textit{Handbook of Applied Cryptography}, CRC Press, 1996 + +\bibitem[3]{ROSE} +Michael Rosing, \textit{Implementing Elliptic Curve Cryptography}, Manning Publications, 1999 + +\bibitem[4]{COMBA} +Paul G. Comba, \textit{Exponentiation Cryptosystems on the IBM PC}. IBM Systems Journal 29(4): 526-538 (1990) + +\bibitem[5]{KARA} +A. Karatsuba, Doklay Akad. Nauk SSSR 145 (1962), pp.293-294 + +\bibitem[6]{KARAP} +Andre Weimerskirch and Christof Paar, \textit{Generalizations of the Karatsuba Algorithm for Polynomial Multiplication}, Submitted to Design, Codes and Cryptography, March 2002 + +\end{thebibliography} + +\input{tommath.ind} + +\chapter{Appendix} +\subsection*{Appendix A -- Source Listing of tommath.h} + +The following is the source listing of the header file ``tommath.h'' for the LibTomMath project. It contains many of +the definitions used throughout the code such as \textbf{mp\_int}, \textbf{MP\_PREC} and so on. The header is +presented here for completeness. + +\index{tommath.h} +\vspace{+3mm}\begin{small} +\hspace{-5.1mm}{\bf File}: tommath.h +\vspace{-3mm} +\begin{alltt} +001 /* LibTomMath, multiple-precision integer library -- Tom St Denis +002 * +003 * LibTomMath is library that provides for multiple-precision +004 * integer arithmetic as well as number theoretic functionality. +005 * +006 * The library is designed directly after the MPI library by +007 * Michael Fromberger but has been written from scratch with +008 * additional optimizations in place. +009 * +010 * The library is free for all purposes without any express +011 * guarantee it works. +012 * +013 * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org +014 */ +015 #ifndef BN_H_ +016 #define BN_H_ +017 +018 #include +019 #include +020 #include +021 #include +022 #include +023 +024 #undef MIN +025 #define MIN(x,y) ((x)<(y)?(x):(y)) +026 #undef MAX +027 #define MAX(x,y) ((x)>(y)?(x):(y)) +028 +029 #ifdef __cplusplus +030 extern "C" \{ +031 +032 /* C++ compilers don't like assigning void * to mp_digit * */ +033 #define OPT_CAST (mp_digit *) +034 +035 #else +036 +037 /* C on the other hand doesn't care */ +038 #define OPT_CAST +039 +040 #endif +041 +042 /* some default configurations. +043 * +044 * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits +045 * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits +046 * +047 * At the very least a mp_digit must be able to hold 7 bits +048 * [any size beyond that is ok provided it doesn't overflow the data type] +049 */ +050 #ifdef MP_8BIT +051 typedef unsigned char mp_digit; +052 typedef unsigned short mp_word; +053 #elif defined(MP_16BIT) +054 typedef unsigned short mp_digit; +055 typedef unsigned long mp_word; +056 #elif defined(MP_64BIT) +057 /* for GCC only on supported platforms */ +058 #ifndef CRYPT +059 typedef unsigned long long ulong64; +060 typedef signed long long long64; +061 #endif +062 +063 typedef ulong64 mp_digit; +064 typedef unsigned long mp_word __attribute__ ((mode(TI))); +065 +066 #define DIGIT_BIT 60 +067 #else +068 /* this is the default case, 28-bit digits */ +069 +070 /* this is to make porting into LibTomCrypt easier :-) */ +071 #ifndef CRYPT +072 #ifdef _MSC_VER +073 typedef unsigned __int64 ulong64; +074 typedef signed __int64 long64; +075 #else +076 typedef unsigned long long ulong64; +077 typedef signed long long long64; +078 #endif +079 #endif +080 +081 typedef unsigned long mp_digit; +082 typedef ulong64 mp_word; +083 +084 #define DIGIT_BIT 28 +085 #endif +086 +087 /* otherwise the bits per digit is calculated automatically from the size of + a mp_digit */ +088 #ifndef DIGIT_BIT +089 #define DIGIT_BIT ((CHAR_BIT * sizeof(mp_digit) - 1)) /* bits per di + git */ +090 #endif +091 +092 +093 #define MP_DIGIT_BIT DIGIT_BIT +094 #define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit) + 1)) +095 #define MP_DIGIT_MAX MP_MASK +096 +097 /* equalities */ +098 #define MP_LT -1 /* less than */ +099 #define MP_EQ 0 /* equal to */ +100 #define MP_GT 1 /* greater than */ +101 +102 #define MP_ZPOS 0 /* positive integer */ +103 #define MP_NEG 1 /* negative */ +104 +105 #define MP_OKAY 0 /* ok result */ +106 #define MP_MEM -2 /* out of mem */ +107 #define MP_VAL -3 /* invalid input */ +108 #define MP_RANGE MP_VAL +109 +110 typedef int mp_err; +111 +112 /* you'll have to tune these... */ +113 extern int KARATSUBA_MUL_CUTOFF, +114 KARATSUBA_SQR_CUTOFF, +115 MONTGOMERY_EXPT_CUTOFF; +116 +117 /* various build options */ +118 #define MP_PREC 64 /* default digits of precision (must + be power of two) */ +119 +120 /* define this to use lower memory usage routines (exptmods mostly) */ +121 /* #define MP_LOW_MEM */ +122 +123 /* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER + _DIGIT*2) */ +124 #define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGI + T_BIT + 1)) +125 +126 typedef struct \{ +127 int used, alloc, sign; +128 mp_digit *dp; +129 \} mp_int; +130 +131 #define USED(m) ((m)->used) +132 #define DIGIT(m,k) ((m)->dp[k]) +133 #define SIGN(m) ((m)->sign) +134 +135 /* ---> init and deinit bignum functions <--- */ +136 +137 /* init a bignum */ +138 int mp_init(mp_int *a); +139 +140 /* free a bignum */ +141 void mp_clear(mp_int *a); +142 +143 /* init a null terminated series of arguments */ +144 int mp_init_multi(mp_int *mp, ...); +145 +146 /* clear a null terminated series of arguments */ +147 void mp_clear_multi(mp_int *mp, ...); +148 +149 /* exchange two ints */ +150 void mp_exch(mp_int *a, mp_int *b); +151 +152 /* shrink ram required for a bignum */ +153 int mp_shrink(mp_int *a); +154 +155 /* grow an int to a given size */ +156 int mp_grow(mp_int *a, int size); +157 +158 /* init to a given number of digits */ +159 int mp_init_size(mp_int *a, int size); +160 +161 /* ---> Basic Manipulations <--- */ +162 +163 #define mp_iszero(a) (((a)->used == 0) ? 1 : 0) +164 #define mp_iseven(a) (((a)->used == 0 || (((a)->dp[0] & 1) == 0)) ? 1 : 0) +165 #define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? 1 : 0) +166 +167 /* set to zero */ +168 void mp_zero(mp_int *a); +169 +170 /* set to a digit */ +171 void mp_set(mp_int *a, mp_digit b); +172 +173 /* set a 32-bit const */ +174 int mp_set_int(mp_int *a, unsigned int b); +175 +176 /* copy, b = a */ +177 int mp_copy(mp_int *a, mp_int *b); +178 +179 /* inits and copies, a = b */ +180 int mp_init_copy(mp_int *a, mp_int *b); +181 +182 /* trim unused digits */ +183 void mp_clamp(mp_int *a); +184 +185 /* ---> digit manipulation <--- */ +186 +187 /* right shift by "b" digits */ +188 void mp_rshd(mp_int *a, int b); +189 +190 /* left shift by "b" digits */ +191 int mp_lshd(mp_int *a, int b); +192 +193 /* c = a / 2**b */ +194 int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d); +195 +196 /* b = a/2 */ +197 int mp_div_2(mp_int *a, mp_int *b); +198 +199 /* c = a * 2**b */ +200 int mp_mul_2d(mp_int *a, int b, mp_int *c); +201 +202 /* b = a*2 */ +203 int mp_mul_2(mp_int *a, mp_int *b); +204 +205 /* c = a mod 2**d */ +206 int mp_mod_2d(mp_int *a, int b, mp_int *c); +207 +208 /* computes a = 2**b */ +209 int mp_2expt(mp_int *a, int b); +210 +211 /* makes a pseudo-random int of a given size */ +212 int mp_rand(mp_int *a, int digits); +213 +214 /* ---> binary operations <--- */ +215 /* c = a XOR b */ +216 int mp_xor(mp_int *a, mp_int *b, mp_int *c); +217 +218 /* c = a OR b */ +219 int mp_or(mp_int *a, mp_int *b, mp_int *c); +220 +221 /* c = a AND b */ +222 int mp_and(mp_int *a, mp_int *b, mp_int *c); +223 +224 /* ---> Basic arithmetic <--- */ +225 +226 /* b = -a */ +227 int mp_neg(mp_int *a, mp_int *b); +228 +229 /* b = |a| */ +230 int mp_abs(mp_int *a, mp_int *b); +231 +232 /* compare a to b */ +233 int mp_cmp(mp_int *a, mp_int *b); +234 +235 /* compare |a| to |b| */ +236 int mp_cmp_mag(mp_int *a, mp_int *b); +237 +238 /* c = a + b */ +239 int mp_add(mp_int *a, mp_int *b, mp_int *c); +240 +241 /* c = a - b */ +242 int mp_sub(mp_int *a, mp_int *b, mp_int *c); +243 +244 /* c = a * b */ +245 int mp_mul(mp_int *a, mp_int *b, mp_int *c); +246 +247 /* b = a*a */ +248 int mp_sqr(mp_int *a, mp_int *b); +249 +250 /* a/b => cb + d == a */ +251 int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d); +252 +253 /* c = a mod b, 0 <= c < b */ +254 int mp_mod(mp_int *a, mp_int *b, mp_int *c); +255 +256 /* ---> single digit functions <--- */ +257 +258 /* compare against a single digit */ +259 int mp_cmp_d(mp_int *a, mp_digit b); +260 +261 /* c = a + b */ +262 int mp_add_d(mp_int *a, mp_digit b, mp_int *c); +263 +264 /* c = a - b */ +265 int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); +266 +267 /* c = a * b */ +268 int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); +269 +270 /* a/b => cb + d == a */ +271 int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); +272 +273 /* c = a**b */ +274 int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); +275 +276 /* c = a mod b, 0 <= c < b */ +277 int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c); +278 +279 /* ---> number theory <--- */ +280 +281 /* d = a + b (mod c) */ +282 int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); +283 +284 /* d = a - b (mod c) */ +285 int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); +286 +287 /* d = a * b (mod c) */ +288 int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); +289 +290 /* c = a * a (mod b) */ +291 int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c); +292 +293 /* c = 1/a (mod b) */ +294 int mp_invmod(mp_int *a, mp_int *b, mp_int *c); +295 +296 /* c = (a, b) */ +297 int mp_gcd(mp_int *a, mp_int *b, mp_int *c); +298 +299 /* c = [a, b] or (a*b)/(a, b) */ +300 int mp_lcm(mp_int *a, mp_int *b, mp_int *c); +301 +302 /* finds one of the b'th root of a, such that |c|**b <= |a| +303 * +304 * returns error if a < 0 and b is even +305 */ +306 int mp_n_root(mp_int *a, mp_digit b, mp_int *c); +307 +308 /* shortcut for square root */ +309 #define mp_sqrt(a, b) mp_n_root(a, 2, b) +310 +311 /* computes the jacobi c = (a | n) (or Legendre if b is prime) */ +312 int mp_jacobi(mp_int *a, mp_int *n, int *c); +313 +314 /* used to setup the Barrett reduction for a given modulus b */ +315 int mp_reduce_setup(mp_int *a, mp_int *b); +316 +317 /* Barrett Reduction, computes a (mod b) with a precomputed value c +318 * +319 * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely +320 * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. +321 */ +322 int mp_reduce(mp_int *a, mp_int *b, mp_int *c); +323 +324 /* setups the montgomery reduction */ +325 int mp_montgomery_setup(mp_int *a, mp_digit *mp); +326 +327 /* computes a = B**n mod b without division or multiplication useful for +328 * normalizing numbers in a Montgomery system. +329 */ +330 int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); +331 +332 /* computes x/R == x (mod N) via Montgomery Reduction */ +333 int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); +334 +335 /* returns 1 if a is a valid DR modulus */ +336 int mp_dr_is_modulus(mp_int *a); +337 +338 /* sets the value of "d" required for mp_dr_reduce */ +339 void mp_dr_setup(mp_int *a, mp_digit *d); +340 +341 /* reduces a modulo b using the Diminished Radix method */ +342 int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); +343 +344 /* d = a**b (mod c) */ +345 int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); +346 +347 /* ---> Primes <--- */ +348 +349 /* number of primes */ +350 #ifdef MP_8BIT +351 #define PRIME_SIZE 31 +352 #else +353 #define PRIME_SIZE 256 +354 #endif +355 +356 /* table of first PRIME_SIZE primes */ +357 extern const mp_digit __prime_tab[]; +358 +359 /* result=1 if a is divisible by one of the first PRIME_SIZE primes */ +360 int mp_prime_is_divisible(mp_int *a, int *result); +361 +362 /* performs one Fermat test of "a" using base "b". +363 * Sets result to 0 if composite or 1 if probable prime +364 */ +365 int mp_prime_fermat(mp_int *a, mp_int *b, int *result); +366 +367 /* performs one Miller-Rabin test of "a" using base "b". +368 * Sets result to 0 if composite or 1 if probable prime +369 */ +370 int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result); +371 +372 /* performs t rounds of Miller-Rabin on "a" using the first +373 * t prime bases. Also performs an initial sieve of trial +374 * division. Determines if "a" is prime with probability +375 * of error no more than (1/4)**t. +376 * +377 * Sets result to 1 if probably prime, 0 otherwise +378 */ +379 int mp_prime_is_prime(mp_int *a, int t, int *result); +380 +381 /* finds the next prime after the number "a" using "t" trials +382 * of Miller-Rabin. +383 */ +384 int mp_prime_next_prime(mp_int *a, int t); +385 +386 +387 /* ---> radix conversion <--- */ +388 int mp_count_bits(mp_int *a); +389 +390 int mp_unsigned_bin_size(mp_int *a); +391 int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c); +392 int mp_to_unsigned_bin(mp_int *a, unsigned char *b); +393 +394 int mp_signed_bin_size(mp_int *a); +395 int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); +396 int mp_to_signed_bin(mp_int *a, unsigned char *b); +397 +398 int mp_read_radix(mp_int *a, char *str, int radix); +399 int mp_toradix(mp_int *a, char *str, int radix); +400 int mp_radix_size(mp_int *a, int radix); +401 +402 int mp_fread(mp_int *a, int radix, FILE *stream); +403 int mp_fwrite(mp_int *a, int radix, FILE *stream); +404 +405 #define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +406 #define mp_raw_size(mp) mp_signed_bin_size(mp) +407 #define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +408 #define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +409 #define mp_mag_size(mp) mp_unsigned_bin_size(mp) +410 #define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) +411 +412 #define mp_tobinary(M, S) mp_toradix((M), (S), 2) +413 #define mp_tooctal(M, S) mp_toradix((M), (S), 8) +414 #define mp_todecimal(M, S) mp_toradix((M), (S), 10) +415 #define mp_tohex(M, S) mp_toradix((M), (S), 16) +416 +417 /* lowlevel functions, do not call! */ +418 int s_mp_add(mp_int *a, mp_int *b, mp_int *c); +419 int s_mp_sub(mp_int *a, mp_int *b, mp_int *c); +420 #define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +421 int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +422 int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +423 int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +424 int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +425 int fast_s_mp_sqr(mp_int *a, mp_int *b); +426 int s_mp_sqr(mp_int *a, mp_int *b); +427 int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c); +428 int mp_karatsuba_sqr(mp_int *a, mp_int *b); +429 int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c); +430 int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); +431 int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode); +432 void bn_reverse(unsigned char *s, int len); +433 +434 #ifdef __cplusplus +435 \} +436 #endif +437 +438 #endif +439 +\end{alltt} +\end{small} + +\end{document} \ No newline at end of file