Skip to content

deprecate mp_n_root_ex and mp_expt_d_ex #294

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

Merged
merged 1 commit into from
May 27, 2019
Merged
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
14 changes: 14 additions & 0 deletions bn_deprecated.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,18 @@ mp_err mp_prime_is_divisible(const mp_int *a, mp_bool *result)
return s_mp_prime_is_divisible(a, result);
}
#endif
#ifdef BN_MP_EXPT_D_EX_C
mp_err mp_expt_d_ex(const mp_int *a, mp_digit b, mp_int *c, int fast)
{
(void)fast;
return mp_expt_d(a, b, c);
}
#endif
#ifdef BN_MP_N_ROOT_EX_C
mp_err mp_n_root_ex(const mp_int *a, mp_digit b, mp_int *c, int fast)
{
(void)fast;
return mp_n_root(a, b, c);
}
#endif
#endif
37 changes: 35 additions & 2 deletions bn_mp_expt_d.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,43 @@
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */

/* wrapper function for mp_expt_d_ex() */
/* calculate c = a**b using a square-multiply algorithm */
mp_err mp_expt_d(const mp_int *a, mp_digit b, mp_int *c)
{
return mp_expt_d_ex(a, b, c, 0);
mp_err err;

mp_int g;

if ((err = mp_init_copy(&g, a)) != MP_OKAY) {
return err;
}

/* set initial result */
mp_set(c, 1uL);

while (b > 0u) {
/* if the bit is set multiply */
if ((b & 1u) != 0u) {
if ((err = mp_mul(c, &g, c)) != MP_OKAY) {
mp_clear(&g);
return err;
}
}

/* square */
if (b > 1u) {
if ((err = mp_sqr(&g, &g)) != MP_OKAY) {
mp_clear(&g);
return err;
}
}

/* shift to next bit */
b >>= 1;
}

mp_clear(&g);
return MP_OKAY;
}

#endif
66 changes: 0 additions & 66 deletions bn_mp_expt_d_ex.c

This file was deleted.

162 changes: 159 additions & 3 deletions bn_mp_n_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,168 @@
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */

/* wrapper function for mp_n_root_ex()
* computes c = (a)**(1/b) such that (c)**b <= a and (c+1)**b > a
/* 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.
*/
mp_err mp_n_root(const mp_int *a, mp_digit b, mp_int *c)
{
return mp_n_root_ex(a, b, c, 0);
mp_int t1, t2, t3, a_;
mp_ord cmp;
int ilog2;
mp_err err;

/* input must be positive if b is even */
if (((b & 1u) == 0u) && (a->sign == MP_NEG)) {
return MP_VAL;
}

if ((err = mp_init_multi(&t1, &t2, &t3, NULL)) != MP_OKAY) {
return err;
}

/* if a is negative fudge the sign but keep track */
a_ = *a;
a_.sign = MP_ZPOS;

/* Compute seed: 2^(log_2(n)/b + 2)*/
ilog2 = mp_count_bits(a);

/*
GCC and clang do not understand the sizeof tests and complain,
icc (the Intel compiler) seems to understand, at least it doesn't complain.
2 of 3 say these macros are necessary, so there they are.
*/
#if ( !(defined MP_8BIT) && !(defined MP_16BIT) )
/*
The type of mp_digit might be larger than an int.
If "b" is larger than INT_MAX it is also larger than
log_2(n) because the bit-length of the "n" is measured
with an int and hence the root is always < 2 (two).
*/
if (sizeof(mp_digit) >= sizeof(int)) {
if (b > (mp_digit)(INT_MAX/2)) {
mp_set(c, 1uL);
c->sign = a->sign;
err = MP_OKAY;
goto LBL_ERR;
}
}
#endif
/* "b" is smaller than INT_MAX, we can cast safely */
if (ilog2 < (int)b) {
mp_set(c, 1uL);
c->sign = a->sign;
err = MP_OKAY;
goto LBL_ERR;
}
ilog2 = ilog2 / ((int)b);
if (ilog2 == 0) {
mp_set(c, 1uL);
c->sign = a->sign;
err = MP_OKAY;
goto LBL_ERR;
}
/* Start value must be larger than root */
ilog2 += 2;
if ((err = mp_2expt(&t2,ilog2)) != MP_OKAY) {
goto LBL_ERR;
}
do {
/* t1 = t2 */
if ((err = mp_copy(&t2, &t1)) != MP_OKAY) {
goto LBL_ERR;
}

/* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */

/* t3 = t1**(b-1) */
if ((err = mp_expt_d(&t1, b - 1u, &t3)) != MP_OKAY) {
goto LBL_ERR;
}
/* numerator */
/* t2 = t1**b */
if ((err = mp_mul(&t3, &t1, &t2)) != MP_OKAY) {
goto LBL_ERR;
}

/* t2 = t1**b - a */
if ((err = mp_sub(&t2, &a_, &t2)) != MP_OKAY) {
goto LBL_ERR;
}

/* denominator */
/* t3 = t1**(b-1) * b */
if ((err = mp_mul_d(&t3, b, &t3)) != MP_OKAY) {
goto LBL_ERR;
}

/* t3 = (t1**b - a)/(b * t1**(b-1)) */
if ((err = mp_div(&t2, &t3, &t3, NULL)) != MP_OKAY) {
goto LBL_ERR;
}

if ((err = mp_sub(&t1, &t3, &t2)) != MP_OKAY) {
goto LBL_ERR;
}
/*
Number of rounds is at most log_2(root). If it is more it
got stuck, so break out of the loop and do the rest manually.
*/
if (ilog2-- == 0) {
break;
}
} while (mp_cmp(&t1, &t2) != MP_EQ);

/* result can be off by a few so check */
/* Loop beneath can overshoot by one if found root is smaller than actual root */
for (;;) {
if ((err = mp_expt_d(&t1, b, &t2)) != MP_OKAY) {
goto LBL_ERR;
}
cmp = mp_cmp(&t2, &a_);
if (cmp == MP_EQ) {
err = MP_OKAY;
goto LBL_ERR;
}
if (cmp == MP_LT) {
if ((err = mp_add_d(&t1, 1uL, &t1)) != MP_OKAY) {
goto LBL_ERR;
}
} else {
break;
}
}
/* correct overshoot from above or from recurrence */
for (;;) {
if ((err = mp_expt_d(&t1, b, &t2)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_cmp(&t2, &a_) == MP_GT) {
if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) {
goto LBL_ERR;
}
} else {
break;
}
}

/* set the result */
mp_exch(&t1, c);

/* set the sign of the result */
c->sign = a->sign;

err = MP_OKAY;

LBL_ERR:
mp_clear_multi(&t1, &t2, &t3, NULL);
return err;
}

#endif
Loading