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   if (a_neg ^ b->neg) {
     76     // only one is negative
     77     if (a_neg) {
     78       tmp = a;
     79       a = b;
     80       b = tmp;
     81     }
     82 
     83     // we are now a - b
     84     if (BN_ucmp(a, b) < 0) {
     85       if (!BN_usub(r, b, a)) {
     86         return 0;
     87       }
     88       r->neg = 1;
     89     } else {
     90       if (!BN_usub(r, a, b)) {
     91         return 0;
     92       }
     93       r->neg = 0;
     94     }
     95     return 1;
     96   }
     97 
     98   ret = BN_uadd(r, a, b);
     99   r->neg = a_neg;
    100   return ret;
    101 }
    102 
    103 int bn_uadd_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    104   // Widths are public, so we normalize to make |a| the larger one.
    105   if (a->width < b->width) {
    106     const BIGNUM *tmp = a;
    107     a = b;
    108     b = tmp;
    109   }
    110 
    111   int max = a->width;
    112   int min = b->width;
    113   if (!bn_wexpand(r, max + 1)) {
    114     return 0;
    115   }
    116   r->width = max + 1;
    117 
    118   BN_ULONG carry = bn_add_words(r->d, a->d, b->d, min);
    119   for (int i = min; i < max; i++) {
    120     // |r| and |a| may alias, so use a temporary.
    121     BN_ULONG tmp = carry + a->d[i];
    122     carry = tmp < a->d[i];
    123     r->d[i] = tmp;
    124   }
    125 
    126   r->d[max] = carry;
    127   return 1;
    128 }
    129 
    130 int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    131   if (!bn_uadd_consttime(r, a, b)) {
    132     return 0;
    133   }
    134   bn_set_minimal_width(r);
    135   return 1;
    136 }
    137 
    138 int BN_add_word(BIGNUM *a, BN_ULONG w) {
    139   BN_ULONG l;
    140   int i;
    141 
    142   // degenerate case: w is zero
    143   if (!w) {
    144     return 1;
    145   }
    146 
    147   // degenerate case: a is zero
    148   if (BN_is_zero(a)) {
    149     return BN_set_word(a, w);
    150   }
    151 
    152   // handle 'a' when negative
    153   if (a->neg) {
    154     a->neg = 0;
    155     i = BN_sub_word(a, w);
    156     if (!BN_is_zero(a)) {
    157       a->neg = !(a->neg);
    158     }
    159     return i;
    160   }
    161 
    162   for (i = 0; w != 0 && i < a->width; i++) {
    163     a->d[i] = l = a->d[i] + w;
    164     w = (w > l) ? 1 : 0;
    165   }
    166 
    167   if (w && i == a->width) {
    168     if (!bn_wexpand(a, a->width + 1)) {
    169       return 0;
    170     }
    171     a->width++;
    172     a->d[i] = w;
    173   }
    174 
    175   return 1;
    176 }
    177 
    178 int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    179   int add = 0, neg = 0;
    180   const BIGNUM *tmp;
    181 
    182   //  a -  b	a-b
    183   //  a - -b	a+b
    184   // -a -  b	-(a+b)
    185   // -a - -b	b-a
    186   if (a->neg) {
    187     if (b->neg) {
    188       tmp = a;
    189       a = b;
    190       b = tmp;
    191     } else {
    192       add = 1;
    193       neg = 1;
    194     }
    195   } else {
    196     if (b->neg) {
    197       add = 1;
    198       neg = 0;
    199     }
    200   }
    201 
    202   if (add) {
    203     if (!BN_uadd(r, a, b)) {
    204       return 0;
    205     }
    206 
    207     r->neg = neg;
    208     return 1;
    209   }
    210 
    211   if (BN_ucmp(a, b) < 0) {
    212     if (!BN_usub(r, b, a)) {
    213       return 0;
    214     }
    215     r->neg = 1;
    216   } else {
    217     if (!BN_usub(r, a, b)) {
    218       return 0;
    219     }
    220     r->neg = 0;
    221   }
    222 
    223   return 1;
    224 }
    225 
    226 int bn_usub_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    227   // |b| may have more words than |a| given non-minimal inputs, but all words
    228   // beyond |a->width| must then be zero.
    229   int b_width = b->width;
    230   if (b_width > a->width) {
    231     if (!bn_fits_in_words(b, a->width)) {
    232       OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3);
    233       return 0;
    234     }
    235     b_width = a->width;
    236   }
    237 
    238   if (!bn_wexpand(r, a->width)) {
    239     return 0;
    240   }
    241 
    242   BN_ULONG borrow = bn_sub_words(r->d, a->d, b->d, b_width);
    243   for (int i = b_width; i < a->width; i++) {
    244     // |r| and |a| may alias, so use a temporary.
    245     BN_ULONG tmp = a->d[i];
    246     r->d[i] = a->d[i] - borrow;
    247     borrow = tmp < r->d[i];
    248   }
    249 
    250   if (borrow) {
    251     OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3);
    252     return 0;
    253   }
    254 
    255   r->width = a->width;
    256   r->neg = 0;
    257   return 1;
    258 }
    259 
    260 int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
    261   if (!bn_usub_consttime(r, a, b)) {
    262     return 0;
    263   }
    264   bn_set_minimal_width(r);
    265   return 1;
    266 }
    267 
    268 int BN_sub_word(BIGNUM *a, BN_ULONG w) {
    269   int i;
    270 
    271   // degenerate case: w is zero
    272   if (!w) {
    273     return 1;
    274   }
    275 
    276   // degenerate case: a is zero
    277   if (BN_is_zero(a)) {
    278     i = BN_set_word(a, w);
    279     if (i != 0) {
    280       BN_set_negative(a, 1);
    281     }
    282     return i;
    283   }
    284 
    285   // handle 'a' when negative
    286   if (a->neg) {
    287     a->neg = 0;
    288     i = BN_add_word(a, w);
    289     a->neg = 1;
    290     return i;
    291   }
    292 
    293   if ((bn_minimal_width(a) == 1) && (a->d[0] < w)) {
    294     a->d[0] = w - a->d[0];
    295     a->neg = 1;
    296     return 1;
    297   }
    298 
    299   i = 0;
    300   for (;;) {
    301     if (a->d[i] >= w) {
    302       a->d[i] -= w;
    303       break;
    304     } else {
    305       a->d[i] -= w;
    306       i++;
    307       w = 1;
    308     }
    309   }
    310 
    311   if ((a->d[i] == 0) && (i == (a->width - 1))) {
    312     a->width--;
    313   }
    314 
    315   return 1;
    316 }
    317