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 <string.h>
     60 
     61 #include <openssl/err.h>
     62 #include <openssl/mem.h>
     63 
     64 #include "internal.h"
     65 
     66 
     67 int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
     68   const BIGNUM *tmp;
     69   int a_neg = a->neg, ret;
     70 
     71   /*  a +  b	a+b
     72    *  a + -b	a-b
     73    * -a +  b	b-a
     74    * -a + -b	-(a+b)
     75    */
     76   if (a_neg ^ b->neg) {
     77     /* only one is negative */
     78     if (a_neg) {
     79       tmp = a;
     80       a = b;
     81       b = tmp;
     82     }
     83 
     84     /* we are now a - b */
     85     if (BN_ucmp(a, b) < 0) {
     86       if (!BN_usub(r, b, a)) {
     87         return 0;
     88       }
     89       r->neg = 1;
     90     } else {
     91       if (!BN_usub(r, a, b)) {
     92         return 0;
     93       }
     94       r->neg = 0;
     95     }
     96     return 1;
     97   }
     98 
     99   ret = BN_uadd(r, a, b);
    100   r->neg = a_neg;
    101   return ret;
    102 }
    103 
    104 int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    105   int max, min, dif;
    106   BN_ULONG *ap, *bp, *rp, carry, t1, t2;
    107   const BIGNUM *tmp;
    108 
    109   if (a->top < b->top) {
    110     tmp = a;
    111     a = b;
    112     b = tmp;
    113   }
    114   max = a->top;
    115   min = b->top;
    116   dif = max - min;
    117 
    118   if (bn_wexpand(r, max + 1) == NULL) {
    119     return 0;
    120   }
    121 
    122   r->top = max;
    123 
    124   ap = a->d;
    125   bp = b->d;
    126   rp = r->d;
    127 
    128   carry = bn_add_words(rp, ap, bp, min);
    129   rp += min;
    130   ap += min;
    131   bp += min;
    132 
    133   if (carry) {
    134     while (dif) {
    135       dif--;
    136       t1 = *(ap++);
    137       t2 = (t1 + 1) & BN_MASK2;
    138       *(rp++) = t2;
    139       if (t2) {
    140         carry = 0;
    141         break;
    142       }
    143     }
    144     if (carry) {
    145       /* carry != 0 => dif == 0 */
    146       *rp = 1;
    147       r->top++;
    148     }
    149   }
    150 
    151   if (dif && rp != ap) {
    152     while (dif--) {
    153       /* copy remaining words if ap != rp */
    154       *(rp++) = *(ap++);
    155     }
    156   }
    157 
    158   r->neg = 0;
    159   return 1;
    160 }
    161 
    162 int BN_add_word(BIGNUM *a, BN_ULONG w) {
    163   BN_ULONG l;
    164   int i;
    165 
    166   w &= BN_MASK2;
    167 
    168   /* degenerate case: w is zero */
    169   if (!w) {
    170     return 1;
    171   }
    172 
    173   /* degenerate case: a is zero */
    174   if (BN_is_zero(a)) {
    175     return BN_set_word(a, w);
    176   }
    177 
    178   /* handle 'a' when negative */
    179   if (a->neg) {
    180     a->neg = 0;
    181     i = BN_sub_word(a, w);
    182     if (!BN_is_zero(a)) {
    183       a->neg = !(a->neg);
    184     }
    185     return i;
    186   }
    187 
    188   for (i = 0; w != 0 && i < a->top; i++) {
    189     a->d[i] = l = (a->d[i] + w) & BN_MASK2;
    190     w = (w > l) ? 1 : 0;
    191   }
    192 
    193   if (w && i == a->top) {
    194     if (bn_wexpand(a, a->top + 1) == NULL) {
    195       return 0;
    196     }
    197     a->top++;
    198     a->d[i] = w;
    199   }
    200 
    201   return 1;
    202 }
    203 
    204 int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    205   int max;
    206   int add = 0, neg = 0;
    207   const BIGNUM *tmp;
    208 
    209   /*  a -  b	a-b
    210    *  a - -b	a+b
    211    * -a -  b	-(a+b)
    212    * -a - -b	b-a
    213    */
    214   if (a->neg) {
    215     if (b->neg) {
    216       tmp = a;
    217       a = b;
    218       b = tmp;
    219     } else {
    220       add = 1;
    221       neg = 1;
    222     }
    223   } else {
    224     if (b->neg) {
    225       add = 1;
    226       neg = 0;
    227     }
    228   }
    229 
    230   if (add) {
    231     if (!BN_uadd(r, a, b)) {
    232       return 0;
    233     }
    234 
    235     r->neg = neg;
    236     return 1;
    237   }
    238 
    239   /* We are actually doing a - b :-) */
    240 
    241   max = (a->top > b->top) ? a->top : b->top;
    242   if (bn_wexpand(r, max) == NULL) {
    243     return 0;
    244   }
    245 
    246   if (BN_ucmp(a, b) < 0) {
    247     if (!BN_usub(r, b, a)) {
    248       return 0;
    249     }
    250     r->neg = 1;
    251   } else {
    252     if (!BN_usub(r, a, b)) {
    253       return 0;
    254     }
    255     r->neg = 0;
    256   }
    257 
    258   return 1;
    259 }
    260 
    261 int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    262   int max, min, dif;
    263   register BN_ULONG t1, t2, *ap, *bp, *rp;
    264   int i, carry;
    265 
    266   max = a->top;
    267   min = b->top;
    268   dif = max - min;
    269 
    270   if (dif < 0) /* hmm... should not be happening */
    271   {
    272     OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3);
    273     return 0;
    274   }
    275 
    276   if (bn_wexpand(r, max) == NULL) {
    277     return 0;
    278   }
    279 
    280   ap = a->d;
    281   bp = b->d;
    282   rp = r->d;
    283 
    284   carry = 0;
    285   for (i = min; i != 0; i--) {
    286     t1 = *(ap++);
    287     t2 = *(bp++);
    288     if (carry) {
    289       carry = (t1 <= t2);
    290       t1 = (t1 - t2 - 1) & BN_MASK2;
    291     } else {
    292       carry = (t1 < t2);
    293       t1 = (t1 - t2) & BN_MASK2;
    294     }
    295     *(rp++) = t1 & BN_MASK2;
    296   }
    297 
    298   if (carry) /* subtracted */
    299   {
    300     if (!dif) {
    301       /* error: a < b */
    302       return 0;
    303     }
    304 
    305     while (dif) {
    306       dif--;
    307       t1 = *(ap++);
    308       t2 = (t1 - 1) & BN_MASK2;
    309       *(rp++) = t2;
    310       if (t1) {
    311         break;
    312       }
    313     }
    314   }
    315 
    316   if (dif > 0 && rp != ap) {
    317     memcpy(rp, ap, sizeof(*rp) * dif);
    318   }
    319 
    320   r->top = max;
    321   r->neg = 0;
    322   bn_correct_top(r);
    323 
    324   return 1;
    325 }
    326 
    327 int BN_sub_word(BIGNUM *a, BN_ULONG w) {
    328   int i;
    329 
    330   w &= BN_MASK2;
    331 
    332   /* degenerate case: w is zero */
    333   if (!w) {
    334     return 1;
    335   }
    336 
    337   /* degenerate case: a is zero */
    338   if (BN_is_zero(a)) {
    339     i = BN_set_word(a, w);
    340     if (i != 0) {
    341       BN_set_negative(a, 1);
    342     }
    343     return i;
    344   }
    345 
    346   /* handle 'a' when negative */
    347   if (a->neg) {
    348     a->neg = 0;
    349     i = BN_add_word(a, w);
    350     a->neg = 1;
    351     return i;
    352   }
    353 
    354   if ((a->top == 1) && (a->d[0] < w)) {
    355     a->d[0] = w - a->d[0];
    356     a->neg = 1;
    357     return 1;
    358   }
    359 
    360   i = 0;
    361   for (;;) {
    362     if (a->d[i] >= w) {
    363       a->d[i] -= w;
    364       break;
    365     } else {
    366       a->d[i] = (a->d[i] - w) & BN_MASK2;
    367       i++;
    368       w = 1;
    369     }
    370   }
    371 
    372   if ((a->d[i] == 0) && (i == (a->top - 1))) {
    373     a->top--;
    374   }
    375 
    376   return 1;
    377 }
    378