summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/bn/bn_div.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/bn/bn_div.c')
-rw-r--r--src/lib/libcrypto/bn/bn_div.c180
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
65int BN_div(dv, rem, m, d,ctx) 66int BN_div(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx)
66BIGNUM *dv;
67BIGNUM *rem;
68BIGNUM *m;
69BIGNUM *d;
70BN_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
122int BN_div(dv, rm, num, divisor,ctx) 121int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
123BIGNUM *dv; 122 BN_CTX *ctx)
124BIGNUM *rm;
125BIGNUM *num;
126BIGNUM *divisor;
127BN_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 */
329int 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