diff options
Diffstat (limited to 'src/lib/libcrypto/bn/bn_div.c')
-rw-r--r-- | src/lib/libcrypto/bn/bn_div.c | 180 |
1 files changed, 126 insertions, 54 deletions
diff --git a/src/lib/libcrypto/bn/bn_div.c b/src/lib/libcrypto/bn/bn_div.c index 2263bdc7da..150dd289a5 100644 --- a/src/lib/libcrypto/bn/bn_div.c +++ b/src/lib/libcrypto/bn/bn_div.c | |||
@@ -57,21 +57,19 @@ | |||
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 | ||
63 | /* The old slow way */ | 64 | /* The old slow way */ |
64 | #if 0 | 65 | #if 0 |
65 | int BN_div(dv, rem, m, d,ctx) | 66 | int BN_div(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx) |
66 | BIGNUM *dv; | ||
67 | BIGNUM *rem; | ||
68 | BIGNUM *m; | ||
69 | BIGNUM *d; | ||
70 | BN_CTX *ctx; | ||
71 | { | 67 | { |
72 | int i,nm,nd; | 68 | int i,nm,nd; |
73 | BIGNUM *D; | 69 | BIGNUM *D; |
74 | 70 | ||
71 | bn_check_top(m); | ||
72 | bn_check_top(d); | ||
75 | if (BN_is_zero(d)) | 73 | if (BN_is_zero(d)) |
76 | { | 74 | { |
77 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); | 75 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); |
@@ -86,9 +84,9 @@ BN_CTX *ctx; | |||
86 | return(1); | 84 | return(1); |
87 | } | 85 | } |
88 | 86 | ||
89 | D=ctx->bn[ctx->tos]; | 87 | D= &(ctx->bn[ctx->tos]); |
90 | if (dv == NULL) dv=ctx->bn[ctx->tos+1]; | 88 | if (dv == NULL) dv= &(ctx->bn[ctx->tos+1]); |
91 | if (rem == NULL) rem=ctx->bn[ctx->tos+2]; | 89 | if (rem == NULL) rem= &(ctx->bn[ctx->tos+2]); |
92 | 90 | ||
93 | nd=BN_num_bits(d); | 91 | nd=BN_num_bits(d); |
94 | nm=BN_num_bits(m); | 92 | nm=BN_num_bits(m); |
@@ -98,6 +96,7 @@ BN_CTX *ctx; | |||
98 | /* The next 2 are needed so we can do a dv->d[0]|=1 later | 96 | /* 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 :-) */ | 97 | * since BN_lshift1 will only work once there is a value :-) */ |
100 | BN_zero(dv); | 98 | BN_zero(dv); |
99 | bn_wexpand(dv,1); | ||
101 | dv->top=1; | 100 | dv->top=1; |
102 | 101 | ||
103 | if (!BN_lshift(D,D,nm-nd)) return(0); | 102 | if (!BN_lshift(D,D,nm-nd)) return(0); |
@@ -107,7 +106,7 @@ BN_CTX *ctx; | |||
107 | if (BN_ucmp(rem,D) >= 0) | 106 | if (BN_ucmp(rem,D) >= 0) |
108 | { | 107 | { |
109 | dv->d[0]|=1; | 108 | dv->d[0]|=1; |
110 | bn_qsub(rem,rem,D); | 109 | if (!BN_usub(rem,rem,D)) return(0); |
111 | } | 110 | } |
112 | /* CAN IMPROVE (and have now :=) */ | 111 | /* CAN IMPROVE (and have now :=) */ |
113 | if (!BN_rshift1(D,D)) return(0); | 112 | if (!BN_rshift1(D,D)) return(0); |
@@ -119,12 +118,8 @@ BN_CTX *ctx; | |||
119 | 118 | ||
120 | #else | 119 | #else |
121 | 120 | ||
122 | int BN_div(dv, rm, num, divisor,ctx) | 121 | int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, |
123 | BIGNUM *dv; | 122 | BN_CTX *ctx) |
124 | BIGNUM *rm; | ||
125 | BIGNUM *num; | ||
126 | BIGNUM *divisor; | ||
127 | BN_CTX *ctx; | ||
128 | { | 123 | { |
129 | int norm_shift,i,j,loop; | 124 | int norm_shift,i,j,loop; |
130 | BIGNUM *tmp,wnum,*snum,*sdiv,*res; | 125 | BIGNUM *tmp,wnum,*snum,*sdiv,*res; |
@@ -132,6 +127,9 @@ BN_CTX *ctx; | |||
132 | BN_ULONG d0,d1; | 127 | BN_ULONG d0,d1; |
133 | int num_n,div_n; | 128 | int num_n,div_n; |
134 | 129 | ||
130 | bn_check_top(num); | ||
131 | bn_check_top(divisor); | ||
132 | |||
135 | if (BN_is_zero(divisor)) | 133 | if (BN_is_zero(divisor)) |
136 | { | 134 | { |
137 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); | 135 | BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); |
@@ -146,12 +144,12 @@ BN_CTX *ctx; | |||
146 | return(1); | 144 | return(1); |
147 | } | 145 | } |
148 | 146 | ||
149 | tmp=ctx->bn[ctx->tos]; | 147 | tmp= &(ctx->bn[ctx->tos]); |
150 | tmp->neg=0; | 148 | tmp->neg=0; |
151 | snum=ctx->bn[ctx->tos+1]; | 149 | snum= &(ctx->bn[ctx->tos+1]); |
152 | sdiv=ctx->bn[ctx->tos+2]; | 150 | sdiv= &(ctx->bn[ctx->tos+2]); |
153 | if (dv == NULL) | 151 | if (dv == NULL) |
154 | res=ctx->bn[ctx->tos+3]; | 152 | res= &(ctx->bn[ctx->tos+3]); |
155 | else res=dv; | 153 | else res=dv; |
156 | 154 | ||
157 | /* First we normalise the numbers */ | 155 | /* First we normalise the numbers */ |
@@ -168,10 +166,10 @@ BN_CTX *ctx; | |||
168 | /* Lets setup a 'window' into snum | 166 | /* Lets setup a 'window' into snum |
169 | * This is the part that corresponds to the current | 167 | * This is the part that corresponds to the current |
170 | * 'area' being divided */ | 168 | * 'area' being divided */ |
169 | BN_init(&wnum); | ||
171 | wnum.d= &(snum->d[loop]); | 170 | wnum.d= &(snum->d[loop]); |
172 | wnum.top= div_n; | 171 | wnum.top= div_n; |
173 | wnum.max= snum->max; /* a bit of a lie */ | 172 | wnum.max= snum->max+1; /* a bit of a lie */ |
174 | wnum.neg= 0; | ||
175 | 173 | ||
176 | /* Get the top 2 words of sdiv */ | 174 | /* Get the top 2 words of sdiv */ |
177 | /* i=sdiv->top; */ | 175 | /* i=sdiv->top; */ |
@@ -183,8 +181,8 @@ BN_CTX *ctx; | |||
183 | 181 | ||
184 | /* Setup to 'res' */ | 182 | /* Setup to 'res' */ |
185 | res->neg= (num->neg^divisor->neg); | 183 | res->neg= (num->neg^divisor->neg); |
186 | res->top=loop; | ||
187 | if (!bn_wexpand(res,(loop+1))) goto err; | 184 | if (!bn_wexpand(res,(loop+1))) goto err; |
185 | res->top=loop; | ||
188 | resp= &(res->d[loop-1]); | 186 | resp= &(res->d[loop-1]); |
189 | 187 | ||
190 | /* space for temp */ | 188 | /* space for temp */ |
@@ -192,7 +190,7 @@ BN_CTX *ctx; | |||
192 | 190 | ||
193 | if (BN_ucmp(&wnum,sdiv) >= 0) | 191 | if (BN_ucmp(&wnum,sdiv) >= 0) |
194 | { | 192 | { |
195 | bn_qsub(&wnum,&wnum,sdiv); | 193 | if (!BN_usub(&wnum,&wnum,sdiv)) goto err; |
196 | *resp=1; | 194 | *resp=1; |
197 | res->d[res->top-1]=1; | 195 | res->d[res->top-1]=1; |
198 | } | 196 | } |
@@ -202,56 +200,98 @@ BN_CTX *ctx; | |||
202 | 200 | ||
203 | for (i=0; i<loop-1; i++) | 201 | for (i=0; i<loop-1; i++) |
204 | { | 202 | { |
205 | BN_ULONG q,n0,n1; | 203 | BN_ULONG q,l0; |
206 | BN_ULONG l0; | 204 | #ifdef BN_DIV3W |
205 | q=bn_div_3_words(wnump,d0,d1); | ||
206 | #else | ||
207 | |||
208 | #if !defined(NO_ASM) && !defined(PEDANTIC) | ||
209 | # if defined(__GNUC__) && __GNUC__>=2 | ||
210 | # if defined(__i386) | ||
211 | /* | ||
212 | * There were two reasons for implementing this template: | ||
213 | * - GNU C generates a call to a function (__udivdi3 to be exact) | ||
214 | * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to | ||
215 | * understand why...); | ||
216 | * - divl doesn't only calculate quotient, but also leaves | ||
217 | * remainder in %edx which we can definitely use here:-) | ||
218 | * | ||
219 | * <appro@fy.chalmers.se> | ||
220 | */ | ||
221 | # define bn_div_words(n0,n1,d0) \ | ||
222 | ({ asm volatile ( \ | ||
223 | "divl %4" \ | ||
224 | : "=a"(q), "=d"(rem) \ | ||
225 | : "a"(n1), "d"(n0), "g"(d0) \ | ||
226 | : "cc"); \ | ||
227 | q; \ | ||
228 | }) | ||
229 | # define REMINDER_IS_ALREADY_CALCULATED | ||
230 | # endif /* __<cpu> */ | ||
231 | # endif /* __GNUC__ */ | ||
232 | #endif /* NO_ASM */ | ||
233 | BN_ULONG n0,n1,rem=0; | ||
207 | 234 | ||
208 | wnum.d--; wnum.top++; | ||
209 | n0=wnump[0]; | 235 | n0=wnump[0]; |
210 | n1=wnump[-1]; | 236 | n1=wnump[-1]; |
211 | if (n0 == d0) | 237 | if (n0 == d0) |
212 | q=BN_MASK2; | 238 | q=BN_MASK2; |
213 | else | 239 | else |
214 | q=bn_div64(n0,n1,d0); | 240 | #if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) |
241 | q=((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0; | ||
242 | #else | ||
243 | q=bn_div_words(n0,n1,d0); | ||
244 | #endif | ||
215 | { | 245 | { |
216 | #ifdef BN_LLONG | 246 | #ifdef BN_LLONG |
217 | BN_ULLONG t1,t2,rem; | 247 | BN_ULLONG t2; |
218 | t1=((BN_ULLONG)n0<<BN_BITS2)|n1; | 248 | |
249 | #ifndef REMINDER_IS_ALREADY_CALCULATED | ||
250 | /* | ||
251 | * rem doesn't have to be BN_ULLONG. The least we | ||
252 | * know it's less that d0, isn't it? | ||
253 | */ | ||
254 | rem=(n1-q*d0)&BN_MASK2; | ||
255 | #endif | ||
256 | t2=(BN_ULLONG)d1*q; | ||
257 | |||
219 | for (;;) | 258 | for (;;) |
220 | { | 259 | { |
221 | t2=(BN_ULLONG)d1*q; | 260 | if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2])) |
222 | rem=t1-(BN_ULLONG)q*d0; | ||
223 | if ((rem>>BN_BITS2) || | ||
224 | (t2 <= ((BN_ULLONG)(rem<<BN_BITS2)+wnump[-2]))) | ||
225 | break; | 261 | break; |
226 | q--; | 262 | q--; |
263 | rem += d0; | ||
264 | if (rem < d0) break; /* don't let rem overflow */ | ||
265 | t2 -= d1; | ||
227 | } | 266 | } |
228 | #else | 267 | #else |
229 | BN_ULONG t1l,t1h,t2l,t2h,t3l,t3h,ql,qh,t3t; | 268 | BN_ULONG t2l,t2h,ql,qh; |
230 | t1h=n0; | 269 | |
231 | t1l=n1; | 270 | #ifndef REMINDER_IS_ALREADY_CALCULATED |
271 | /* | ||
272 | * It's more than enough with the only multiplication. | ||
273 | * See the comment above in BN_LLONG section... | ||
274 | */ | ||
275 | rem=(n1-q*d0)&BN_MASK2; | ||
276 | #endif | ||
277 | t2l=LBITS(d1); t2h=HBITS(d1); | ||
278 | ql =LBITS(q); qh =HBITS(q); | ||
279 | mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ | ||
280 | |||
232 | for (;;) | 281 | for (;;) |
233 | { | 282 | { |
234 | t2l=LBITS(d1); t2h=HBITS(d1); | 283 | if ((t2h < rem) || |
235 | ql =LBITS(q); qh =HBITS(q); | 284 | ((t2h == rem) && (t2l <= wnump[-2]))) |
236 | mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ | 285 | break; |
237 | |||
238 | t3t=LBITS(d0); t3h=HBITS(d0); | ||
239 | mul64(t3t,t3h,ql,qh); /* t3=t1-(BN_ULLONG)q*d0; */ | ||
240 | t3l=(t1l-t3t)&BN_MASK2; | ||
241 | if (t3l > t1l) t3h++; | ||
242 | t3h=(t1h-t3h)&BN_MASK2; | ||
243 | |||
244 | /*if ((t3>>BN_BITS2) || | ||
245 | (t2 <= ((t3<<BN_BITS2)+wnump[-2]))) | ||
246 | break; */ | ||
247 | if (t3h) break; | ||
248 | if (t2h < t3l) break; | ||
249 | if ((t2h == t3l) && (t2l <= wnump[-2])) break; | ||
250 | |||
251 | q--; | 286 | q--; |
287 | rem += d0; | ||
288 | if (rem < d0) break; /* don't let rem overflow */ | ||
289 | if (t2l < d1) t2h--; t2l -= d1; | ||
252 | } | 290 | } |
253 | #endif | 291 | #endif |
254 | } | 292 | } |
293 | #endif /* !BN_DIV3W */ | ||
294 | wnum.d--; wnum.top++; | ||
255 | l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); | 295 | l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); |
256 | tmp->d[div_n]=l0; | 296 | tmp->d[div_n]=l0; |
257 | for (j=div_n+1; j>0; j--) | 297 | for (j=div_n+1; j>0; j--) |
@@ -284,3 +324,35 @@ err: | |||
284 | } | 324 | } |
285 | 325 | ||
286 | #endif | 326 | #endif |
327 | |||
328 | /* rem != m */ | ||
329 | int BN_mod(BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) | ||
330 | { | ||
331 | #if 0 /* The old slow way */ | ||
332 | int i,nm,nd; | ||
333 | BIGNUM *dv; | ||
334 | |||
335 | if (BN_ucmp(m,d) < 0) | ||
336 | return((BN_copy(rem,m) == NULL)?0:1); | ||
337 | |||
338 | dv= &(ctx->bn[ctx->tos]); | ||
339 | |||
340 | if (!BN_copy(rem,m)) return(0); | ||
341 | |||
342 | nm=BN_num_bits(rem); | ||
343 | nd=BN_num_bits(d); | ||
344 | if (!BN_lshift(dv,d,nm-nd)) return(0); | ||
345 | for (i=nm-nd; i>=0; i--) | ||
346 | { | ||
347 | if (BN_cmp(rem,dv) >= 0) | ||
348 | { | ||
349 | if (!BN_sub(rem,rem,dv)) return(0); | ||
350 | } | ||
351 | if (!BN_rshift1(dv,dv)) return(0); | ||
352 | } | ||
353 | return(1); | ||
354 | #else | ||
355 | return(BN_div(NULL,rem,m,d,ctx)); | ||
356 | #endif | ||
357 | } | ||
358 | |||