comparison bn_mp_div.c @ 2:86e0b50a9b58 libtommath-orig ltm-0.30-orig

ltm 0.30 orig import
author Matt Johnston <matt@ucc.asn.au>
date Mon, 31 May 2004 18:25:22 +0000
parents
children d29b64170cf0
comparison
equal deleted inserted replaced
-1:000000000000 2:86e0b50a9b58
1 /* LibTomMath, multiple-precision integer library -- Tom St Denis
2 *
3 * LibTomMath is a library that provides multiple-precision
4 * integer arithmetic as well as number theoretic functionality.
5 *
6 * The library was designed directly after the MPI library by
7 * Michael Fromberger but has been written from scratch with
8 * additional optimizations in place.
9 *
10 * The library is free for all purposes without any express
11 * guarantee it works.
12 *
13 * Tom St Denis, [email protected], http://math.libtomcrypt.org
14 */
15 #include <tommath.h>
16
17 /* integer signed division.
18 * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
19 * HAC pp.598 Algorithm 14.20
20 *
21 * Note that the description in HAC is horribly
22 * incomplete. For example, it doesn't consider
23 * the case where digits are removed from 'x' in
24 * the inner loop. It also doesn't consider the
25 * case that y has fewer than three digits, etc..
26 *
27 * The overall algorithm is as described as
28 * 14.20 from HAC but fixed to treat these cases.
29 */
30 int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
31 {
32 mp_int q, x, y, t1, t2;
33 int res, n, t, i, norm, neg;
34
35 /* is divisor zero ? */
36 if (mp_iszero (b) == 1) {
37 return MP_VAL;
38 }
39
40 /* if a < b then q=0, r = a */
41 if (mp_cmp_mag (a, b) == MP_LT) {
42 if (d != NULL) {
43 res = mp_copy (a, d);
44 } else {
45 res = MP_OKAY;
46 }
47 if (c != NULL) {
48 mp_zero (c);
49 }
50 return res;
51 }
52
53 if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
54 return res;
55 }
56 q.used = a->used + 2;
57
58 if ((res = mp_init (&t1)) != MP_OKAY) {
59 goto __Q;
60 }
61
62 if ((res = mp_init (&t2)) != MP_OKAY) {
63 goto __T1;
64 }
65
66 if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
67 goto __T2;
68 }
69
70 if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
71 goto __X;
72 }
73
74 /* fix the sign */
75 neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
76 x.sign = y.sign = MP_ZPOS;
77
78 /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
79 norm = mp_count_bits(&y) % DIGIT_BIT;
80 if (norm < (int)(DIGIT_BIT-1)) {
81 norm = (DIGIT_BIT-1) - norm;
82 if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
83 goto __Y;
84 }
85 if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
86 goto __Y;
87 }
88 } else {
89 norm = 0;
90 }
91
92 /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
93 n = x.used - 1;
94 t = y.used - 1;
95
96 /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
97 if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
98 goto __Y;
99 }
100
101 while (mp_cmp (&x, &y) != MP_LT) {
102 ++(q.dp[n - t]);
103 if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
104 goto __Y;
105 }
106 }
107
108 /* reset y by shifting it back down */
109 mp_rshd (&y, n - t);
110
111 /* step 3. for i from n down to (t + 1) */
112 for (i = n; i >= (t + 1); i--) {
113 if (i > x.used) {
114 continue;
115 }
116
117 /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
118 * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
119 if (x.dp[i] == y.dp[t]) {
120 q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
121 } else {
122 mp_word tmp;
123 tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
124 tmp |= ((mp_word) x.dp[i - 1]);
125 tmp /= ((mp_word) y.dp[t]);
126 if (tmp > (mp_word) MP_MASK)
127 tmp = MP_MASK;
128 q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
129 }
130
131 /* while (q{i-t-1} * (yt * b + y{t-1})) >
132 xi * b**2 + xi-1 * b + xi-2
133
134 do q{i-t-1} -= 1;
135 */
136 q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
137 do {
138 q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
139
140 /* find left hand */
141 mp_zero (&t1);
142 t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
143 t1.dp[1] = y.dp[t];
144 t1.used = 2;
145 if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
146 goto __Y;
147 }
148
149 /* find right hand */
150 t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
151 t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
152 t2.dp[2] = x.dp[i];
153 t2.used = 3;
154 } while (mp_cmp_mag(&t1, &t2) == MP_GT);
155
156 /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
157 if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
158 goto __Y;
159 }
160
161 if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
162 goto __Y;
163 }
164
165 if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
166 goto __Y;
167 }
168
169 /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
170 if (x.sign == MP_NEG) {
171 if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
172 goto __Y;
173 }
174 if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
175 goto __Y;
176 }
177 if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
178 goto __Y;
179 }
180
181 q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
182 }
183 }
184
185 /* now q is the quotient and x is the remainder
186 * [which we have to normalize]
187 */
188
189 /* get sign before writing to c */
190 x.sign = a->sign;
191
192 if (c != NULL) {
193 mp_clamp (&q);
194 mp_exch (&q, c);
195 c->sign = neg;
196 }
197
198 if (d != NULL) {
199 mp_div_2d (&x, norm, &x, NULL);
200 mp_exch (&x, d);
201 }
202
203 res = MP_OKAY;
204
205 __Y:mp_clear (&y);
206 __X:mp_clear (&x);
207 __T2:mp_clear (&t2);
208 __T1:mp_clear (&t1);
209 __Q:mp_clear (&q);
210 return res;
211 }