Home | History | Annotate | Download | only in src
      1 /*############################################################################
      2 # Copyright 2017 Intel Corporation
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #     http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 ############################################################################*/
     16 /*
     17 ===============================================================================
     18 
     19 Copyright (c) 2013, Kenneth MacKay
     20 All rights reserved.
     21 https://github.com/kmackay/micro-ecc
     22 
     23 Redistribution and use in source and binary forms, with or without modification,
     24 are permitted provided that the following conditions are met:
     25  * Redistributions of source code must retain the above copyright notice, this
     26    list of conditions and the following disclaimer.
     27  * Redistributions in binary form must reproduce the above copyright notice,
     28    this list of conditions and the following disclaimer in the documentation
     29    and/or other materials provided with the distribution.
     30 
     31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     32 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     33 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     34 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     35 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     36 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     37 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     38 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     40 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     41 
     42 ===============================================================================
     43 */
     44 /// Implementation of Large Integer math
     45 
     46 #include "epid/member/tiny/math/vli.h"
     47 #include "epid/member/tiny/math/mathtypes.h"
     48 #include "epid/member/tiny/math/serialize.h"
     49 
     50 uint32_t VliAdd(VeryLargeInt* result, VeryLargeInt const* left,
     51                 VeryLargeInt const* right) {
     52   uint32_t carry = 0;
     53   uint32_t i;
     54   for (i = 0; i < NUM_ECC_DIGITS; ++i) {
     55     uint32_t sum = left->word[i] + right->word[i] + carry;
     56     carry = (sum < left->word[i]) | ((sum == left->word[i]) && carry);
     57     result->word[i] = sum;
     58   }
     59   return carry;
     60 }
     61 
     62 void VliMul(VeryLargeIntProduct* result, VeryLargeInt const* left,
     63             VeryLargeInt const* right) {
     64   uint64_t tmp_r1 = 0;
     65   uint32_t tmp_r2 = 0;
     66   uint32_t i, k;
     67   /* Compute each digit of result in sequence, maintaining the carries. */
     68   for (k = 0; k < (uint32_t)(NUM_ECC_DIGITS * 2 - 1); ++k) {
     69     uint32_t min_idx =
     70         (k < (uint32_t)NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS);
     71     for (i = min_idx; i <= k && i < (uint32_t)NUM_ECC_DIGITS; ++i) {
     72       uint64_t product = (uint64_t)left->word[i] * right->word[k - i];
     73       tmp_r1 += product;
     74       tmp_r2 += (tmp_r1 < product);
     75     }
     76     result->word[k] = (uint32_t)tmp_r1;
     77     tmp_r1 = (tmp_r1 >> 32) | (((uint64_t)tmp_r2) << 32);
     78     tmp_r2 = 0;
     79   }
     80   result->word[NUM_ECC_DIGITS * 2 - 1] = (uint32_t)tmp_r1;
     81 }
     82 
     83 void VliRShift(VeryLargeInt* result, VeryLargeInt const* in, uint32_t shift) {
     84   uint32_t i;
     85   for (i = 0; i < NUM_ECC_DIGITS - 1; i++) {
     86     result->word[i] = (in->word[i] >> shift) | in->word[i + 1] << (32 - shift);
     87   }
     88   result->word[NUM_ECC_DIGITS - 1] = in->word[NUM_ECC_DIGITS - 1] >> shift;
     89 }
     90 
     91 uint32_t VliSub(VeryLargeInt* result, VeryLargeInt const* left,
     92                 VeryLargeInt const* right) {
     93   uint32_t borrow = 0;
     94 
     95   int i;
     96   for (i = 0; i < NUM_ECC_DIGITS; ++i) {
     97     uint32_t diff = left->word[i] - right->word[i] - borrow;
     98     borrow = (diff > left->word[i]) | ((diff == left->word[i]) && borrow);
     99     result->word[i] = diff;
    100   }
    101   return borrow;
    102 }
    103 
    104 void VliSet(VeryLargeInt* result, VeryLargeInt const* in) {
    105   uint32_t i;
    106   for (i = 0; i < NUM_ECC_DIGITS; ++i) {
    107     result->word[i] = in->word[i];
    108   }
    109 }
    110 
    111 void VliClear(VeryLargeInt* result) {
    112   uint32_t i;
    113   for (i = 0; i < NUM_ECC_DIGITS; ++i) {
    114     result->word[i] = 0;
    115   }
    116 }
    117 
    118 int VliIsZero(VeryLargeInt const* in) {
    119   uint32_t i, acc = 0;
    120   for (i = 0; i < NUM_ECC_DIGITS; ++i) {
    121     acc += (in->word[i] != 0);
    122   }
    123   return (!acc);
    124 }
    125 
    126 void VliCondSet(VeryLargeInt* result, VeryLargeInt const* true_val,
    127                 VeryLargeInt const* false_val, int truth_val) {
    128   int i;
    129   for (i = 0; i < NUM_ECC_DIGITS; i++)
    130     result->word[i] = (!truth_val) * false_val->word[i] +
    131                       (truth_val != 0) * true_val->word[i];
    132 }
    133 
    134 uint32_t VliTestBit(VeryLargeInt const* in, uint32_t bit) {
    135   return ((in->word[bit >> 5] >> (bit & 31)) &
    136           1);  // p_bit % 32 = p_bit & 0x0000001F = 31
    137 }
    138 
    139 int VliRand(VeryLargeInt* result, BitSupplier rnd_func, void* rnd_param) {
    140   uint32_t t[NUM_ECC_DIGITS] = {0};
    141   if (rnd_func(t, sizeof(VeryLargeInt) * 8, rnd_param)) {
    142     return 0;
    143   }
    144   VliDeserialize(result, (BigNumStr const*)t);
    145   return 1;
    146 }
    147 
    148 int VliCmp(VeryLargeInt const* left, VeryLargeInt const* right) {
    149   int i, cmp = 0;
    150   for (i = NUM_ECC_DIGITS - 1; i >= 0; --i) {
    151     cmp |=
    152         ((left->word[i] > right->word[i]) - (left->word[i] < right->word[i])) *
    153         (!cmp);
    154   }
    155   return cmp;
    156 }
    157 
    158 void VliModAdd(VeryLargeInt* result, VeryLargeInt const* left,
    159                VeryLargeInt const* right, VeryLargeInt const* mod) {
    160   VeryLargeInt tmp;
    161   uint32_t carry = VliAdd(result, left, right);
    162   carry = VliSub(&tmp, result, mod) - carry;
    163   VliCondSet(result, result, &tmp, carry);
    164 }
    165 
    166 void VliModSub(VeryLargeInt* result, VeryLargeInt const* left,
    167                VeryLargeInt const* right, VeryLargeInt const* mod) {
    168   VeryLargeInt tmp;
    169   uint32_t borrow = VliSub(result, left, right);
    170   VliAdd(&tmp, result, mod);
    171   VliCondSet(result, &tmp, result, borrow);
    172 }
    173 
    174 void VliModMul(VeryLargeInt* result, VeryLargeInt const* left,
    175                VeryLargeInt const* right, VeryLargeInt const* mod) {
    176   VeryLargeIntProduct product;
    177   VliMul(&product, left, right);
    178   VliModBarrett(result, &product, mod);
    179 }
    180 
    181 static void vliSquare(VeryLargeIntProduct* p_result,
    182                       VeryLargeInt const* p_left) {
    183   uint64_t tmp_r1 = 0;
    184   uint32_t tmp_r2 = 0;
    185   uint32_t i, k;
    186   for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) {
    187     uint32_t min_idx = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS);
    188     for (i = min_idx; i <= k && i <= k - i; ++i) {
    189       uint64_t l_product = (uint64_t)p_left->word[i] * p_left->word[k - i];
    190       if (i < k - i) {
    191         tmp_r2 += l_product >> 63;
    192         l_product *= 2;
    193       }
    194       tmp_r1 += l_product;
    195       tmp_r2 += (tmp_r1 < l_product);
    196     }
    197     p_result->word[k] = (uint32_t)tmp_r1;
    198     tmp_r1 = (tmp_r1 >> 32) | (((uint64_t)tmp_r2) << 32);
    199     tmp_r2 = 0;
    200   }
    201 
    202   p_result->word[NUM_ECC_DIGITS * 2 - 1] = (uint32_t)tmp_r1;
    203 }
    204 
    205 void VliModExp(VeryLargeInt* result, VeryLargeInt const* base,
    206                VeryLargeInt const* exp, VeryLargeInt const* mod) {
    207   VeryLargeInt acc, tmp;
    208   VeryLargeIntProduct product;
    209   uint32_t j;
    210   int i;
    211   VliClear(&acc);
    212   acc.word[0] = 1;
    213   for (i = NUM_ECC_DIGITS - 1; i >= 0; i--) {
    214     for (j = 1U << 31; j > 0; j = j >> 1) {
    215       vliSquare(&product, &acc);
    216       VliModBarrett(&acc, &product, mod);
    217       VliMul(&product, &acc, base);
    218       VliModBarrett(&tmp, &product, mod);
    219       VliCondSet(&acc, &tmp, &acc, j & (exp->word[i]));
    220     }
    221   }
    222   VliSet(result, &acc);
    223 }
    224 
    225 void VliModInv(VeryLargeInt* result, VeryLargeInt const* input,
    226                VeryLargeInt const* mod) {
    227   VeryLargeInt power;
    228   VliSet(&power, mod);
    229   power.word[0] -= 2;
    230   VliModExp(result, input, &power, mod);
    231 }
    232 
    233 void VliModSquare(VeryLargeInt* result, VeryLargeInt const* input,
    234                   VeryLargeInt const* mod) {
    235   VeryLargeIntProduct product;
    236   vliSquare(&product, input);
    237   VliModBarrett(result, &product, mod);
    238 }
    239 
    240 /* Computes p_result = p_in << c, returning carry.
    241  * Can modify in place (if p_result == p_in). 0 < p_shift < 32. */
    242 static uint32_t vliLShift(VeryLargeIntProduct* p_result,
    243                           VeryLargeIntProduct const* p_in, uint32_t p_shift) {
    244   int i;
    245   uint32_t carry = p_in->word[NUM_ECC_DIGITS * 2 - 1];
    246   for (i = NUM_ECC_DIGITS * 2 - 1; i > 0; --i)
    247     p_result->word[i] =
    248         ((p_in->word[i] << p_shift) | (p_in->word[i - 1] >> (32 - p_shift)));
    249   p_result->word[0] = p_in->word[0] << p_shift;
    250   return carry >> (32 - p_shift);
    251 }
    252 
    253 static void vliScalarMult(VeryLargeInt* p_result, VeryLargeInt* p_left,
    254                           uint32_t p_right) {
    255   int i;
    256   uint64_t tmpresult;
    257   uint32_t left = 0, right;
    258   for (i = 0; i < NUM_ECC_DIGITS - 1; i++) {
    259     tmpresult = p_left->word[i] * ((uint64_t)p_right);
    260     right = left + ((uint32_t)tmpresult);
    261     left = (right < left) + ((uint32_t)(tmpresult >> 32));
    262     p_result->word[i] = right;
    263   }
    264   p_result->word[NUM_ECC_DIGITS - 1] = left;
    265 }
    266 
    267 static void vliProdRShift(VeryLargeIntProduct* result,
    268                           VeryLargeIntProduct const* in, uint32_t shift,
    269                           uint32_t len) {
    270   uint32_t i;
    271   for (i = 0; i < len - 1; i++) {
    272     result->word[i] = (in->word[i] >> shift) | in->word[i + 1] << (32 - shift);
    273   }
    274   result->word[len - 1] = in->word[len - 1] >> shift;
    275 }
    276 
    277 /* WARNING THIS METHOD MAKES STRONG ASSUMPTIONS ABOUT THE INVOLVED PRIMES
    278  * All primes used for computations in Intel(R) EPID 2.0 begin with 32 ones.
    279  * This method assumes 2^256 - p_mod
    280  * begins with 32 zeros, and is tuned to this assumption. Violating this
    281  * assumption will cause it not
    282  * to work. It also assumes that it does not end with 32 zeros.
    283  */
    284 void VliModBarrett(VeryLargeInt* result, VeryLargeIntProduct const* input,
    285                    VeryLargeInt const* mod) {
    286   int i;
    287   VeryLargeIntProduct tmpprod;
    288   VeryLargeInt negprime, linear;
    289   uint32_t carry = 0;
    290   VliSet((VeryLargeInt*)&tmpprod.word[0], (VeryLargeInt const*)&input->word[0]);
    291   VliSet((VeryLargeInt*)&tmpprod.word[NUM_ECC_DIGITS],
    292          (VeryLargeInt const*)&input->word[NUM_ECC_DIGITS]);
    293   // negative prime is ~q + 1, so we store this in
    294   for (i = 0; i < NUM_ECC_DIGITS - 1; i++) negprime.word[i] = ~mod->word[i];
    295   negprime.word[0]++;
    296   for (i = 0; i < NUM_ECC_DIGITS; i++) {
    297     vliScalarMult(&linear, &negprime, tmpprod.word[2 * NUM_ECC_DIGITS - 1]);
    298     tmpprod.word[2 * NUM_ECC_DIGITS - 1] = 0;
    299     tmpprod.word[2 * NUM_ECC_DIGITS - 1] =
    300         VliAdd((VeryLargeInt*)&tmpprod.word[NUM_ECC_DIGITS - 1],
    301                (VeryLargeInt const*)&tmpprod.word[7], &linear);
    302     vliLShift(&tmpprod, &tmpprod, 31);
    303   }
    304   // shift the 256+32-NUM_ECC_DIGITS-1 bits in the largest 9 limbs back to the
    305   // base
    306   vliProdRShift(&tmpprod,
    307                 (VeryLargeIntProduct const*)&tmpprod.word[NUM_ECC_DIGITS - 1],
    308                 (31 * 8) % 32, NUM_ECC_DIGITS + 1);
    309   vliScalarMult(&linear, &negprime, tmpprod.word[NUM_ECC_DIGITS]);
    310   carry = VliAdd((VeryLargeInt*)&tmpprod.word[0],
    311                  (VeryLargeInt const*)&tmpprod.word[0],
    312                  (VeryLargeInt const*)&linear);
    313   carry |= (-1 < VliCmp((VeryLargeInt const*)&tmpprod.word[0], mod));
    314   vliScalarMult(&linear, &negprime, carry);
    315   VliAdd(result, (VeryLargeInt const*)&tmpprod.word[0], &linear);
    316 }
    317