|
3 | 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
4 | 4 | /* SPDX-License-Identifier: Unlicense */
|
5 | 5 |
|
6 |
| -/* wrapper function for mp_n_root_ex() |
7 |
| - * computes c = (a)**(1/b) such that (c)**b <= a and (c+1)**b > a |
| 6 | +/* find the n'th root of an integer |
| 7 | + * |
| 8 | + * Result found such that (c)**b <= a and (c+1)**b > a |
| 9 | + * |
| 10 | + * This algorithm uses Newton's approximation |
| 11 | + * x[i+1] = x[i] - f(x[i])/f'(x[i]) |
| 12 | + * which will find the root in log(N) time where |
| 13 | + * each step involves a fair bit. |
8 | 14 | */
|
9 | 15 | mp_err mp_n_root(const mp_int *a, mp_digit b, mp_int *c)
|
10 | 16 | {
|
11 |
| - return mp_n_root_ex(a, b, c, 0); |
| 17 | + mp_int t1, t2, t3, a_; |
| 18 | + mp_ord cmp; |
| 19 | + int ilog2; |
| 20 | + mp_err err; |
| 21 | + |
| 22 | + /* input must be positive if b is even */ |
| 23 | + if (((b & 1u) == 0u) && (a->sign == MP_NEG)) { |
| 24 | + return MP_VAL; |
| 25 | + } |
| 26 | + |
| 27 | + if ((err = mp_init_multi(&t1, &t2, &t3, NULL)) != MP_OKAY) { |
| 28 | + return err; |
| 29 | + } |
| 30 | + |
| 31 | + /* if a is negative fudge the sign but keep track */ |
| 32 | + a_ = *a; |
| 33 | + a_.sign = MP_ZPOS; |
| 34 | + |
| 35 | + /* Compute seed: 2^(log_2(n)/b + 2)*/ |
| 36 | + ilog2 = mp_count_bits(a); |
| 37 | + |
| 38 | + /* |
| 39 | + GCC and clang do not understand the sizeof tests and complain, |
| 40 | + icc (the Intel compiler) seems to understand, at least it doesn't complain. |
| 41 | + 2 of 3 say these macros are necessary, so there they are. |
| 42 | + */ |
| 43 | +#if ( !(defined MP_8BIT) && !(defined MP_16BIT) ) |
| 44 | + /* |
| 45 | + The type of mp_digit might be larger than an int. |
| 46 | + If "b" is larger than INT_MAX it is also larger than |
| 47 | + log_2(n) because the bit-length of the "n" is measured |
| 48 | + with an int and hence the root is always < 2 (two). |
| 49 | + */ |
| 50 | + if (sizeof(mp_digit) >= sizeof(int)) { |
| 51 | + if (b > (mp_digit)(INT_MAX/2)) { |
| 52 | + mp_set(c, 1uL); |
| 53 | + c->sign = a->sign; |
| 54 | + err = MP_OKAY; |
| 55 | + goto LBL_ERR; |
| 56 | + } |
| 57 | + } |
| 58 | +#endif |
| 59 | + /* "b" is smaller than INT_MAX, we can cast safely */ |
| 60 | + if (ilog2 < (int)b) { |
| 61 | + mp_set(c, 1uL); |
| 62 | + c->sign = a->sign; |
| 63 | + err = MP_OKAY; |
| 64 | + goto LBL_ERR; |
| 65 | + } |
| 66 | + ilog2 = ilog2 / ((int)b); |
| 67 | + if (ilog2 == 0) { |
| 68 | + mp_set(c, 1uL); |
| 69 | + c->sign = a->sign; |
| 70 | + err = MP_OKAY; |
| 71 | + goto LBL_ERR; |
| 72 | + } |
| 73 | + /* Start value must be larger than root */ |
| 74 | + ilog2 += 2; |
| 75 | + if ((err = mp_2expt(&t2,ilog2)) != MP_OKAY) { |
| 76 | + goto LBL_ERR; |
| 77 | + } |
| 78 | + do { |
| 79 | + /* t1 = t2 */ |
| 80 | + if ((err = mp_copy(&t2, &t1)) != MP_OKAY) { |
| 81 | + goto LBL_ERR; |
| 82 | + } |
| 83 | + |
| 84 | + /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ |
| 85 | + |
| 86 | + /* t3 = t1**(b-1) */ |
| 87 | + if ((err = mp_expt_d(&t1, b - 1u, &t3)) != MP_OKAY) { |
| 88 | + goto LBL_ERR; |
| 89 | + } |
| 90 | + /* numerator */ |
| 91 | + /* t2 = t1**b */ |
| 92 | + if ((err = mp_mul(&t3, &t1, &t2)) != MP_OKAY) { |
| 93 | + goto LBL_ERR; |
| 94 | + } |
| 95 | + |
| 96 | + /* t2 = t1**b - a */ |
| 97 | + if ((err = mp_sub(&t2, &a_, &t2)) != MP_OKAY) { |
| 98 | + goto LBL_ERR; |
| 99 | + } |
| 100 | + |
| 101 | + /* denominator */ |
| 102 | + /* t3 = t1**(b-1) * b */ |
| 103 | + if ((err = mp_mul_d(&t3, b, &t3)) != MP_OKAY) { |
| 104 | + goto LBL_ERR; |
| 105 | + } |
| 106 | + |
| 107 | + /* t3 = (t1**b - a)/(b * t1**(b-1)) */ |
| 108 | + if ((err = mp_div(&t2, &t3, &t3, NULL)) != MP_OKAY) { |
| 109 | + goto LBL_ERR; |
| 110 | + } |
| 111 | + |
| 112 | + if ((err = mp_sub(&t1, &t3, &t2)) != MP_OKAY) { |
| 113 | + goto LBL_ERR; |
| 114 | + } |
| 115 | + /* |
| 116 | + Number of rounds is at most log_2(root). If it is more it |
| 117 | + got stuck, so break out of the loop and do the rest manually. |
| 118 | + */ |
| 119 | + if (ilog2-- == 0) { |
| 120 | + break; |
| 121 | + } |
| 122 | + } while (mp_cmp(&t1, &t2) != MP_EQ); |
| 123 | + |
| 124 | + /* result can be off by a few so check */ |
| 125 | + /* Loop beneath can overshoot by one if found root is smaller than actual root */ |
| 126 | + for (;;) { |
| 127 | + if ((err = mp_expt_d(&t1, b, &t2)) != MP_OKAY) { |
| 128 | + goto LBL_ERR; |
| 129 | + } |
| 130 | + cmp = mp_cmp(&t2, &a_); |
| 131 | + if (cmp == MP_EQ) { |
| 132 | + err = MP_OKAY; |
| 133 | + goto LBL_ERR; |
| 134 | + } |
| 135 | + if (cmp == MP_LT) { |
| 136 | + if ((err = mp_add_d(&t1, 1uL, &t1)) != MP_OKAY) { |
| 137 | + goto LBL_ERR; |
| 138 | + } |
| 139 | + } else { |
| 140 | + break; |
| 141 | + } |
| 142 | + } |
| 143 | + /* correct overshoot from above or from recurrence */ |
| 144 | + for (;;) { |
| 145 | + if ((err = mp_expt_d(&t1, b, &t2)) != MP_OKAY) { |
| 146 | + goto LBL_ERR; |
| 147 | + } |
| 148 | + if (mp_cmp(&t2, &a_) == MP_GT) { |
| 149 | + if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) { |
| 150 | + goto LBL_ERR; |
| 151 | + } |
| 152 | + } else { |
| 153 | + break; |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + /* set the result */ |
| 158 | + mp_exch(&t1, c); |
| 159 | + |
| 160 | + /* set the sign of the result */ |
| 161 | + c->sign = a->sign; |
| 162 | + |
| 163 | + err = MP_OKAY; |
| 164 | + |
| 165 | +LBL_ERR: |
| 166 | + mp_clear_multi(&t1, &t2, &t3, NULL); |
| 167 | + return err; |
12 | 168 | }
|
13 | 169 |
|
14 | 170 | #endif
|
0 commit comments