Home | History | Annotate | Download | only in bn
      1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      2  * All rights reserved.
      3  *
      4  * This package is an SSL implementation written
      5  * by Eric Young (eay (at) cryptsoft.com).
      6  * The implementation was written so as to conform with Netscapes SSL.
      7  *
      8  * This library is free for commercial and non-commercial use as long as
      9  * the following conditions are aheared to.  The following conditions
     10  * apply to all code found in this distribution, be it the RC4, RSA,
     11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     12  * included with this distribution is covered by the same copyright terms
     13  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     14  *
     15  * Copyright remains Eric Young's, and as such any Copyright notices in
     16  * the code are not to be removed.
     17  * If this package is used in a product, Eric Young should be given attribution
     18  * as the author of the parts of the library used.
     19  * This can be in the form of a textual message at program startup or
     20  * in documentation (online or textual) provided with the package.
     21  *
     22  * Redistribution and use in source and binary forms, with or without
     23  * modification, are permitted provided that the following conditions
     24  * are met:
     25  * 1. Redistributions of source code must retain the copyright
     26  *    notice, this list of conditions and the following disclaimer.
     27  * 2. Redistributions in binary form must reproduce the above copyright
     28  *    notice, this list of conditions and the following disclaimer in the
     29  *    documentation and/or other materials provided with the distribution.
     30  * 3. All advertising materials mentioning features or use of this software
     31  *    must display the following acknowledgement:
     32  *    "This product includes cryptographic software written by
     33  *     Eric Young (eay (at) cryptsoft.com)"
     34  *    The word 'cryptographic' can be left out if the rouines from the library
     35  *    being used are not cryptographic related :-).
     36  * 4. If you include any Windows specific code (or a derivative thereof) from
     37  *    the apps directory (application code) you must include an acknowledgement:
     38  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     39  *
     40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     50  * SUCH DAMAGE.
     51  *
     52  * The licence and distribution terms for any publically available version or
     53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     54  * copied and put under another distribution licence
     55  * [including the GNU Public Licence.] */
     56 
     57 #include <openssl/bn.h>
     58 
     59 #include <openssl/err.h>
     60 #include <openssl/mem.h>
     61 
     62 #include "internal.h"
     63 
     64 
     65 int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
     66   const BIGNUM *tmp;
     67   int a_neg = a->neg, ret;
     68 
     69   /*  a +  b	a+b
     70    *  a + -b	a-b
     71    * -a +  b	b-a
     72    * -a + -b	-(a+b)
     73    */
     74   if (a_neg ^ b->neg) {
     75     /* only one is negative */
     76     if (a_neg) {
     77       tmp = a;
     78       a = b;
     79       b = tmp;
     80     }
     81 
     82     /* we are now a - b */
     83     if (BN_ucmp(a, b) < 0) {
     84       if (!BN_usub(r, b, a)) {
     85         return 0;
     86       }
     87       r->neg = 1;
     88     } else {
     89       if (!BN_usub(r, a, b)) {
     90         return 0;
     91       }
     92       r->neg = 0;
     93     }
     94     return 1;
     95   }
     96 
     97   ret = BN_uadd(r, a, b);
     98   r->neg = a_neg;
     99   return ret;
    100 }
    101 
    102 int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    103   int max, min, dif;
    104   BN_ULONG *ap, *bp, *rp, carry, t1, t2;
    105   const BIGNUM *tmp;
    106 
    107   if (a->top < b->top) {
    108     tmp = a;
    109     a = b;
    110     b = tmp;
    111   }
    112   max = a->top;
    113   min = b->top;
    114   dif = max - min;
    115 
    116   if (bn_wexpand(r, max + 1) == NULL) {
    117     return 0;
    118   }
    119 
    120   r->top = max;
    121 
    122   ap = a->d;
    123   bp = b->d;
    124   rp = r->d;
    125 
    126   carry = bn_add_words(rp, ap, bp, min);
    127   rp += min;
    128   ap += min;
    129   bp += min;
    130 
    131   if (carry) {
    132     while (dif) {
    133       dif--;
    134       t1 = *(ap++);
    135       t2 = (t1 + 1) & BN_MASK2;
    136       *(rp++) = t2;
    137       if (t2) {
    138         carry = 0;
    139         break;
    140       }
    141     }
    142     if (carry) {
    143       /* carry != 0 => dif == 0 */
    144       *rp = 1;
    145       r->top++;
    146     }
    147   }
    148 
    149   if (dif && rp != ap) {
    150     while (dif--) {
    151       /* copy remaining words if ap != rp */
    152       *(rp++) = *(ap++);
    153     }
    154   }
    155 
    156   r->neg = 0;
    157   return 1;
    158 }
    159 
    160 int BN_add_word(BIGNUM *a, BN_ULONG w) {
    161   BN_ULONG l;
    162   int i;
    163 
    164   w &= BN_MASK2;
    165 
    166   /* degenerate case: w is zero */
    167   if (!w) {
    168     return 1;
    169   }
    170 
    171   /* degenerate case: a is zero */
    172   if (BN_is_zero(a)) {
    173     return BN_set_word(a, w);
    174   }
    175 
    176   /* handle 'a' when negative */
    177   if (a->neg) {
    178     a->neg = 0;
    179     i = BN_sub_word(a, w);
    180     if (!BN_is_zero(a)) {
    181       a->neg = !(a->neg);
    182     }
    183     return i;
    184   }
    185 
    186   for (i = 0; w != 0 && i < a->top; i++) {
    187     a->d[i] = l = (a->d[i] + w) & BN_MASK2;
    188     w = (w > l) ? 1 : 0;
    189   }
    190 
    191   if (w && i == a->top) {
    192     if (bn_wexpand(a, a->top + 1) == NULL) {
    193       return 0;
    194     }
    195     a->top++;
    196     a->d[i] = w;
    197   }
    198 
    199   return 1;
    200 }
    201 
    202 int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    203   int max;
    204   int add = 0, neg = 0;
    205   const BIGNUM *tmp;
    206 
    207   /*  a -  b	a-b
    208    *  a - -b	a+b
    209    * -a -  b	-(a+b)
    210    * -a - -b	b-a
    211    */
    212   if (a->neg) {
    213     if (b->neg) {
    214       tmp = a;
    215       a = b;
    216       b = tmp;
    217     } else {
    218       add = 1;
    219       neg = 1;
    220     }
    221   } else {
    222     if (b->neg) {
    223       add = 1;
    224       neg = 0;
    225     }
    226   }
    227 
    228   if (add) {
    229     if (!BN_uadd(r, a, b)) {
    230       return 0;
    231     }
    232 
    233     r->neg = neg;
    234     return 1;
    235   }
    236 
    237   /* We are actually doing a - b :-) */
    238 
    239   max = (a->top > b->top) ? a->top : b->top;
    240   if (bn_wexpand(r, max) == NULL) {
    241     return 0;
    242   }
    243 
    244   if (BN_ucmp(a, b) < 0) {
    245     if (!BN_usub(r, b, a)) {
    246       return 0;
    247     }
    248     r->neg = 1;
    249   } else {
    250     if (!BN_usub(r, a, b)) {
    251       return 0;
    252     }
    253     r->neg = 0;
    254   }
    255 
    256   return 1;
    257 }
    258 
    259 int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    260   int max, min, dif;
    261   register BN_ULONG t1, t2, *ap, *bp, *rp;
    262   int i, carry;
    263 
    264   max = a->top;
    265   min = b->top;
    266   dif = max - min;
    267 
    268   if (dif < 0) /* hmm... should not be happening */
    269   {
    270     OPENSSL_PUT_ERROR(BN, BN_usub, BN_R_ARG2_LT_ARG3);
    271     return 0;
    272   }
    273 
    274   if (bn_wexpand(r, max) == NULL) {
    275     return 0;
    276   }
    277 
    278   ap = a->d;
    279   bp = b->d;
    280   rp = r->d;
    281 
    282   carry = 0;
    283   for (i = min; i != 0; i--) {
    284     t1 = *(ap++);
    285     t2 = *(bp++);
    286     if (carry) {
    287       carry = (t1 <= t2);
    288       t1 = (t1 - t2 - 1) & BN_MASK2;
    289     } else {
    290       carry = (t1 < t2);
    291       t1 = (t1 - t2) & BN_MASK2;
    292     }
    293     *(rp++) = t1 & BN_MASK2;
    294   }
    295 
    296   if (carry) /* subtracted */
    297   {
    298     if (!dif) {
    299       /* error: a < b */
    300       return 0;
    301     }
    302 
    303     while (dif) {
    304       dif--;
    305       t1 = *(ap++);
    306       t2 = (t1 - 1) & BN_MASK2;
    307       *(rp++) = t2;
    308       if (t1) {
    309         break;
    310       }
    311     }
    312   }
    313 
    314   if (rp != ap) {
    315     for (;;) {
    316       if (!dif--) {
    317         break;
    318       }
    319       rp[0] = ap[0];
    320       if (!dif--) {
    321         break;
    322       }
    323       rp[1] = ap[1];
    324       if (!dif--) {
    325         break;
    326       }
    327       rp[2] = ap[2];
    328       if (!dif--) {
    329         break;
    330       }
    331       rp[3] = ap[3];
    332       rp += 4;
    333       ap += 4;
    334     }
    335   }
    336 
    337   r->top = max;
    338   r->neg = 0;
    339   bn_correct_top(r);
    340 
    341   return 1;
    342 }
    343 
    344 int BN_sub_word(BIGNUM *a, BN_ULONG w) {
    345   int i;
    346 
    347   w &= BN_MASK2;
    348 
    349   /* degenerate case: w is zero */
    350   if (!w) {
    351     return 1;
    352   }
    353 
    354   /* degenerate case: a is zero */
    355   if (BN_is_zero(a)) {
    356     i = BN_set_word(a, w);
    357     if (i != 0) {
    358       BN_set_negative(a, 1);
    359     }
    360     return i;
    361   }
    362 
    363   /* handle 'a' when negative */
    364   if (a->neg) {
    365     a->neg = 0;
    366     i = BN_add_word(a, w);
    367     a->neg = 1;
    368     return i;
    369   }
    370 
    371   if ((a->top == 1) && (a->d[0] < w)) {
    372     a->d[0] = w - a->d[0];
    373     a->neg = 1;
    374     return 1;
    375   }
    376 
    377   i = 0;
    378   for (;;) {
    379     if (a->d[i] >= w) {
    380       a->d[i] -= w;
    381       break;
    382     } else {
    383       a->d[i] = (a->d[i] - w) & BN_MASK2;
    384       i++;
    385       w = 1;
    386     }
    387   }
    388 
    389   if ((a->d[i] == 0) && (i == (a->top - 1))) {
    390     a->top--;
    391   }
    392 
    393   return 1;
    394 }
    395