diff options
Diffstat (limited to 'src/lib/libcrypto/bn/bn_div.c')
-rw-r--r-- | src/lib/libcrypto/bn/bn_div.c | 221 |
1 files changed, 148 insertions, 73 deletions
diff --git a/src/lib/libcrypto/bn/bn_div.c b/src/lib/libcrypto/bn/bn_div.c index 2263bdc7da..f9a095e3b3 100644 --- a/src/lib/libcrypto/bn/bn_div.c +++ b/src/lib/libcrypto/bn/bn_div.c | |||
@@ -57,21 +57,22 @@ | |||
57 | */ | 57 | */ |
58 | 58 | ||
59 | #include <stdio.h> | 59 | #include <stdio.h> |
60 | #include <openssl/bn.h> | ||
60 | #include "cryptlib.h" | 61 | #include "cryptlib.h" |
61 | #include "bn_lcl.h" | 62 | #include "bn_lcl.h" |
62 | 63 | ||
64 | |||
63 | /* The old slow way */ | 65 | /* The old slow way */ |
64 | #if 0 | 66 | #if 0 |
65 | int BN_div(dv, rem, m, d,ctx) | 67 | int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, |
66 | BIGNUM *dv; | 68 | BN_CTX *ctx) |
67 | BIGNUM *rem; | ||
68 | BIGNUM *m; | ||
69 | BIGNUM *d; | ||
70 | BN_CTX *ctx; | ||
71 | { | 69 | { |
72 | int i,nm,nd; | 70 | int i,nm,nd; |
71 | int ret = 0; | ||
73 | BIGNUM *D; | 72 | BIGNUM *D; |
74 | 73 | ||
74 | bn_check_top(m); | ||
75 | bn_check_top(d); | ||
75 | if (BN_is_zero(d)) | 76 | if (BN_is_zero(d)) |
76 | { | 77 | { |
77 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); | 78 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); |
@@ -86,45 +87,83 @@ BN_CTX *ctx; | |||
86 | return(1); | 87 | return(1); |
87 | } | 88 | } |
88 | 89 | ||
89 | D=ctx->bn[ctx->tos]; | 90 | BN_CTX_start(ctx); |
90 | if (dv == NULL) dv=ctx->bn[ctx->tos+1]; | 91 | D = BN_CTX_get(ctx); |
91 | if (rem == NULL) rem=ctx->bn[ctx->tos+2]; | 92 | if (dv == NULL) dv = BN_CTX_get(ctx); |
93 | if (rem == NULL) rem = BN_CTX_get(ctx); | ||
94 | if (D == NULL || dv == NULL || rem == NULL) | ||
95 | goto end; | ||
92 | 96 | ||
93 | nd=BN_num_bits(d); | 97 | nd=BN_num_bits(d); |
94 | nm=BN_num_bits(m); | 98 | nm=BN_num_bits(m); |
95 | if (BN_copy(D,d) == NULL) return(0); | 99 | if (BN_copy(D,d) == NULL) goto end; |
96 | if (BN_copy(rem,m) == NULL) return(0); | 100 | if (BN_copy(rem,m) == NULL) goto end; |
97 | 101 | ||
98 | /* The next 2 are needed so we can do a dv->d[0]|=1 later | 102 | /* The next 2 are needed so we can do a dv->d[0]|=1 later |
99 | * since BN_lshift1 will only work once there is a value :-) */ | 103 | * since BN_lshift1 will only work once there is a value :-) */ |
100 | BN_zero(dv); | 104 | BN_zero(dv); |
105 | bn_wexpand(dv,1); | ||
101 | dv->top=1; | 106 | dv->top=1; |
102 | 107 | ||
103 | if (!BN_lshift(D,D,nm-nd)) return(0); | 108 | if (!BN_lshift(D,D,nm-nd)) goto end; |
104 | for (i=nm-nd; i>=0; i--) | 109 | for (i=nm-nd; i>=0; i--) |
105 | { | 110 | { |
106 | if (!BN_lshift1(dv,dv)) return(0); | 111 | if (!BN_lshift1(dv,dv)) goto end; |
107 | if (BN_ucmp(rem,D) >= 0) | 112 | if (BN_ucmp(rem,D) >= 0) |
108 | { | 113 | { |
109 | dv->d[0]|=1; | 114 | dv->d[0]|=1; |
110 | bn_qsub(rem,rem,D); | 115 | if (!BN_usub(rem,rem,D)) goto end; |
111 | } | 116 | } |
112 | /* CAN IMPROVE (and have now :=) */ | 117 | /* CAN IMPROVE (and have now :=) */ |
113 | if (!BN_rshift1(D,D)) return(0); | 118 | if (!BN_rshift1(D,D)) goto end; |
114 | } | 119 | } |
115 | rem->neg=BN_is_zero(rem)?0:m->neg; | 120 | rem->neg=BN_is_zero(rem)?0:m->neg; |
116 | dv->neg=m->neg^d->neg; | 121 | dv->neg=m->neg^d->neg; |
117 | return(1); | 122 | ret = 1; |
123 | end: | ||
124 | BN_CTX_end(ctx); | ||
125 | return(ret); | ||
118 | } | 126 | } |
119 | 127 | ||
120 | #else | 128 | #else |
121 | 129 | ||
122 | int BN_div(dv, rm, num, divisor,ctx) | 130 | #if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \ |
123 | BIGNUM *dv; | 131 | && !defined(PEDANTIC) && !defined(BN_DIV3W) |
124 | BIGNUM *rm; | 132 | # if defined(__GNUC__) && __GNUC__>=2 |
125 | BIGNUM *num; | 133 | # if defined(__i386) || defined (__i386__) |
126 | BIGNUM *divisor; | 134 | /* |
127 | BN_CTX *ctx; | 135 | * There were two reasons for implementing this template: |
136 | * - GNU C generates a call to a function (__udivdi3 to be exact) | ||
137 | * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to | ||
138 | * understand why...); | ||
139 | * - divl doesn't only calculate quotient, but also leaves | ||
140 | * remainder in %edx which we can definitely use here:-) | ||
141 | * | ||
142 | * <appro@fy.chalmers.se> | ||
143 | */ | ||
144 | # define bn_div_words(n0,n1,d0) \ | ||
145 | ({ asm volatile ( \ | ||
146 | "divl %4" \ | ||
147 | : "=a"(q), "=d"(rem) \ | ||
148 | : "a"(n1), "d"(n0), "g"(d0) \ | ||
149 | : "cc"); \ | ||
150 | q; \ | ||
151 | }) | ||
152 | # define REMAINDER_IS_ALREADY_CALCULATED | ||
153 | # endif /* __<cpu> */ | ||
154 | # endif /* __GNUC__ */ | ||
155 | #endif /* OPENSSL_NO_ASM */ | ||
156 | |||
157 | |||
158 | /* BN_div computes dv := num / divisor, rounding towards zero, and sets up | ||
159 | * rm such that dv*divisor + rm = num holds. | ||
160 | * Thus: | ||
161 | * dv->neg == num->neg ^ divisor->neg (unless the result is zero) | ||
162 | * rm->neg == num->neg (unless the remainder is zero) | ||
163 | * If 'dv' or 'rm' is NULL, the respective value is not returned. | ||
164 | */ | ||
165 | int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, | ||
166 | BN_CTX *ctx) | ||
128 | { | 167 | { |
129 | int norm_shift,i,j,loop; | 168 | int norm_shift,i,j,loop; |
130 | BIGNUM *tmp,wnum,*snum,*sdiv,*res; | 169 | BIGNUM *tmp,wnum,*snum,*sdiv,*res; |
@@ -132,6 +171,9 @@ BN_CTX *ctx; | |||
132 | BN_ULONG d0,d1; | 171 | BN_ULONG d0,d1; |
133 | int num_n,div_n; | 172 | int num_n,div_n; |
134 | 173 | ||
174 | bn_check_top(num); | ||
175 | bn_check_top(divisor); | ||
176 | |||
135 | if (BN_is_zero(divisor)) | 177 | if (BN_is_zero(divisor)) |
136 | { | 178 | { |
137 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); | 179 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); |
@@ -146,20 +188,22 @@ BN_CTX *ctx; | |||
146 | return(1); | 188 | return(1); |
147 | } | 189 | } |
148 | 190 | ||
149 | tmp=ctx->bn[ctx->tos]; | 191 | BN_CTX_start(ctx); |
150 | tmp->neg=0; | 192 | tmp=BN_CTX_get(ctx); |
151 | snum=ctx->bn[ctx->tos+1]; | 193 | snum=BN_CTX_get(ctx); |
152 | sdiv=ctx->bn[ctx->tos+2]; | 194 | sdiv=BN_CTX_get(ctx); |
153 | if (dv == NULL) | 195 | if (dv == NULL) |
154 | res=ctx->bn[ctx->tos+3]; | 196 | res=BN_CTX_get(ctx); |
155 | else res=dv; | 197 | else res=dv; |
198 | if (sdiv == NULL || res == NULL) goto err; | ||
199 | tmp->neg=0; | ||
156 | 200 | ||
157 | /* First we normalise the numbers */ | 201 | /* First we normalise the numbers */ |
158 | norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); | 202 | norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); |
159 | BN_lshift(sdiv,divisor,norm_shift); | 203 | if (!(BN_lshift(sdiv,divisor,norm_shift))) goto err; |
160 | sdiv->neg=0; | 204 | sdiv->neg=0; |
161 | norm_shift+=BN_BITS2; | 205 | norm_shift+=BN_BITS2; |
162 | BN_lshift(snum,num,norm_shift); | 206 | if (!(BN_lshift(snum,num,norm_shift))) goto err; |
163 | snum->neg=0; | 207 | snum->neg=0; |
164 | div_n=sdiv->top; | 208 | div_n=sdiv->top; |
165 | num_n=snum->top; | 209 | num_n=snum->top; |
@@ -168,10 +212,10 @@ BN_CTX *ctx; | |||
168 | /* Lets setup a 'window' into snum | 212 | /* Lets setup a 'window' into snum |
169 | * This is the part that corresponds to the current | 213 | * This is the part that corresponds to the current |
170 | * 'area' being divided */ | 214 | * 'area' being divided */ |
215 | BN_init(&wnum); | ||
171 | wnum.d= &(snum->d[loop]); | 216 | wnum.d= &(snum->d[loop]); |
172 | wnum.top= div_n; | 217 | wnum.top= div_n; |
173 | wnum.max= snum->max; /* a bit of a lie */ | 218 | wnum.dmax= snum->dmax+1; /* a bit of a lie */ |
174 | wnum.neg= 0; | ||
175 | 219 | ||
176 | /* Get the top 2 words of sdiv */ | 220 | /* Get the top 2 words of sdiv */ |
177 | /* i=sdiv->top; */ | 221 | /* i=sdiv->top; */ |
@@ -183,8 +227,8 @@ BN_CTX *ctx; | |||
183 | 227 | ||
184 | /* Setup to 'res' */ | 228 | /* Setup to 'res' */ |
185 | res->neg= (num->neg^divisor->neg); | 229 | res->neg= (num->neg^divisor->neg); |
186 | res->top=loop; | ||
187 | if (!bn_wexpand(res,(loop+1))) goto err; | 230 | if (!bn_wexpand(res,(loop+1))) goto err; |
231 | res->top=loop; | ||
188 | resp= &(res->d[loop-1]); | 232 | resp= &(res->d[loop-1]); |
189 | 233 | ||
190 | /* space for temp */ | 234 | /* space for temp */ |
@@ -192,74 +236,98 @@ BN_CTX *ctx; | |||
192 | 236 | ||
193 | if (BN_ucmp(&wnum,sdiv) >= 0) | 237 | if (BN_ucmp(&wnum,sdiv) >= 0) |
194 | { | 238 | { |
195 | bn_qsub(&wnum,&wnum,sdiv); | 239 | if (!BN_usub(&wnum,&wnum,sdiv)) goto err; |
196 | *resp=1; | 240 | *resp=1; |
197 | res->d[res->top-1]=1; | 241 | res->d[res->top-1]=1; |
198 | } | 242 | } |
199 | else | 243 | else |
200 | res->top--; | 244 | res->top--; |
245 | if (res->top == 0) | ||
246 | res->neg = 0; | ||
201 | resp--; | 247 | resp--; |
202 | 248 | ||
203 | for (i=0; i<loop-1; i++) | 249 | for (i=0; i<loop-1; i++) |
204 | { | 250 | { |
205 | BN_ULONG q,n0,n1; | 251 | BN_ULONG q,l0; |
206 | BN_ULONG l0; | 252 | #if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM) |
253 | BN_ULONG bn_div_3_words(BN_ULONG*,BN_ULONG,BN_ULONG); | ||
254 | q=bn_div_3_words(wnump,d1,d0); | ||
255 | #else | ||
256 | BN_ULONG n0,n1,rem=0; | ||
207 | 257 | ||
208 | wnum.d--; wnum.top++; | ||
209 | n0=wnump[0]; | 258 | n0=wnump[0]; |
210 | n1=wnump[-1]; | 259 | n1=wnump[-1]; |
211 | if (n0 == d0) | 260 | if (n0 == d0) |
212 | q=BN_MASK2; | 261 | q=BN_MASK2; |
213 | else | 262 | else /* n0 < d0 */ |
214 | q=bn_div64(n0,n1,d0); | ||
215 | { | ||
216 | #ifdef BN_LLONG | ||
217 | BN_ULLONG t1,t2,rem; | ||
218 | t1=((BN_ULLONG)n0<<BN_BITS2)|n1; | ||
219 | for (;;) | ||
220 | { | 263 | { |
264 | #ifdef BN_LLONG | ||
265 | BN_ULLONG t2; | ||
266 | |||
267 | #if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) | ||
268 | q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0); | ||
269 | #else | ||
270 | q=bn_div_words(n0,n1,d0); | ||
271 | #endif | ||
272 | |||
273 | #ifndef REMAINDER_IS_ALREADY_CALCULATED | ||
274 | /* | ||
275 | * rem doesn't have to be BN_ULLONG. The least we | ||
276 | * know it's less that d0, isn't it? | ||
277 | */ | ||
278 | rem=(n1-q*d0)&BN_MASK2; | ||
279 | #endif | ||
221 | t2=(BN_ULLONG)d1*q; | 280 | t2=(BN_ULLONG)d1*q; |
222 | rem=t1-(BN_ULLONG)q*d0; | 281 | |
223 | if ((rem>>BN_BITS2) || | 282 | for (;;) |
224 | (t2 <= ((BN_ULLONG)(rem<<BN_BITS2)+wnump[-2]))) | 283 | { |
225 | break; | 284 | if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2])) |
226 | q--; | 285 | break; |
227 | } | 286 | q--; |
287 | rem += d0; | ||
288 | if (rem < d0) break; /* don't let rem overflow */ | ||
289 | t2 -= d1; | ||
290 | } | ||
291 | #else /* !BN_LLONG */ | ||
292 | BN_ULONG t2l,t2h,ql,qh; | ||
293 | |||
294 | q=bn_div_words(n0,n1,d0); | ||
295 | #ifndef REMAINDER_IS_ALREADY_CALCULATED | ||
296 | rem=(n1-q*d0)&BN_MASK2; | ||
297 | #endif | ||
298 | |||
299 | #ifdef BN_UMULT_HIGH | ||
300 | t2l = d1 * q; | ||
301 | t2h = BN_UMULT_HIGH(d1,q); | ||
228 | #else | 302 | #else |
229 | BN_ULONG t1l,t1h,t2l,t2h,t3l,t3h,ql,qh,t3t; | ||
230 | t1h=n0; | ||
231 | t1l=n1; | ||
232 | for (;;) | ||
233 | { | ||
234 | t2l=LBITS(d1); t2h=HBITS(d1); | 303 | t2l=LBITS(d1); t2h=HBITS(d1); |
235 | ql =LBITS(q); qh =HBITS(q); | 304 | ql =LBITS(q); qh =HBITS(q); |
236 | mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ | 305 | mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ |
306 | #endif | ||
237 | 307 | ||
238 | t3t=LBITS(d0); t3h=HBITS(d0); | 308 | for (;;) |
239 | mul64(t3t,t3h,ql,qh); /* t3=t1-(BN_ULLONG)q*d0; */ | 309 | { |
240 | t3l=(t1l-t3t)&BN_MASK2; | 310 | if ((t2h < rem) || |
241 | if (t3l > t1l) t3h++; | 311 | ((t2h == rem) && (t2l <= wnump[-2]))) |
242 | t3h=(t1h-t3h)&BN_MASK2; | 312 | break; |
243 | 313 | q--; | |
244 | /*if ((t3>>BN_BITS2) || | 314 | rem += d0; |
245 | (t2 <= ((t3<<BN_BITS2)+wnump[-2]))) | 315 | if (rem < d0) break; /* don't let rem overflow */ |
246 | break; */ | 316 | if (t2l < d1) t2h--; t2l -= d1; |
247 | if (t3h) break; | 317 | } |
248 | if (t2h < t3l) break; | 318 | #endif /* !BN_LLONG */ |
249 | if ((t2h == t3l) && (t2l <= wnump[-2])) break; | ||
250 | |||
251 | q--; | ||
252 | } | 319 | } |
253 | #endif | 320 | #endif /* !BN_DIV3W */ |
254 | } | 321 | |
255 | l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); | 322 | l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); |
323 | wnum.d--; wnum.top++; | ||
256 | tmp->d[div_n]=l0; | 324 | tmp->d[div_n]=l0; |
257 | for (j=div_n+1; j>0; j--) | 325 | for (j=div_n+1; j>0; j--) |
258 | if (tmp->d[j-1]) break; | 326 | if (tmp->d[j-1]) break; |
259 | tmp->top=j; | 327 | tmp->top=j; |
260 | 328 | ||
261 | j=wnum.top; | 329 | j=wnum.top; |
262 | BN_sub(&wnum,&wnum,tmp); | 330 | if (!BN_sub(&wnum,&wnum,tmp)) goto err; |
263 | 331 | ||
264 | snum->top=snum->top+wnum.top-j; | 332 | snum->top=snum->top+wnum.top-j; |
265 | 333 | ||
@@ -267,7 +335,7 @@ BN_CTX *ctx; | |||
267 | { | 335 | { |
268 | q--; | 336 | q--; |
269 | j=wnum.top; | 337 | j=wnum.top; |
270 | BN_add(&wnum,&wnum,sdiv); | 338 | if (!BN_add(&wnum,&wnum,sdiv)) goto err; |
271 | snum->top+=wnum.top-j; | 339 | snum->top+=wnum.top-j; |
272 | } | 340 | } |
273 | *(resp--)=q; | 341 | *(resp--)=q; |
@@ -275,11 +343,18 @@ BN_CTX *ctx; | |||
275 | } | 343 | } |
276 | if (rm != NULL) | 344 | if (rm != NULL) |
277 | { | 345 | { |
346 | /* Keep a copy of the neg flag in num because if rm==num | ||
347 | * BN_rshift() will overwrite it. | ||
348 | */ | ||
349 | int neg = num->neg; | ||
278 | BN_rshift(rm,snum,norm_shift); | 350 | BN_rshift(rm,snum,norm_shift); |
279 | rm->neg=num->neg; | 351 | if (!BN_is_zero(rm)) |
352 | rm->neg = neg; | ||
280 | } | 353 | } |
354 | BN_CTX_end(ctx); | ||
281 | return(1); | 355 | return(1); |
282 | err: | 356 | err: |
357 | BN_CTX_end(ctx); | ||
283 | return(0); | 358 | return(0); |
284 | } | 359 | } |
285 | 360 | ||