Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

balancing multiplication #2

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions bn_mp_balance_mul.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <tommath.h>
#ifdef BN_MP_BALANCE_MUL_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was 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@gmail.com, http://libtom.org
*/

/* c = |a| * |b| using balancing multiplication.
* If |a| is much less than |b|,
* we firstly split b into chunks such that length of each one is
* roughly equal to that of |a|.
*/
int mp_balance_mul (mp_int * a, mp_int * b, mp_int * c)
{
/* the following algorithm is taken from
* Ruby core; namely, function 'bigmul1_balance'
* from 'bignum.c'
*/
mp_int t1, t2, tmp;
long i, an, bn, r, n;
int res, olduse, min, max;
int err = MP_MEM;

mp_digit *bds, *cds, *t1ds;

an = a->used;
bn = b->used;
if ((res = mp_grow(c, an + bn)) != MP_OKAY) {
return res;
}

if (mp_init_size(&t1, an) != MP_OKAY) {
goto ERR;
}

bds = b->dp;
cds = c->dp;
t1ds = t1.dp;

n = 0;

mp_int x;

c->used = an + bn;
while (bn > 0) {
r = MIN(an, bn);
for (i = 0; i < r; ++i)
t1ds[i] = bds[n + i];
t1.used = r;

mp_init_size(&t2, an + r);
mp_mul(a, &t1, &t2);

if (t2.used > c->used - n) {
min = c->used - n; max = t2.used;
x.used = t2.used; x.dp = t2.dp;
} else {
min = t2.used; max = c->used - n;
x.used = c->used - n; x.dp = c->dp + n;
}

register mp_digit u, *tmpx, *tmpt2, *tmpcn;
register int i;
tmpx = tmpcn = x.dp; tmpt2 = t2.dp;
u = 0;
for (i = 0; i < min; i++) {
*tmpcn = *tmpx++ + *tmpt2++ + u;
u = *tmpcn >> ((mp_digit)DIGIT_BIT);
*tmpcn++ &= MP_MASK;
}
if (min != max) {
for (; i < max; i++) {
*tmpcn = x.dp[i] + u;
u = *tmpcn >> ((mp_digit)DIGIT_BIT);
*tmpcn++ &= MP_MASK;
}
}
*tmpcn++ = u;

bn -= r;
n += r;
}
mp_clamp(c);
return MP_OKAY;
ERR:
return err;
}
#endif

/* $Source$ */
/* $Revision$ */
/* $Date$ */
28 changes: 24 additions & 4 deletions bn_mp_mul.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,27 @@ int mp_mul (mp_int * a, mp_int * b, mp_int * c)
int res, neg;
neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;

int an, bn, tn;
mp_int * t;
an = a -> used;
bn = b -> used;
if (an > bn) {
tn = an; an = bn; bn = tn;
t = a; a = b; b = t;
}
/* now a->used <= b->used */

/* use Toom-Cook? */
#ifdef BN_MP_TOOM_MUL_C
if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
if (a->used >= TOOM_MUL_CUTOFF) {
if (2 * an <= bn) goto balance;
res = mp_toom_mul(a, b, c);
} else
#endif
#ifdef BN_MP_KARATSUBA_MUL_C
/* use Karatsuba? */
if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
if (a->used >= KARATSUBA_MUL_CUTOFF) {
if (2 * an <= bn) goto balance;
res = mp_karatsuba_mul (a, b, c);
} else
#endif
Expand All @@ -44,8 +56,7 @@ int mp_mul (mp_int * a, mp_int * b, mp_int * c)

#ifdef BN_FAST_S_MP_MUL_DIGS_C
if ((digs < MP_WARRAY) &&
MIN(a->used, b->used) <=
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
a->used <= (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
res = fast_s_mp_mul_digs (a, b, c, digs);
} else
#endif
Expand All @@ -56,8 +67,17 @@ int mp_mul (mp_int * a, mp_int * b, mp_int * c)
#endif

}
ret:
c->sign = (c->used > 0) ? neg : MP_ZPOS;
return res;

balance:
/* if a is much smaller than b
* use balance multiplication
* (the idea is taken from Ruby core)
*/
res = mp_balance_mul(a, b, c);
goto ret;
}
#endif

Expand Down
2 changes: 1 addition & 1 deletion makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ bn_mp_fread.o bn_mp_fwrite.o bn_mp_cnt_lsb.o bn_error.o \
bn_mp_init_multi.o bn_mp_clear_multi.o bn_mp_exteuclid.o bn_mp_toradix_n.o \
bn_mp_prime_random_ex.o bn_mp_get_int.o bn_mp_sqrt.o bn_mp_is_square.o bn_mp_init_set.o \
bn_mp_init_set_int.o bn_mp_invmod_slow.o bn_mp_prime_rabin_miller_trials.o \
bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin_n.o
bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin_n.o bn_mp_balance_mul.o

$(LIBNAME): $(OBJECTS)
$(AR) $(ARFLAGS) $@ $(OBJECTS)
Expand Down
1 change: 1 addition & 0 deletions tommath.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
int fast_s_mp_sqr(mp_int *a, mp_int *b);
int s_mp_sqr(mp_int *a, mp_int *b);
int mp_balance_mul(mp_int *a, mp_int *b, mp_int *c);
int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c);
int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c);
int mp_karatsuba_sqr(mp_int *a, mp_int *b);
Expand Down
2 changes: 2 additions & 0 deletions tommath_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define BN_MP_ADD_D_C
#define BN_MP_ADDMOD_C
#define BN_MP_AND_C
#define BN_MP_BALANCE_MUL_C
#define BN_MP_CLAMP_C
#define BN_MP_CLEAR_C
#define BN_MP_CLEAR_MULTI_C
Expand Down Expand Up @@ -552,6 +553,7 @@
#endif

#if defined(BN_MP_MUL_C)
#define BN_MP_BALANCE_MUL_C
#define BN_MP_TOOM_MUL_C
#define BN_MP_KARATSUBA_MUL_C
#define BN_FAST_S_MP_MUL_DIGS_C
Expand Down