summaryrefslogtreecommitdiff
path: root/crypto/bn/bn_add.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/bn/bn_add.c')
-rw-r--r--crypto/bn/bn_add.c192
1 files changed, 172 insertions, 20 deletions
diff --git a/crypto/bn/bn_add.c b/crypto/bn/bn_add.c
index efb2e312e8..27b781a367 100644
--- a/crypto/bn/bn_add.c
+++ b/crypto/bn/bn_add.c
@@ -66,9 +66,11 @@ BIGNUM *r;
BIGNUM *a;
BIGNUM *b;
{
- int i;
BIGNUM *tmp;
+ bn_check_top(a);
+ bn_check_top(b);
+
/* a + b a+b
* a + -b a-b
* -a + b b-a
@@ -84,14 +86,12 @@ BIGNUM *b;
if (BN_ucmp(a,b) < 0)
{
- if (bn_wexpand(r,b->top) == NULL) return(0);
- bn_qsub(r,b,a);
+ if (!BN_usub(r,b,a)) return(0);
r->neg=1;
}
else
{
- if (bn_wexpand(r,a->top) == NULL) return(0);
- bn_qsub(r,a,b);
+ if (!BN_usub(r,a,b)) return(0);
r->neg=0;
}
return(1);
@@ -102,23 +102,12 @@ BIGNUM *b;
else
r->neg=0;
- i=(a->top > b->top);
-
- if (i)
- {
- if (bn_wexpand(r,a->top+1) == NULL) return(0);
- bn_qadd(r,a,b);
- }
- else
- {
- if (bn_wexpand(r,b->top+1) == NULL) return(0);
- bn_qadd(r,b,a);
- }
+ if (!BN_uadd(r,a,b)) return(0);
return(1);
}
/* unsigned add of b to a, r must be large enough */
-void bn_qadd(r,a,b)
+int BN_uadd(r,a,b)
BIGNUM *r;
BIGNUM *a;
BIGNUM *b;
@@ -126,11 +115,22 @@ BIGNUM *b;
register int i;
int max,min;
BN_ULONG *ap,*bp,*rp,carry,t1;
+ BIGNUM *tmp;
+
+ bn_check_top(a);
+ bn_check_top(b);
+ if (a->top < b->top)
+ { tmp=a; a=b; b=tmp; }
max=a->top;
min=b->top;
+
+ if (bn_wexpand(r,max+1) == NULL)
+ return(0);
+
r->top=max;
+
ap=a->d;
bp=b->d;
rp=r->d;
@@ -160,8 +160,160 @@ BIGNUM *b;
r->top++;
}
}
- for (; i<max; i++)
- *(rp++)= *(ap++);
+ if (rp != ap)
+ {
+ for (; i<max; i++)
+ *(rp++)= *(ap++);
+ }
/* memcpy(rp,ap,sizeof(*ap)*(max-i));*/
+ return(1);
+ }
+
+/* unsigned subtraction of b from a, a must be larger than b. */
+int BN_usub(r, a, b)
+BIGNUM *r;
+BIGNUM *a;
+BIGNUM *b;
+ {
+ int max,min,ret=1;
+ register BN_ULONG t1,t2,*ap,*bp,*rp;
+ int i,carry;
+#if defined(IRIX_CC_BUG) && !defined(LINT)
+ int dummy;
+#endif
+
+ bn_check_top(a);
+ bn_check_top(b);
+
+ if (a->top < b->top) /* hmm... should not be happening */
+ {
+ BNerr(BN_F_BN_USUB,BN_R_ARG2_LT_ARG3);
+ return(0);
+ }
+
+ max=a->top;
+ min=b->top;
+ if (bn_wexpand(r,max) == NULL) return(0);
+
+ ap=a->d;
+ bp=b->d;
+ rp=r->d;
+
+#if 1
+ carry=0;
+ for (i=0; i<min; i++)
+ {
+ t1= *(ap++);
+ t2= *(bp++);
+ if (carry)
+ {
+ carry=(t1 <= t2);
+ t1=(t1-t2-1)&BN_MASK2;
+ }
+ else
+ {
+ carry=(t1 < t2);
+ t1=(t1-t2)&BN_MASK2;
+ }
+#if defined(IRIX_CC_BUG) && !defined(LINT)
+ dummy=t1;
+#endif
+ *(rp++)=t1&BN_MASK2;
+ }
+#else
+ carry=bn_sub_words(rp,ap,bp,min);
+ ap+=min;
+ bp+=min;
+ rp+=min;
+ i=min;
+#endif
+ if (carry) /* subtracted */
+ {
+ while (i < max)
+ {
+ i++;
+ t1= *(ap++);
+ t2=(t1-1)&BN_MASK2;
+ *(rp++)=t2;
+ if (t1 > t2) break;
+ }
+ }
+#if 0
+ memcpy(rp,ap,sizeof(*rp)*(max-i));
+#else
+ if (rp != ap)
+ {
+ for (;;)
+ {
+ if (i++ >= max) break;
+ rp[0]=ap[0];
+ if (i++ >= max) break;
+ rp[1]=ap[1];
+ if (i++ >= max) break;
+ rp[2]=ap[2];
+ if (i++ >= max) break;
+ rp[3]=ap[3];
+ rp+=4;
+ ap+=4;
+ }
+ }
+#endif
+
+ r->top=max;
+ bn_fix_top(r);
+ return(1);
+ }
+
+int BN_sub(r, a, b)
+BIGNUM *r;
+BIGNUM *a;
+BIGNUM *b;
+ {
+ int max;
+ int add=0,neg=0;
+ BIGNUM *tmp;
+
+ bn_check_top(a);
+ bn_check_top(b);
+
+ /* a - b a-b
+ * a - -b a+b
+ * -a - b -(a+b)
+ * -a - -b b-a
+ */
+ if (a->neg)
+ {
+ if (b->neg)
+ { tmp=a; a=b; b=tmp; }
+ else
+ { add=1; neg=1; }
+ }
+ else
+ {
+ if (b->neg) { add=1; neg=0; }
+ }
+
+ if (add)
+ {
+ if (!BN_uadd(r,a,b)) return(0);
+ r->neg=neg;
+ return(1);
+ }
+
+ /* We are actually doing a - b :-) */
+
+ max=(a->top > b->top)?a->top:b->top;
+ if (bn_wexpand(r,max) == NULL) return(0);
+ if (BN_ucmp(a,b) < 0)
+ {
+ if (!BN_usub(r,b,a)) return(0);
+ r->neg=1;
+ }
+ else
+ {
+ if (!BN_usub(r,a,b)) return(0);
+ r->neg=0;
+ }
+ return(1);
}