comparison libtommath/bn_mp_div.c @ 1692:1051e4eea25a

Update LibTomMath to 1.2.0 (#84) * update C files * update other files * update headers * update makefiles * remove mp_set/get_double() * use ltm 1.2.0 API * update ltm_desc * use bundled tommath if system-tommath is too old * XMALLOC etc. were changed to MP_MALLOC etc.
author Steffen Jaeckel <s@jaeckel.eu>
date Tue, 26 May 2020 17:36:47 +0200
parents f52919ffd3b1
children
comparison
equal deleted inserted replaced
1691:2d3745d58843 1692:1051e4eea25a
1 #include "tommath_private.h" 1 #include "tommath_private.h"
2 #ifdef BN_MP_DIV_C 2 #ifdef BN_MP_DIV_C
3 /* LibTomMath, multiple-precision integer library -- Tom St Denis 3 /* LibTomMath, multiple-precision integer library -- Tom St Denis */
4 * 4 /* SPDX-License-Identifier: Unlicense */
5 * LibTomMath is a library that provides multiple-precision
6 * integer arithmetic as well as number theoretic functionality.
7 *
8 * The library was designed directly after the MPI library by
9 * Michael Fromberger but has been written from scratch with
10 * additional optimizations in place.
11 *
12 * SPDX-License-Identifier: Unlicense
13 */
14 5
15 #ifdef BN_MP_DIV_SMALL 6 #ifdef BN_MP_DIV_SMALL
16 7
17 /* slower bit-bang division... also smaller */ 8 /* slower bit-bang division... also smaller */
18 int mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) 9 mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
19 { 10 {
20 mp_int ta, tb, tq, q; 11 mp_int ta, tb, tq, q;
21 int res, n, n2; 12 int n, n2;
13 mp_err err;
22 14
23 /* is divisor zero ? */ 15 /* is divisor zero ? */
24 if (mp_iszero(b) == MP_YES) { 16 if (MP_IS_ZERO(b)) {
25 return MP_VAL; 17 return MP_VAL;
26 } 18 }
27 19
28 /* if a < b then q=0, r = a */ 20 /* if a < b then q=0, r = a */
29 if (mp_cmp_mag(a, b) == MP_LT) { 21 if (mp_cmp_mag(a, b) == MP_LT) {
30 if (d != NULL) { 22 if (d != NULL) {
31 res = mp_copy(a, d); 23 err = mp_copy(a, d);
32 } else { 24 } else {
33 res = MP_OKAY; 25 err = MP_OKAY;
34 } 26 }
35 if (c != NULL) { 27 if (c != NULL) {
36 mp_zero(c); 28 mp_zero(c);
37 } 29 }
38 return res; 30 return err;
39 } 31 }
40 32
41 /* init our temps */ 33 /* init our temps */
42 if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) { 34 if ((err = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
43 return res; 35 return err;
44 } 36 }
45 37
46 38
47 mp_set(&tq, 1uL); 39 mp_set(&tq, 1uL);
48 n = mp_count_bits(a) - mp_count_bits(b); 40 n = mp_count_bits(a) - mp_count_bits(b);
49 if (((res = mp_abs(a, &ta)) != MP_OKAY) || 41 if ((err = mp_abs(a, &ta)) != MP_OKAY) goto LBL_ERR;
50 ((res = mp_abs(b, &tb)) != MP_OKAY) || 42 if ((err = mp_abs(b, &tb)) != MP_OKAY) goto LBL_ERR;
51 ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || 43 if ((err = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) goto LBL_ERR;
52 ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { 44 if ((err = mp_mul_2d(&tq, n, &tq)) != MP_OKAY) goto LBL_ERR;
53 goto LBL_ERR;
54 }
55 45
56 while (n-- >= 0) { 46 while (n-- >= 0) {
57 if (mp_cmp(&tb, &ta) != MP_GT) { 47 if (mp_cmp(&tb, &ta) != MP_GT) {
58 if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || 48 if ((err = mp_sub(&ta, &tb, &ta)) != MP_OKAY) goto LBL_ERR;
59 ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { 49 if ((err = mp_add(&q, &tq, &q)) != MP_OKAY) goto LBL_ERR;
60 goto LBL_ERR; 50 }
61 } 51 if ((err = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) goto LBL_ERR;
62 } 52 if ((err = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY) goto LBL_ERR;
63 if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
64 ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
65 goto LBL_ERR;
66 }
67 } 53 }
68 54
69 /* now q == quotient and ta == remainder */ 55 /* now q == quotient and ta == remainder */
70 n = a->sign; 56 n = a->sign;
71 n2 = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; 57 n2 = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
72 if (c != NULL) { 58 if (c != NULL) {
73 mp_exch(c, &q); 59 mp_exch(c, &q);
74 c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; 60 c->sign = MP_IS_ZERO(c) ? MP_ZPOS : n2;
75 } 61 }
76 if (d != NULL) { 62 if (d != NULL) {
77 mp_exch(d, &ta); 63 mp_exch(d, &ta);
78 d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; 64 d->sign = MP_IS_ZERO(d) ? MP_ZPOS : n;
79 } 65 }
80 LBL_ERR: 66 LBL_ERR:
81 mp_clear_multi(&ta, &tb, &tq, &q, NULL); 67 mp_clear_multi(&ta, &tb, &tq, &q, NULL);
82 return res; 68 return err;
83 } 69 }
84 70
85 #else 71 #else
86 72
87 /* integer signed division. 73 /* integer signed division.
95 * case that y has fewer than three digits, etc.. 81 * case that y has fewer than three digits, etc..
96 * 82 *
97 * The overall algorithm is as described as 83 * The overall algorithm is as described as
98 * 14.20 from HAC but fixed to treat these cases. 84 * 14.20 from HAC but fixed to treat these cases.
99 */ 85 */
100 int mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) 86 mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
101 { 87 {
102 mp_int q, x, y, t1, t2; 88 mp_int q, x, y, t1, t2;
103 int res, n, t, i, norm, neg; 89 int n, t, i, norm;
90 mp_sign neg;
91 mp_err err;
104 92
105 /* is divisor zero ? */ 93 /* is divisor zero ? */
106 if (mp_iszero(b) == MP_YES) { 94 if (MP_IS_ZERO(b)) {
107 return MP_VAL; 95 return MP_VAL;
108 } 96 }
109 97
110 /* if a < b then q=0, r = a */ 98 /* if a < b then q=0, r = a */
111 if (mp_cmp_mag(a, b) == MP_LT) { 99 if (mp_cmp_mag(a, b) == MP_LT) {
112 if (d != NULL) { 100 if (d != NULL) {
113 res = mp_copy(a, d); 101 err = mp_copy(a, d);
114 } else { 102 } else {
115 res = MP_OKAY; 103 err = MP_OKAY;
116 } 104 }
117 if (c != NULL) { 105 if (c != NULL) {
118 mp_zero(c); 106 mp_zero(c);
119 } 107 }
120 return res; 108 return err;
121 } 109 }
122 110
123 if ((res = mp_init_size(&q, a->used + 2)) != MP_OKAY) { 111 if ((err = mp_init_size(&q, a->used + 2)) != MP_OKAY) {
124 return res; 112 return err;
125 } 113 }
126 q.used = a->used + 2; 114 q.used = a->used + 2;
127 115
128 if ((res = mp_init(&t1)) != MP_OKAY) { 116 if ((err = mp_init(&t1)) != MP_OKAY) goto LBL_Q;
129 goto LBL_Q; 117
130 } 118 if ((err = mp_init(&t2)) != MP_OKAY) goto LBL_T1;
131 119
132 if ((res = mp_init(&t2)) != MP_OKAY) { 120 if ((err = mp_init_copy(&x, a)) != MP_OKAY) goto LBL_T2;
133 goto LBL_T1; 121
134 } 122 if ((err = mp_init_copy(&y, b)) != MP_OKAY) goto LBL_X;
135
136 if ((res = mp_init_copy(&x, a)) != MP_OKAY) {
137 goto LBL_T2;
138 }
139
140 if ((res = mp_init_copy(&y, b)) != MP_OKAY) {
141 goto LBL_X;
142 }
143 123
144 /* fix the sign */ 124 /* fix the sign */
145 neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; 125 neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
146 x.sign = y.sign = MP_ZPOS; 126 x.sign = y.sign = MP_ZPOS;
147 127
148 /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ 128 /* normalize both x and y, ensure that y >= b/2, [b == 2**MP_DIGIT_BIT] */
149 norm = mp_count_bits(&y) % DIGIT_BIT; 129 norm = mp_count_bits(&y) % MP_DIGIT_BIT;
150 if (norm < (DIGIT_BIT - 1)) { 130 if (norm < (MP_DIGIT_BIT - 1)) {
151 norm = (DIGIT_BIT - 1) - norm; 131 norm = (MP_DIGIT_BIT - 1) - norm;
152 if ((res = mp_mul_2d(&x, norm, &x)) != MP_OKAY) { 132 if ((err = mp_mul_2d(&x, norm, &x)) != MP_OKAY) goto LBL_Y;
153 goto LBL_Y; 133 if ((err = mp_mul_2d(&y, norm, &y)) != MP_OKAY) goto LBL_Y;
154 }
155 if ((res = mp_mul_2d(&y, norm, &y)) != MP_OKAY) {
156 goto LBL_Y;
157 }
158 } else { 134 } else {
159 norm = 0; 135 norm = 0;
160 } 136 }
161 137
162 /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ 138 /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
163 n = x.used - 1; 139 n = x.used - 1;
164 t = y.used - 1; 140 t = y.used - 1;
165 141
166 /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ 142 /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
167 if ((res = mp_lshd(&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ 143 /* y = y*b**{n-t} */
168 goto LBL_Y; 144 if ((err = mp_lshd(&y, n - t)) != MP_OKAY) goto LBL_Y;
169 }
170 145
171 while (mp_cmp(&x, &y) != MP_LT) { 146 while (mp_cmp(&x, &y) != MP_LT) {
172 ++(q.dp[n - t]); 147 ++(q.dp[n - t]);
173 if ((res = mp_sub(&x, &y, &x)) != MP_OKAY) { 148 if ((err = mp_sub(&x, &y, &x)) != MP_OKAY) goto LBL_Y;
174 goto LBL_Y;
175 }
176 } 149 }
177 150
178 /* reset y by shifting it back down */ 151 /* reset y by shifting it back down */
179 mp_rshd(&y, n - t); 152 mp_rshd(&y, n - t);
180 153
185 } 158 }
186 159
187 /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 160 /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
188 * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ 161 * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
189 if (x.dp[i] == y.dp[t]) { 162 if (x.dp[i] == y.dp[t]) {
190 q.dp[(i - t) - 1] = ((mp_digit)1 << (mp_digit)DIGIT_BIT) - (mp_digit)1; 163 q.dp[(i - t) - 1] = ((mp_digit)1 << (mp_digit)MP_DIGIT_BIT) - (mp_digit)1;
191 } else { 164 } else {
192 mp_word tmp; 165 mp_word tmp;
193 tmp = (mp_word)x.dp[i] << (mp_word)DIGIT_BIT; 166 tmp = (mp_word)x.dp[i] << (mp_word)MP_DIGIT_BIT;
194 tmp |= (mp_word)x.dp[i - 1]; 167 tmp |= (mp_word)x.dp[i - 1];
195 tmp /= (mp_word)y.dp[t]; 168 tmp /= (mp_word)y.dp[t];
196 if (tmp > (mp_word)MP_MASK) { 169 if (tmp > (mp_word)MP_MASK) {
197 tmp = MP_MASK; 170 tmp = MP_MASK;
198 } 171 }
211 /* find left hand */ 184 /* find left hand */
212 mp_zero(&t1); 185 mp_zero(&t1);
213 t1.dp[0] = ((t - 1) < 0) ? 0u : y.dp[t - 1]; 186 t1.dp[0] = ((t - 1) < 0) ? 0u : y.dp[t - 1];
214 t1.dp[1] = y.dp[t]; 187 t1.dp[1] = y.dp[t];
215 t1.used = 2; 188 t1.used = 2;
216 if ((res = mp_mul_d(&t1, q.dp[(i - t) - 1], &t1)) != MP_OKAY) { 189 if ((err = mp_mul_d(&t1, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y;
217 goto LBL_Y;
218 }
219 190
220 /* find right hand */ 191 /* find right hand */
221 t2.dp[0] = ((i - 2) < 0) ? 0u : x.dp[i - 2]; 192 t2.dp[0] = ((i - 2) < 0) ? 0u : x.dp[i - 2];
222 t2.dp[1] = ((i - 1) < 0) ? 0u : x.dp[i - 1]; 193 t2.dp[1] = x.dp[i - 1]; /* i >= 1 always holds */
223 t2.dp[2] = x.dp[i]; 194 t2.dp[2] = x.dp[i];
224 t2.used = 3; 195 t2.used = 3;
225 } while (mp_cmp_mag(&t1, &t2) == MP_GT); 196 } while (mp_cmp_mag(&t1, &t2) == MP_GT);
226 197
227 /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ 198 /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
228 if ((res = mp_mul_d(&y, q.dp[(i - t) - 1], &t1)) != MP_OKAY) { 199 if ((err = mp_mul_d(&y, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y;
229 goto LBL_Y; 200
230 } 201 if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y;
231 202
232 if ((res = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) { 203 if ((err = mp_sub(&x, &t1, &x)) != MP_OKAY) goto LBL_Y;
233 goto LBL_Y;
234 }
235
236 if ((res = mp_sub(&x, &t1, &x)) != MP_OKAY) {
237 goto LBL_Y;
238 }
239 204
240 /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ 205 /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
241 if (x.sign == MP_NEG) { 206 if (x.sign == MP_NEG) {
242 if ((res = mp_copy(&y, &t1)) != MP_OKAY) { 207 if ((err = mp_copy(&y, &t1)) != MP_OKAY) goto LBL_Y;
243 goto LBL_Y; 208 if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y;
244 } 209 if ((err = mp_add(&x, &t1, &x)) != MP_OKAY) goto LBL_Y;
245 if ((res = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) {
246 goto LBL_Y;
247 }
248 if ((res = mp_add(&x, &t1, &x)) != MP_OKAY) {
249 goto LBL_Y;
250 }
251 210
252 q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & MP_MASK; 211 q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & MP_MASK;
253 } 212 }
254 } 213 }
255 214
265 mp_exch(&q, c); 224 mp_exch(&q, c);
266 c->sign = neg; 225 c->sign = neg;
267 } 226 }
268 227
269 if (d != NULL) { 228 if (d != NULL) {
270 if ((res = mp_div_2d(&x, norm, &x, NULL)) != MP_OKAY) { 229 if ((err = mp_div_2d(&x, norm, &x, NULL)) != MP_OKAY) goto LBL_Y;
271 goto LBL_Y;
272 }
273 mp_exch(&x, d); 230 mp_exch(&x, d);
274 } 231 }
275 232
276 res = MP_OKAY; 233 err = MP_OKAY;
277 234
278 LBL_Y: 235 LBL_Y:
279 mp_clear(&y); 236 mp_clear(&y);
280 LBL_X: 237 LBL_X:
281 mp_clear(&x); 238 mp_clear(&x);
283 mp_clear(&t2); 240 mp_clear(&t2);
284 LBL_T1: 241 LBL_T1:
285 mp_clear(&t1); 242 mp_clear(&t1);
286 LBL_Q: 243 LBL_Q:
287 mp_clear(&q); 244 mp_clear(&q);
288 return res; 245 return err;
289 } 246 }
290 247
291 #endif 248 #endif
292 249
293 #endif 250 #endif
294
295 /* ref: HEAD -> master, tag: v1.1.0 */
296 /* git commit: 08549ad6bc8b0cede0b357a9c341c5c6473a9c55 */
297 /* commit time: 2019-01-28 20:32:32 +0100 */