4 //FIXME Not checked on threadsafety yet; after checking please remove this line
5 /* crypto/bn/bn_div.c */
6 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
9 * This package is an SSL implementation written
10 * by Eric Young (eay@cryptsoft.com).
11 * The implementation was written so as to conform with Netscapes SSL.
13 * This library is free for commercial and non-commercial use as long as
14 * the following conditions are aheared to. The following conditions
15 * apply to all code found in this distribution, be it the RC4, RSA,
16 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
17 * included with this distribution is covered by the same copyright terms
18 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
20 * Copyright remains Eric Young's, and as such any Copyright notices in
21 * the code are not to be removed.
22 * If this package is used in a product, Eric Young should be given attribution
23 * as the author of the parts of the library used.
24 * This can be in the form of a textual message at program startup or
25 * in documentation (online or textual) provided with the package.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * "This product includes cryptographic software written by
38 * Eric Young (eay@cryptsoft.com)"
39 * The word 'cryptographic' can be left out if the rouines from the library
40 * being used are not cryptographic related :-).
41 * 4. If you include any Windows specific code (or a derivative thereof) from
42 * the apps directory (application code) you must include an acknowledgement:
43 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
45 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * The license and distribution terms for any publically available version or
58 * derivative of this code cannot be changed. i.e. this code cannot simply be
59 * copied and put under another distribution license
60 * [including the GNU Public License.]
64 #include "openssl_mods.h"
67 /* The old slow way */
69 int BN_div(BIGNUM
*dv
, BIGNUM
*rem
, const BIGNUM
*m
, const BIGNUM
*d
,
87 if(BN_copy(rem
, m
) == NULL
) { return (0); }
89 if(dv
!= NULL
) { BN_zero(dv
); }
95 if(dv
== NULL
) { dv
= BN_CTX_get(ctx
); }
96 if(rem
== NULL
) { rem
= BN_CTX_get(ctx
); }
97 if(D
== NULL
|| dv
== NULL
|| rem
== NULL
)
102 if(BN_copy(D
, d
) == NULL
) { goto end
; }
103 if(BN_copy(rem
, m
) == NULL
) { goto end
; }
105 /* The next 2 are needed so we can do a dv->d[0]|=1 later
106 * since BN_lshift1 will only work once there is a value :-) */
111 if(!BN_lshift(D
, D
, nm
- nd
)) { goto end
; }
112 for(i
= nm
- nd
; i
>= 0; i
--)
114 if(!BN_lshift1(dv
, dv
)) { goto end
; }
115 if(BN_ucmp(rem
, D
) >= 0)
118 if(!BN_usub(rem
, rem
, D
)) { goto end
; }
120 /* CAN IMPROVE (and have now :=) */
121 if(!BN_rshift1(D
, D
)) { goto end
; }
123 rem
->neg
= BN_is_zero(rem
) ? 0 : m
->neg
;
124 dv
->neg
= m
->neg
^ d
->neg
;
133 #if !defined(NO_ASM) && !defined(NO_INLINE_ASM) && !defined(PEDANTIC) && !defined(BN_DIV3W)
134 # if defined(__GNUC__) && __GNUC__>=2
135 # if defined(__i386) || defined (__i386__)
137 * There were two reasons for implementing this template:
138 * - GNU C generates a call to a function (__udivdi3 to be exact)
139 * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to
140 * understand why...);
141 * - divl doesn't only calculate quotient, but also leaves
142 * remainder in %edx which we can definitely use here:-)
144 * <appro@fy.chalmers.se>
146 # define bn_div_words(n0,n1,d0) \
147 ({ __asm__ volatile ( \
149 : "=a"(q), "=d"(rem) \
150 : "a"(n1), "d"(n0), "g"(d0) \
154 # define REMAINDER_IS_ALREADY_CALCULATED
155 # endif /* __<cpu> */
156 # endif /* __GNUC__ */
159 int BN_div(BIGNUM
*dv
, BIGNUM
*rm
, const BIGNUM
*num
, const BIGNUM
*divisor
,
162 int norm_shift
, i
, j
, loop
;
163 BIGNUM
*tmp
, wnum
, *snum
, *sdiv
, *res
;
164 BN_ULONG
*resp
, *wnump
;
169 bn_check_top(divisor
);
171 if(BN_is_zero(divisor
))
176 if(BN_ucmp(num
, divisor
) < 0)
180 if(BN_copy(rm
, num
) == NULL
) { return (0); }
182 if(dv
!= NULL
) { BN_zero(dv
); }
187 tmp
= BN_CTX_get(ctx
);
188 snum
= BN_CTX_get(ctx
);
189 sdiv
= BN_CTX_get(ctx
);
191 { res
= BN_CTX_get(ctx
); }
193 if(sdiv
== NULL
|| res
== NULL
) { goto err
; }
196 /* First we normalise the numbers */
197 norm_shift
= BN_BITS2
- ((BN_num_bits(divisor
)) % BN_BITS2
);
198 BN_lshift(sdiv
, divisor
, norm_shift
);
200 norm_shift
+= BN_BITS2
;
201 BN_lshift(snum
, num
, norm_shift
);
205 loop
= num_n
- div_n
;
207 /* Lets setup a 'window' into snum
208 * This is the part that corresponds to the current
209 * 'area' being divided */
211 wnum
.d
= &(snum
->d
[loop
]);
213 wnum
.dmax
= snum
->dmax
+ 1; /* a bit of a lie */
215 /* Get the top 2 words of sdiv */
217 d0
= sdiv
->d
[div_n
- 1];
218 d1
= (div_n
== 1) ? 0 : sdiv
->d
[div_n
- 2];
220 /* pointer to the 'top' of snum */
221 wnump
= &(snum
->d
[num_n
- 1]);
224 res
->neg
= (num
->neg
^ divisor
->neg
);
225 if(!bn_wexpand(res
, (loop
+ 1))) { goto err
; }
227 resp
= &(res
->d
[loop
- 1]);
230 if(!bn_wexpand(tmp
, (div_n
+ 1))) { goto err
; }
232 if(BN_ucmp(&wnum
, sdiv
) >= 0)
234 if(!BN_usub(&wnum
, &wnum
, sdiv
)) { goto err
; }
236 res
->d
[res
->top
- 1] = 1;
242 for(i
= 0; i
< loop
- 1; i
++)
245 #if defined(BN_DIV3W) && !defined(NO_ASM)
246 BN_ULONG
bn_div_3_words(BN_ULONG
*, BN_ULONG
, BN_ULONG
);
247 q
= bn_div_3_words(wnump
, d1
, d0
);
249 BN_ULONG n0
, n1
, rem
= 0;
260 #if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
261 q
= (BN_ULONG
)(((((BN_ULLONG
)n0
) << BN_BITS2
) | n1
) / d0
);
263 q
= bn_div_words(n0
, n1
, d0
);
266 #ifndef REMAINDER_IS_ALREADY_CALCULATED
268 * rem doesn't have to be BN_ULLONG. The least we
269 * know it's less that d0, isn't it?
271 rem
= (n1
- q
* d0
)&BN_MASK2
;
273 t2
= (BN_ULLONG
)d1
* q
;
277 if(t2
<= ((((BN_ULLONG
)rem
) << BN_BITS2
) | wnump
[-2]))
281 if(rem
< d0
) { break; } /* don't let rem overflow */
284 #else /* !BN_LLONG */
285 BN_ULONG t2l
, t2h
, ql
, qh
;
287 q
= bn_div_words(n0
, n1
, d0
);
288 #ifndef REMAINDER_IS_ALREADY_CALCULATED
289 rem
= (n1
- q
* d0
)&BN_MASK2
;
294 t2h
= BN_UMULT_HIGH(d1
, q
);
300 mul64(t2l
, t2h
, ql
, qh
); /* t2=(BN_ULLONG)d1*q; */
306 ((t2h
== rem
) && (t2l
<= wnump
[-2])))
310 if(rem
< d0
) { break; } /* don't let rem overflow */
311 if(t2l
< d1
) { t2h
--; }
314 #endif /* !BN_LLONG */
316 #endif /* !BN_DIV3W */
318 l0
= bn_mul_words(tmp
->d
, sdiv
->d
, div_n
, q
);
322 for(j
= div_n
+ 1; j
> 0; j
--)
323 if(tmp
->d
[j
- 1]) { break; }
327 BN_sub(&wnum
, &wnum
, tmp
);
329 snum
->top
= snum
->top
+ wnum
.top
- j
;
335 BN_add(&wnum
, &wnum
, sdiv
);
336 snum
->top
+= wnum
.top
- j
;
343 BN_rshift(rm
, snum
, norm_shift
);
356 int BN_mod(BIGNUM
*rem
, const BIGNUM
*m
, const BIGNUM
*d
, BN_CTX
*ctx
)
358 #if 0 /* The old slow way */
362 if(BN_ucmp(m
, d
) < 0)
363 { return ((BN_copy(rem
, m
) == NULL
) ? 0 : 1); }
366 dv
= BN_CTX_get(ctx
);
368 if(!BN_copy(rem
, m
)) { goto err
; }
370 nm
= BN_num_bits(rem
);
372 if(!BN_lshift(dv
, d
, nm
- nd
)) { goto err
; }
373 for(i
= nm
- nd
; i
>= 0; i
--)
375 if(BN_cmp(rem
, dv
) >= 0)
377 if(!BN_sub(rem
, rem
, dv
)) { goto err
; }
379 if(!BN_rshift1(dv
, dv
)) { goto err
; }
387 return (BN_div(NULL
, rem
, m
, d
, ctx
));