sl@0: /* crypto/bn/bn_mul.c */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: sl@0: #ifndef BN_DEBUG sl@0: # undef NDEBUG /* avoid conflicting definitions */ sl@0: # define NDEBUG sl@0: #endif sl@0: sl@0: #include sl@0: #include sl@0: #include "cryptlib.h" sl@0: #include "bn_lcl.h" sl@0: sl@0: #if defined(OPENSSL_NO_ASM) || !defined(OPENSSL_BN_ASM_PART_WORDS) sl@0: /* Here follows specialised variants of bn_add_words() and sl@0: bn_sub_words(). They have the property performing operations on sl@0: arrays of different sizes. The sizes of those arrays is expressed through sl@0: cl, which is the common length ( basicall, min(len(a),len(b)) ), and dl, sl@0: which is the delta between the two lengths, calculated as len(a)-len(b). sl@0: All lengths are the number of BN_ULONGs... For the operations that require sl@0: a result array as parameter, it must have the length cl+abs(dl). sl@0: These functions should probably end up in bn_asm.c as soon as there are sl@0: assembler counterparts for the systems that use assembler files. */ sl@0: sl@0: EXPORT_C BN_ULONG bn_sub_part_words(BN_ULONG *r, sl@0: const BN_ULONG *a, const BN_ULONG *b, sl@0: int cl, int dl) sl@0: { sl@0: BN_ULONG c, t; sl@0: sl@0: assert(cl >= 0); sl@0: c = bn_sub_words(r, a, b, cl); sl@0: sl@0: if (dl == 0) sl@0: return c; sl@0: sl@0: r += cl; sl@0: a += cl; sl@0: b += cl; sl@0: sl@0: if (dl < 0) sl@0: { sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_sub_part_words %d + %d (dl < 0, c = %d)\n", cl, dl, c); sl@0: #endif sl@0: for (;;) sl@0: { sl@0: t = b[0]; sl@0: r[0] = (0-t-c)&BN_MASK2; sl@0: if (t != 0) c=1; sl@0: if (++dl >= 0) break; sl@0: sl@0: t = b[1]; sl@0: r[1] = (0-t-c)&BN_MASK2; sl@0: if (t != 0) c=1; sl@0: if (++dl >= 0) break; sl@0: sl@0: t = b[2]; sl@0: r[2] = (0-t-c)&BN_MASK2; sl@0: if (t != 0) c=1; sl@0: if (++dl >= 0) break; sl@0: sl@0: t = b[3]; sl@0: r[3] = (0-t-c)&BN_MASK2; sl@0: if (t != 0) c=1; sl@0: if (++dl >= 0) break; sl@0: sl@0: b += 4; sl@0: r += 4; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: int save_dl = dl; sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_sub_part_words %d + %d (dl > 0, c = %d)\n", cl, dl, c); sl@0: #endif sl@0: while(c) sl@0: { sl@0: t = a[0]; sl@0: r[0] = (t-c)&BN_MASK2; sl@0: if (t != 0) c=0; sl@0: if (--dl <= 0) break; sl@0: sl@0: t = a[1]; sl@0: r[1] = (t-c)&BN_MASK2; sl@0: if (t != 0) c=0; sl@0: if (--dl <= 0) break; sl@0: sl@0: t = a[2]; sl@0: r[2] = (t-c)&BN_MASK2; sl@0: if (t != 0) c=0; sl@0: if (--dl <= 0) break; sl@0: sl@0: t = a[3]; sl@0: r[3] = (t-c)&BN_MASK2; sl@0: if (t != 0) c=0; sl@0: if (--dl <= 0) break; sl@0: sl@0: save_dl = dl; sl@0: a += 4; sl@0: r += 4; sl@0: } sl@0: if (dl > 0) sl@0: { sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_sub_part_words %d + %d (dl > 0, c == 0)\n", cl, dl); sl@0: #endif sl@0: if (save_dl > dl) sl@0: { sl@0: switch (save_dl - dl) sl@0: { sl@0: case 1: sl@0: r[1] = a[1]; sl@0: if (--dl <= 0) break; sl@0: case 2: sl@0: r[2] = a[2]; sl@0: if (--dl <= 0) break; sl@0: case 3: sl@0: r[3] = a[3]; sl@0: if (--dl <= 0) break; sl@0: } sl@0: a += 4; sl@0: r += 4; sl@0: } sl@0: } sl@0: if (dl > 0) sl@0: { sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_sub_part_words %d + %d (dl > 0, copy)\n", cl, dl); sl@0: #endif sl@0: for(;;) sl@0: { sl@0: r[0] = a[0]; sl@0: if (--dl <= 0) break; sl@0: r[1] = a[1]; sl@0: if (--dl <= 0) break; sl@0: r[2] = a[2]; sl@0: if (--dl <= 0) break; sl@0: r[3] = a[3]; sl@0: if (--dl <= 0) break; sl@0: sl@0: a += 4; sl@0: r += 4; sl@0: } sl@0: } sl@0: } sl@0: return c; sl@0: } sl@0: #endif sl@0: sl@0: EXPORT_C BN_ULONG bn_add_part_words(BN_ULONG *r, sl@0: const BN_ULONG *a, const BN_ULONG *b, sl@0: int cl, int dl) sl@0: { sl@0: BN_ULONG c, l, t; sl@0: sl@0: assert(cl >= 0); sl@0: c = bn_add_words(r, a, b, cl); sl@0: sl@0: if (dl == 0) sl@0: return c; sl@0: sl@0: r += cl; sl@0: a += cl; sl@0: b += cl; sl@0: sl@0: if (dl < 0) sl@0: { sl@0: int save_dl = dl; sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_add_part_words %d + %d (dl < 0, c = %d)\n", cl, dl, c); sl@0: #endif sl@0: while (c) sl@0: { sl@0: l=(c+b[0])&BN_MASK2; sl@0: c=(l < c); sl@0: r[0]=l; sl@0: if (++dl >= 0) break; sl@0: sl@0: l=(c+b[1])&BN_MASK2; sl@0: c=(l < c); sl@0: r[1]=l; sl@0: if (++dl >= 0) break; sl@0: sl@0: l=(c+b[2])&BN_MASK2; sl@0: c=(l < c); sl@0: r[2]=l; sl@0: if (++dl >= 0) break; sl@0: sl@0: l=(c+b[3])&BN_MASK2; sl@0: c=(l < c); sl@0: r[3]=l; sl@0: if (++dl >= 0) break; sl@0: sl@0: save_dl = dl; sl@0: b+=4; sl@0: r+=4; sl@0: } sl@0: if (dl < 0) sl@0: { sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_add_part_words %d + %d (dl < 0, c == 0)\n", cl, dl); sl@0: #endif sl@0: if (save_dl < dl) sl@0: { sl@0: switch (dl - save_dl) sl@0: { sl@0: case 1: sl@0: r[1] = b[1]; sl@0: if (++dl >= 0) break; sl@0: case 2: sl@0: r[2] = b[2]; sl@0: if (++dl >= 0) break; sl@0: case 3: sl@0: r[3] = b[3]; sl@0: if (++dl >= 0) break; sl@0: } sl@0: b += 4; sl@0: r += 4; sl@0: } sl@0: } sl@0: if (dl < 0) sl@0: { sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_add_part_words %d + %d (dl < 0, copy)\n", cl, dl); sl@0: #endif sl@0: for(;;) sl@0: { sl@0: r[0] = b[0]; sl@0: if (++dl >= 0) break; sl@0: r[1] = b[1]; sl@0: if (++dl >= 0) break; sl@0: r[2] = b[2]; sl@0: if (++dl >= 0) break; sl@0: r[3] = b[3]; sl@0: if (++dl >= 0) break; sl@0: sl@0: b += 4; sl@0: r += 4; sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: int save_dl = dl; sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_add_part_words %d + %d (dl > 0)\n", cl, dl); sl@0: #endif sl@0: while (c) sl@0: { sl@0: t=(a[0]+c)&BN_MASK2; sl@0: c=(t < c); sl@0: r[0]=t; sl@0: if (--dl <= 0) break; sl@0: sl@0: t=(a[1]+c)&BN_MASK2; sl@0: c=(t < c); sl@0: r[1]=t; sl@0: if (--dl <= 0) break; sl@0: sl@0: t=(a[2]+c)&BN_MASK2; sl@0: c=(t < c); sl@0: r[2]=t; sl@0: if (--dl <= 0) break; sl@0: sl@0: t=(a[3]+c)&BN_MASK2; sl@0: c=(t < c); sl@0: r[3]=t; sl@0: if (--dl <= 0) break; sl@0: sl@0: save_dl = dl; sl@0: a+=4; sl@0: r+=4; sl@0: } sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_add_part_words %d + %d (dl > 0, c == 0)\n", cl, dl); sl@0: #endif sl@0: if (dl > 0) sl@0: { sl@0: if (save_dl > dl) sl@0: { sl@0: switch (save_dl - dl) sl@0: { sl@0: case 1: sl@0: r[1] = a[1]; sl@0: if (--dl <= 0) break; sl@0: case 2: sl@0: r[2] = a[2]; sl@0: if (--dl <= 0) break; sl@0: case 3: sl@0: r[3] = a[3]; sl@0: if (--dl <= 0) break; sl@0: } sl@0: a += 4; sl@0: r += 4; sl@0: } sl@0: } sl@0: if (dl > 0) sl@0: { sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr, " bn_add_part_words %d + %d (dl > 0, copy)\n", cl, dl); sl@0: #endif sl@0: for(;;) sl@0: { sl@0: r[0] = a[0]; sl@0: if (--dl <= 0) break; sl@0: r[1] = a[1]; sl@0: if (--dl <= 0) break; sl@0: r[2] = a[2]; sl@0: if (--dl <= 0) break; sl@0: r[3] = a[3]; sl@0: if (--dl <= 0) break; sl@0: sl@0: a += 4; sl@0: r += 4; sl@0: } sl@0: } sl@0: } sl@0: return c; sl@0: } sl@0: sl@0: #ifdef BN_RECURSION sl@0: /* Karatsuba recursive multiplication algorithm sl@0: * (cf. Knuth, The Art of Computer Programming, Vol. 2) */ sl@0: sl@0: /* r is 2*n2 words in size, sl@0: * a and b are both n2 words in size. sl@0: * n2 must be a power of 2. sl@0: * We multiply and return the result. sl@0: * t must be 2*n2 words in size sl@0: * We calculate sl@0: * a[0]*b[0] sl@0: * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0]) sl@0: * a[1]*b[1] sl@0: */ sl@0: EXPORT_C void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, sl@0: int dna, int dnb, BN_ULONG *t) sl@0: { sl@0: int n=n2/2,c1,c2; sl@0: int tna=n+dna, tnb=n+dnb; sl@0: unsigned int neg,zero; sl@0: BN_ULONG ln,lo,*p; sl@0: sl@0: # ifdef BN_COUNT sl@0: fprintf(stderr," bn_mul_recursive %d * %d\n",n2,n2); sl@0: # endif sl@0: # ifdef BN_MUL_COMBA sl@0: # if 0 sl@0: if (n2 == 4) sl@0: { sl@0: bn_mul_comba4(r,a,b); sl@0: return; sl@0: } sl@0: # endif sl@0: /* Only call bn_mul_comba 8 if n2 == 8 and the sl@0: * two arrays are complete [steve] sl@0: */ sl@0: if (n2 == 8 && dna == 0 && dnb == 0) sl@0: { sl@0: bn_mul_comba8(r,a,b); sl@0: return; sl@0: } sl@0: # endif /* BN_MUL_COMBA */ sl@0: /* Else do normal multiply */ sl@0: if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) sl@0: { sl@0: bn_mul_normal(r,a,n2+dna,b,n2+dnb); sl@0: if ((dna + dnb) < 0) sl@0: memset(&r[2*n2 + dna + dnb], 0, sl@0: sizeof(BN_ULONG) * -(dna + dnb)); sl@0: return; sl@0: } sl@0: /* r=(a[0]-a[1])*(b[1]-b[0]) */ sl@0: c1=bn_cmp_part_words(a,&(a[n]),tna,n-tna); sl@0: c2=bn_cmp_part_words(&(b[n]),b,tnb,tnb-n); sl@0: zero=neg=0; sl@0: switch (c1*3+c2) sl@0: { sl@0: case -4: sl@0: bn_sub_part_words(t, &(a[n]),a, tna,tna-n); /* - */ sl@0: bn_sub_part_words(&(t[n]),b, &(b[n]),tnb,n-tnb); /* - */ sl@0: break; sl@0: case -3: sl@0: zero=1; sl@0: break; sl@0: case -2: sl@0: bn_sub_part_words(t, &(a[n]),a, tna,tna-n); /* - */ sl@0: bn_sub_part_words(&(t[n]),&(b[n]),b, tnb,tnb-n); /* + */ sl@0: neg=1; sl@0: break; sl@0: case -1: sl@0: case 0: sl@0: case 1: sl@0: zero=1; sl@0: break; sl@0: case 2: sl@0: bn_sub_part_words(t, a, &(a[n]),tna,n-tna); /* + */ sl@0: bn_sub_part_words(&(t[n]),b, &(b[n]),tnb,n-tnb); /* - */ sl@0: neg=1; sl@0: break; sl@0: case 3: sl@0: zero=1; sl@0: break; sl@0: case 4: sl@0: bn_sub_part_words(t, a, &(a[n]),tna,n-tna); sl@0: bn_sub_part_words(&(t[n]),&(b[n]),b, tnb,tnb-n); sl@0: break; sl@0: } sl@0: sl@0: # ifdef BN_MUL_COMBA sl@0: if (n == 4 && dna == 0 && dnb == 0) /* XXX: bn_mul_comba4 could take sl@0: extra args to do this well */ sl@0: { sl@0: if (!zero) sl@0: bn_mul_comba4(&(t[n2]),t,&(t[n])); sl@0: else sl@0: memset(&(t[n2]),0,8*sizeof(BN_ULONG)); sl@0: sl@0: bn_mul_comba4(r,a,b); sl@0: bn_mul_comba4(&(r[n2]),&(a[n]),&(b[n])); sl@0: } sl@0: else if (n == 8 && dna == 0 && dnb == 0) /* XXX: bn_mul_comba8 could sl@0: take extra args to do this sl@0: well */ sl@0: { sl@0: if (!zero) sl@0: bn_mul_comba8(&(t[n2]),t,&(t[n])); sl@0: else sl@0: memset(&(t[n2]),0,16*sizeof(BN_ULONG)); sl@0: sl@0: bn_mul_comba8(r,a,b); sl@0: bn_mul_comba8(&(r[n2]),&(a[n]),&(b[n])); sl@0: } sl@0: else sl@0: # endif /* BN_MUL_COMBA */ sl@0: { sl@0: p= &(t[n2*2]); sl@0: if (!zero) sl@0: bn_mul_recursive(&(t[n2]),t,&(t[n]),n,0,0,p); sl@0: else sl@0: memset(&(t[n2]),0,n2*sizeof(BN_ULONG)); sl@0: bn_mul_recursive(r,a,b,n,0,0,p); sl@0: bn_mul_recursive(&(r[n2]),&(a[n]),&(b[n]),n,dna,dnb,p); sl@0: } sl@0: sl@0: /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign sl@0: * r[10] holds (a[0]*b[0]) sl@0: * r[32] holds (b[1]*b[1]) sl@0: */ sl@0: sl@0: c1=(int)(bn_add_words(t,r,&(r[n2]),n2)); sl@0: sl@0: if (neg) /* if t[32] is negative */ sl@0: { sl@0: c1-=(int)(bn_sub_words(&(t[n2]),t,&(t[n2]),n2)); sl@0: } sl@0: else sl@0: { sl@0: /* Might have a carry */ sl@0: c1+=(int)(bn_add_words(&(t[n2]),&(t[n2]),t,n2)); sl@0: } sl@0: sl@0: /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) sl@0: * r[10] holds (a[0]*b[0]) sl@0: * r[32] holds (b[1]*b[1]) sl@0: * c1 holds the carry bits sl@0: */ sl@0: c1+=(int)(bn_add_words(&(r[n]),&(r[n]),&(t[n2]),n2)); sl@0: if (c1) sl@0: { sl@0: p= &(r[n+n2]); sl@0: lo= *p; sl@0: ln=(lo+c1)&BN_MASK2; sl@0: *p=ln; sl@0: sl@0: /* The overflow will stop before we over write sl@0: * words we should not overwrite */ sl@0: if (ln < (BN_ULONG)c1) sl@0: { sl@0: do { sl@0: p++; sl@0: lo= *p; sl@0: ln=(lo+1)&BN_MASK2; sl@0: *p=ln; sl@0: } while (ln == 0); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /* n+tn is the word length sl@0: * t needs to be n*4 is size, as does r */ sl@0: EXPORT_C void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n, sl@0: int tna, int tnb, BN_ULONG *t) sl@0: { sl@0: int i,j,n2=n*2; sl@0: int c1,c2,neg,zero; sl@0: BN_ULONG ln,lo,*p; sl@0: sl@0: # ifdef BN_COUNT sl@0: fprintf(stderr," bn_mul_part_recursive (%d+%d) * (%d+%d)\n", sl@0: tna, n, tnb, n); sl@0: # endif sl@0: if (n < 8) sl@0: { sl@0: bn_mul_normal(r,a,n+tna,b,n+tnb); sl@0: return; sl@0: } sl@0: sl@0: /* r=(a[0]-a[1])*(b[1]-b[0]) */ sl@0: c1=bn_cmp_part_words(a,&(a[n]),tna,n-tna); sl@0: c2=bn_cmp_part_words(&(b[n]),b,tnb,tnb-n); sl@0: zero=neg=0; sl@0: switch (c1*3+c2) sl@0: { sl@0: case -4: sl@0: bn_sub_part_words(t, &(a[n]),a, tna,tna-n); /* - */ sl@0: bn_sub_part_words(&(t[n]),b, &(b[n]),tnb,n-tnb); /* - */ sl@0: break; sl@0: case -3: sl@0: zero=1; sl@0: /* break; */ sl@0: case -2: sl@0: bn_sub_part_words(t, &(a[n]),a, tna,tna-n); /* - */ sl@0: bn_sub_part_words(&(t[n]),&(b[n]),b, tnb,tnb-n); /* + */ sl@0: neg=1; sl@0: break; sl@0: case -1: sl@0: case 0: sl@0: case 1: sl@0: zero=1; sl@0: /* break; */ sl@0: case 2: sl@0: bn_sub_part_words(t, a, &(a[n]),tna,n-tna); /* + */ sl@0: bn_sub_part_words(&(t[n]),b, &(b[n]),tnb,n-tnb); /* - */ sl@0: neg=1; sl@0: break; sl@0: case 3: sl@0: zero=1; sl@0: /* break; */ sl@0: case 4: sl@0: bn_sub_part_words(t, a, &(a[n]),tna,n-tna); sl@0: bn_sub_part_words(&(t[n]),&(b[n]),b, tnb,tnb-n); sl@0: break; sl@0: } sl@0: /* The zero case isn't yet implemented here. The speedup sl@0: would probably be negligible. */ sl@0: # if 0 sl@0: if (n == 4) sl@0: { sl@0: bn_mul_comba4(&(t[n2]),t,&(t[n])); sl@0: bn_mul_comba4(r,a,b); sl@0: bn_mul_normal(&(r[n2]),&(a[n]),tn,&(b[n]),tn); sl@0: memset(&(r[n2+tn*2]),0,sizeof(BN_ULONG)*(n2-tn*2)); sl@0: } sl@0: else sl@0: # endif sl@0: if (n == 8) sl@0: { sl@0: bn_mul_comba8(&(t[n2]),t,&(t[n])); sl@0: bn_mul_comba8(r,a,b); sl@0: bn_mul_normal(&(r[n2]),&(a[n]),tna,&(b[n]),tnb); sl@0: memset(&(r[n2+tna+tnb]),0,sizeof(BN_ULONG)*(n2-tna-tnb)); sl@0: } sl@0: else sl@0: { sl@0: p= &(t[n2*2]); sl@0: bn_mul_recursive(&(t[n2]),t,&(t[n]),n,0,0,p); sl@0: bn_mul_recursive(r,a,b,n,0,0,p); sl@0: i=n/2; sl@0: /* If there is only a bottom half to the number, sl@0: * just do it */ sl@0: if (tna > tnb) sl@0: j = tna - i; sl@0: else sl@0: j = tnb - i; sl@0: if (j == 0) sl@0: { sl@0: bn_mul_recursive(&(r[n2]),&(a[n]),&(b[n]), sl@0: i,tna-i,tnb-i,p); sl@0: memset(&(r[n2+i*2]),0,sizeof(BN_ULONG)*(n2-i*2)); sl@0: } sl@0: else if (j > 0) /* eg, n == 16, i == 8 and tn == 11 */ sl@0: { sl@0: bn_mul_part_recursive(&(r[n2]),&(a[n]),&(b[n]), sl@0: i,tna-i,tnb-i,p); sl@0: memset(&(r[n2+tna+tnb]),0, sl@0: sizeof(BN_ULONG)*(n2-tna-tnb)); sl@0: } sl@0: else /* (j < 0) eg, n == 16, i == 8 and tn == 5 */ sl@0: { sl@0: memset(&(r[n2]),0,sizeof(BN_ULONG)*n2); sl@0: if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL sl@0: && tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) sl@0: { sl@0: bn_mul_normal(&(r[n2]),&(a[n]),tna,&(b[n]),tnb); sl@0: } sl@0: else sl@0: { sl@0: for (;;) sl@0: { sl@0: i/=2; sl@0: if (i <= tna && tna == tnb) sl@0: { sl@0: bn_mul_recursive(&(r[n2]), sl@0: &(a[n]),&(b[n]), sl@0: i,tna-i,tnb-i,p); sl@0: break; sl@0: } sl@0: else if (i < tna || i < tnb) sl@0: { sl@0: bn_mul_part_recursive(&(r[n2]), sl@0: &(a[n]),&(b[n]), sl@0: i,tna-i,tnb-i,p); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign sl@0: * r[10] holds (a[0]*b[0]) sl@0: * r[32] holds (b[1]*b[1]) sl@0: */ sl@0: sl@0: c1=(int)(bn_add_words(t,r,&(r[n2]),n2)); sl@0: sl@0: if (neg) /* if t[32] is negative */ sl@0: { sl@0: c1-=(int)(bn_sub_words(&(t[n2]),t,&(t[n2]),n2)); sl@0: } sl@0: else sl@0: { sl@0: /* Might have a carry */ sl@0: c1+=(int)(bn_add_words(&(t[n2]),&(t[n2]),t,n2)); sl@0: } sl@0: sl@0: /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) sl@0: * r[10] holds (a[0]*b[0]) sl@0: * r[32] holds (b[1]*b[1]) sl@0: * c1 holds the carry bits sl@0: */ sl@0: c1+=(int)(bn_add_words(&(r[n]),&(r[n]),&(t[n2]),n2)); sl@0: if (c1) sl@0: { sl@0: p= &(r[n+n2]); sl@0: lo= *p; sl@0: ln=(lo+c1)&BN_MASK2; sl@0: *p=ln; sl@0: sl@0: /* The overflow will stop before we over write sl@0: * words we should not overwrite */ sl@0: if (ln < (BN_ULONG)c1) sl@0: { sl@0: do { sl@0: p++; sl@0: lo= *p; sl@0: ln=(lo+1)&BN_MASK2; sl@0: *p=ln; sl@0: } while (ln == 0); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /* a and b must be the same size, which is n2. sl@0: * r needs to be n2 words and t needs to be n2*2 sl@0: */ sl@0: EXPORT_C void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, sl@0: BN_ULONG *t) sl@0: { sl@0: int n=n2/2; sl@0: sl@0: # ifdef BN_COUNT sl@0: fprintf(stderr," bn_mul_low_recursive %d * %d\n",n2,n2); sl@0: # endif sl@0: sl@0: bn_mul_recursive(r,a,b,n,0,0,&(t[0])); sl@0: if (n >= BN_MUL_LOW_RECURSIVE_SIZE_NORMAL) sl@0: { sl@0: bn_mul_low_recursive(&(t[0]),&(a[0]),&(b[n]),n,&(t[n2])); sl@0: bn_add_words(&(r[n]),&(r[n]),&(t[0]),n); sl@0: bn_mul_low_recursive(&(t[0]),&(a[n]),&(b[0]),n,&(t[n2])); sl@0: bn_add_words(&(r[n]),&(r[n]),&(t[0]),n); sl@0: } sl@0: else sl@0: { sl@0: bn_mul_low_normal(&(t[0]),&(a[0]),&(b[n]),n); sl@0: bn_mul_low_normal(&(t[n]),&(a[n]),&(b[0]),n); sl@0: bn_add_words(&(r[n]),&(r[n]),&(t[0]),n); sl@0: bn_add_words(&(r[n]),&(r[n]),&(t[n]),n); sl@0: } sl@0: } sl@0: sl@0: /* a and b must be the same size, which is n2. sl@0: * r needs to be n2 words and t needs to be n2*2 sl@0: * l is the low words of the output. sl@0: * t needs to be n2*3 sl@0: */ sl@0: EXPORT_C void bn_mul_high(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, BN_ULONG *l, int n2, sl@0: BN_ULONG *t) sl@0: { sl@0: int i,n; sl@0: int c1,c2; sl@0: int neg,oneg,zero; sl@0: BN_ULONG ll,lc,*lp,*mp; sl@0: sl@0: # ifdef BN_COUNT sl@0: fprintf(stderr," bn_mul_high %d * %d\n",n2,n2); sl@0: # endif sl@0: n=n2/2; sl@0: sl@0: /* Calculate (al-ah)*(bh-bl) */ sl@0: neg=zero=0; sl@0: c1=bn_cmp_words(&(a[0]),&(a[n]),n); sl@0: c2=bn_cmp_words(&(b[n]),&(b[0]),n); sl@0: switch (c1*3+c2) sl@0: { sl@0: case -4: sl@0: bn_sub_words(&(r[0]),&(a[n]),&(a[0]),n); sl@0: bn_sub_words(&(r[n]),&(b[0]),&(b[n]),n); sl@0: break; sl@0: case -3: sl@0: zero=1; sl@0: break; sl@0: case -2: sl@0: bn_sub_words(&(r[0]),&(a[n]),&(a[0]),n); sl@0: bn_sub_words(&(r[n]),&(b[n]),&(b[0]),n); sl@0: neg=1; sl@0: break; sl@0: case -1: sl@0: case 0: sl@0: case 1: sl@0: zero=1; sl@0: break; sl@0: case 2: sl@0: bn_sub_words(&(r[0]),&(a[0]),&(a[n]),n); sl@0: bn_sub_words(&(r[n]),&(b[0]),&(b[n]),n); sl@0: neg=1; sl@0: break; sl@0: case 3: sl@0: zero=1; sl@0: break; sl@0: case 4: sl@0: bn_sub_words(&(r[0]),&(a[0]),&(a[n]),n); sl@0: bn_sub_words(&(r[n]),&(b[n]),&(b[0]),n); sl@0: break; sl@0: } sl@0: sl@0: oneg=neg; sl@0: /* t[10] = (a[0]-a[1])*(b[1]-b[0]) */ sl@0: /* r[10] = (a[1]*b[1]) */ sl@0: # ifdef BN_MUL_COMBA sl@0: if (n == 8) sl@0: { sl@0: bn_mul_comba8(&(t[0]),&(r[0]),&(r[n])); sl@0: bn_mul_comba8(r,&(a[n]),&(b[n])); sl@0: } sl@0: else sl@0: # endif sl@0: { sl@0: bn_mul_recursive(&(t[0]),&(r[0]),&(r[n]),n,0,0,&(t[n2])); sl@0: bn_mul_recursive(r,&(a[n]),&(b[n]),n,0,0,&(t[n2])); sl@0: } sl@0: sl@0: /* s0 == low(al*bl) sl@0: * s1 == low(ah*bh)+low((al-ah)*(bh-bl))+low(al*bl)+high(al*bl) sl@0: * We know s0 and s1 so the only unknown is high(al*bl) sl@0: * high(al*bl) == s1 - low(ah*bh+s0+(al-ah)*(bh-bl)) sl@0: * high(al*bl) == s1 - (r[0]+l[0]+t[0]) sl@0: */ sl@0: if (l != NULL) sl@0: { sl@0: lp= &(t[n2+n]); sl@0: c1=(int)(bn_add_words(lp,&(r[0]),&(l[0]),n)); sl@0: } sl@0: else sl@0: { sl@0: c1=0; sl@0: lp= &(r[0]); sl@0: } sl@0: sl@0: if (neg) sl@0: neg=(int)(bn_sub_words(&(t[n2]),lp,&(t[0]),n)); sl@0: else sl@0: { sl@0: bn_add_words(&(t[n2]),lp,&(t[0]),n); sl@0: neg=0; sl@0: } sl@0: sl@0: if (l != NULL) sl@0: { sl@0: bn_sub_words(&(t[n2+n]),&(l[n]),&(t[n2]),n); sl@0: } sl@0: else sl@0: { sl@0: lp= &(t[n2+n]); sl@0: mp= &(t[n2]); sl@0: for (i=0; i 0) sl@0: { sl@0: lc=c1; sl@0: do { sl@0: ll=(r[i]+lc)&BN_MASK2; sl@0: r[i++]=ll; sl@0: lc=(lc > ll); sl@0: } while (lc); sl@0: } sl@0: else sl@0: { sl@0: lc= -c1; sl@0: do { sl@0: ll=r[i]; sl@0: r[i++]=(ll-lc)&BN_MASK2; sl@0: lc=(lc > ll); sl@0: } while (lc); sl@0: } sl@0: } sl@0: if (c2 != 0) /* Add starting at r[1] */ sl@0: { sl@0: i=n; sl@0: if (c2 > 0) sl@0: { sl@0: lc=c2; sl@0: do { sl@0: ll=(r[i]+lc)&BN_MASK2; sl@0: r[i++]=ll; sl@0: lc=(lc > ll); sl@0: } while (lc); sl@0: } sl@0: else sl@0: { sl@0: lc= -c2; sl@0: do { sl@0: ll=r[i]; sl@0: r[i++]=(ll-lc)&BN_MASK2; sl@0: lc=(lc > ll); sl@0: } while (lc); sl@0: } sl@0: } sl@0: } sl@0: #endif /* BN_RECURSION */ sl@0: sl@0: EXPORT_C int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) sl@0: { sl@0: int ret=0; sl@0: int top,al,bl; sl@0: BIGNUM *rr; sl@0: #if defined(BN_MUL_COMBA) || defined(BN_RECURSION) sl@0: int i; sl@0: #endif sl@0: #ifdef BN_RECURSION sl@0: BIGNUM *t=NULL; sl@0: int j=0,k; sl@0: #endif sl@0: sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr,"BN_mul %d * %d\n",a->top,b->top); sl@0: #endif sl@0: sl@0: bn_check_top(a); sl@0: bn_check_top(b); sl@0: bn_check_top(r); sl@0: sl@0: al=a->top; sl@0: bl=b->top; sl@0: sl@0: if ((al == 0) || (bl == 0)) sl@0: { sl@0: BN_zero(r); sl@0: return(1); sl@0: } sl@0: top=al+bl; sl@0: sl@0: BN_CTX_start(ctx); sl@0: if ((r == a) || (r == b)) sl@0: { sl@0: if ((rr = BN_CTX_get(ctx)) == NULL) goto err; sl@0: } sl@0: else sl@0: rr = r; sl@0: rr->neg=a->neg^b->neg; sl@0: sl@0: #if defined(BN_MUL_COMBA) || defined(BN_RECURSION) sl@0: i = al-bl; sl@0: #endif sl@0: #ifdef BN_MUL_COMBA sl@0: if (i == 0) sl@0: { sl@0: # if 0 sl@0: if (al == 4) sl@0: { sl@0: if (bn_wexpand(rr,8) == NULL) goto err; sl@0: rr->top=8; sl@0: bn_mul_comba4(rr->d,a->d,b->d); sl@0: goto end; sl@0: } sl@0: # endif sl@0: if (al == 8) sl@0: { sl@0: if (bn_wexpand(rr,16) == NULL) goto err; sl@0: rr->top=16; sl@0: bn_mul_comba8(rr->d,a->d,b->d); sl@0: goto end; sl@0: } sl@0: } sl@0: #endif /* BN_MUL_COMBA */ sl@0: #ifdef BN_RECURSION sl@0: if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) sl@0: { sl@0: if (i >= -1 && i <= 1) sl@0: { sl@0: int sav_j =0; sl@0: /* Find out the power of two lower or equal sl@0: to the longest of the two numbers */ sl@0: if (i >= 0) sl@0: { sl@0: j = BN_num_bits_word((BN_ULONG)al); sl@0: } sl@0: if (i == -1) sl@0: { sl@0: j = BN_num_bits_word((BN_ULONG)bl); sl@0: } sl@0: sav_j = j; sl@0: j = 1<<(j-1); sl@0: assert(j <= al || j <= bl); sl@0: k = j+j; sl@0: t = BN_CTX_get(ctx); sl@0: if (al > j || bl > j) sl@0: { sl@0: bn_wexpand(t,k*4); sl@0: bn_wexpand(rr,k*4); sl@0: bn_mul_part_recursive(rr->d,a->d,b->d, sl@0: j,al-j,bl-j,t->d); sl@0: } sl@0: else /* al <= j || bl <= j */ sl@0: { sl@0: bn_wexpand(t,k*2); sl@0: bn_wexpand(rr,k*2); sl@0: bn_mul_recursive(rr->d,a->d,b->d, sl@0: j,al-j,bl-j,t->d); sl@0: } sl@0: rr->top=top; sl@0: goto end; sl@0: } sl@0: #if 0 sl@0: if (i == 1 && !BN_get_flags(b,BN_FLG_STATIC_DATA)) sl@0: { sl@0: BIGNUM *tmp_bn = (BIGNUM *)b; sl@0: if (bn_wexpand(tmp_bn,al) == NULL) goto err; sl@0: tmp_bn->d[bl]=0; sl@0: bl++; sl@0: i--; sl@0: } sl@0: else if (i == -1 && !BN_get_flags(a,BN_FLG_STATIC_DATA)) sl@0: { sl@0: BIGNUM *tmp_bn = (BIGNUM *)a; sl@0: if (bn_wexpand(tmp_bn,bl) == NULL) goto err; sl@0: tmp_bn->d[al]=0; sl@0: al++; sl@0: i++; sl@0: } sl@0: if (i == 0) sl@0: { sl@0: /* symmetric and > 4 */ sl@0: /* 16 or larger */ sl@0: j=BN_num_bits_word((BN_ULONG)al); sl@0: j=1<<(j-1); sl@0: k=j+j; sl@0: t = BN_CTX_get(ctx); sl@0: if (al == j) /* exact multiple */ sl@0: { sl@0: if (bn_wexpand(t,k*2) == NULL) goto err; sl@0: if (bn_wexpand(rr,k*2) == NULL) goto err; sl@0: bn_mul_recursive(rr->d,a->d,b->d,al,t->d); sl@0: } sl@0: else sl@0: { sl@0: if (bn_wexpand(t,k*4) == NULL) goto err; sl@0: if (bn_wexpand(rr,k*4) == NULL) goto err; sl@0: bn_mul_part_recursive(rr->d,a->d,b->d,al-j,j,t->d); sl@0: } sl@0: rr->top=top; sl@0: goto end; sl@0: } sl@0: #endif sl@0: } sl@0: #endif /* BN_RECURSION */ sl@0: if (bn_wexpand(rr,top) == NULL) goto err; sl@0: rr->top=top; sl@0: bn_mul_normal(rr->d,a->d,al,b->d,bl); sl@0: sl@0: #if defined(BN_MUL_COMBA) || defined(BN_RECURSION) sl@0: end: sl@0: #endif sl@0: bn_correct_top(rr); sl@0: if (r != rr) BN_copy(r,rr); sl@0: ret=1; sl@0: err: sl@0: bn_check_top(r); sl@0: BN_CTX_end(ctx); sl@0: return(ret); sl@0: } sl@0: sl@0: EXPORT_C void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb) sl@0: { sl@0: BN_ULONG *rr; sl@0: sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr," bn_mul_normal %d * %d\n",na,nb); sl@0: #endif sl@0: sl@0: if (na < nb) sl@0: { sl@0: int itmp; sl@0: BN_ULONG *ltmp; sl@0: sl@0: itmp=na; na=nb; nb=itmp; sl@0: ltmp=a; a=b; b=ltmp; sl@0: sl@0: } sl@0: rr= &(r[na]); sl@0: if (nb <= 0) sl@0: { sl@0: (void)bn_mul_words(r,a,na,0); sl@0: return; sl@0: } sl@0: else sl@0: rr[0]=bn_mul_words(r,a,na,b[0]); sl@0: sl@0: for (;;) sl@0: { sl@0: if (--nb <= 0) return; sl@0: rr[1]=bn_mul_add_words(&(r[1]),a,na,b[1]); sl@0: if (--nb <= 0) return; sl@0: rr[2]=bn_mul_add_words(&(r[2]),a,na,b[2]); sl@0: if (--nb <= 0) return; sl@0: rr[3]=bn_mul_add_words(&(r[3]),a,na,b[3]); sl@0: if (--nb <= 0) return; sl@0: rr[4]=bn_mul_add_words(&(r[4]),a,na,b[4]); sl@0: rr+=4; sl@0: r+=4; sl@0: b+=4; sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n) sl@0: { sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr," bn_mul_low_normal %d * %d\n",n,n); sl@0: #endif sl@0: bn_mul_words(r,a,n,b[0]); sl@0: sl@0: for (;;) sl@0: { sl@0: if (--n <= 0) return; sl@0: bn_mul_add_words(&(r[1]),a,n,b[1]); sl@0: if (--n <= 0) return; sl@0: bn_mul_add_words(&(r[2]),a,n,b[2]); sl@0: if (--n <= 0) return; sl@0: bn_mul_add_words(&(r[3]),a,n,b[3]); sl@0: if (--n <= 0) return; sl@0: bn_mul_add_words(&(r[4]),a,n,b[4]); sl@0: r+=4; sl@0: b+=4; sl@0: } sl@0: }