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/mem.h>
     60 #include <openssl/type_check.h>
     61 
     62 #include "internal.h"
     63 #include "../../internal.h"
     64 
     65 
     66 int BN_ucmp(const BIGNUM *a, const BIGNUM *b) {
     67   int a_width = bn_minimal_width(a);
     68   int b_width = bn_minimal_width(b);
     69   int i = a_width - b_width;
     70   if (i != 0) {
     71     return i;
     72   }
     73 
     74   const BN_ULONG *ap = a->d;
     75   const BN_ULONG *bp = b->d;
     76   for (i = a_width - 1; i >= 0; i--) {
     77     BN_ULONG t1 = ap[i];
     78     BN_ULONG t2 = bp[i];
     79     if (t1 != t2) {
     80       return (t1 > t2) ? 1 : -1;
     81     }
     82   }
     83 
     84   return 0;
     85 }
     86 
     87 int BN_cmp(const BIGNUM *a, const BIGNUM *b) {
     88   int i;
     89   int gt, lt;
     90   BN_ULONG t1, t2;
     91 
     92   if ((a == NULL) || (b == NULL)) {
     93     if (a != NULL) {
     94       return -1;
     95     } else if (b != NULL) {
     96       return 1;
     97     } else {
     98       return 0;
     99     }
    100   }
    101 
    102   if (a->neg != b->neg) {
    103     if (a->neg) {
    104       return -1;
    105     }
    106     return 1;
    107   }
    108   if (a->neg == 0) {
    109     gt = 1;
    110     lt = -1;
    111   } else {
    112     gt = -1;
    113     lt = 1;
    114   }
    115 
    116   int a_width = bn_minimal_width(a);
    117   int b_width = bn_minimal_width(b);
    118   if (a_width > b_width) {
    119     return gt;
    120   }
    121   if (a_width < b_width) {
    122     return lt;
    123   }
    124 
    125   for (i = a_width - 1; i >= 0; i--) {
    126     t1 = a->d[i];
    127     t2 = b->d[i];
    128     if (t1 > t2) {
    129       return gt;
    130     } if (t1 < t2) {
    131       return lt;
    132     }
    133   }
    134 
    135   return 0;
    136 }
    137 
    138 int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n) {
    139   int i;
    140   BN_ULONG aa, bb;
    141 
    142   aa = a[n - 1];
    143   bb = b[n - 1];
    144   if (aa != bb) {
    145     return (aa > bb) ? 1 : -1;
    146   }
    147 
    148   for (i = n - 2; i >= 0; i--) {
    149     aa = a[i];
    150     bb = b[i];
    151     if (aa != bb) {
    152       return (aa > bb) ? 1 : -1;
    153     }
    154   }
    155   return 0;
    156 }
    157 
    158 int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) {
    159   int n, i;
    160   n = cl - 1;
    161 
    162   if (dl < 0) {
    163     for (i = dl; i < 0; i++) {
    164       if (b[n - i] != 0) {
    165         return -1;  // a < b
    166       }
    167     }
    168   }
    169   if (dl > 0) {
    170     for (i = dl; i > 0; i--) {
    171       if (a[n + i] != 0) {
    172         return 1;  // a > b
    173       }
    174     }
    175   }
    176 
    177   return bn_cmp_words(a, b, cl);
    178 }
    179 
    180 static int bn_less_than_words_impl(const BN_ULONG *a, size_t a_len,
    181                                    const BN_ULONG *b, size_t b_len) {
    182   OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
    183                          crypto_word_t_too_small);
    184   int ret = 0;
    185   // Process the common words in little-endian order.
    186   size_t min = a_len < b_len ? a_len : b_len;
    187   for (size_t i = 0; i < min; i++) {
    188     crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
    189     crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
    190     ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0));
    191   }
    192 
    193   // If |a| or |b| has non-zero words beyond |min|, they take precedence.
    194   if (a_len < b_len) {
    195     crypto_word_t mask = 0;
    196     for (size_t i = a_len; i < b_len; i++) {
    197       mask |= b[i];
    198     }
    199     ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, 1);
    200   } else if (b_len < a_len) {
    201     crypto_word_t mask = 0;
    202     for (size_t i = b_len; i < a_len; i++) {
    203       mask |= a[i];
    204     }
    205     ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, 0);
    206   }
    207 
    208   return ret;
    209 }
    210 
    211 int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) {
    212   return bn_less_than_words_impl(a, len, b, len);
    213 }
    214 
    215 int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) {
    216   switch (bn_minimal_width(bn)) {
    217     case 1:
    218       return bn->d[0] == w;
    219     case 0:
    220       return w == 0;
    221     default:
    222       return 0;
    223   }
    224 }
    225 
    226 int BN_cmp_word(const BIGNUM *a, BN_ULONG b) {
    227   BIGNUM b_bn;
    228   BN_init(&b_bn);
    229 
    230   b_bn.d = &b;
    231   b_bn.top = b > 0;
    232   b_bn.dmax = 1;
    233   b_bn.flags = BN_FLG_STATIC_DATA;
    234   return BN_cmp(a, &b_bn);
    235 }
    236 
    237 int BN_is_zero(const BIGNUM *bn) {
    238   return bn_minimal_width(bn) == 0;
    239 }
    240 
    241 int BN_is_one(const BIGNUM *bn) {
    242   return bn->neg == 0 && BN_abs_is_word(bn, 1);
    243 }
    244 
    245 int BN_is_word(const BIGNUM *bn, BN_ULONG w) {
    246   return BN_abs_is_word(bn, w) && (w == 0 || bn->neg == 0);
    247 }
    248 
    249 int BN_is_odd(const BIGNUM *bn) {
    250   return bn->top > 0 && (bn->d[0] & 1) == 1;
    251 }
    252 
    253 int BN_is_pow2(const BIGNUM *bn) {
    254   int width = bn_minimal_width(bn);
    255   if (width == 0 || bn->neg) {
    256     return 0;
    257   }
    258 
    259   for (int i = 0; i < width - 1; i++) {
    260     if (bn->d[i] != 0) {
    261       return 0;
    262     }
    263   }
    264 
    265   return 0 == (bn->d[width-1] & (bn->d[width-1] - 1));
    266 }
    267 
    268 int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) {
    269   BN_ULONG mask = 0;
    270   // If |a| or |b| has more words than the other, all those words must be zero.
    271   for (int i = a->top; i < b->top; i++) {
    272     mask |= b->d[i];
    273   }
    274   for (int i = b->top; i < a->top; i++) {
    275     mask |= a->d[i];
    276   }
    277   // Common words must match.
    278   int min = a->top < b->top ? a->top : b->top;
    279   for (int i = 0; i < min; i++) {
    280     mask |= (a->d[i] ^ b->d[i]);
    281   }
    282   // The sign bit must match.
    283   mask |= (a->neg ^ b->neg);
    284   return mask == 0;
    285 }
    286 
    287 int BN_less_than_consttime(const BIGNUM *a, const BIGNUM *b) {
    288   // We do not attempt to process the sign bit in constant time. Negative
    289   // |BIGNUM|s should never occur in crypto, only calculators.
    290   if (a->neg && !b->neg) {
    291     return 1;
    292   }
    293   if (b->neg && !a->neg) {
    294     return 0;
    295   }
    296   if (a->neg && b->neg) {
    297     const BIGNUM *tmp = a;
    298     a = b;
    299     b = tmp;
    300   }
    301   return bn_less_than_words_impl(a->d, a->top, b->d, b->top);
    302 }
    303