Home | History | Annotate | Download | only in ec
      1 /* Copyright (c) 2018, Google Inc.
      2  *
      3  * Permission to use, copy, modify, and/or distribute this software for any
      4  * purpose with or without fee is hereby granted, provided that the above
      5  * copyright notice and this permission notice appear in all copies.
      6  *
      7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
     14 
     15 #include <openssl/ec.h>
     16 #include <openssl/err.h>
     17 
     18 #include <assert.h>
     19 
     20 #include "internal.h"
     21 #include "../bn/internal.h"
     22 #include "../../internal.h"
     23 
     24 
     25 int ec_bignum_to_felem(const EC_GROUP *group, EC_FELEM *out, const BIGNUM *in) {
     26   if (BN_is_negative(in) || BN_cmp(in, &group->field) >= 0) {
     27     OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
     28     return 0;
     29   }
     30   return group->meth->bignum_to_felem(group, out, in);
     31 }
     32 
     33 int ec_felem_to_bignum(const EC_GROUP *group, BIGNUM *out, const EC_FELEM *in) {
     34   return group->meth->felem_to_bignum(group, out, in);
     35 }
     36 
     37 void ec_felem_neg(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a) {
     38   // -a is zero if a is zero and p-a otherwise.
     39   BN_ULONG mask = ec_felem_non_zero_mask(group, a);
     40   BN_ULONG borrow =
     41       bn_sub_words(out->words, group->field.d, a->words, group->field.width);
     42   assert(borrow == 0);
     43   (void)borrow;
     44   for (int i = 0; i < group->field.width; i++) {
     45     out->words[i] &= mask;
     46   }
     47 }
     48 
     49 void ec_felem_add(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
     50                   const EC_FELEM *b) {
     51   EC_FELEM tmp;
     52   bn_mod_add_words(out->words, a->words, b->words, group->field.d, tmp.words,
     53                    group->field.width);
     54 }
     55 
     56 void ec_felem_sub(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
     57                   const EC_FELEM *b) {
     58   EC_FELEM tmp;
     59   bn_mod_sub_words(out->words, a->words, b->words, group->field.d, tmp.words,
     60                    group->field.width);
     61 }
     62 
     63 BN_ULONG ec_felem_non_zero_mask(const EC_GROUP *group, const EC_FELEM *a) {
     64   BN_ULONG mask = 0;
     65   for (int i = 0; i < group->field.width; i++) {
     66     mask |= a->words[i];
     67   }
     68   return ~constant_time_is_zero_w(mask);
     69 }
     70 
     71 void ec_felem_select(const EC_GROUP *group, EC_FELEM *out, BN_ULONG mask,
     72                      const EC_FELEM *a, const EC_FELEM *b) {
     73   bn_select_words(out->words, mask, a->words, b->words, group->field.width);
     74 }
     75 
     76 int ec_felem_equal(const EC_GROUP *group, const EC_FELEM *a,
     77                    const EC_FELEM *b) {
     78   // Note this function is variable-time. Constant-time operations should use
     79   // |ec_felem_non_zero_mask|.
     80   return OPENSSL_memcmp(a->words, b->words,
     81                         group->field.width * sizeof(BN_ULONG)) == 0;
     82 }
     83