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 645c87c606SMark Murray 6574664626SKris Kennaway /* The old slow way */ 6674664626SKris Kennaway #if 0 67f579bf8eSKris Kennaway int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, 68f579bf8eSKris Kennaway BN_CTX *ctx) 6974664626SKris Kennaway { 7074664626SKris Kennaway int i,nm,nd; 71f579bf8eSKris Kennaway int ret = 0; 7274664626SKris Kennaway BIGNUM *D; 7374664626SKris Kennaway 7474664626SKris Kennaway bn_check_top(m); 7574664626SKris Kennaway bn_check_top(d); 7674664626SKris Kennaway if (BN_is_zero(d)) 7774664626SKris Kennaway { 7874664626SKris Kennaway BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); 7974664626SKris Kennaway return(0); 8074664626SKris Kennaway } 8174664626SKris Kennaway 8274664626SKris Kennaway if (BN_ucmp(m,d) < 0) 8374664626SKris Kennaway { 8474664626SKris Kennaway if (rem != NULL) 8574664626SKris Kennaway { if (BN_copy(rem,m) == NULL) return(0); } 8674664626SKris Kennaway if (dv != NULL) BN_zero(dv); 8774664626SKris Kennaway return(1); 8874664626SKris Kennaway } 8974664626SKris Kennaway 90f579bf8eSKris Kennaway BN_CTX_start(ctx); 91f579bf8eSKris Kennaway D = BN_CTX_get(ctx); 92f579bf8eSKris Kennaway if (dv == NULL) dv = BN_CTX_get(ctx); 93f579bf8eSKris Kennaway if (rem == NULL) rem = BN_CTX_get(ctx); 94f579bf8eSKris Kennaway if (D == NULL || dv == NULL || rem == NULL) 95f579bf8eSKris Kennaway goto end; 9674664626SKris Kennaway 9774664626SKris Kennaway nd=BN_num_bits(d); 9874664626SKris Kennaway nm=BN_num_bits(m); 99f579bf8eSKris Kennaway if (BN_copy(D,d) == NULL) goto end; 100f579bf8eSKris Kennaway if (BN_copy(rem,m) == NULL) goto end; 10174664626SKris Kennaway 10274664626SKris Kennaway /* The next 2 are needed so we can do a dv->d[0]|=1 later 10374664626SKris Kennaway * since BN_lshift1 will only work once there is a value :-) */ 10474664626SKris Kennaway BN_zero(dv); 10574664626SKris Kennaway bn_wexpand(dv,1); 10674664626SKris Kennaway dv->top=1; 10774664626SKris Kennaway 108f579bf8eSKris Kennaway if (!BN_lshift(D,D,nm-nd)) goto end; 10974664626SKris Kennaway for (i=nm-nd; i>=0; i--) 11074664626SKris Kennaway { 111f579bf8eSKris Kennaway if (!BN_lshift1(dv,dv)) goto end; 11274664626SKris Kennaway if (BN_ucmp(rem,D) >= 0) 11374664626SKris Kennaway { 11474664626SKris Kennaway dv->d[0]|=1; 115f579bf8eSKris Kennaway if (!BN_usub(rem,rem,D)) goto end; 11674664626SKris Kennaway } 11774664626SKris Kennaway /* CAN IMPROVE (and have now :=) */ 118f579bf8eSKris Kennaway if (!BN_rshift1(D,D)) goto end; 11974664626SKris Kennaway } 12074664626SKris Kennaway rem->neg=BN_is_zero(rem)?0:m->neg; 12174664626SKris Kennaway dv->neg=m->neg^d->neg; 122f579bf8eSKris Kennaway ret = 1; 123f579bf8eSKris Kennaway end: 124f579bf8eSKris Kennaway BN_CTX_end(ctx); 125f579bf8eSKris Kennaway return(ret); 12674664626SKris Kennaway } 12774664626SKris Kennaway 12874664626SKris Kennaway #else 12974664626SKris Kennaway 1305c87c606SMark Murray #if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \ 1315c87c606SMark Murray && !defined(PEDANTIC) && !defined(BN_DIV3W) 132f579bf8eSKris Kennaway # if defined(__GNUC__) && __GNUC__>=2 133a21b1b38SKris Kennaway # if defined(__i386) || defined (__i386__) 134f579bf8eSKris Kennaway /* 135f579bf8eSKris Kennaway * There were two reasons for implementing this template: 136f579bf8eSKris Kennaway * - GNU C generates a call to a function (__udivdi3 to be exact) 137f579bf8eSKris Kennaway * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to 138f579bf8eSKris Kennaway * understand why...); 139f579bf8eSKris Kennaway * - divl doesn't only calculate quotient, but also leaves 140f579bf8eSKris Kennaway * remainder in %edx which we can definitely use here:-) 141f579bf8eSKris Kennaway * 142f579bf8eSKris Kennaway * <appro@fy.chalmers.se> 143f579bf8eSKris Kennaway */ 144f579bf8eSKris Kennaway # define bn_div_words(n0,n1,d0) \ 145f579bf8eSKris Kennaway ({ asm volatile ( \ 146f579bf8eSKris Kennaway "divl %4" \ 147f579bf8eSKris Kennaway : "=a"(q), "=d"(rem) \ 148f579bf8eSKris Kennaway : "a"(n1), "d"(n0), "g"(d0) \ 149f579bf8eSKris Kennaway : "cc"); \ 150f579bf8eSKris Kennaway q; \ 151f579bf8eSKris Kennaway }) 152f579bf8eSKris Kennaway # define REMAINDER_IS_ALREADY_CALCULATED 1535c87c606SMark Murray # elif defined(__x86_64) && defined(SIXTY_FOUR_BIT_LONG) 1545c87c606SMark Murray /* 1555c87c606SMark Murray * Same story here, but it's 128-bit by 64-bit division. Wow! 1565c87c606SMark Murray * <appro@fy.chalmers.se> 1575c87c606SMark Murray */ 1585c87c606SMark Murray # define bn_div_words(n0,n1,d0) \ 1595c87c606SMark Murray ({ asm volatile ( \ 1605c87c606SMark Murray "divq %4" \ 1615c87c606SMark Murray : "=a"(q), "=d"(rem) \ 1625c87c606SMark Murray : "a"(n1), "d"(n0), "g"(d0) \ 1635c87c606SMark Murray : "cc"); \ 1645c87c606SMark Murray q; \ 1655c87c606SMark Murray }) 1665c87c606SMark Murray # define REMAINDER_IS_ALREADY_CALCULATED 167f579bf8eSKris Kennaway # endif /* __<cpu> */ 168f579bf8eSKris Kennaway # endif /* __GNUC__ */ 1695c87c606SMark Murray #endif /* OPENSSL_NO_ASM */ 170f579bf8eSKris Kennaway 1715c87c606SMark Murray 172db522d3aSSimon L. B. Nielsen /* BN_div[_no_branch] computes dv := num / divisor, rounding towards 173db522d3aSSimon L. B. Nielsen * zero, and sets up rm such that dv*divisor + rm = num holds. 1745c87c606SMark Murray * Thus: 1755c87c606SMark Murray * dv->neg == num->neg ^ divisor->neg (unless the result is zero) 1765c87c606SMark Murray * rm->neg == num->neg (unless the remainder is zero) 1775c87c606SMark Murray * If 'dv' or 'rm' is NULL, the respective value is not returned. 1785c87c606SMark Murray */ 179db522d3aSSimon L. B. Nielsen static int BN_div_no_branch(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, 180db522d3aSSimon L. B. Nielsen const BIGNUM *divisor, BN_CTX *ctx); 18174664626SKris Kennaway int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, 18274664626SKris Kennaway BN_CTX *ctx) 18374664626SKris Kennaway { 1843b4e3dcbSSimon L. B. Nielsen int norm_shift,i,loop; 18574664626SKris Kennaway BIGNUM *tmp,wnum,*snum,*sdiv,*res; 18674664626SKris Kennaway BN_ULONG *resp,*wnump; 18774664626SKris Kennaway BN_ULONG d0,d1; 18874664626SKris Kennaway int num_n,div_n; 18974664626SKris Kennaway 190db522d3aSSimon L. B. Nielsen /* Invalid zero-padding would have particularly bad consequences 191db522d3aSSimon L. B. Nielsen * in the case of 'num', so don't just rely on bn_check_top() for this one 192db522d3aSSimon L. B. Nielsen * (bn_check_top() works only for BN_DEBUG builds) */ 193db522d3aSSimon L. B. Nielsen if (num->top > 0 && num->d[num->top - 1] == 0) 194db522d3aSSimon L. B. Nielsen { 195db522d3aSSimon L. B. Nielsen BNerr(BN_F_BN_DIV,BN_R_NOT_INITIALIZED); 196db522d3aSSimon L. B. Nielsen return 0; 197db522d3aSSimon L. B. Nielsen } 198db522d3aSSimon L. B. Nielsen 199db522d3aSSimon L. B. Nielsen bn_check_top(num); 200db522d3aSSimon L. B. Nielsen 201db522d3aSSimon L. B. Nielsen if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0) || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) 202db522d3aSSimon L. B. Nielsen { 203db522d3aSSimon L. B. Nielsen return BN_div_no_branch(dv, rm, num, divisor, ctx); 204db522d3aSSimon L. B. Nielsen } 205db522d3aSSimon L. B. Nielsen 2063b4e3dcbSSimon L. B. Nielsen bn_check_top(dv); 2073b4e3dcbSSimon L. B. Nielsen bn_check_top(rm); 208db522d3aSSimon L. B. Nielsen /* bn_check_top(num); */ /* 'num' has been checked already */ 20974664626SKris Kennaway bn_check_top(divisor); 21074664626SKris Kennaway 21174664626SKris Kennaway if (BN_is_zero(divisor)) 21274664626SKris Kennaway { 21374664626SKris Kennaway BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); 21474664626SKris Kennaway return(0); 21574664626SKris Kennaway } 21674664626SKris Kennaway 21774664626SKris Kennaway if (BN_ucmp(num,divisor) < 0) 21874664626SKris Kennaway { 21974664626SKris Kennaway if (rm != NULL) 22074664626SKris Kennaway { if (BN_copy(rm,num) == NULL) return(0); } 22174664626SKris Kennaway if (dv != NULL) BN_zero(dv); 22274664626SKris Kennaway return(1); 22374664626SKris Kennaway } 22474664626SKris Kennaway 225f579bf8eSKris Kennaway BN_CTX_start(ctx); 226f579bf8eSKris Kennaway tmp=BN_CTX_get(ctx); 227f579bf8eSKris Kennaway snum=BN_CTX_get(ctx); 228f579bf8eSKris Kennaway sdiv=BN_CTX_get(ctx); 22974664626SKris Kennaway if (dv == NULL) 230f579bf8eSKris Kennaway res=BN_CTX_get(ctx); 23174664626SKris Kennaway else res=dv; 232de7cdddaSKris Kennaway if (sdiv == NULL || res == NULL) goto err; 23374664626SKris Kennaway 23474664626SKris Kennaway /* First we normalise the numbers */ 23574664626SKris Kennaway norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); 2364f20a5a2SJacques Vidrine if (!(BN_lshift(sdiv,divisor,norm_shift))) goto err; 23774664626SKris Kennaway sdiv->neg=0; 23874664626SKris Kennaway norm_shift+=BN_BITS2; 2394f20a5a2SJacques Vidrine if (!(BN_lshift(snum,num,norm_shift))) goto err; 24074664626SKris Kennaway snum->neg=0; 24174664626SKris Kennaway div_n=sdiv->top; 24274664626SKris Kennaway num_n=snum->top; 24374664626SKris Kennaway loop=num_n-div_n; 24474664626SKris Kennaway /* Lets setup a 'window' into snum 24574664626SKris Kennaway * This is the part that corresponds to the current 24674664626SKris Kennaway * 'area' being divided */ 2473b4e3dcbSSimon L. B. Nielsen wnum.neg = 0; 24874664626SKris Kennaway wnum.d = &(snum->d[loop]); 24974664626SKris Kennaway wnum.top = div_n; 2503b4e3dcbSSimon L. B. Nielsen /* only needed when BN_ucmp messes up the values between top and max */ 2513b4e3dcbSSimon L. B. Nielsen wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ 25274664626SKris Kennaway 25374664626SKris Kennaway /* Get the top 2 words of sdiv */ 2543b4e3dcbSSimon L. B. Nielsen /* div_n=sdiv->top; */ 25574664626SKris Kennaway d0=sdiv->d[div_n-1]; 25674664626SKris Kennaway d1=(div_n == 1)?0:sdiv->d[div_n-2]; 25774664626SKris Kennaway 25874664626SKris Kennaway /* pointer to the 'top' of snum */ 25974664626SKris Kennaway wnump= &(snum->d[num_n-1]); 26074664626SKris Kennaway 26174664626SKris Kennaway /* Setup to 'res' */ 26274664626SKris Kennaway res->neg= (num->neg^divisor->neg); 26374664626SKris Kennaway if (!bn_wexpand(res,(loop+1))) goto err; 26474664626SKris Kennaway res->top=loop; 26574664626SKris Kennaway resp= &(res->d[loop-1]); 26674664626SKris Kennaway 26774664626SKris Kennaway /* space for temp */ 26874664626SKris Kennaway if (!bn_wexpand(tmp,(div_n+1))) goto err; 26974664626SKris Kennaway 27074664626SKris Kennaway if (BN_ucmp(&wnum,sdiv) >= 0) 27174664626SKris Kennaway { 2723b4e3dcbSSimon L. B. Nielsen /* If BN_DEBUG_RAND is defined BN_ucmp changes (via 2733b4e3dcbSSimon L. B. Nielsen * bn_pollute) the const bignum arguments => 2743b4e3dcbSSimon L. B. Nielsen * clean the values between top and max again */ 2753b4e3dcbSSimon L. B. Nielsen bn_clear_top2max(&wnum); 2763b4e3dcbSSimon L. B. Nielsen bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n); 27774664626SKris Kennaway *resp=1; 27874664626SKris Kennaway } 27974664626SKris Kennaway else 28074664626SKris Kennaway res->top--; 2813b4e3dcbSSimon L. B. Nielsen /* if res->top == 0 then clear the neg value otherwise decrease 2823b4e3dcbSSimon L. B. Nielsen * the resp pointer */ 2835c87c606SMark Murray if (res->top == 0) 2845c87c606SMark Murray res->neg = 0; 2853b4e3dcbSSimon L. B. Nielsen else 28674664626SKris Kennaway resp--; 28774664626SKris Kennaway 2883b4e3dcbSSimon L. B. Nielsen for (i=0; i<loop-1; i++, wnump--, resp--) 28974664626SKris Kennaway { 29074664626SKris Kennaway BN_ULONG q,l0; 2913b4e3dcbSSimon L. B. Nielsen /* the first part of the loop uses the top two words of 2923b4e3dcbSSimon L. B. Nielsen * snum and sdiv to calculate a BN_ULONG q such that 2933b4e3dcbSSimon L. B. Nielsen * | wnum - sdiv * q | < sdiv */ 2945c87c606SMark Murray #if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM) 2955740a5e3SKris Kennaway BN_ULONG bn_div_3_words(BN_ULONG*,BN_ULONG,BN_ULONG); 296f579bf8eSKris Kennaway q=bn_div_3_words(wnump,d1,d0); 29774664626SKris Kennaway #else 29874664626SKris Kennaway BN_ULONG n0,n1,rem=0; 29974664626SKris Kennaway 30074664626SKris Kennaway n0=wnump[0]; 30174664626SKris Kennaway n1=wnump[-1]; 30274664626SKris Kennaway if (n0 == d0) 30374664626SKris Kennaway q=BN_MASK2; 304f579bf8eSKris Kennaway else /* n0 < d0 */ 30574664626SKris Kennaway { 30674664626SKris Kennaway #ifdef BN_LLONG 30774664626SKris Kennaway BN_ULLONG t2; 30874664626SKris Kennaway 309f579bf8eSKris Kennaway #if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) 310f579bf8eSKris Kennaway q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0); 311f579bf8eSKris Kennaway #else 312f579bf8eSKris Kennaway q=bn_div_words(n0,n1,d0); 3135c87c606SMark Murray #ifdef BN_DEBUG_LEVITTE 3145c87c606SMark Murray fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 3155c87c606SMark Murray X) -> 0x%08X\n", 3165c87c606SMark Murray n0, n1, d0, q); 3175c87c606SMark Murray #endif 318f579bf8eSKris Kennaway #endif 319f579bf8eSKris Kennaway 320f579bf8eSKris Kennaway #ifndef REMAINDER_IS_ALREADY_CALCULATED 32174664626SKris Kennaway /* 32274664626SKris Kennaway * rem doesn't have to be BN_ULLONG. The least we 32374664626SKris Kennaway * know it's less that d0, isn't it? 32474664626SKris Kennaway */ 32574664626SKris Kennaway rem=(n1-q*d0)&BN_MASK2; 32674664626SKris Kennaway #endif 32774664626SKris Kennaway t2=(BN_ULLONG)d1*q; 32874664626SKris Kennaway 32974664626SKris Kennaway for (;;) 33074664626SKris Kennaway { 33174664626SKris Kennaway if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2])) 33274664626SKris Kennaway break; 33374664626SKris Kennaway q--; 33474664626SKris Kennaway rem += d0; 33574664626SKris Kennaway if (rem < d0) break; /* don't let rem overflow */ 33674664626SKris Kennaway t2 -= d1; 33774664626SKris Kennaway } 338f579bf8eSKris Kennaway #else /* !BN_LLONG */ 33974664626SKris Kennaway BN_ULONG t2l,t2h,ql,qh; 34074664626SKris Kennaway 341f579bf8eSKris Kennaway q=bn_div_words(n0,n1,d0); 3425c87c606SMark Murray #ifdef BN_DEBUG_LEVITTE 3435c87c606SMark Murray fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 3445c87c606SMark Murray X) -> 0x%08X\n", 3455c87c606SMark Murray n0, n1, d0, q); 3465c87c606SMark Murray #endif 347f579bf8eSKris Kennaway #ifndef REMAINDER_IS_ALREADY_CALCULATED 34874664626SKris Kennaway rem=(n1-q*d0)&BN_MASK2; 34974664626SKris Kennaway #endif 350f579bf8eSKris Kennaway 3515c87c606SMark Murray #if defined(BN_UMULT_LOHI) 3525c87c606SMark Murray BN_UMULT_LOHI(t2l,t2h,d1,q); 3535c87c606SMark Murray #elif defined(BN_UMULT_HIGH) 354f579bf8eSKris Kennaway t2l = d1 * q; 355f579bf8eSKris Kennaway t2h = BN_UMULT_HIGH(d1,q); 356f579bf8eSKris Kennaway #else 35774664626SKris Kennaway t2l=LBITS(d1); t2h=HBITS(d1); 35874664626SKris Kennaway ql =LBITS(q); qh =HBITS(q); 35974664626SKris Kennaway mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ 360f579bf8eSKris Kennaway #endif 36174664626SKris Kennaway 36274664626SKris Kennaway for (;;) 36374664626SKris Kennaway { 36474664626SKris Kennaway if ((t2h < rem) || 36574664626SKris Kennaway ((t2h == rem) && (t2l <= wnump[-2]))) 36674664626SKris Kennaway break; 36774664626SKris Kennaway q--; 36874664626SKris Kennaway rem += d0; 36974664626SKris Kennaway if (rem < d0) break; /* don't let rem overflow */ 37074664626SKris Kennaway if (t2l < d1) t2h--; t2l -= d1; 37174664626SKris Kennaway } 372f579bf8eSKris Kennaway #endif /* !BN_LLONG */ 37374664626SKris Kennaway } 37474664626SKris Kennaway #endif /* !BN_DIV3W */ 375f579bf8eSKris Kennaway 37674664626SKris Kennaway l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); 37774664626SKris Kennaway tmp->d[div_n]=l0; 3783b4e3dcbSSimon L. B. Nielsen wnum.d--; 3793b4e3dcbSSimon L. B. Nielsen /* ingore top values of the bignums just sub the two 3803b4e3dcbSSimon L. B. Nielsen * BN_ULONG arrays with bn_sub_words */ 3813b4e3dcbSSimon L. B. Nielsen if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n+1)) 38274664626SKris Kennaway { 3833b4e3dcbSSimon L. B. Nielsen /* Note: As we have considered only the leading 3843b4e3dcbSSimon L. B. Nielsen * two BN_ULONGs in the calculation of q, sdiv * q 3853b4e3dcbSSimon L. B. Nielsen * might be greater than wnum (but then (q-1) * sdiv 3863b4e3dcbSSimon L. B. Nielsen * is less or equal than wnum) 3873b4e3dcbSSimon L. B. Nielsen */ 38874664626SKris Kennaway q--; 3893b4e3dcbSSimon L. B. Nielsen if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) 3903b4e3dcbSSimon L. B. Nielsen /* we can't have an overflow here (assuming 3913b4e3dcbSSimon L. B. Nielsen * that q != 0, but if q == 0 then tmp is 3923b4e3dcbSSimon L. B. Nielsen * zero anyway) */ 3933b4e3dcbSSimon L. B. Nielsen (*wnump)++; 39474664626SKris Kennaway } 3953b4e3dcbSSimon L. B. Nielsen /* store part of the result */ 3963b4e3dcbSSimon L. B. Nielsen *resp = q; 39774664626SKris Kennaway } 3983b4e3dcbSSimon L. B. Nielsen bn_correct_top(snum); 39974664626SKris Kennaway if (rm != NULL) 40074664626SKris Kennaway { 4015c87c606SMark Murray /* Keep a copy of the neg flag in num because if rm==num 4025c87c606SMark Murray * BN_rshift() will overwrite it. 4035c87c606SMark Murray */ 4045c87c606SMark Murray int neg = num->neg; 40574664626SKris Kennaway BN_rshift(rm,snum,norm_shift); 4065c87c606SMark Murray if (!BN_is_zero(rm)) 4075c87c606SMark Murray rm->neg = neg; 4083b4e3dcbSSimon L. B. Nielsen bn_check_top(rm); 40974664626SKris Kennaway } 410f579bf8eSKris Kennaway BN_CTX_end(ctx); 41174664626SKris Kennaway return(1); 41274664626SKris Kennaway err: 4133b4e3dcbSSimon L. B. Nielsen bn_check_top(rm); 414f579bf8eSKris Kennaway BN_CTX_end(ctx); 41574664626SKris Kennaway return(0); 41674664626SKris Kennaway } 41774664626SKris Kennaway 418db522d3aSSimon L. B. Nielsen 419db522d3aSSimon L. B. Nielsen /* BN_div_no_branch is a special version of BN_div. It does not contain 420db522d3aSSimon L. B. Nielsen * branches that may leak sensitive information. 421db522d3aSSimon L. B. Nielsen */ 422db522d3aSSimon L. B. Nielsen static int BN_div_no_branch(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, 423db522d3aSSimon L. B. Nielsen const BIGNUM *divisor, BN_CTX *ctx) 424db522d3aSSimon L. B. Nielsen { 425db522d3aSSimon L. B. Nielsen int norm_shift,i,loop; 426db522d3aSSimon L. B. Nielsen BIGNUM *tmp,wnum,*snum,*sdiv,*res; 427db522d3aSSimon L. B. Nielsen BN_ULONG *resp,*wnump; 428db522d3aSSimon L. B. Nielsen BN_ULONG d0,d1; 429db522d3aSSimon L. B. Nielsen int num_n,div_n; 430db522d3aSSimon L. B. Nielsen 431db522d3aSSimon L. B. Nielsen bn_check_top(dv); 432db522d3aSSimon L. B. Nielsen bn_check_top(rm); 433db522d3aSSimon L. B. Nielsen /* bn_check_top(num); */ /* 'num' has been checked in BN_div() */ 434db522d3aSSimon L. B. Nielsen bn_check_top(divisor); 435db522d3aSSimon L. B. Nielsen 436db522d3aSSimon L. B. Nielsen if (BN_is_zero(divisor)) 437db522d3aSSimon L. B. Nielsen { 438db522d3aSSimon L. B. Nielsen BNerr(BN_F_BN_DIV_NO_BRANCH,BN_R_DIV_BY_ZERO); 439db522d3aSSimon L. B. Nielsen return(0); 440db522d3aSSimon L. B. Nielsen } 441db522d3aSSimon L. B. Nielsen 442db522d3aSSimon L. B. Nielsen BN_CTX_start(ctx); 443db522d3aSSimon L. B. Nielsen tmp=BN_CTX_get(ctx); 444db522d3aSSimon L. B. Nielsen snum=BN_CTX_get(ctx); 445db522d3aSSimon L. B. Nielsen sdiv=BN_CTX_get(ctx); 446db522d3aSSimon L. B. Nielsen if (dv == NULL) 447db522d3aSSimon L. B. Nielsen res=BN_CTX_get(ctx); 448db522d3aSSimon L. B. Nielsen else res=dv; 449db522d3aSSimon L. B. Nielsen if (sdiv == NULL || res == NULL) goto err; 450db522d3aSSimon L. B. Nielsen 451db522d3aSSimon L. B. Nielsen /* First we normalise the numbers */ 452db522d3aSSimon L. B. Nielsen norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); 453db522d3aSSimon L. B. Nielsen if (!(BN_lshift(sdiv,divisor,norm_shift))) goto err; 454db522d3aSSimon L. B. Nielsen sdiv->neg=0; 455db522d3aSSimon L. B. Nielsen norm_shift+=BN_BITS2; 456db522d3aSSimon L. B. Nielsen if (!(BN_lshift(snum,num,norm_shift))) goto err; 457db522d3aSSimon L. B. Nielsen snum->neg=0; 458db522d3aSSimon L. B. Nielsen 459db522d3aSSimon L. B. Nielsen /* Since we don't know whether snum is larger than sdiv, 460db522d3aSSimon L. B. Nielsen * we pad snum with enough zeroes without changing its 461db522d3aSSimon L. B. Nielsen * value. 462db522d3aSSimon L. B. Nielsen */ 463db522d3aSSimon L. B. Nielsen if (snum->top <= sdiv->top+1) 464db522d3aSSimon L. B. Nielsen { 465db522d3aSSimon L. B. Nielsen if (bn_wexpand(snum, sdiv->top + 2) == NULL) goto err; 466db522d3aSSimon L. B. Nielsen for (i = snum->top; i < sdiv->top + 2; i++) snum->d[i] = 0; 467db522d3aSSimon L. B. Nielsen snum->top = sdiv->top + 2; 468db522d3aSSimon L. B. Nielsen } 469db522d3aSSimon L. B. Nielsen else 470db522d3aSSimon L. B. Nielsen { 471db522d3aSSimon L. B. Nielsen if (bn_wexpand(snum, snum->top + 1) == NULL) goto err; 472db522d3aSSimon L. B. Nielsen snum->d[snum->top] = 0; 473db522d3aSSimon L. B. Nielsen snum->top ++; 474db522d3aSSimon L. B. Nielsen } 475db522d3aSSimon L. B. Nielsen 476db522d3aSSimon L. B. Nielsen div_n=sdiv->top; 477db522d3aSSimon L. B. Nielsen num_n=snum->top; 478db522d3aSSimon L. B. Nielsen loop=num_n-div_n; 479db522d3aSSimon L. B. Nielsen /* Lets setup a 'window' into snum 480db522d3aSSimon L. B. Nielsen * This is the part that corresponds to the current 481db522d3aSSimon L. B. Nielsen * 'area' being divided */ 482db522d3aSSimon L. B. Nielsen wnum.neg = 0; 483db522d3aSSimon L. B. Nielsen wnum.d = &(snum->d[loop]); 484db522d3aSSimon L. B. Nielsen wnum.top = div_n; 485db522d3aSSimon L. B. Nielsen /* only needed when BN_ucmp messes up the values between top and max */ 486db522d3aSSimon L. B. Nielsen wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ 487db522d3aSSimon L. B. Nielsen 488db522d3aSSimon L. B. Nielsen /* Get the top 2 words of sdiv */ 489db522d3aSSimon L. B. Nielsen /* div_n=sdiv->top; */ 490db522d3aSSimon L. B. Nielsen d0=sdiv->d[div_n-1]; 491db522d3aSSimon L. B. Nielsen d1=(div_n == 1)?0:sdiv->d[div_n-2]; 492db522d3aSSimon L. B. Nielsen 493db522d3aSSimon L. B. Nielsen /* pointer to the 'top' of snum */ 494db522d3aSSimon L. B. Nielsen wnump= &(snum->d[num_n-1]); 495db522d3aSSimon L. B. Nielsen 496db522d3aSSimon L. B. Nielsen /* Setup to 'res' */ 497db522d3aSSimon L. B. Nielsen res->neg= (num->neg^divisor->neg); 498db522d3aSSimon L. B. Nielsen if (!bn_wexpand(res,(loop+1))) goto err; 499db522d3aSSimon L. B. Nielsen res->top=loop-1; 500db522d3aSSimon L. B. Nielsen resp= &(res->d[loop-1]); 501db522d3aSSimon L. B. Nielsen 502db522d3aSSimon L. B. Nielsen /* space for temp */ 503db522d3aSSimon L. B. Nielsen if (!bn_wexpand(tmp,(div_n+1))) goto err; 504db522d3aSSimon L. B. Nielsen 505db522d3aSSimon L. B. Nielsen /* if res->top == 0 then clear the neg value otherwise decrease 506db522d3aSSimon L. B. Nielsen * the resp pointer */ 507db522d3aSSimon L. B. Nielsen if (res->top == 0) 508db522d3aSSimon L. B. Nielsen res->neg = 0; 509db522d3aSSimon L. B. Nielsen else 510db522d3aSSimon L. B. Nielsen resp--; 511db522d3aSSimon L. B. Nielsen 512db522d3aSSimon L. B. Nielsen for (i=0; i<loop-1; i++, wnump--, resp--) 513db522d3aSSimon L. B. Nielsen { 514db522d3aSSimon L. B. Nielsen BN_ULONG q,l0; 515db522d3aSSimon L. B. Nielsen /* the first part of the loop uses the top two words of 516db522d3aSSimon L. B. Nielsen * snum and sdiv to calculate a BN_ULONG q such that 517db522d3aSSimon L. B. Nielsen * | wnum - sdiv * q | < sdiv */ 518db522d3aSSimon L. B. Nielsen #if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM) 519db522d3aSSimon L. B. Nielsen BN_ULONG bn_div_3_words(BN_ULONG*,BN_ULONG,BN_ULONG); 520db522d3aSSimon L. B. Nielsen q=bn_div_3_words(wnump,d1,d0); 521db522d3aSSimon L. B. Nielsen #else 522db522d3aSSimon L. B. Nielsen BN_ULONG n0,n1,rem=0; 523db522d3aSSimon L. B. Nielsen 524db522d3aSSimon L. B. Nielsen n0=wnump[0]; 525db522d3aSSimon L. B. Nielsen n1=wnump[-1]; 526db522d3aSSimon L. B. Nielsen if (n0 == d0) 527db522d3aSSimon L. B. Nielsen q=BN_MASK2; 528db522d3aSSimon L. B. Nielsen else /* n0 < d0 */ 529db522d3aSSimon L. B. Nielsen { 530db522d3aSSimon L. B. Nielsen #ifdef BN_LLONG 531db522d3aSSimon L. B. Nielsen BN_ULLONG t2; 532db522d3aSSimon L. B. Nielsen 533db522d3aSSimon L. B. Nielsen #if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) 534db522d3aSSimon L. B. Nielsen q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0); 535db522d3aSSimon L. B. Nielsen #else 536db522d3aSSimon L. B. Nielsen q=bn_div_words(n0,n1,d0); 537db522d3aSSimon L. B. Nielsen #ifdef BN_DEBUG_LEVITTE 538db522d3aSSimon L. B. Nielsen fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 539db522d3aSSimon L. B. Nielsen X) -> 0x%08X\n", 540db522d3aSSimon L. B. Nielsen n0, n1, d0, q); 541db522d3aSSimon L. B. Nielsen #endif 542db522d3aSSimon L. B. Nielsen #endif 543db522d3aSSimon L. B. Nielsen 544db522d3aSSimon L. B. Nielsen #ifndef REMAINDER_IS_ALREADY_CALCULATED 545db522d3aSSimon L. B. Nielsen /* 546db522d3aSSimon L. B. Nielsen * rem doesn't have to be BN_ULLONG. The least we 547db522d3aSSimon L. B. Nielsen * know it's less that d0, isn't it? 548db522d3aSSimon L. B. Nielsen */ 549db522d3aSSimon L. B. Nielsen rem=(n1-q*d0)&BN_MASK2; 550db522d3aSSimon L. B. Nielsen #endif 551db522d3aSSimon L. B. Nielsen t2=(BN_ULLONG)d1*q; 552db522d3aSSimon L. B. Nielsen 553db522d3aSSimon L. B. Nielsen for (;;) 554db522d3aSSimon L. B. Nielsen { 555db522d3aSSimon L. B. Nielsen if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2])) 556db522d3aSSimon L. B. Nielsen break; 557db522d3aSSimon L. B. Nielsen q--; 558db522d3aSSimon L. B. Nielsen rem += d0; 559db522d3aSSimon L. B. Nielsen if (rem < d0) break; /* don't let rem overflow */ 560db522d3aSSimon L. B. Nielsen t2 -= d1; 561db522d3aSSimon L. B. Nielsen } 562db522d3aSSimon L. B. Nielsen #else /* !BN_LLONG */ 563db522d3aSSimon L. B. Nielsen BN_ULONG t2l,t2h,ql,qh; 564db522d3aSSimon L. B. Nielsen 565db522d3aSSimon L. B. Nielsen q=bn_div_words(n0,n1,d0); 566db522d3aSSimon L. B. Nielsen #ifdef BN_DEBUG_LEVITTE 567db522d3aSSimon L. B. Nielsen fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ 568db522d3aSSimon L. B. Nielsen X) -> 0x%08X\n", 569db522d3aSSimon L. B. Nielsen n0, n1, d0, q); 570db522d3aSSimon L. B. Nielsen #endif 571db522d3aSSimon L. B. Nielsen #ifndef REMAINDER_IS_ALREADY_CALCULATED 572db522d3aSSimon L. B. Nielsen rem=(n1-q*d0)&BN_MASK2; 573db522d3aSSimon L. B. Nielsen #endif 574db522d3aSSimon L. B. Nielsen 575db522d3aSSimon L. B. Nielsen #if defined(BN_UMULT_LOHI) 576db522d3aSSimon L. B. Nielsen BN_UMULT_LOHI(t2l,t2h,d1,q); 577db522d3aSSimon L. B. Nielsen #elif defined(BN_UMULT_HIGH) 578db522d3aSSimon L. B. Nielsen t2l = d1 * q; 579db522d3aSSimon L. B. Nielsen t2h = BN_UMULT_HIGH(d1,q); 580db522d3aSSimon L. B. Nielsen #else 581db522d3aSSimon L. B. Nielsen t2l=LBITS(d1); t2h=HBITS(d1); 582db522d3aSSimon L. B. Nielsen ql =LBITS(q); qh =HBITS(q); 583db522d3aSSimon L. B. Nielsen mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ 584db522d3aSSimon L. B. Nielsen #endif 585db522d3aSSimon L. B. Nielsen 586db522d3aSSimon L. B. Nielsen for (;;) 587db522d3aSSimon L. B. Nielsen { 588db522d3aSSimon L. B. Nielsen if ((t2h < rem) || 589db522d3aSSimon L. B. Nielsen ((t2h == rem) && (t2l <= wnump[-2]))) 590db522d3aSSimon L. B. Nielsen break; 591db522d3aSSimon L. B. Nielsen q--; 592db522d3aSSimon L. B. Nielsen rem += d0; 593db522d3aSSimon L. B. Nielsen if (rem < d0) break; /* don't let rem overflow */ 594db522d3aSSimon L. B. Nielsen if (t2l < d1) t2h--; t2l -= d1; 595db522d3aSSimon L. B. Nielsen } 596db522d3aSSimon L. B. Nielsen #endif /* !BN_LLONG */ 597db522d3aSSimon L. B. Nielsen } 598db522d3aSSimon L. B. Nielsen #endif /* !BN_DIV3W */ 599db522d3aSSimon L. B. Nielsen 600db522d3aSSimon L. B. Nielsen l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); 601db522d3aSSimon L. B. Nielsen tmp->d[div_n]=l0; 602db522d3aSSimon L. B. Nielsen wnum.d--; 603db522d3aSSimon L. B. Nielsen /* ingore top values of the bignums just sub the two 604db522d3aSSimon L. B. Nielsen * BN_ULONG arrays with bn_sub_words */ 605db522d3aSSimon L. B. Nielsen if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n+1)) 606db522d3aSSimon L. B. Nielsen { 607db522d3aSSimon L. B. Nielsen /* Note: As we have considered only the leading 608db522d3aSSimon L. B. Nielsen * two BN_ULONGs in the calculation of q, sdiv * q 609db522d3aSSimon L. B. Nielsen * might be greater than wnum (but then (q-1) * sdiv 610db522d3aSSimon L. B. Nielsen * is less or equal than wnum) 611db522d3aSSimon L. B. Nielsen */ 612db522d3aSSimon L. B. Nielsen q--; 613db522d3aSSimon L. B. Nielsen if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) 614db522d3aSSimon L. B. Nielsen /* we can't have an overflow here (assuming 615db522d3aSSimon L. B. Nielsen * that q != 0, but if q == 0 then tmp is 616db522d3aSSimon L. B. Nielsen * zero anyway) */ 617db522d3aSSimon L. B. Nielsen (*wnump)++; 618db522d3aSSimon L. B. Nielsen } 619db522d3aSSimon L. B. Nielsen /* store part of the result */ 620db522d3aSSimon L. B. Nielsen *resp = q; 621db522d3aSSimon L. B. Nielsen } 622db522d3aSSimon L. B. Nielsen bn_correct_top(snum); 623db522d3aSSimon L. B. Nielsen if (rm != NULL) 624db522d3aSSimon L. B. Nielsen { 625db522d3aSSimon L. B. Nielsen /* Keep a copy of the neg flag in num because if rm==num 626db522d3aSSimon L. B. Nielsen * BN_rshift() will overwrite it. 627db522d3aSSimon L. B. Nielsen */ 628db522d3aSSimon L. B. Nielsen int neg = num->neg; 629db522d3aSSimon L. B. Nielsen BN_rshift(rm,snum,norm_shift); 630db522d3aSSimon L. B. Nielsen if (!BN_is_zero(rm)) 631db522d3aSSimon L. B. Nielsen rm->neg = neg; 632db522d3aSSimon L. B. Nielsen bn_check_top(rm); 633db522d3aSSimon L. B. Nielsen } 634db522d3aSSimon L. B. Nielsen bn_correct_top(res); 635db522d3aSSimon L. B. Nielsen BN_CTX_end(ctx); 636db522d3aSSimon L. B. Nielsen return(1); 637db522d3aSSimon L. B. Nielsen err: 638db522d3aSSimon L. B. Nielsen bn_check_top(rm); 639db522d3aSSimon L. B. Nielsen BN_CTX_end(ctx); 640db522d3aSSimon L. B. Nielsen return(0); 641db522d3aSSimon L. B. Nielsen } 642db522d3aSSimon L. B. Nielsen 64374664626SKris Kennaway #endif 644