From 390fa39dc519551eb3c6e93fe3fa52a9ec9d9833 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Fri, 28 Feb 2003 16:02:06 +0000 Subject: [PATCH] added libtommath-0.01 --- b.bat | 3 + bn.c | 1983 +++++++++++++++++++++++++++++++++++++++++++++++++++ bn.h | 225 ++++++ bn.pdf | Bin 0 -> 135254 bytes bn.tex | 411 +++++++++++ changes.txt | 6 + demo.c | 238 +++++++ makefile | 24 + timer.asm | 28 + 9 files changed, 2918 insertions(+) create mode 100644 b.bat create mode 100644 bn.c create mode 100644 bn.h create mode 100644 bn.pdf create mode 100644 bn.tex create mode 100644 changes.txt create mode 100644 demo.c create mode 100644 makefile create mode 100644 timer.asm diff --git a/b.bat b/b.bat new file mode 100644 index 0000000..1142d35 --- /dev/null +++ b/b.bat @@ -0,0 +1,3 @@ +nasm -f coff timer.asm +gcc -Wall -W -O3 -fomit-frame-pointer -funroll-loops -DTIMER demo.c bn.c timer.o -o demo +gcc -I./mtest/ -DU_MPI -Wall -W -O3 -fomit-frame-pointer -funroll-loops -DTIMER demo.c mtest/mpi.c timer.o -o mpidemo diff --git a/bn.c b/bn.c new file mode 100644 index 0000000..82262f5 --- /dev/null +++ b/bn.c @@ -0,0 +1,1983 @@ +/* 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://libtommath.iahu.ca + */ +#include "bn.h" + +/* chars used in radix conversions */ +static const char *s_rmap = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +#undef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#undef MAX +#define MAX(x,y) ((x)>(y)?(x):(y)) + +/* init a new bigint */ +int mp_init(mp_int *a) +{ + a->dp = calloc(sizeof(mp_digit), 16); + if (a->dp == NULL) { + return MP_MEM; + } + a->used = 0; + a->alloc = 16; + a->sign = MP_ZPOS; + return MP_OKAY; +} + +/* clear one (frees) */ +void mp_clear(mp_int *a) +{ + if (a->dp != NULL) { + memset(a->dp, 0, sizeof(mp_digit) * a->alloc); + free(a->dp); + a->dp = NULL; + } +} + +/* grow as required */ +static int mp_grow(mp_int *a, int size) +{ + int i; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + size += 16 - (size & 15); /* ensure its to the next multiple of 16 words */ + a->dp = realloc(a->dp, sizeof(mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + i = a->alloc; + a->alloc = size; + + /* zero top words */ + for (; i < size; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + +/* shrink a bignum */ +int mp_shrink(mp_int *a) +{ + if (a->alloc != a->used) { + if ((a->dp = realloc(a->dp, sizeof(mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->alloc = a->used; + } + return MP_OKAY; +} + +/* trim unused digits */ +static 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; + } +} + +/* 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); +} + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b) +{ + mp_zero(a); + a->dp[0] = b & MP_MASK; + a->used = 1; +} + +/* set a 32-bit const */ +int mp_set_int(mp_int *a, unsigned long b) +{ + int res, x; + if ((res = mp_grow(a, 32/DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + /* set four bits at a time, simplest solution to the what if DIGIT_BIT==7 case */ + for (x = 0; x < 8; x++) { + mp_mul_2d(a, 4, a); + a->dp[0] |= (b>>28)&15; + b <<= 4; + } + mp_clamp(a); + return MP_OKAY; +} + +/* init a mp_init and grow it to a given size */ +int mp_init_size(mp_int *a, int size) +{ + int res; + + if ((res = mp_init(a)) != MP_OKAY) { + return res; + } + return mp_grow(a, size); +} + +/* copy, b = a */ +int mp_copy(mp_int *a, mp_int *b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a->dp == b->dp) + return MP_OKAY; + + /* grow dest */ + if ((res = mp_grow(b, a->used)) != MP_OKAY) { + return res; + } + + mp_zero(b); + b->used = a->used; + b->sign = a->sign; + for (n = 0; n < a->used; n++) { + b->dp[n] = a->dp[n]; + } + return MP_OKAY; +} + +/* 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); +} + +/* compare maginitude of two ints (unsigned) */ +static int s_mp_cmp(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; +} + +/* 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 s_mp_cmp(a, b); +} + +/* 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; + } +} + +/* 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; + } + + /* shift the digits down */ + for (x = 0; x < (a->used - b); x++) { + a->dp[x] = a->dp[x + b]; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + a->dp[x] = 0; + } + mp_clamp(a); +} + +/* 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; + } + + /* increment the used by the shift amount than copy upwards */ + a->used += b; + for (x = a->used-1; x >= b; x--) { + a->dp[x] = a->dp[x - b]; + } + + /* zero the lower digits */ + for (x = 0; x < b; x++) { + a->dp[x] = 0; + } + mp_clamp(a); + return MP_OKAY; +} + +/* 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)) { + return mp_copy(a, c); + } + + /* copy */ + if ((res = mp_copy(a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above */ + 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)<<(b % DIGIT_BIT)) - ((mp_digit)1)); + mp_clamp(c); + return MP_OKAY; +} + +/* 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; + + if (d != NULL) { + if ((res = mp_mod_2d(a, b, d)) != MP_OKAY) { + return res; + } + } + + /* copy */ + if ((res = mp_copy(a, c)) != MP_OKAY) { + return res; + } + + /* shift by as many digits in the bit count */ + mp_rshd(c, b/DIGIT_BIT); + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit)(b % DIGIT_BIT); + if (D != 0) { + r = 0; + for (x = c->used - 1; x >= 0; x--) { + rr = c->dp[x] & ((mp_digit)((1U<dp[x] = (c->dp[x] >> D) | (r << (DIGIT_BIT-D)); + r = rr; + } + } + mp_clamp(c); + return MP_OKAY; +} + +/* 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 ((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) { + r = 0; + for (x = 0; x < a->used; x++) { + rr = (c->dp[x] >> (DIGIT_BIT - d)) & ((mp_digit)((1U<dp[x] = ((c->dp[x] << d) | r) & MP_MASK; + r = rr; + } + } + mp_clamp(c); + return MP_OKAY; +} + +/* b = a/2 */ +int mp_div_2(mp_int *a, mp_int *b) +{ + return mp_div_2d(a, 1, b, NULL); +} + +/* b = a*2 */ +int mp_mul_2(mp_int *a, mp_int *b) +{ + return mp_mul_2d(a, 1, b); +} + +/* low level addition */ +static int s_mp_add(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int t, *x; + int res, min, max, i; + mp_digit u; + + /* find sizes */ + 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 ((res = mp_init_size(&t, max+1)) != MP_OKAY) { + return res; + } + t.used = max+1; + + /* add digits from lower part */ + u = 0; + for (i = 0; i < min; i++) { + t.dp[i] = a->dp[i] + b->dp[i] + u; + u = (t.dp[i] >> DIGIT_BIT) & 1; + t.dp[i] &= MP_MASK; + } + + /* now copy higher words if any */ + if (min != max) { + for (; i < max; i++) { + t.dp[i] = x->dp[i] + u; + u = (t.dp[i] >> DIGIT_BIT) & 1; + t.dp[i] &= MP_MASK; + } + } + + /* add carry */ + t.dp[i] = u; + + mp_clamp(&t); + if ((res = mp_copy(&t, c)) != MP_OKAY) { + mp_clear(&t); + return res; + } + mp_clear(&t); + return MP_OKAY; +} + +/* low level subtraction (assumes a > b) */ +static int s_mp_sub(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int t; + int res, min, max, i; + mp_digit u; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if ((res = mp_init_size(&t, max+1)) != MP_OKAY) { + return res; + } + t.used = max+1; + + /* sub digits from lower part */ + u = 0; + for (i = 0; i < min; i++) { + t.dp[i] = a->dp[i] - (b->dp[i] + u); + u = (t.dp[i] >> DIGIT_BIT) & 1; + t.dp[i] &= MP_MASK; + } + + /* now copy higher words if any */ + if (min != max) { + for (; i < max; i++) { + t.dp[i] = a->dp[i] - u; + u = (t.dp[i] >> DIGIT_BIT) & 1; + t.dp[i] &= MP_MASK; + } + } + + mp_clamp(&t); + if ((res = mp_copy(&t, c)) != MP_OKAY) { + mp_clear(&t); + return res; + } + + mp_clear(&t); + return MP_OKAY; +} + +/* low level multiplication */ +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) + +/* fast multiplier */ +/* multiplies |a| * |b| and only computes upto digs digits of result */ +static int fast_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_word W[512]; + mp_digit tmpx, *tmpt, *tmpy; + +// printf("\nHOLA\n"); + + if ((res = mp_init_size(&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* clear temp buf */ + memset(W, 0, digs*sizeof(mp_word)); + + pa = a->used; + for (ix = 0; ix < pa; ix++) { + pb = MIN(b->used, digs - ix); + tmpx = a->dp[ix]; + tmpt = &(t.dp[ix]); + tmpy = b->dp; + for (iy = 0; iy < pb; iy++) { + W[iy+ix] += ((mp_word)tmpx) * ((mp_word)*tmpy++); + } + } + + /* now convert the array W downto what we need */ + for (ix = 1; ix < digs; ix++) { + W[ix] = W[ix] + (W[ix-1] >> ((mp_word)DIGIT_BIT)); + t.dp[ix-1] = W[ix-1] & ((mp_word)MP_MASK); + } + t.dp[digs-1] = W[digs-1] & ((mp_word)MP_MASK); + + mp_clamp(&t); + if ((res = mp_copy(&t, c)) != MP_OKAY) { + mp_clear(&t); + return res; + } + mp_clear(&t); + + return MP_OKAY; +} + +/* multiplies |a| * |b| and only computes upto digs digits of result */ +static 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 < 512) && digs < (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; + + pa = a->used; + for (ix = 0; ix < pa; ix++) { + u = 0; + pb = MIN(b->used, digs - ix); + tmpx = a->dp[ix]; + tmpt = &(t.dp[ix]); + tmpy = b->dp; + for (iy = 0; iy < pb; iy++) { + r = ((mp_word)*tmpt) + ((mp_word)tmpx) * ((mp_word)*tmpy++) + ((mp_word)u); + *tmpt++ = (mp_digit)(r & ((mp_word)MP_MASK)); + u = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); + } + if (ix+iyused + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + memset(W, 0, (pa + pb + 1) * sizeof(mp_word)); + for (ix = 0; ix < pa; ix++) { + tmpx = a->dp[ix]; + tmpt = &(t.dp[digs]); + tmpy = b->dp + (digs - ix); + for (iy = digs - ix; iy < pb; iy++) { + W[ix+iy] += ((mp_word)tmpx) * ((mp_word)*tmpy++); + } + } + + /* now convert the array W downto what we need */ + for (ix = 1; ix < (pa+pb+1); ix++) { + W[ix] = W[ix] + (W[ix-1] >> ((mp_word)DIGIT_BIT)); + t.dp[ix-1] = W[ix-1] & ((mp_word)MP_MASK); + } + t.dp[(pa+pb+1)-1] = W[(pa+pb+1)-1] & ((mp_word)MP_MASK); + + + mp_clamp(&t); + if ((res = mp_copy(&t, c)) != MP_OKAY) { + mp_clear(&t); + return res; + } + mp_clear(&t); + + return MP_OKAY; +} + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +static 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 ((digs < 512) && digs < (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++) { + u = 0; + tmpx = a->dp[ix]; + tmpt = &(t.dp[digs]); + tmpy = b->dp + (digs - ix); + for (iy = digs - ix; iy < pb; iy++) { + r = ((mp_word)*tmpt) + ((mp_word)tmpx) * ((mp_word)*tmpy++) + ((mp_word)u); + *tmpt++ = (mp_digit)(r & ((mp_word)MP_MASK)); + u = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp(&t); + if ((res = mp_copy(&t, c)) != MP_OKAY) { + mp_clear(&t); + return res; + } + mp_clear(&t); + + return MP_OKAY; +} + +/* fast squaring */ +static int fast_s_mp_sqr(mp_int *a, mp_int *b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r, W[512]; + mp_digit tmpx, *tmpy; + + pa = a->used; + if ((res = mp_init_size(&t, pa + pa + 1)) != MP_OKAY) { + return res; + } + t.used = pa + pa + 1; + + /* zero temp buffer */ + memset(W, 0, (pa+pa+1)*sizeof(mp_word)); + + for (ix = 0; ix < pa; ix++) { + W[ix+ix] += ((mp_word)a->dp[ix]) * ((mp_word)a->dp[ix]); + tmpx = a->dp[ix]; + tmpy = &(a->dp[ix+1]); + for (iy = ix + 1; iy < pa; iy++) { + r = ((mp_word)tmpx) * ((mp_word)*tmpy++); + W[ix+iy] += r + r; + } + } + for (ix = 1; ix < (pa+pa+1); ix++) { + W[ix] = W[ix] + (W[ix-1] >> ((mp_word)DIGIT_BIT)); + t.dp[ix-1] = W[ix-1] & ((mp_word)MP_MASK); + } + t.dp[(pa+pa+1)-1] = W[(pa+pa+1)-1] & ((mp_word)MP_MASK); + + mp_clamp(&t); + if ((res = mp_copy(&t, b)) != MP_OKAY) { + mp_clear(&t); + return res; + } + mp_clear(&t); + return MP_OKAY; +} + +/* low level squaring, b = a*a */ +static 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; + + /* can we use the fast multiplier? */ + if (((a->used * 2 + 1) < 512) && a->used < (1<<( (CHAR_BIT*sizeof(mp_word)) - (2*DIGIT_BIT) - 1))) { + return fast_s_mp_sqr(a,b); + } + + 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++) { + r = ((mp_word)t.dp[ix+ix]) + ((mp_word)a->dp[ix]) * ((mp_word)a->dp[ix]); + t.dp[ix+ix] = (mp_digit)(r & ((mp_word)MP_MASK)); + u = (r >> ((mp_word)DIGIT_BIT)); + tmpx = a->dp[ix]; + tmpt = &(t.dp[ix+ix+1]); + for (iy = ix + 1; iy < pa; iy++) { + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + r = ((mp_word)*tmpt) + r + r + ((mp_word)u); + *tmpt++ = (mp_digit)(r & ((mp_word)MP_MASK)); + 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); + if ((res = mp_copy(&t, b)) != MP_OKAY) { + mp_clear(&t); + return res; + } + mp_clear(&t); + return MP_OKAY; +} + +/* high level addition (handles signs) */ +int mp_add(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 */ + 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 (s_mp_cmp(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 (s_mp_cmp(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; +} + +/* 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 (s_mp_cmp(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 (s_mp_cmp(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; +} + +/* c = |a| * |b| using Karatsuba */ +static 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, neg, x; + + 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(&t1) != MP_OKAY) goto Y1; + if (mp_init(&t2) != MP_OKAY) goto T1; + if (mp_init(&x0y0) != MP_OKAY) goto T2; + if (mp_init(&x1y1) != 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; + + for (x = 0; x < B; x++) { + x0.dp[x] = a->dp[x]; + y0.dp[x] = b->dp[x]; + } + for (x = B; x < a->used; x++) { + x1.dp[x-B] = a->dp[x]; + } + for (x = B; x < b->used; x++) { + y1.dp[x-B] = b->dp[x]; + } + + mp_clamp(&x0); + mp_clamp(&x1); + mp_clamp(&y0); + mp_clamp(&y1); + + /* 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 */ + neg = (t1.sign == t2.sign) ? MP_ZPOS : MP_NEG; + if (mp_mul(&t1, &t2, &t1) != MP_OKAY) goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ + t1.sign = neg; + + /* 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))<used, b->used) > KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul(a, b, c); + } else { + res = s_mp_mul(a, b, c); + } + c->sign = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + return res; +} + +/* Karatsuba squaring, computes b = a*a */ +static 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_copy(&x0, a) != MP_OKAY) goto ERR; + if (mp_init_copy(&x1, a) != MP_OKAY) goto X0; + + /* init temps */ + if (mp_init(&t1) != MP_OKAY) goto X1; + if (mp_init(&t2) != MP_OKAY) goto T1; + if (mp_init(&x0x0) != MP_OKAY) goto T2; + if (mp_init(&x1x1) != MP_OKAY) goto X0X0; + + /* now shift the digits */ + mp_mod_2d(&x0, B*DIGIT_BIT, &x0); + mp_rshd(&x1, B); + + /* now calc the products x0*x0 and x1*x1 */ + if (s_mp_sqr(&x0, &x0x0) != MP_OKAY) goto X1X1; /* x0x0 = x0*x0 */ + if (s_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 (s_mp_sqr(&t1, &t1) != MP_OKAY) goto X1X1; /* t1 = (x1 - x0) * (y1 - y0) */ + + /* add x0y0 */ + if (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))<used > KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr(a, b); + } else { + res = s_mp_sqr(a, b); + } + b->sign = MP_ZPOS; + return res; +} + + +/* integer signed division. c*b + d == a [e.g. a/b, c=quotient, d=remainder] */ +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; + + /* if a < b then q=0, r = a */ + if (s_mp_cmp(a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy(a, d); + d->sign = a->sign; + } 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 */ + norm = 0; + while ((y.dp[y.used-1] & (((mp_digit)1)<<(DIGIT_BIT-1))) == ((mp_digit)0)) { + ++norm; + if ((res = mp_mul_2d(&x, 1, &x)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_mul_2d(&y, 1, &y)) != MP_OKAY) { + goto __Y; + } + } + + /* 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--) { + /* 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< (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 */ + 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 && x.used != 0) { + 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] */ + if (c != NULL) { + mp_clamp(&q); + mp_copy(&q, c); + c->sign = neg; + } + + if (d != NULL) { + x.sign = a->sign; + mp_div_2d(&x, norm, &x, NULL); + mp_clamp(&x); + mp_copy(&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; +} + +/* 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(&t)) != MP_OKAY) { + return res; + } + mp_set(&t, b); + res = mp_add(a, &t, c); + + mp_clear(&t); + return res; +} + +/* 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; +} + +/* multiply by a digit */ +int mp_mul_d(mp_int *a, mp_digit b, mp_int *c) +{ + int res, pa, ix; + mp_word r; + mp_digit u; + mp_int t; + + pa = a->used; + if ((res = mp_init_size(&t, pa + 2)) != MP_OKAY) { + return res; + } + t.used = pa + 2; + + u = 0; + for (ix = 0; ix < pa; ix++) { + r = ((mp_word)u) + ((mp_word)a->dp[ix]) * ((mp_word)b); + t.dp[ix] = (mp_digit)(r & ((mp_word)MP_MASK)); + u = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); + } + t.dp[ix] = u; + + mp_clamp(&t); + if ((res = mp_copy(&t, c)) != MP_OKAY) { + mp_clear(&t); + return res; + } + mp_clear(&t); + return MP_OKAY; +} + +/* 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); + + if (d != NULL) { + *d = t2.dp[0]; + } + + mp_clear(&t); + mp_clear(&t2); + return res; +} + +/* simple modular functions */ + +/* d = a + b (mod c) */ +int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d) +{ + int res; + + if ((res = mp_add(a, b, d)) != MP_OKAY) { + return res; + } + return mp_mod(d, c, d); +} + +/* d = a - b (mod c) */ +int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d) +{ + int res; + + if ((res = mp_sub(a, b, d)) != MP_OKAY) { + return res; + } + return mp_mod(d, c, d); +} + +/* d = a * b (mod c) */ +int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d) +{ + int res; + + if ((res = mp_mul(a, b, d)) != MP_OKAY) { + return res; + } + return mp_mod(d, c, d); +} + +/* c = a * a (mod b) */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c) +{ + int res; + + if ((res = mp_sqr(a, c)) != MP_OKAY) { + return res; + } + return mp_mod(c, b, c); +} + +/* 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 ((u.dp[0] & 1) == 0 && (v.dp[0] & 1) == 0) { + ++k; + mp_div_2d(&u, 1, &u, NULL); + mp_div_2d(&v, 1, &v, NULL); + } + + /* B2. Initialize */ + if ((u.dp[0] & 1) == 1) { + if ((res = mp_copy(&v, &t)) != MP_OKAY) { + goto __T; + } + t.sign = MP_NEG; + } else { + if ((res = mp_copy(&u, &t)) != MP_OKAY) { + goto __T; + } + } + + do { + /* B3 (and B4). Halve t, if even */ + while (t.used != 0 && (t.dp[0] & 1) == 0) { + mp_div_2d(&t, 1, &t, NULL); + } + + /* 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; + } + + if ((res = mp_copy(&u, c)) != MP_OKAY) { + goto __T; + } + c->sign = neg; +__T: mp_clear(&t); +__V: mp_clear(&u); +__U: mp_clear(&v); + + return res; +} + +/* computes least common multipble 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; +} + +/* computes the modular inverse via extended euclidean algorithm, that is c = 1/a mod b */ +int mp_invmod(mp_int *a, mp_int *b, mp_int *c) +{ + int res; + mp_int t1, t2, t3, u1, u2, u3, v1, v2, v3, q; + + 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 ((res = mp_init(&u1)) != MP_OKAY) { + goto __T3; + } + + if ((res = mp_init(&u2)) != MP_OKAY) { + goto __U1; + } + + if ((res = mp_init(&u3)) != MP_OKAY) { + goto __U2; + } + + if ((res = mp_init(&v1)) != MP_OKAY) { + goto __U3; + } + + if ((res = mp_init(&v2)) != MP_OKAY) { + goto __V1; + } + + if ((res = mp_init(&v3)) != MP_OKAY) { + goto __V2; + } + + if ((res = mp_init(&q)) != MP_OKAY) { + goto __V3; + } + + /* (u1, u2, u3) = (1, 0, a) */ + mp_set(&u1, 1); + if ((res = mp_copy(a, &u3)) != MP_OKAY) { + goto __Q; + } + + /* (v1, v2, v3) = (0, 1, b) */ + mp_set(&u2, 1); + if ((res = mp_copy(b, &v3)) != MP_OKAY) { + goto __Q; + } + + while (mp_iszero(&v3) == 0) { + if ((res = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) { + goto __Q; + } + + /* (t1, t2, t3) = (u1, u2, u3) - q*(v1, v2, v3) */ + if ((res = mp_mul(&q, &v1, &t1)) != MP_OKAY) { goto __Q; } + if ((res = mp_sub(&u1, &t1, &t1)) != MP_OKAY) { goto __Q; } + if ((res = mp_mul(&q, &v2, &t2)) != MP_OKAY) { goto __Q; } + if ((res = mp_sub(&u2, &t2, &t2)) != MP_OKAY) { goto __Q; } + if ((res = mp_mul(&q, &v3, &t3)) != MP_OKAY) { goto __Q; } + if ((res = mp_sub(&u3, &t3, &t3)) != MP_OKAY) { goto __Q; } + + /* u = v */ + if ((res = mp_copy(&v1, &u1)) != MP_OKAY) { goto __Q; } + if ((res = mp_copy(&v2, &u2)) != MP_OKAY) { goto __Q; } + if ((res = mp_copy(&v3, &u3)) != MP_OKAY) { goto __Q; } + + /* v = t */ + if ((res = mp_copy(&t1, &v1)) != MP_OKAY) { goto __Q; } + if ((res = mp_copy(&t2, &v2)) != MP_OKAY) { goto __Q; } + if ((res = mp_copy(&t3, &v3)) != MP_OKAY) { goto __Q; } + } + + /* if u3 != 1, then there is no inverse */ + if (mp_cmp_d(&u3, 1) != MP_EQ) { + res = MP_VAL; + goto __Q; + } + + /* u1 is the inverse */ + res = mp_copy(&u1, c); +__Q : mp_clear(&q); +__V3: mp_clear(&v3); +__V2: mp_clear(&v1); +__V1: mp_clear(&v1); +__U3: mp_clear(&u3); +__U2: mp_clear(&u2); +__U1: mp_clear(&u1); +__T3: mp_clear(&t3); +__T2: mp_clear(&t2); +__T1: mp_clear(&t1); + return res; +} + +/* 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; + + mp_set(a, 1); + if ((res = mp_lshd(a, b->used * 2)) != MP_OKAY) { + return res; + } + return mp_div(a, b, a, NULL); +} + +/* reduces x mod m, assumes 0 < x < m^2, mu is precomputed via mp_reduce_setup */ +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) */ + mp_mod_2d(x, DIGIT_BIT * (um + 1), x); + + /* q = q * m mod b^(k+1), quick (no division) */ + s_mp_mul_digs(&q, m, &q, um + 1); + + /* 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; +} + +int mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) +{ + mp_int M[64], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, z, winsize, tab[64]; + + /* find window size */ + x = mp_count_bits(X); + if (x <= 18) { winsize = 2; } + else if (x <= 84) { winsize = 3; } + else if (x <= 300) { winsize = 4; } + else if (x <= 930) { winsize = 5; } + else { winsize = 6; } + + /* init G array */ + for (x = 0; x < (1<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 = 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 (y == 0 && mode == 0) continue; + + /* if the bit is zero and mode == 1 then we square */ + if (y == 0 && mode == 1) { + 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 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) { + bitbuf >>= (winsize - bitcpy); + /* square first */ + 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; + } + } + + /* 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; + } + } + + err = mp_copy(&res, Y); +__RES: mp_clear(&res); +__MU : mp_clear(&mu); +__M : + for (x = 0; x < (1< radix conversion <-- */ +/* reverse an array, used for radix code */ +static void 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; + } +} + +/* 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) { + ++r; + q >>= 1UL; + } + return r; +} + +/* 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); + a->used = (c/DIGIT_BIT) + ((c % DIGIT_BIT) != 0 ? 1: 0); + if ((res = mp_grow(a, a->used)) != MP_OKAY) { + return res; + } + 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; +} + +/* 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; +} + +/* 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)); + } + mp_div_2d(&t, 8, &t, NULL); + } + reverse(b, x); + return MP_OKAY; +} + +/* 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; +} + +/* get the size for an unsigned equivalent */ +int mp_unsigned_bin_size(mp_int *a) +{ + return (mp_count_bits(a)/8 + ((mp_count_bits(a)&7) != 0 ? 1 : 0)); +} + +/* get the size for an signed equivalent */ +int mp_signed_bin_size(mp_int *a) +{ + return 1 + (mp_count_bits(a)/8 + ((mp_count_bits(a)&7) != 0 ? 1 : 0)); +} + +/* read a string [ASCII] in a given radix */ +int mp_read_radix(mp_int *a, unsigned char *str, int radix) +{ + int y, res, neg; + + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if (*str == (unsigned char)'-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + mp_zero(a); + while (*str) { + for (y = 0; y < 64; y++) { + if (*str == (unsigned char)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, unsigned char *str, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + unsigned 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) { + return res; + } + *str++ = (unsigned char)s_rmap[d]; + ++digs; + } + reverse(_s, digs); + *str++ = (unsigned char)'\0'; + mp_clear(&t); + return MP_OKAY; +} + diff --git a/bn.h b/bn.h new file mode 100644 index 0000000..2c780e6 --- /dev/null +++ b/bn.h @@ -0,0 +1,225 @@ +/* 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://libtommath.iahu.ca + */ + +#ifndef BN_H_ +#define BN_H_ + +#include +#include +#include +#include +#include + +/* 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 + * + * 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] + */ +#ifdef MP_8BIT + typedef unsigned char mp_digit; + typedef unsigned short mp_word; +#elif defined(MP_16BIT) + typedef unsigned short mp_digit; + typedef unsigned long mp_word; +#else + typedef unsigned long mp_digit; + typedef unsigned long long mp_word; + #define DIGIT_BIT 28U +#endif + +#ifndef DIGIT_BIT + #define DIGIT_BIT ((CHAR_BIT * sizeof(mp_digit) - 1)) /* bits per digit */ +#endif + +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) + +/* equalities */ +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM 1 /* out of mem */ +#define MP_VAL 2 /* invalid input */ + +#define KARATSUBA_MUL_CUTOFF 80 /* Min. number of digits before Karatsuba multiplication is used. */ +#define KARATSUBA_SQR_CUTOFF 80 /* Min. number of digits before Karatsuba squaring is used. */ + +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + +/* ---> init and deinit bignum functions <--- */ + +/* init a bignum */ +int mp_init(mp_int *a); + +/* free a bignum */ +void mp_clear(mp_int *a); + +/* shrink ram required for a bignum */ +int mp_shrink(mp_int *a); + +/* ---> Basic Manipulations <--- */ + +#define mp_iszero(a) (((a)->used == 0) ? 1 : 0) +#define mp_iseven(a) (((a)->used == 0 || (((a)->dp[0] & 1) == 0)) ? 1 : 0) +#define mp_isodd(a) (((a)->used > 0 || (((a)->dp[0] & 1) == 1)) ? 1 : 0) + +/* set to zero */ +void mp_zero(mp_int *a); + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b); + +/* set a 32-bit const */ +int mp_set_int(mp_int *a, unsigned long b); + +/* init to a given number of digits */ +int mp_init_size(mp_int *a, int size); + +/* copy, b = a */ +int mp_copy(mp_int *a, mp_int *b); + +/* inits and copies, a = b */ +int mp_init_copy(mp_int *a, mp_int *b); + +/* ---> digit manipulation <--- */ + +/* right shift by "b" digits */ +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 */ +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 */ +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 */ +int mp_mod_2d(mp_int *a, int b, mp_int *c); + +/* ---> Basic arithmetic <--- */ + +/* compare a to b */ +int mp_cmp(mp_int *a, mp_int *b); + +/* c = a + b */ +int mp_add(mp_int *a, mp_int *b, mp_int *c); + +/* c = a - b */ +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 */ +int mp_sqr(mp_int *a, mp_int *b); + +/* a/b => cb + d == a */ +int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c == a mod b */ +#define mp_mod(a, b, c) mp_div(a, b, NULL, c) + +/* ---> single digit functions <--- */ + +/* compare against a single digit */ +int mp_cmp_d(mp_int *a, mp_digit b); + +/* c = a + b */ +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a - b */ +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a * b */ +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 mod b */ +#define mp_mod_d(a,b,c) mp_div_d(a, b, NULL, c) + +/* ---> number theory <--- */ + +/* d = a + b (mod c) */ +int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a - b (mod c) */ +int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a * b (mod c) */ +int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a * a (mod b) */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = 1/a (mod b) */ +int mp_invmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = (a, b) */ +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); + +/* used to setup the Barrett reduction for a given modulus b */ +int mp_reduce_setup(mp_int *a, mp_int *b); + +/* Barrett Reduction, computes a (mod b) with a precomputed value c */ +int mp_reduce(mp_int *a, mp_int *b, mp_int *c); + +/* d = a^b (mod c) */ +int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* ---> radix conversion <--- */ + +int mp_count_bits(mp_int *a); + +int mp_unsigned_bin_size(mp_int *a); +int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c); +int mp_to_unsigned_bin(mp_int *a, unsigned char *b); + +int mp_signed_bin_size(mp_int *a); +int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); +int mp_to_signed_bin(mp_int *a, unsigned char *b); + +int mp_read_radix(mp_int *a, unsigned char *str, int radix); +int mp_toradix(mp_int *a, unsigned char *str, int radix); + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +#endif + diff --git a/bn.pdf b/bn.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0550ee583d8471bd679528fd44b04d099ec951e0 GIT binary patch literal 135254 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

csUg z?IL5sr=;wUUDLejX$2WRD#dE&vBFPEMwi_!j(In0+Od%7hZpVh?Q`ndl;T&UuimX- z#v3O*XKmW^pk~>p%lfSi-1jQEz_WJUD)siEQ?_k_{N4__C3yz@GxwYCuA6<@|7G+U z563lOwyP|664~Pq6qfgY^72r%Hg`;Q){)F_t1Z8O-)i7zx{W2}-xUn6bT}3jn*03? z{R#7`k~Pe&qvyGqFZ^yj-c`X>6m88O;2rRM%OU+vGefK%l6w5Bc3cu891o&-&Jg8Zre-E?-^6%UXF}5W#(>rN3F|> zJ$<7K-`gM6SHb+WK@rz*rrmSK@ub3qQ7hG1ciR=s0~^z?-m*4}A3V6>tqEgo7fxF6 zFyqLLSASS-a`|)Wua56s{Fk|j)8S#B!+sim_|LvkyDOt5SQ#h5ClFd>V&}7Zg>LN! zYMC7ZEdWF6iXB4#&xayntW2Elw>MVSfqwN04xB&V-Obg>h?VgYtgHit>q++88$9`Y zp@9H>A^km-t3Y+Jtk+^?EJPOi&oM^T0s4bsWyVaugiJt5ZJGZO7}%NUw>x~#31G2~ zY`$LId3@C!nOJ*;)pY@6F=B`eff{0ntP?E+h|CyPX3TjDd2e3_V)f8Cp(D{RqHxAo zP5`SQKn&fpkgOLa^)){0qyZP#@w9_3{*7d^Bq?Kz9pCx8lh&aXKzC3h4)%yR*c;$qh7vO*0HOQIQqhK&Pdc;ENWji$r3hXZSHgav_tjbXns(&&aV zh(H8ygw8U4K$tALgPw#B5fCRu+eN|vgL}O&);KrFjB%FU0M8oh2k*q{?@;kCT7!a& zJJdI}8+1e(iFAa7-ar!9;jGjtBO*hPc3_$wOL#4S4OoiR5fLkt8jV^jvsn-t7A=FH z4}yXhsQstOeAU|Mut<%JoP(lc|B#yICLiC)^spw%i=*}O0h zsHC&5j-r5(J8RWST_lpF_V2m{5iUxdT4v)ilOhP3peQ*>5%6bkF>AEyU=s*Dh45^m z`vO3h1t2?E)w1`I1BnLH#X%x$%EaT|vDhqrJimVmU zD2C(l`bas4ybI%FA&6B>BY6tf4@MIl+a%!wAQ_|46vJY=fc=bt$-U(g1cf$1h~&Zz z%VV~J5iP*32{E5Q(L6>2J|3qL0x6*U=jiIP6(JW$lp$S26QFG{97HrZj}otoX*|c1 zm|Q{*;mf!To}*digWzd`z-2&WG=cRS!BcWHH;C#ZctT<;f&(ky zd^AO4eMxW(E#NX(MlRqoptUq^E0zHl#AL7}3!5{<`mwaYOJqR5;rcO*9QQwhCBRr% zeGEgx;y^5efnkd4$1tSS*8~Q#*^A2}SHs&2hDMVKy1IP`Hbu}<8Y$^ZLO_AySXoBe z=P;8=d<`t?FtcR5kqk{^K1tFP%i(q*1sZMR5w}gC7zrO|Jd;Ai#}KrD z_Xo}JXqAHTQ4*h|X{pW>4@9gi4Z{f6kAnDooR6Y7$#^3Lmcn(R;K%{If59vgKc!#^ zhmS#+cO`bFVBZn$Llh;TcdEz+&^COYBw%9`93&v-qZw(R(+tVrzQ({ThT8>JhG=yl zlFKkWdMRTxXb47QNpu*3n2&`nm+WXymGC|oYb2x$2tlFKoi!aI+}>jN4^WA(wVDH8WJlH{Q! zVi^!w3~yGP#t3NhT5lV`ScSzVP9x#Xh0`cWe?VDqHVL1+_dKc7D#IewS`)N+%O`9d yERxarGTxDqXhjNg(br3NO>iX8!Sjq?iA cb + d == a */ +int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c == a mod b */ +#define mp_mod(a, b, c) mp_div(a, b, NULL, c) +\end{verbatim} + +The \textbf{mp\_cmp} will compare two integers. It will return \textbf{MP\_LT} if the first parameter is less than +the second, \textbf{MP\_GT} if it is greater or \textbf{MP\_EQ} if they are equal. These constants are the same as from +MPI. + +The \textbf{mp\_add}, \textbf{mp\_sub}, \textbf{mp\_mul}, \textbf{mp\_div}, \textbf{mp\_sqr} and \textbf{mp\_mod} are all +fairly straight forward to understand. Note that in mp\_div either $c$ (the quotient) or $d$ (the remainder) can be +passed as NULL to ignore it. For example, if you only want the quotient $z = \lfloor x/y \rfloor$ then a call such as +mp\_div(\&x, \&y, \&z, NULL) is acceptable. + +There is a related class of ``single digit'' functions that are like the above except they use a digit as the second +operand. + +\begin{verbatim} +/* compare against a single digit */ +int mp_cmp_d(mp_int *a, mp_digit b); + +/* c = a + b */ +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a - b */ +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a * b */ +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 mod b */ +#define mp_mod_d(a,b,c) mp_div_d(a, b, NULL, c) +\end{verbatim} + +Note that care should be taken for the value of the digit passed. By default, any 28-bit integer is a valid digit that can +be passed into the function. However, if MP\_8BIT or MP\_16BIT is defined only 7 or 15-bit (respectively) integers +can be passed into it. + +\subsection{Modular Arithmetic} + +There are some trivial modular arithmetic functions. + +\begin{verbatim} +/* d = a + b (mod c) */ +int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a - b (mod c) */ +int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a * b (mod c) */ +int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a * a (mod b) */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = 1/a (mod b) */ +int mp_invmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = (a, b) */ +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); + +/* d = a^b (mod c) */ +int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); +\end{verbatim} + +These are all fairly simple to understand. The \textbf{mp\_invmod} is a modular multiplicative inverse. That is it +stores in the third parameter an integer such that $ac \equiv 1 \mbox{ (mod }b\mbox{)}$ provided such integer exists. If +there is no such integer the function returns \textbf{MP\_VAL}. + +\subsection{Radix Conversions} +To read or store integers in other formats there are the following functions. + +\begin{verbatim} +int mp_unsigned_bin_size(mp_int *a); +int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c); +int mp_to_unsigned_bin(mp_int *a, unsigned char *b); + +int mp_signed_bin_size(mp_int *a); +int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); +int mp_to_signed_bin(mp_int *a, unsigned char *b); + +int mp_read_radix(mp_int *a, unsigned char *str, int radix); +int mp_toradix(mp_int *a, unsigned char *str, int radix); +\end{verbatim} + +The integers are stored in big endian format as most libraries (and MPI) expect. The \textbf{mp\_read\_radix} and +\textbf{mp\_toradix} functions read and write (respectively) null terminated ASCII strings in a given radix. Valid values +for the radix are between 2 and 64 (inclusively). + +\section{Timing Analysis} +\subsection{Observed Timings} +A simple test program ``demo.c'' was developed which builds with either MPI or LibTomMath (without modification). The +test was conducted on an AMD Athlon XP processor with 266Mhz DDR memory and the GCC 3.2 compiler\footnote{With build +options ``-O3 -fomit-frame-pointer -funroll-loops''}. The multiplications and squarings were repeated 10,000 times +each while the modular exponentiation (exptmod) were performed 10 times each. The RDTSC (Read Time Stamp Counter) instruction +was used to measure the time the entire iterations took and was divided by the number of iterations to get an +average. The following results were observed. + +\begin{small} +\begin{center} +\begin{tabular}{c|c|c|c} +\hline \textbf{Operation} & \textbf{Size (bits)} & \textbf{Time with MPI (cycles)} & \textbf{Time with LibTomMath (cycles)} \\ +\hline +Multiply & 128 & 1,394 & 915 \\ +Multiply & 256 & 2,559 & 1,893 \\ +Multiply & 512 & 7,919 & 3,770 \\ +Multiply & 1024 & 28,460 & 9,970 \\ +Multiply & 2048 & 109,637 & 32,264 \\ +Multiply & 4096 & 467,226 & 129,645 \\ +\hline +Square & 128 & 1,288 & 1,147 \\ +Square & 256 & 1,705 & 2,129 \\ +Square & 512 & 5,365 & 3,755 \\ +Square & 1024 & 18,836 & 9,267 \\ +Square & 2048 & 72,334 & 28,387 \\ +Square & 4096 & 306,252 & 112,391 \\ +\hline +Exptmod & 512 & 30,497,732 & 7,222,872 \\ +Exptmod & 768 & 98,943,020 & 16,474,567 \\ +Exptmod & 1024 & 221,123,749 & 30,070,883 \\ +Exptmod & 2048 & 1,694,796,907 & 154,697,320 \\ +Exptmod & 2560 & 3,262,360,107 & 318,998,183 \\ +Exptmod & 3072 & 5,647,243,373 & 494,313,122 \\ +Exptmod & 4096 & 13,345,194,048 & 1,036,254,558 + +\end{tabular} +\end{center} +\end{small} + +\subsection{Digit Size} +The first major constribution to the time savings is the fact that 28 bits are stored per digit instead of the MPI +defualt of 16. This means in many of the algorithms the savings can be considerable. Consider a baseline multiplier +with a 1024-bit input. With MPI the input would be 64 16-bit digits whereas in LibTomMath it would be 37 28-bit digits. +A savings of $64^2 - 37^2 = 2727$ single precision multiplications. + +\subsection{Multiplication Algorithms} +For most inputs a typical baseline $O(n^2)$ multiplier is used which is similar to that of MPI. There are two variants +of the baseline multiplier. The normal and the fast variants. The normal baseline multiplier is the exact same as the +algorithm from MPI. The fast baseline multiplier is optimized for cases where the number of input digits $N$ is less +than or equal to $2^{w}/\beta^2$. Where $w$ is the number of bits in a \textbf{mp\_word}. By default a mp\_word is +64-bits which means $N \le 256$ is allowed which represents numbers upto $7168$ bits. + +The fast baseline multiplier is optimized by removing the carry operations from the inner loop. This is often referred +to as the ``comba'' method since it computes the products a columns first then figures out the carries. This has the +effect of making a very simple and paralizable inner loop. + +For large inputs, typically 80 digits\footnote{By default that is 2240-bits or more.} or more the Karatsuba method is +used. This method has significant overhead but an asymptotic running time of $O(n^{1.584})$ which means for fairly large +inputs this method is faster. The Karatsuba implementation is recursive which means for extremely large inputs they +will benefit from the algorithm. + +MPI only implements the slower baseline multiplier where carries are dealt with in the inner loop. As a result even at +smaller numbers (below the Karatsuba cutoff) the LibTomCrypt multipliers are faster. + +\subsection{Squaring Algorithms} + +Similar to the multiplication algorithms there are two baseline squaring algorithms. Both have an asymptotic running +time of $O((t^2 + t)/2)$. The normal baseline squaring is the same from MPI and the fast is a ``comba'' squaring +algorithm. The comba method is used if the number of digits $N$ is less than $2^{w-1}/\beta^2$ which by default +covers numbers upto $3584$ bits. + +There is also a Karatsuba squaring method which achieves a running time of $O(n^{1.584})$ after considerably large +inputs. + +MPI only implements the slower baseline squaring algorithm. As a result LibTomMath is considerably faster at squaring +than MPI is. + +\subsection{Exponentiation Algorithms} + +LibTomMath implements a sliding window $k$-ary left to right exponentiation algorithm. For a given exponent size $L$ an +appropriate window size $k$ is chosen. There are always at most $L$ modular squarings and $\lfloor L/k \rfloor$ modular +multiplications. The $k$-ary method works by precomputing values $g(x) = b^x$ for $0 \le x < 2^k$ and a given base +$b$. Then the multiplications are grouped in windows of $k$ bits. The sliding window technique has the benefit +that it can skip multiplications if there are zero bits following or preceding a window. Consider the exponent +$e = 11110001_2$ if $k = 2$ then there will be a two squarings, a multiplication of $g(3)$, two squarings, a multiplication +of $g(3)$, four squarings and and a multiplication by $g(1)$. In total there are 8 squarings and 3 multiplications. + +MPI uses a binary square-multiply method. For the same exponent $e$ it would have had 8 squarings and 5 multiplications. +There is a precomputation phase for the method LibTomCrypt uses but it generally cuts down considerably on the number +of multiplications. Consider a 512-bit exponent. The worst case for the LibTomMath method results in 512 squarings and +124 multiplications. The MPI method would have 512 squarings and 512 multiplications. Randomly every $2k$ bits another +multiplication is saved via the sliding-window technique on top of the savings the $k$-ary method provides. + +Both LibTomMath and MPI use Barrett reduction instead of division to reduce the numbers modulo the modulus given. +However, LibTomMath can take advantage of the fact that the multiplications required within the Barrett reduction +do not to give full precision. As a result the reduction step is much faster and just as accurate. The LibTomMath code +will automatically determine at run-time (e.g. when its called) whether the faster multiplier can be used. The +faster multipliers have also been optimized into the two variants (baseline and fast baseline). + +As a result of all these changes exponentiation in LibTomMath is much faster than compared to MPI. + + + +\end{document} \ No newline at end of file diff --git a/changes.txt b/changes.txt new file mode 100644 index 0000000..83dd60d --- /dev/null +++ b/changes.txt @@ -0,0 +1,6 @@ +Dec 25th,2002 +v0.01 -- Initial release. Gimme a break. + -- Todo list, + add details to manual [e.g. algorithms] + more comments in code + example programs \ No newline at end of file diff --git a/demo.c b/demo.c new file mode 100644 index 0000000..b6f21db --- /dev/null +++ b/demo.c @@ -0,0 +1,238 @@ +#include + +#ifdef U_MPI +#include +#include +#include +#include +#include + #include "mpi.h" +#else + #include "bn.h" +#endif + +#ifdef TIMER +extern unsigned long long rdtsc(void); +extern void reset(void); +#endif + +static void draw(mp_int *a) +{ + char buf[4096]; + int x; + printf("a->used == %d\na->alloc == %d\na->sign == %d\n", a->used, a->alloc, a->sign); + mp_toradix(a, buf, 10); + printf("num == %s\n", buf); + printf("\n"); +} + +int main(void) +{ + mp_int a, b, c, d, e, f; + unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n; + unsigned char cmd[4096], buf[4096]; + int rr; + +#ifdef TIMER + int n; + unsigned long long tt; +#endif + + mp_init(&a); + mp_init(&b); + mp_init(&c); + mp_init(&d); + mp_init(&e); + mp_init(&f); + + +#ifdef TIMER + + mp_read_radix(&a, "340282366920938463463374607431768211455", 10); + while (a.used * DIGIT_BIT < 8192) { + reset(); + for (rr = 0; rr < 10000; rr++) { + mp_mul(&a, &a, &b); + } + tt = rdtsc(); + printf("Multiplying %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((unsigned long long)10000)); + mp_copy(&b, &a); + } + + + mp_read_radix(&a, "340282366920938463463374607431768211455", 10); + while (a.used * DIGIT_BIT < 8192) { + reset(); + for (rr = 0; rr < 10000; rr++) { + mp_sqr(&a, &b); + } + tt = rdtsc(); + printf("Squaring %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((unsigned long long)10000)); + mp_copy(&b, &a); + } + + { + char *primes[] = { + "17933601194860113372237070562165128350027320072176844226673287945873370751245439587792371960615073855669274087805055507977323024886880985062002853331424203", + "2893527720709661239493896562339544088620375736490408468011883030469939904368086092336458298221245707898933583190713188177399401852627749210994595974791782790253946539043962213027074922559572312141181787434278708783207966459019479487", + "347743159439876626079252796797422223177535447388206607607181663903045907591201940478223621722118173270898487582987137708656414344685816179420855160986340457973820182883508387588163122354089264395604796675278966117567294812714812796820596564876450716066283126720010859041484786529056457896367683122960411136319", + "47266428956356393164697365098120418976400602706072312735924071745438532218237979333351774907308168340693326687317443721193266215155735814510792148768576498491199122744351399489453533553203833318691678263241941706256996197460424029012419012634671862283532342656309677173602509498417976091509154360039893165037637034737020327399910409885798185771003505320583967737293415979917317338985837385734747478364242020380416892056650841470869294527543597349250299539682430605173321029026555546832473048600327036845781970289288898317888427517364945316709081173840186150794397479045034008257793436817683392375274635794835245695887", + "436463808505957768574894870394349739623346440601945961161254440072143298152040105676491048248110146278752857839930515766167441407021501229924721335644557342265864606569000117714935185566842453630868849121480179691838399545644365571106757731317371758557990781880691336695584799313313687287468894148823761785582982549586183756806449017542622267874275103877481475534991201849912222670102069951687572917937634467778042874315463238062009202992087620963771759666448266532858079402669920025224220613419441069718482837399612644978839925207109870840278194042158748845445131729137117098529028886770063736487420613144045836803985635654192482395882603511950547826439092832800532152534003936926017612446606135655146445620623395788978726744728503058670046885876251527122350275750995227", + "11424167473351836398078306042624362277956429440521137061889702611766348760692206243140413411077394583180726863277012016602279290144126785129569474909173584789822341986742719230331946072730319555984484911716797058875905400999504305877245849119687509023232790273637466821052576859232452982061831009770786031785669030271542286603956118755585683996118896215213488875253101894663403069677745948305893849505434201763745232895780711972432011344857521691017896316861403206449421332243658855453435784006517202894181640562433575390821384210960117518650374602256601091379644034244332285065935413233557998331562749140202965844219336298970011513882564935538704289446968322281451907487362046511461221329799897350993370560697505809686438782036235372137015731304779072430260986460269894522159103008260495503005267165927542949439526272736586626709581721032189532726389643625590680105784844246152702670169304203783072275089194754889511973916207", + "1214855636816562637502584060163403830270705000634713483015101384881871978446801224798536155406895823305035467591632531067547890948695117172076954220727075688048751022421198712032848890056357845974246560748347918630050853933697792254955890439720297560693579400297062396904306270145886830719309296352765295712183040773146419022875165382778007040109957609739589875590885701126197906063620133954893216612678838507540777138437797705602453719559017633986486649523611975865005712371194067612263330335590526176087004421363598470302731349138773205901447704682181517904064735636518462452242791676541725292378925568296858010151852326316777511935037531017413910506921922450666933202278489024521263798482237150056835746454842662048692127173834433089016107854491097456725016327709663199738238442164843147132789153725513257167915555162094970853584447993125488607696008169807374736711297007473812256272245489405898470297178738029484459690836250560495461579533254473316340608217876781986188705928270735695752830825527963838355419762516246028680280988020401914551825487349990306976304093109384451438813251211051597392127491464898797406789175453067960072008590614886532333015881171367104445044718144312416815712216611576221546455968770801413440778423979", + NULL + }; + srand(time(NULL)); + for (n = 0; primes[n]; n++) { + mp_read_radix(&a, primes[n], 10); + mp_zero(&b); + for (rr = 0; rr < mp_count_bits(&a); rr++) { + mp_mul_2d(&b, 1, &b); + b.dp[0] |= (rand()&1); + } + mp_sub_d(&a, 1, &c); + mp_mod(&b, &c, &b); + mp_set(&c, 3); + reset(); + for (rr = 0; rr < 20; rr++) { + mp_exptmod(&c, &b, &a, &d); + } + tt = rdtsc(); + mp_sub_d(&a, 1, &e); + mp_sub(&e, &b, &b); + mp_exptmod(&c, &b, &a, &e); /* c^(p-1-b) mod a */ + mp_mulmod(&e, &d, &a, &d); /* c^b * c^(p-1-b) == c^p-1 == 1 */ + if (mp_cmp_d(&d, 1)) { + printf("Different (%d)!!!\n", mp_count_bits(&a)); + draw(&d); + exit(0); + } + printf("Exponentiating %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((unsigned long long)20)); + } + } + +#endif + + expt_n = lcm_n = gcd_n = add_n = sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = 0; + for (;;) { + printf("add=%7lu sub=%7lu mul=%7lu div=%7lu sqr=%7lu mul2d=%7lu div2d=%7lu gcd=%7lu lcm=%7lu expt=%7lu\r", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n); + fgets(cmd, 4095, stdin); + cmd[strlen(cmd)-1] = 0; + printf("%s ]\r",cmd); + if (!strcmp(cmd, "mul2d")) { ++mul2d_n; + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); + fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); + + mp_mul_2d(&a, rr, &a); + a.sign = b.sign; + if (mp_cmp(&a, &b) != MP_EQ) { + printf("mul2d failed, rr == %d\n",rr); + draw(&a); + draw(&b); + return 0; + } + } else if (!strcmp(cmd, "div2d")) { ++div2d_n; + fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 10); + fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); + fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 10); + + 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; } + if (mp_cmp(&a, &b) != MP_EQ) { + printf("div2d failed, rr == %d\n",rr); + draw(&a); + draw(&b); + 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); + mp_add(&a, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("add %lu failure!\n", add_n); +draw(&a);draw(&b);draw(&c);draw(&d); + return 0; + } + } 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); + mp_sub(&a, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + 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); + mp_mul(&a, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + 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); + + 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); +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); + mp_sqr(&a, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + 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); + mp_gcd(&a, &b, &d); + d.sign = c.sign; + if (mp_cmp(&c, &d) != MP_EQ) { + printf("gcd %lu failure!\n", sqr_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); + mp_lcm(&a, &b, &d); + d.sign = c.sign; + if (mp_cmp(&c, &d) != MP_EQ) { + printf("lcm %lu failure!\n", sqr_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); + mp_exptmod(&a, &b, &c, &e); + if (mp_cmp(&d, &e) != MP_EQ) { + printf("expt %lu failure!\n", sqr_n); + draw(&a);draw(&b);draw(&c);draw(&d); draw(&e); + return 0; + } + } + } + return 0; +} + diff --git a/makefile b/makefile new file mode 100644 index 0000000..7c85121 --- /dev/null +++ b/makefile @@ -0,0 +1,24 @@ +CC = gcc +CFLAGS += -Wall -W -O3 -funroll-loops + +VERSION=0.01 + +default: test + +test: bn.o demo.o + $(CC) bn.o demo.o -o demo + +docdvi: bn.tex + latex bn + +docs: docdvi + pdflatex bn + rm -f bn.log bn.aux bn.dvi + +clean: + rm -f *.o *.exe mtest/*.exe bn.log bn.aux bn.dvi *.s + +zipup: clean docs + chdir .. ; rm -rf ltm* libtommath-$(VERSION) ; mkdir libtommath-$(VERSION) ; \ + cp -R ./libtommath/* ./libtommath-$(VERSION)/ ; tar -c libtommath-$(VERSION)/* > ltm-$(VERSION).tar ; \ + bzip2 -9vv ltm-$(VERSION).tar ; zip -9 -r ltm-$(VERSION).zip libtommath-$(VERSION)/* \ No newline at end of file diff --git a/timer.asm b/timer.asm new file mode 100644 index 0000000..e8b6383 --- /dev/null +++ b/timer.asm @@ -0,0 +1,28 @@ +; Simple RDTSC reader for NASM +; +; build with "nasm -f ___ timer.asm" where ___ is coff or elf [or whatever] +; +; Most *nix installs use elf so it would be "nasm -f elf timer.asm" +; +; Tom St Denis +[bits 32] +[section .data] +timer dd 0, 0 +[section .text] +[global _rdtsc] +_rdtsc: + rdtsc + sub eax,[timer] + sbb edx,[timer+4] + ret + +[global _reset] +_reset: + push eax + push edx + rdtsc + mov [timer],eax + mov [timer+4],edx + pop edx + pop eax + ret \ No newline at end of file