There's a slight possibility that a is 0 in BN_sub_word(), and might
[openssl.git] / crypto / bn / bn_word.c
index b61ddd95cebd836b673b3654028f38f18d29000d..f3bdde969cc376a9344b9d58c6d8c6a97766bcd6 100644 (file)
@@ -1,5 +1,5 @@
 /* crypto/bn/bn_word.c */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
  * This package is an SSL implementation written
@@ -60,9 +60,7 @@
 #include "cryptlib.h"
 #include "bn_lcl.h"
 
-BN_ULONG BN_mod_word(a, w)
-BIGNUM *a;
-unsigned long w;
+BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w)
        {
 #ifndef BN_LLONG
        BN_ULONG ret=0;
@@ -71,11 +69,12 @@ unsigned long w;
 #endif
        int i;
 
+       w&=BN_MASK2;
        for (i=a->top-1; i>=0; i--)
                {
 #ifndef BN_LLONG
-               ret=((ret<<BN_BITS4)|((a->d[i]>>BN_BITS4)&BN_MASK2l))%(int)w;
-               ret=((ret<<BN_BITS4)|(a->d[i]&BN_MASK2l))%(int)w;
+               ret=((ret<<BN_BITS4)|((a->d[i]>>BN_BITS4)&BN_MASK2l))%w;
+               ret=((ret<<BN_BITS4)|(a->d[i]&BN_MASK2l))%w;
 #else
                ret=(BN_ULLONG)(((ret<<(BN_ULLONG)BN_BITS2)|a->d[i])%
                        (BN_ULLONG)w);
@@ -84,41 +83,43 @@ unsigned long w;
        return((BN_ULONG)ret);
        }
 
-BN_ULONG BN_div_word(a, w)
-BIGNUM *a;
-unsigned long w;
+BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w)
        {
        BN_ULONG ret;
        int i;
 
        if (a->top == 0) return(0);
        ret=0;
+       w&=BN_MASK2;
        for (i=a->top-1; i>=0; i--)
                {
-#ifndef BN_LLONG
-               ret=((ret<<BN_BITS4)|((a->d[i]>>BN_BITS4)&BN_MASK2l))%(int)w;
-               ret=((ret<<BN_BITS4)|(a->d[i]&BN_MASK2l))%(int)w;
-#else
-               BN_ULLONG ll;
-
-               ll=((BN_ULLONG)ret<<(BN_ULONG)BN_BITS2)|a->d[i];
-               a->d[i]=(BN_ULONG)(ll/w);
-               ret=(BN_ULONG)(ll%w);
-#endif
+               BN_ULONG l,d;
+               
+               l=a->d[i];
+               d=bn_div_words(ret,l,w);
+               ret=(l-((d*w)&BN_MASK2))&BN_MASK2;
+               a->d[i]=d;
                }
-       if (a->d[a->top-1] == 0)
+       if ((a->top > 0) && (a->d[a->top-1] == 0))
                a->top--;
        return(ret);
        }
 
-int BN_add_word(a, w)
-BIGNUM *a;
-unsigned long w;
+int BN_add_word(BIGNUM *a, BN_ULONG w)
        {
        BN_ULONG l;
        int i;
 
-       if (bn_expand(a,a->top*BN_BITS2+1) == NULL) return(0);
+       if (a->neg)
+               {
+               a->neg=0;
+               i=BN_sub_word(a,w);
+               if (!BN_is_zero(a))
+                       a->neg=!(a->neg);
+               return(i);
+               }
+       w&=BN_MASK2;
+       if (bn_wexpand(a,a->top+1) == NULL) return(0);
        i=0;
        for (;;)
                {
@@ -135,21 +136,59 @@ unsigned long w;
        return(1);
        }
 
-#ifdef undef
-BN_ULONG *BN_mod_inverse_word(a)
-BN_ULONG a;
+int BN_sub_word(BIGNUM *a, BN_ULONG w)
        {
-       BN_ULONG A,B,X,Y,M,D,R,RET,T;
-       int sign,hight=1;
+       int i;
 
-       X=0;
-       Y=1;
-       A=0;
-       B=a;
-       sign=1;
+       if (BN_is_zero(a) || a->neg)
+               {
+               a->neg=0;
+               i=BN_add_word(a,w);
+               a->neg=1;
+               return(i);
+               }
 
-       while (B != 0)
+       w&=BN_MASK2;
+       if ((a->top == 1) && (a->d[0] < w))
                {
+               a->d[0]=w-a->d[0];
+               a->neg=1;
+               return(1);
+               }
+       i=0;
+       for (;;)
+               {
+               if (a->d[i] >= w)
+                       {
+                       a->d[i]-=w;
+                       break;
+                       }
+               else
+                       {
+                       a->d[i]=(a->d[i]-w)&BN_MASK2;
+                       i++;
+                       w=1;
+                       }
+               }
+       if ((a->d[i] == 0) && (i == (a->top-1)))
+               a->top--;
+       return(1);
+       }
 
-#endif
+int BN_mul_word(BIGNUM *a, BN_ULONG w)
+       {
+       BN_ULONG ll;
+
+       w&=BN_MASK2;
+       if (a->top)
+               {
+               ll=bn_mul_words(a->d,a->d,a->top,w);
+               if (ll)
+                       {
+                       if (bn_wexpand(a,a->top+1) == NULL) return(0);
+                       a->d[a->top++]=ll;
+                       }
+               }
+       return(1);
+       }