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 /* ====================================================================
     58  * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
     59  *
     60  * Redistribution and use in source and binary forms, with or without
     61  * modification, are permitted provided that the following conditions
     62  * are met:
     63  *
     64  * 1. Redistributions of source code must retain the above copyright
     65  *    notice, this list of conditions and the following disclaimer.
     66  *
     67  * 2. Redistributions in binary form must reproduce the above copyright
     68  *    notice, this list of conditions and the following disclaimer in
     69  *    the documentation and/or other materials provided with the
     70  *    distribution.
     71  *
     72  * 3. All advertising materials mentioning features or use of this
     73  *    software must display the following acknowledgment:
     74  *    "This product includes software developed by the OpenSSL Project
     75  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
     76  *
     77  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
     78  *    endorse or promote products derived from this software without
     79  *    prior written permission. For written permission, please contact
     80  *    openssl-core (at) openssl.org.
     81  *
     82  * 5. Products derived from this software may not be called "OpenSSL"
     83  *    nor may "OpenSSL" appear in their names without prior written
     84  *    permission of the OpenSSL Project.
     85  *
     86  * 6. Redistributions of any form whatsoever must retain the following
     87  *    acknowledgment:
     88  *    "This product includes software developed by the OpenSSL Project
     89  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
     90  *
     91  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
     92  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     93  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     94  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
     95  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     96  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     97  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     98  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     99  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    100  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    101  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    102  * OF THE POSSIBILITY OF SUCH DAMAGE.
    103  * ====================================================================
    104  *
    105  * This product includes cryptographic software written by Eric Young
    106  * (eay (at) cryptsoft.com).  This product includes software written by Tim
    107  * Hudson (tjh (at) cryptsoft.com). */
    108 
    109 #include <openssl/bn.h>
    110 
    111 #include <assert.h>
    112 #include <string.h>
    113 
    114 #include <openssl/err.h>
    115 #include <openssl/mem.h>
    116 #include <openssl/thread.h>
    117 
    118 #include "internal.h"
    119 #include "../internal.h"
    120 
    121 
    122 #if !defined(OPENSSL_NO_ASM) &&                         \
    123     (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
    124      defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
    125 #define OPENSSL_BN_ASM_MONT
    126 #endif
    127 
    128 static int bn_mod_mul_montgomery_fallback(BIGNUM *r, const BIGNUM *a,
    129                                           const BIGNUM *b,
    130                                           const BN_MONT_CTX *mont, BN_CTX *ctx);
    131 
    132 
    133 BN_MONT_CTX *BN_MONT_CTX_new(void) {
    134   BN_MONT_CTX *ret = OPENSSL_malloc(sizeof(BN_MONT_CTX));
    135 
    136   if (ret == NULL) {
    137     return NULL;
    138   }
    139 
    140   OPENSSL_memset(ret, 0, sizeof(BN_MONT_CTX));
    141   BN_init(&ret->RR);
    142   BN_init(&ret->N);
    143 
    144   return ret;
    145 }
    146 
    147 void BN_MONT_CTX_free(BN_MONT_CTX *mont) {
    148   if (mont == NULL) {
    149     return;
    150   }
    151 
    152   BN_free(&mont->RR);
    153   BN_free(&mont->N);
    154   OPENSSL_free(mont);
    155 }
    156 
    157 BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, const BN_MONT_CTX *from) {
    158   if (to == from) {
    159     return to;
    160   }
    161 
    162   if (!BN_copy(&to->RR, &from->RR) ||
    163       !BN_copy(&to->N, &from->N)) {
    164     return NULL;
    165   }
    166   to->n0[0] = from->n0[0];
    167   to->n0[1] = from->n0[1];
    168   return to;
    169 }
    170 
    171 OPENSSL_COMPILE_ASSERT(BN_MONT_CTX_N0_LIMBS == 1 || BN_MONT_CTX_N0_LIMBS == 2,
    172                        BN_MONT_CTX_N0_LIMBS_VALUE_INVALID);
    173 OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) * BN_MONT_CTX_N0_LIMBS ==
    174                        sizeof(uint64_t), BN_MONT_CTX_set_64_bit_mismatch);
    175 
    176 int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
    177   if (BN_is_zero(mod)) {
    178     OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
    179     return 0;
    180   }
    181   if (!BN_is_odd(mod)) {
    182     OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
    183     return 0;
    184   }
    185   if (BN_is_negative(mod)) {
    186     OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
    187     return 0;
    188   }
    189 
    190   /* Save the modulus. */
    191   if (!BN_copy(&mont->N, mod)) {
    192     OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
    193     return 0;
    194   }
    195 
    196   /* Find n0 such that n0 * N == -1 (mod r).
    197    *
    198    * Only certain BN_BITS2<=32 platforms actually make use of n0[1]. For the
    199    * others, we could use a shorter R value and use faster |BN_ULONG|-based
    200    * math instead of |uint64_t|-based math, which would be double-precision.
    201    * However, currently only the assembler files know which is which. */
    202   uint64_t n0 = bn_mont_n0(mod);
    203   mont->n0[0] = (BN_ULONG)n0;
    204 #if BN_MONT_CTX_N0_LIMBS == 2
    205   mont->n0[1] = (BN_ULONG)(n0 >> BN_BITS2);
    206 #else
    207   mont->n0[1] = 0;
    208 #endif
    209 
    210   /* Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS such that R
    211    * > mod. Even though the assembly on some 32-bit platforms works with 64-bit
    212    * values, using |BN_BITS2| here, rather than |BN_MONT_CTX_N0_LIMBS *
    213    * BN_BITS2|, is correct because R**2 will still be a multiple of the latter
    214    * as |BN_MONT_CTX_N0_LIMBS| is either one or two.
    215    *
    216    * XXX: This is not constant time with respect to |mont->N|, but it should
    217    * be. */
    218   unsigned lgBigR = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
    219   if (!bn_mod_exp_base_2_vartime(&mont->RR, lgBigR * 2, &mont->N)) {
    220     return 0;
    221   }
    222 
    223   return 1;
    224 }
    225 
    226 int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
    227                            const BIGNUM *mod, BN_CTX *bn_ctx) {
    228   CRYPTO_MUTEX_lock_read(lock);
    229   BN_MONT_CTX *ctx = *pmont;
    230   CRYPTO_MUTEX_unlock_read(lock);
    231 
    232   if (ctx) {
    233     return 1;
    234   }
    235 
    236   CRYPTO_MUTEX_lock_write(lock);
    237   ctx = *pmont;
    238   if (ctx) {
    239     goto out;
    240   }
    241 
    242   ctx = BN_MONT_CTX_new();
    243   if (ctx == NULL) {
    244     goto out;
    245   }
    246   if (!BN_MONT_CTX_set(ctx, mod, bn_ctx)) {
    247     BN_MONT_CTX_free(ctx);
    248     ctx = NULL;
    249     goto out;
    250   }
    251   *pmont = ctx;
    252 
    253 out:
    254   CRYPTO_MUTEX_unlock_write(lock);
    255   return ctx != NULL;
    256 }
    257 
    258 int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
    259                      BN_CTX *ctx) {
    260   return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx);
    261 }
    262 
    263 static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
    264                                    const BN_MONT_CTX *mont) {
    265   BN_ULONG *ap, *np, *rp, n0, v, carry;
    266   int nl, max, i;
    267 
    268   const BIGNUM *n = &mont->N;
    269   nl = n->top;
    270   if (nl == 0) {
    271     ret->top = 0;
    272     return 1;
    273   }
    274 
    275   max = (2 * nl); /* carry is stored separately */
    276   if (bn_wexpand(r, max) == NULL) {
    277     return 0;
    278   }
    279 
    280   r->neg ^= n->neg;
    281   np = n->d;
    282   rp = r->d;
    283 
    284   /* clear the top words of T */
    285   if (max > r->top) {
    286     OPENSSL_memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG));
    287   }
    288 
    289   r->top = max;
    290   n0 = mont->n0[0];
    291 
    292   for (carry = 0, i = 0; i < nl; i++, rp++) {
    293     v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2);
    294     v = (v + carry + rp[nl]) & BN_MASK2;
    295     carry |= (v != rp[nl]);
    296     carry &= (v <= rp[nl]);
    297     rp[nl] = v;
    298   }
    299 
    300   if (bn_wexpand(ret, nl) == NULL) {
    301     return 0;
    302   }
    303   ret->top = nl;
    304   ret->neg = r->neg;
    305 
    306   rp = ret->d;
    307   ap = &(r->d[nl]);
    308 
    309   {
    310     BN_ULONG *nrp;
    311     uintptr_t m;
    312 
    313     v = bn_sub_words(rp, ap, np, nl) - carry;
    314     /* if subtraction result is real, then trick unconditional memcpy below to
    315      * perform in-place "refresh" instead of actual copy. */
    316     m = (0u - (uintptr_t)v);
    317     nrp = (BN_ULONG *)(((uintptr_t)rp & ~m) | ((uintptr_t)ap & m));
    318 
    319     for (i = 0, nl -= 4; i < nl; i += 4) {
    320       BN_ULONG t1, t2, t3, t4;
    321 
    322       t1 = nrp[i + 0];
    323       t2 = nrp[i + 1];
    324       t3 = nrp[i + 2];
    325       ap[i + 0] = 0;
    326       t4 = nrp[i + 3];
    327       ap[i + 1] = 0;
    328       rp[i + 0] = t1;
    329       ap[i + 2] = 0;
    330       rp[i + 1] = t2;
    331       ap[i + 3] = 0;
    332       rp[i + 2] = t3;
    333       rp[i + 3] = t4;
    334     }
    335 
    336     for (nl += 4; i < nl; i++) {
    337       rp[i] = nrp[i], ap[i] = 0;
    338     }
    339   }
    340 
    341   bn_correct_top(r);
    342   bn_correct_top(ret);
    343 
    344   return 1;
    345 }
    346 
    347 int BN_from_montgomery(BIGNUM *r, const BIGNUM *a, const BN_MONT_CTX *mont,
    348                        BN_CTX *ctx) {
    349   int ret = 0;
    350   BIGNUM *t;
    351 
    352   BN_CTX_start(ctx);
    353   t = BN_CTX_get(ctx);
    354   if (t == NULL ||
    355       !BN_copy(t, a)) {
    356     goto err;
    357   }
    358 
    359   ret = BN_from_montgomery_word(r, t, mont);
    360 
    361 err:
    362   BN_CTX_end(ctx);
    363 
    364   return ret;
    365 }
    366 
    367 int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
    368                           const BN_MONT_CTX *mont, BN_CTX *ctx) {
    369 #if !defined(OPENSSL_BN_ASM_MONT)
    370   return bn_mod_mul_montgomery_fallback(r, a, b, mont, ctx);
    371 #else
    372   int num = mont->N.top;
    373 
    374   /* |bn_mul_mont| requires at least 128 bits of limbs, at least for x86. */
    375   if (num < (128 / BN_BITS2) ||
    376       a->top != num ||
    377       b->top != num) {
    378     return bn_mod_mul_montgomery_fallback(r, a, b, mont, ctx);
    379   }
    380 
    381   if (bn_wexpand(r, num) == NULL) {
    382     return 0;
    383   }
    384   if (!bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
    385     /* The check above ensures this won't happen. */
    386     assert(0);
    387     OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
    388     return 0;
    389   }
    390   r->neg = a->neg ^ b->neg;
    391   r->top = num;
    392   bn_correct_top(r);
    393 
    394   return 1;
    395 #endif
    396 }
    397 
    398 static int bn_mod_mul_montgomery_fallback(BIGNUM *r, const BIGNUM *a,
    399                                           const BIGNUM *b,
    400                                           const BN_MONT_CTX *mont,
    401                                           BN_CTX *ctx) {
    402   int ret = 0;
    403 
    404   BN_CTX_start(ctx);
    405   BIGNUM *tmp = BN_CTX_get(ctx);
    406   if (tmp == NULL) {
    407     goto err;
    408   }
    409 
    410   if (a == b) {
    411     if (!BN_sqr(tmp, a, ctx)) {
    412       goto err;
    413     }
    414   } else {
    415     if (!BN_mul(tmp, a, b, ctx)) {
    416       goto err;
    417     }
    418   }
    419 
    420   /* reduce from aRR to aR */
    421   if (!BN_from_montgomery_word(r, tmp, mont)) {
    422     goto err;
    423   }
    424 
    425   ret = 1;
    426 
    427 err:
    428   BN_CTX_end(ctx);
    429   return ret;
    430 }
    431