1
/* crypto/bn/bn_div.c */
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
5
* This package is an SSL implementation written
6
* by Eric Young (eay@cryptsoft.com).
7
* The implementation was written so as to conform with Netscapes SSL.
9
* This library is free for commercial and non-commercial use as long as
10
* the following conditions are aheared to. The following conditions
11
* apply to all code found in this distribution, be it the RC4, RSA,
12
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
13
* included with this distribution is covered by the same copyright terms
14
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
16
* Copyright remains Eric Young's, and as such any Copyright notices in
17
* the code are not to be removed.
18
* If this package is used in a product, Eric Young should be given attribution
19
* as the author of the parts of the library used.
20
* This can be in the form of a textual message at program startup or
21
* in documentation (online or textual) provided with the package.
23
* Redistribution and use in source and binary forms, with or without
24
* modification, are permitted provided that the following conditions
26
* 1. Redistributions of source code must retain the copyright
27
* notice, this list of conditions and the following disclaimer.
28
* 2. Redistributions in binary form must reproduce the above copyright
29
* notice, this list of conditions and the following disclaimer in the
30
* documentation and/or other materials provided with the distribution.
31
* 3. All advertising materials mentioning features or use of this software
32
* must display the following acknowledgement:
33
* "This product includes cryptographic software written by
34
* Eric Young (eay@cryptsoft.com)"
35
* The word 'cryptographic' can be left out if the rouines from the library
36
* being used are not cryptographic related :-).
37
* 4. If you include any Windows specific code (or a derivative thereof) from
38
* the apps directory (application code) you must include an acknowledgement:
39
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
41
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53
* The licence and distribution terms for any publically available version or
54
* derivative of this code cannot be changed. i.e. this code cannot simply be
55
* copied and put under another distribution licence
56
* [including the GNU Public Licence.]
63
/* The old slow way */
65
int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
76
BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO);
83
{ if (BN_copy(rem,m) == NULL) return(0); }
84
if (dv != NULL) BN_zero(dv);
90
if (dv == NULL) dv = BN_CTX_get(ctx);
91
if (rem == NULL) rem = BN_CTX_get(ctx);
92
if (D == NULL || dv == NULL || rem == NULL)
97
if (BN_copy(D,d) == NULL) goto end;
98
if (BN_copy(rem,m) == NULL) goto end;
100
/* The next 2 are needed so we can do a dv->d[0]|=1 later
101
* since BN_lshift1 will only work once there is a value :-) */
106
if (!BN_lshift(D,D,nm-nd)) goto end;
107
for (i=nm-nd; i>=0; i--)
109
if (!BN_lshift1(dv,dv)) goto end;
110
if (BN_ucmp(rem,D) >= 0)
113
if (!BN_usub(rem,rem,D)) goto end;
115
/* CAN IMPROVE (and have now :=) */
116
if (!BN_rshift1(D,D)) goto end;
118
rem->neg=BN_is_zero(rem)?0:m->neg;
119
dv->neg=m->neg^d->neg;
128
#if !defined(NO_ASM) && !defined(NO_INLINE_ASM) && !defined(PEDANTIC) && !defined(BN_DIV3W)
129
# if defined(__GNUC__) && __GNUC__>=2
130
# if defined(__i386) || defined (__i386__)
132
* There were two reasons for implementing this template:
133
* - GNU C generates a call to a function (__udivdi3 to be exact)
134
* in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to
135
* understand why...);
136
* - divl doesn't only calculate quotient, but also leaves
137
* remainder in %edx which we can definitely use here:-)
139
* <appro@fy.chalmers.se>
141
# define bn_div_words(n0,n1,d0) \
144
: "=a"(q), "=d"(rem) \
145
: "a"(n1), "d"(n0), "g"(d0) \
149
# define REMAINDER_IS_ALREADY_CALCULATED
150
# endif /* __<cpu> */
151
# endif /* __GNUC__ */
154
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
157
int norm_shift,i,j,loop;
158
BIGNUM *tmp,wnum,*snum,*sdiv,*res;
159
BN_ULONG *resp,*wnump;
164
bn_check_top(divisor);
166
if (BN_is_zero(divisor))
168
BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO);
172
if (BN_ucmp(num,divisor) < 0)
175
{ if (BN_copy(rm,num) == NULL) return(0); }
176
if (dv != NULL) BN_zero(dv);
182
snum=BN_CTX_get(ctx);
183
sdiv=BN_CTX_get(ctx);
187
if (sdiv==NULL || res == NULL) goto err;
190
/* First we normalise the numbers */
191
norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2);
192
if (!(BN_lshift(sdiv,divisor,norm_shift))) goto err;
194
norm_shift+=BN_BITS2;
195
if (!(BN_lshift(snum,num,norm_shift))) goto err;
201
/* Lets setup a 'window' into snum
202
* This is the part that corresponds to the current
203
* 'area' being divided */
205
wnum.d= &(snum->d[loop]);
207
wnum.dmax= snum->dmax+1; /* a bit of a lie */
209
/* Get the top 2 words of sdiv */
212
d1=(div_n == 1)?0:sdiv->d[div_n-2];
214
/* pointer to the 'top' of snum */
215
wnump= &(snum->d[num_n-1]);
218
res->neg= (num->neg^divisor->neg);
219
if (!bn_wexpand(res,(loop+1))) goto err;
221
resp= &(res->d[loop-1]);
224
if (!bn_wexpand(tmp,(div_n+1))) goto err;
226
if (BN_ucmp(&wnum,sdiv) >= 0)
228
if (!BN_usub(&wnum,&wnum,sdiv)) goto err;
230
res->d[res->top-1]=1;
236
for (i=0; i<loop-1; i++)
239
#if defined(BN_DIV3W) && !defined(NO_ASM)
240
BN_ULONG bn_div_3_words(BN_ULONG*,BN_ULONG,BN_ULONG);
241
q=bn_div_3_words(wnump,d1,d0);
243
BN_ULONG n0,n1,rem=0;
254
#if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
255
q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0);
257
q=bn_div_words(n0,n1,d0);
260
#ifndef REMAINDER_IS_ALREADY_CALCULATED
262
* rem doesn't have to be BN_ULLONG. The least we
263
* know it's less that d0, isn't it?
265
rem=(n1-q*d0)&BN_MASK2;
271
if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2]))
275
if (rem < d0) break; /* don't let rem overflow */
278
#else /* !BN_LLONG */
279
BN_ULONG t2l,t2h,ql,qh;
281
q=bn_div_words(n0,n1,d0);
282
#ifndef REMAINDER_IS_ALREADY_CALCULATED
283
rem=(n1-q*d0)&BN_MASK2;
288
t2h = BN_UMULT_HIGH(d1,q);
290
t2l=LBITS(d1); t2h=HBITS(d1);
291
ql =LBITS(q); qh =HBITS(q);
292
mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */
298
((t2h == rem) && (t2l <= wnump[-2])))
302
if (rem < d0) break; /* don't let rem overflow */
303
if (t2l < d1) t2h--; t2l -= d1;
305
#endif /* !BN_LLONG */
307
#endif /* !BN_DIV3W */
309
l0=bn_mul_words(tmp->d,sdiv->d,div_n,q);
310
wnum.d--; wnum.top++;
312
for (j=div_n+1; j>0; j--)
313
if (tmp->d[j-1]) break;
317
if (!BN_sub(&wnum,&wnum,tmp)) goto err;
319
snum->top=snum->top+wnum.top-j;
325
if (!BN_add(&wnum,&wnum,sdiv)) goto err;
326
snum->top+=wnum.top-j;
333
BN_rshift(rm,snum,norm_shift);
346
int BN_mod(BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
348
#if 0 /* The old slow way */
352
if (BN_ucmp(m,d) < 0)
353
return((BN_copy(rem,m) == NULL)?0:1);
358
if (!BN_copy(rem,m)) goto err;
362
if (!BN_lshift(dv,d,nm-nd)) goto err;
363
for (i=nm-nd; i>=0; i--)
365
if (BN_cmp(rem,dv) >= 0)
367
if (!BN_sub(rem,rem,dv)) goto err;
369
if (!BN_rshift1(dv,dv)) goto err;
377
return(BN_div(NULL,rem,m,d,ctx));