174664626SKris Kennaway /* crypto/bn/bn_div.c */ 274664626SKris Kennaway /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 374664626SKris Kennaway * All rights reserved. 474664626SKris Kennaway * 574664626SKris Kennaway * This package is an SSL implementation written 674664626SKris Kennaway * by Eric Young (eay@cryptsoft.com). 774664626SKris Kennaway * The implementation was written so as to conform with Netscapes SSL. 874664626SKris Kennaway * 974664626SKris Kennaway * This library is free for commercial and non-commercial use as long as 1074664626SKris Kennaway * the following conditions are aheared to. The following conditions 1174664626SKris Kennaway * apply to all code found in this distribution, be it the RC4, RSA, 1274664626SKris Kennaway * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1374664626SKris Kennaway * included with this distribution is covered by the same copyright terms 1474664626SKris Kennaway * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1574664626SKris Kennaway * 1674664626SKris Kennaway * Copyright remains Eric Young's, and as such any Copyright notices in 1774664626SKris Kennaway * the code are not to be removed. 1874664626SKris Kennaway * If this package is used in a product, Eric Young should be given attribution 1974664626SKris Kennaway * as the author of the parts of the library used. 2074664626SKris Kennaway * This can be in the form of a textual message at program startup or 2174664626SKris Kennaway * in documentation (online or textual) provided with the package. 2274664626SKris Kennaway * 2374664626SKris Kennaway * Redistribution and use in source and binary forms, with or without 2474664626SKris Kennaway * modification, are permitted provided that the following conditions 2574664626SKris Kennaway * are met: 2674664626SKris Kennaway * 1. Redistributions of source code must retain the copyright 2774664626SKris Kennaway * notice, this list of conditions and the following disclaimer. 2874664626SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 2974664626SKris Kennaway * notice, this list of conditions and the following disclaimer in the 3074664626SKris Kennaway * documentation and/or other materials provided with the distribution. 3174664626SKris Kennaway * 3. All advertising materials mentioning features or use of this software 3274664626SKris Kennaway * must display the following acknowledgement: 3374664626SKris Kennaway * "This product includes cryptographic software written by 3474664626SKris Kennaway * Eric Young (eay@cryptsoft.com)" 3574664626SKris Kennaway * The word 'cryptographic' can be left out if the rouines from the library 3674664626SKris Kennaway * being used are not cryptographic related :-). 3774664626SKris Kennaway * 4. If you include any Windows specific code (or a derivative thereof) from 3874664626SKris Kennaway * the apps directory (application code) you must include an acknowledgement: 3974664626SKris Kennaway * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4074664626SKris Kennaway * 4174664626SKris Kennaway * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4274664626SKris Kennaway * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4374664626SKris Kennaway * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4474664626SKris Kennaway * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4574664626SKris Kennaway * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4674664626SKris Kennaway * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4774664626SKris Kennaway * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4874664626SKris Kennaway * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4974664626SKris Kennaway * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5074664626SKris Kennaway * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5174664626SKris Kennaway * SUCH DAMAGE. 5274664626SKris Kennaway * 5374664626SKris Kennaway * The licence and distribution terms for any publically available version or 5474664626SKris Kennaway * derivative of this code cannot be changed. i.e. this code cannot simply be 5574664626SKris Kennaway * copied and put under another distribution licence 5674664626SKris Kennaway * [including the GNU Public Licence.] 5774664626SKris Kennaway */ 5874664626SKris Kennaway 5974664626SKris Kennaway #include <stdio.h> 6074664626SKris Kennaway #include <openssl/bn.h> 6174664626SKris Kennaway #include "cryptlib.h" 6274664626SKris Kennaway #include "bn_lcl.h" 6374664626SKris Kennaway 6474664626SKris Kennaway /* The old slow way */ 6574664626SKris Kennaway #if 0 66f579bf8eSKris Kennaway int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, 67f579bf8eSKris Kennaway BN_CTX *ctx) 6874664626SKris Kennaway { 6974664626SKris Kennaway int i, nm, nd; 70f579bf8eSKris Kennaway int ret = 0; 7174664626SKris Kennaway BIGNUM *D; 7274664626SKris Kennaway 7374664626SKris Kennaway bn_check_top(m); 7474664626SKris Kennaway bn_check_top(d); 756f9291ceSJung-uk Kim if (BN_is_zero(d)) { 7674664626SKris Kennaway BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO); 7774664626SKris Kennaway return (0); 7874664626SKris Kennaway } 7974664626SKris Kennaway 806f9291ceSJung-uk Kim if (BN_ucmp(m, d) < 0) { 816f9291ceSJung-uk Kim if (rem != NULL) { 826f9291ceSJung-uk Kim if (BN_copy(rem, m) == NULL) 836f9291ceSJung-uk Kim return (0); 846f9291ceSJung-uk Kim } 856f9291ceSJung-uk Kim if (dv != NULL) 866f9291ceSJung-uk Kim BN_zero(dv); 8774664626SKris Kennaway return (1); 8874664626SKris Kennaway } 8974664626SKris Kennaway 90f579bf8eSKris Kennaway BN_CTX_start(ctx); 91f579bf8eSKris Kennaway D = BN_CTX_get(ctx); 926f9291ceSJung-uk Kim if (dv == NULL) 936f9291ceSJung-uk Kim dv = BN_CTX_get(ctx); 946f9291ceSJung-uk Kim if (rem == NULL) 956f9291ceSJung-uk Kim rem = BN_CTX_get(ctx); 96f579bf8eSKris Kennaway if (D == NULL || dv == NULL || rem == NULL) 97f579bf8eSKris Kennaway goto end; 9874664626SKris Kennaway 9974664626SKris Kennaway nd = BN_num_bits(d); 10074664626SKris Kennaway nm = BN_num_bits(m); 1016f9291ceSJung-uk Kim if (BN_copy(D, d) == NULL) 1026f9291ceSJung-uk Kim goto end; 1036f9291ceSJung-uk Kim if (BN_copy(rem, m) == NULL) 1046f9291ceSJung-uk Kim goto end; 10574664626SKris Kennaway 1066f9291ceSJung-uk Kim /* 1076f9291ceSJung-uk Kim * The next 2 are needed so we can do a dv->d[0]|=1 later since 1086f9291ceSJung-uk Kim * BN_lshift1 will only work once there is a value :-) 1096f9291ceSJung-uk Kim */ 11074664626SKris Kennaway BN_zero(dv); 1116f9291ceSJung-uk Kim if (bn_wexpand(dv, 1) == NULL) 1126f9291ceSJung-uk Kim goto end; 11374664626SKris Kennaway dv->top = 1; 11474664626SKris Kennaway 1156f9291ceSJung-uk Kim if (!BN_lshift(D, D, nm - nd)) 1166f9291ceSJung-uk Kim goto end; 1176f9291ceSJung-uk Kim for (i = nm - nd; i >= 0; i--) { 1186f9291ceSJung-uk Kim if (!BN_lshift1(dv, dv)) 1196f9291ceSJung-uk Kim goto end; 1206f9291ceSJung-uk Kim if (BN_ucmp(rem, D) >= 0) { 12174664626SKris Kennaway dv->d[0] |= 1; 1226f9291ceSJung-uk Kim if (!BN_usub(rem, rem, D)) 1236f9291ceSJung-uk Kim goto end; 12474664626SKris Kennaway } 12574664626SKris Kennaway /* CAN IMPROVE (and have now :=) */ 1266f9291ceSJung-uk Kim if (!BN_rshift1(D, D)) 1276f9291ceSJung-uk Kim goto end; 12874664626SKris Kennaway } 12974664626SKris Kennaway rem->neg = BN_is_zero(rem) ? 0 : m->neg; 13074664626SKris Kennaway dv->neg = m->neg ^ d->neg; 131f579bf8eSKris Kennaway ret = 1; 132f579bf8eSKris Kennaway end: 133f579bf8eSKris Kennaway BN_CTX_end(ctx); 134f579bf8eSKris Kennaway return (ret); 13574664626SKris Kennaway } 13674664626SKris Kennaway 13774664626SKris Kennaway #else 13874664626SKris Kennaway 1395c87c606SMark Murray # if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \ 1405c87c606SMark Murray && !defined(PEDANTIC) && !defined(BN_DIV3W) 141f579bf8eSKris Kennaway # if defined(__GNUC__) && __GNUC__>=2 142a21b1b38SKris Kennaway # if defined(__i386) || defined (__i386__) 1436f9291ceSJung-uk Kim /*- 144f579bf8eSKris Kennaway * There were two reasons for implementing this template: 145f579bf8eSKris Kennaway * - GNU C generates a call to a function (__udivdi3 to be exact) 146f579bf8eSKris Kennaway * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to 147f579bf8eSKris Kennaway * understand why...); 148f579bf8eSKris Kennaway * - divl doesn't only calculate quotient, but also leaves 149f579bf8eSKris Kennaway * remainder in %edx which we can definitely use here:-) 150f579bf8eSKris Kennaway * 151f579bf8eSKris Kennaway * <appro@fy.chalmers.se> 152f579bf8eSKris Kennaway */ 15309286989SJung-uk Kim # undef bn_div_words 154f579bf8eSKris Kennaway # define bn_div_words(n0,n1,d0) \ 155f579bf8eSKris Kennaway ({ asm volatile ( \ 156f579bf8eSKris Kennaway "divl %4" \ 157f579bf8eSKris Kennaway : "=a"(q), "=d"(rem) \ 158*aeb5019cSJung-uk Kim : "a"(n1), "d"(n0), "r"(d0) \ 159f579bf8eSKris Kennaway : "cc"); \ 160f579bf8eSKris Kennaway q; \ 161f579bf8eSKris Kennaway }) 162f579bf8eSKris Kennaway # define REMAINDER_IS_ALREADY_CALCULATED 1635c87c606SMark Murray # elif defined(__x86_64) && defined(SIXTY_FOUR_BIT_LONG) 1645c87c606SMark Murray /* 1655c87c606SMark Murray * Same story here, but it's 128-bit by 64-bit division. Wow! 1665c87c606SMark Murray * <appro@fy.chalmers.se> 1675c87c606SMark Murray */ 16809286989SJung-uk Kim # undef bn_div_words 1695c87c606SMark Murray # define bn_div_words(n0,n1,d0) \ 1705c87c606SMark Murray ({ asm volatile ( \ 1715c87c606SMark Murray "divq %4" \ 1725c87c606SMark Murray : "=a"(q), "=d"(rem) \ 173*aeb5019cSJung-uk Kim : "a"(n1), "d"(n0), "r"(d0) \ 1745c87c606SMark Murray : "cc"); \ 1755c87c606SMark Murray q; \ 1765c87c606SMark Murray }) 1775c87c606SMark Murray # define REMAINDER_IS_ALREADY_CALCULATED 178f579bf8eSKris Kennaway # endif /* __<cpu> */ 179f579bf8eSKris Kennaway # endif /* __GNUC__ */ 1805c87c606SMark Murray # endif /* OPENSSL_NO_ASM */ 181f579bf8eSKris Kennaway 1826f9291ceSJung-uk Kim /*- 1836f9291ceSJung-uk Kim * BN_div computes dv := num / divisor, rounding towards 184db522d3aSSimon L. B. Nielsen * zero, and sets up rm such that dv*divisor + rm = num holds. 1855c87c606SMark Murray * Thus: 1865c87c606SMark Murray * dv->neg == num->neg ^ divisor->neg (unless the result is zero) 1875c87c606SMark Murray * rm->neg == num->neg (unless the remainder is zero) 1885c87c606SMark Murray * If 'dv' or 'rm' is NULL, the respective value is not returned. 1895c87c606SMark Murray */ 19074664626SKris Kennaway int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, 19174664626SKris Kennaway BN_CTX *ctx) 19274664626SKris Kennaway { 1933b4e3dcbSSimon L. B. Nielsen int norm_shift, i, loop; 19474664626SKris Kennaway BIGNUM *tmp, wnum, *snum, *sdiv, *res; 19574664626SKris Kennaway BN_ULONG *resp, *wnump; 19674664626SKris Kennaway BN_ULONG d0, d1; 19774664626SKris Kennaway int num_n, div_n; 1981f13597dSJung-uk Kim int no_branch = 0; 19974664626SKris Kennaway 2006f9291ceSJung-uk Kim /* 2016f9291ceSJung-uk Kim * Invalid zero-padding would have particularly bad consequences so don't 2026f9291ceSJung-uk Kim * just rely on bn_check_top() here (bn_check_top() works only for 2036f9291ceSJung-uk Kim * BN_DEBUG builds) 2046f9291ceSJung-uk Kim */ 205751d2991SJung-uk Kim if ((num->top > 0 && num->d[num->top - 1] == 0) || 2066f9291ceSJung-uk Kim (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) { 207db522d3aSSimon L. B. Nielsen BNerr(BN_F_BN_DIV, BN_R_NOT_INITIALIZED); 208db522d3aSSimon L. B. Nielsen return 0; 209db522d3aSSimon L. B. Nielsen } 210db522d3aSSimon L. B. Nielsen 211db522d3aSSimon L. B. Nielsen bn_check_top(num); 212751d2991SJung-uk Kim bn_check_top(divisor); 213db522d3aSSimon L. B. Nielsen 2146f9291ceSJung-uk Kim if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0) 2156f9291ceSJung-uk Kim || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) { 2161f13597dSJung-uk Kim no_branch = 1; 217db522d3aSSimon L. B. Nielsen } 218db522d3aSSimon L. B. Nielsen 2193b4e3dcbSSimon L. B. Nielsen bn_check_top(dv); 2203b4e3dcbSSimon L. B. Nielsen bn_check_top(rm); 2216f9291ceSJung-uk Kim /*- bn_check_top(num); *//* 2226f9291ceSJung-uk Kim * 'num' has been checked already 2236f9291ceSJung-uk Kim */ 2246f9291ceSJung-uk Kim /*- bn_check_top(divisor); *//* 2256f9291ceSJung-uk Kim * 'divisor' has been checked already 2266f9291ceSJung-uk Kim */ 22774664626SKris Kennaway 2286f9291ceSJung-uk Kim if (BN_is_zero(divisor)) { 22974664626SKris Kennaway BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO); 23074664626SKris Kennaway return (0); 23174664626SKris Kennaway } 23274664626SKris Kennaway 2336f9291ceSJung-uk Kim if (!no_branch && BN_ucmp(num, divisor) < 0) { 2346f9291ceSJung-uk Kim if (rm != NULL) { 2356f9291ceSJung-uk Kim if (BN_copy(rm, num) == NULL) 2366f9291ceSJung-uk Kim return (0); 2376f9291ceSJung-uk Kim } 2386f9291ceSJung-uk Kim if (dv != NULL) 2396f9291ceSJung-uk Kim BN_zero(dv); 24074664626SKris Kennaway return (1); 24174664626SKris Kennaway } 24274664626SKris Kennaway 243f579bf8eSKris Kennaway BN_CTX_start(ctx); 244f579bf8eSKris Kennaway tmp = BN_CTX_get(ctx); 245f579bf8eSKris Kennaway snum = BN_CTX_get(ctx); 246f579bf8eSKris Kennaway sdiv = BN_CTX_get(ctx); 24774664626SKris Kennaway if (dv == NULL) 248f579bf8eSKris Kennaway res = BN_CTX_get(ctx); 2496f9291ceSJung-uk Kim else 2506f9291ceSJung-uk Kim res = dv; 2516a599222SSimon L. B. Nielsen if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) 2526a599222SSimon L. B. Nielsen goto err; 25374664626SKris Kennaway 25474664626SKris Kennaway /* First we normalise the numbers */ 25574664626SKris Kennaway norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2); 2566f9291ceSJung-uk Kim if (!(BN_lshift(sdiv, divisor, norm_shift))) 2576f9291ceSJung-uk Kim goto err; 25874664626SKris Kennaway sdiv->neg = 0; 25974664626SKris Kennaway norm_shift += BN_BITS2; 2606f9291ceSJung-uk Kim if (!(BN_lshift(snum, num, norm_shift))) 2616f9291ceSJung-uk Kim goto err; 26274664626SKris Kennaway snum->neg = 0; 26374664626SKris Kennaway 2646f9291ceSJung-uk Kim if (no_branch) { 2656f9291ceSJung-uk Kim /* 2666f9291ceSJung-uk Kim * Since we don't know whether snum is larger than sdiv, we pad snum 2676f9291ceSJung-uk Kim * with enough zeroes without changing its value. 268db522d3aSSimon L. B. Nielsen */ 2696f9291ceSJung-uk Kim if (snum->top <= sdiv->top + 1) { 2706f9291ceSJung-uk Kim if (bn_wexpand(snum, sdiv->top + 2) == NULL) 2716f9291ceSJung-uk Kim goto err; 2726f9291ceSJung-uk Kim for (i = snum->top; i < sdiv->top + 2; i++) 2736f9291ceSJung-uk Kim snum->d[i] = 0; 274db522d3aSSimon L. B. Nielsen snum->top = sdiv->top + 2; 2756f9291ceSJung-uk Kim } else { 2766f9291ceSJung-uk Kim if (bn_wexpand(snum, snum->top + 1) == NULL) 2776f9291ceSJung-uk Kim goto err; 278db522d3aSSimon L. B. Nielsen snum->d[snum->top] = 0; 279db522d3aSSimon L. B. Nielsen snum->top++; 280db522d3aSSimon L. B. Nielsen } 2811f13597dSJung-uk Kim } 282db522d3aSSimon L. B. Nielsen 283db522d3aSSimon L. B. Nielsen div_n = sdiv->top; 284db522d3aSSimon L. B. Nielsen num_n = snum->top; 285db522d3aSSimon L. B. Nielsen loop = num_n - div_n; 2866f9291ceSJung-uk Kim /* 2876f9291ceSJung-uk Kim * Lets setup a 'window' into snum This is the part that corresponds to 2886f9291ceSJung-uk Kim * the current 'area' being divided 2896f9291ceSJung-uk Kim */ 290db522d3aSSimon L. B. Nielsen wnum.neg = 0; 291db522d3aSSimon L. B. Nielsen wnum.d = &(snum->d[loop]); 292db522d3aSSimon L. B. Nielsen wnum.top = div_n; 2936f9291ceSJung-uk Kim /* 2946f9291ceSJung-uk Kim * only needed when BN_ucmp messes up the values between top and max 2956f9291ceSJung-uk Kim */ 296db522d3aSSimon L. B. Nielsen wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ 297db522d3aSSimon L. B. Nielsen 298db522d3aSSimon L. B. Nielsen /* Get the top 2 words of sdiv */ 299db522d3aSSimon L. B. Nielsen /* div_n=sdiv->top; */ 300db522d3aSSimon L. B. Nielsen d0 = sdiv->d[div_n - 1]; 301db522d3aSSimon L. B. Nielsen d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2]; 302db522d3aSSimon L. B. Nielsen 303db522d3aSSimon L. B. Nielsen /* pointer to the 'top' of snum */ 304db522d3aSSimon L. B. Nielsen wnump = &(snum->d[num_n - 1]); 305db522d3aSSimon L. B. Nielsen 306db522d3aSSimon L. B. Nielsen /* Setup to 'res' */ 307db522d3aSSimon L. B. Nielsen res->neg = (num->neg ^ divisor->neg); 3086f9291ceSJung-uk Kim if (!bn_wexpand(res, (loop + 1))) 3096f9291ceSJung-uk Kim goto err; 3101f13597dSJung-uk Kim res->top = loop - no_branch; 311db522d3aSSimon L. B. Nielsen resp = &(res->d[loop - 1]); 312db522d3aSSimon L. B. Nielsen 313db522d3aSSimon L. B. Nielsen /* space for temp */ 3146f9291ceSJung-uk Kim if (!bn_wexpand(tmp, (div_n + 1))) 3156f9291ceSJung-uk Kim goto err; 316db522d3aSSimon L. B. Nielsen 3176f9291ceSJung-uk Kim if (!no_branch) { 3186f9291ceSJung-uk Kim if (BN_ucmp(&wnum, sdiv) >= 0) { 3196f9291ceSJung-uk Kim /* 3206f9291ceSJung-uk Kim * If BN_DEBUG_RAND is defined BN_ucmp changes (via bn_pollute) 3216f9291ceSJung-uk Kim * the const bignum arguments => clean the values between top and 3226f9291ceSJung-uk Kim * max again 3236f9291ceSJung-uk Kim */ 3241f13597dSJung-uk Kim bn_clear_top2max(&wnum); 3251f13597dSJung-uk Kim bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n); 3261f13597dSJung-uk Kim *resp = 1; 3276f9291ceSJung-uk Kim } else 3281f13597dSJung-uk Kim res->top--; 3291f13597dSJung-uk Kim } 3301f13597dSJung-uk Kim 3316f9291ceSJung-uk Kim /* 3326f9291ceSJung-uk Kim * if res->top == 0 then clear the neg value otherwise decrease the resp 3336f9291ceSJung-uk Kim * pointer 3346f9291ceSJung-uk Kim */ 335db522d3aSSimon L. B. Nielsen if (res->top == 0) 336db522d3aSSimon L. B. Nielsen res->neg = 0; 337db522d3aSSimon L. B. Nielsen else 338db522d3aSSimon L. B. Nielsen resp--; 339db522d3aSSimon L. B. Nielsen 3406f9291ceSJung-uk Kim for (i = 0; i < loop - 1; i++, wnump--, resp--) { 341db522d3aSSimon L. B. Nielsen BN_ULONG q, l0; 3426f9291ceSJung-uk Kim /* 3436f9291ceSJung-uk Kim * the first part of the loop uses the top two words of snum and sdiv 3446f9291ceSJung-uk Kim * to calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv 3456f9291ceSJung-uk Kim */ 346db522d3aSSimon L. B. Nielsen # if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM) 347db522d3aSSimon L. B. Nielsen BN_ULONG bn_div_3_words(BN_ULONG *, BN_ULONG, BN_ULONG); 348db522d3aSSimon L. B. Nielsen q = bn_div_3_words(wnump, d1, d0); 349db522d3aSSimon L. B. Nielsen # else 350db522d3aSSimon L. B. Nielsen BN_ULONG n0, n1, rem = 0; 351db522d3aSSimon L. B. Nielsen 352db522d3aSSimon L. B. Nielsen n0 = wnump[0]; 353db522d3aSSimon L. B. Nielsen n1 = wnump[-1]; 354db522d3aSSimon L. B. Nielsen if (n0 == d0) 355db522d3aSSimon L. B. Nielsen q = BN_MASK2; 3566f9291ceSJung-uk Kim else { /* n0 < d0 */ 3576f9291ceSJung-uk Kim 358db522d3aSSimon L. B. Nielsen # ifdef BN_LLONG 359db522d3aSSimon L. B. Nielsen BN_ULLONG t2; 360db522d3aSSimon L. B. Nielsen 361db522d3aSSimon L. B. Nielsen # if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) 362db522d3aSSimon L. B. Nielsen q = (BN_ULONG)(((((BN_ULLONG) n0) << BN_BITS2) | n1) / d0); 363db522d3aSSimon L. B. Nielsen # else 364db522d3aSSimon L. B. Nielsen q = bn_div_words(n0, n1, d0); 365db522d3aSSimon L. B. Nielsen # ifdef BN_DEBUG_LEVITTE 366db522d3aSSimon L. B. Nielsen fprintf(stderr, "DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 3676f9291ceSJung-uk Kim X) -> 0x%08X\n", n0, n1, d0, q); 368db522d3aSSimon L. B. Nielsen # endif 369db522d3aSSimon L. B. Nielsen # endif 370db522d3aSSimon L. B. Nielsen 371db522d3aSSimon L. B. Nielsen # ifndef REMAINDER_IS_ALREADY_CALCULATED 372db522d3aSSimon L. B. Nielsen /* 373db522d3aSSimon L. B. Nielsen * rem doesn't have to be BN_ULLONG. The least we 374db522d3aSSimon L. B. Nielsen * know it's less that d0, isn't it? 375db522d3aSSimon L. B. Nielsen */ 376db522d3aSSimon L. B. Nielsen rem = (n1 - q * d0) & BN_MASK2; 377db522d3aSSimon L. B. Nielsen # endif 378db522d3aSSimon L. B. Nielsen t2 = (BN_ULLONG) d1 *q; 379db522d3aSSimon L. B. Nielsen 3806f9291ceSJung-uk Kim for (;;) { 381db522d3aSSimon L. B. Nielsen if (t2 <= ((((BN_ULLONG) rem) << BN_BITS2) | wnump[-2])) 382db522d3aSSimon L. B. Nielsen break; 383db522d3aSSimon L. B. Nielsen q--; 384db522d3aSSimon L. B. Nielsen rem += d0; 3856f9291ceSJung-uk Kim if (rem < d0) 3866f9291ceSJung-uk Kim break; /* don't let rem overflow */ 387db522d3aSSimon L. B. Nielsen t2 -= d1; 388db522d3aSSimon L. B. Nielsen } 389db522d3aSSimon L. B. Nielsen # else /* !BN_LLONG */ 390ab8565e2SSimon L. B. Nielsen BN_ULONG t2l, t2h; 391db522d3aSSimon L. B. Nielsen 392db522d3aSSimon L. B. Nielsen q = bn_div_words(n0, n1, d0); 393db522d3aSSimon L. B. Nielsen # ifdef BN_DEBUG_LEVITTE 394db522d3aSSimon L. B. Nielsen fprintf(stderr, "DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 3956f9291ceSJung-uk Kim X) -> 0x%08X\n", n0, n1, d0, q); 396db522d3aSSimon L. B. Nielsen # endif 397db522d3aSSimon L. B. Nielsen # ifndef REMAINDER_IS_ALREADY_CALCULATED 398db522d3aSSimon L. B. Nielsen rem = (n1 - q * d0) & BN_MASK2; 399db522d3aSSimon L. B. Nielsen # endif 400db522d3aSSimon L. B. Nielsen 401db522d3aSSimon L. B. Nielsen # if defined(BN_UMULT_LOHI) 402db522d3aSSimon L. B. Nielsen BN_UMULT_LOHI(t2l, t2h, d1, q); 403db522d3aSSimon L. B. Nielsen # elif defined(BN_UMULT_HIGH) 404db522d3aSSimon L. B. Nielsen t2l = d1 * q; 405db522d3aSSimon L. B. Nielsen t2h = BN_UMULT_HIGH(d1, q); 406db522d3aSSimon L. B. Nielsen # else 4071f13597dSJung-uk Kim { 4081f13597dSJung-uk Kim BN_ULONG ql, qh; 4096f9291ceSJung-uk Kim t2l = LBITS(d1); 4106f9291ceSJung-uk Kim t2h = HBITS(d1); 4116f9291ceSJung-uk Kim ql = LBITS(q); 4126f9291ceSJung-uk Kim qh = HBITS(q); 413db522d3aSSimon L. B. Nielsen mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */ 4141f13597dSJung-uk Kim } 415db522d3aSSimon L. B. Nielsen # endif 416db522d3aSSimon L. B. Nielsen 4176f9291ceSJung-uk Kim for (;;) { 4186f9291ceSJung-uk Kim if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) 419db522d3aSSimon L. B. Nielsen break; 420db522d3aSSimon L. B. Nielsen q--; 421db522d3aSSimon L. B. Nielsen rem += d0; 4226f9291ceSJung-uk Kim if (rem < d0) 4236f9291ceSJung-uk Kim break; /* don't let rem overflow */ 4246f9291ceSJung-uk Kim if (t2l < d1) 4256f9291ceSJung-uk Kim t2h--; 4266f9291ceSJung-uk Kim t2l -= d1; 427db522d3aSSimon L. B. Nielsen } 428db522d3aSSimon L. B. Nielsen # endif /* !BN_LLONG */ 429db522d3aSSimon L. B. Nielsen } 430db522d3aSSimon L. B. Nielsen # endif /* !BN_DIV3W */ 431db522d3aSSimon L. B. Nielsen 432db522d3aSSimon L. B. Nielsen l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q); 433db522d3aSSimon L. B. Nielsen tmp->d[div_n] = l0; 434db522d3aSSimon L. B. Nielsen wnum.d--; 4356f9291ceSJung-uk Kim /* 4366f9291ceSJung-uk Kim * ingore top values of the bignums just sub the two BN_ULONG arrays 4376f9291ceSJung-uk Kim * with bn_sub_words 4386f9291ceSJung-uk Kim */ 4396f9291ceSJung-uk Kim if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) { 4406f9291ceSJung-uk Kim /* 4416f9291ceSJung-uk Kim * Note: As we have considered only the leading two BN_ULONGs in 4426f9291ceSJung-uk Kim * the calculation of q, sdiv * q might be greater than wnum (but 4436f9291ceSJung-uk Kim * then (q-1) * sdiv is less or equal than wnum) 444db522d3aSSimon L. B. Nielsen */ 445db522d3aSSimon L. B. Nielsen q--; 446db522d3aSSimon L. B. Nielsen if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) 4476f9291ceSJung-uk Kim /* 4486f9291ceSJung-uk Kim * we can't have an overflow here (assuming that q != 0, but 4496f9291ceSJung-uk Kim * if q == 0 then tmp is zero anyway) 4506f9291ceSJung-uk Kim */ 451db522d3aSSimon L. B. Nielsen (*wnump)++; 452db522d3aSSimon L. B. Nielsen } 453db522d3aSSimon L. B. Nielsen /* store part of the result */ 454db522d3aSSimon L. B. Nielsen *resp = q; 455db522d3aSSimon L. B. Nielsen } 456db522d3aSSimon L. B. Nielsen bn_correct_top(snum); 4576f9291ceSJung-uk Kim if (rm != NULL) { 4586f9291ceSJung-uk Kim /* 4596f9291ceSJung-uk Kim * Keep a copy of the neg flag in num because if rm==num BN_rshift() 4606f9291ceSJung-uk Kim * will overwrite it. 461db522d3aSSimon L. B. Nielsen */ 462db522d3aSSimon L. B. Nielsen int neg = num->neg; 463db522d3aSSimon L. B. Nielsen BN_rshift(rm, snum, norm_shift); 464db522d3aSSimon L. B. Nielsen if (!BN_is_zero(rm)) 465db522d3aSSimon L. B. Nielsen rm->neg = neg; 466db522d3aSSimon L. B. Nielsen bn_check_top(rm); 467db522d3aSSimon L. B. Nielsen } 4686f9291ceSJung-uk Kim if (no_branch) 4696f9291ceSJung-uk Kim bn_correct_top(res); 470db522d3aSSimon L. B. Nielsen BN_CTX_end(ctx); 471db522d3aSSimon L. B. Nielsen return (1); 472db522d3aSSimon L. B. Nielsen err: 473db522d3aSSimon L. B. Nielsen bn_check_top(rm); 474db522d3aSSimon L. B. Nielsen BN_CTX_end(ctx); 475db522d3aSSimon L. B. Nielsen return (0); 476db522d3aSSimon L. B. Nielsen } 47774664626SKris Kennaway #endif 478