1/* Copyright 2018 The BoringSSL Authors 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#include <openssl/mem.h> 18 19#include "../../internal.h" 20#include "../bn/internal.h" 21#include "internal.h" 22 23 24int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out, 25 const BIGNUM *in) { 26 // Scalars, which are often secret, must be reduced modulo the order. Those 27 // that are not will be discarded, so leaking the result of the comparison is 28 // safe. 29 if (!bn_copy_words(out->words, group->order.N.width, in) || 30 !constant_time_declassify_int(bn_less_than_words( 31 out->words, group->order.N.d, group->order.N.width))) { 32 OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR); 33 return 0; 34 } 35 return 1; 36} 37 38int ec_scalar_equal_vartime(const EC_GROUP *group, const EC_SCALAR *a, 39 const EC_SCALAR *b) { 40 return OPENSSL_memcmp(a->words, b->words, 41 group->order.N.width * sizeof(BN_ULONG)) == 0; 42} 43 44int ec_scalar_is_zero(const EC_GROUP *group, const EC_SCALAR *a) { 45 BN_ULONG mask = 0; 46 for (int i = 0; i < group->order.N.width; i++) { 47 mask |= a->words[i]; 48 } 49 return mask == 0; 50} 51 52int ec_random_scalar(const EC_GROUP *group, EC_SCALAR *out, 53 const uint8_t additional_data[32]) { 54 return bn_rand_range_words(out->words, 0, group->order.N.d, 55 group->order.N.width, additional_data); 56} 57 58int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out, 59 const uint8_t additional_data[32]) { 60 return bn_rand_range_words(out->words, 1, group->order.N.d, 61 group->order.N.width, additional_data); 62} 63 64void ec_scalar_to_bytes(const EC_GROUP *group, uint8_t *out, size_t *out_len, 65 const EC_SCALAR *in) { 66 size_t len = BN_num_bytes(&group->order.N); 67 bn_words_to_big_endian(out, len, in->words, group->order.N.width); 68 *out_len = len; 69} 70 71int ec_scalar_from_bytes(const EC_GROUP *group, EC_SCALAR *out, 72 const uint8_t *in, size_t len) { 73 if (len != BN_num_bytes(&group->order.N)) { 74 OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR); 75 return 0; 76 } 77 78 bn_big_endian_to_words(out->words, group->order.N.width, in, len); 79 80 if (!bn_less_than_words(out->words, group->order.N.d, group->order.N.width)) { 81 OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR); 82 return 0; 83 } 84 85 return 1; 86} 87 88void ec_scalar_reduce(const EC_GROUP *group, EC_SCALAR *out, 89 const BN_ULONG *words, size_t num) { 90 // Convert "from" Montgomery form so the value is reduced modulo the order. 91 bn_from_montgomery_small(out->words, group->order.N.width, words, num, 92 &group->order); 93 // Convert "to" Montgomery form to remove the R^-1 factor added. 94 ec_scalar_to_montgomery(group, out, out); 95} 96 97void ec_scalar_add(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a, 98 const EC_SCALAR *b) { 99 const BIGNUM *order = &group->order.N; 100 BN_ULONG tmp[EC_MAX_WORDS]; 101 bn_mod_add_words(r->words, a->words, b->words, order->d, tmp, order->width); 102 OPENSSL_cleanse(tmp, sizeof(tmp)); 103} 104 105void ec_scalar_sub(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a, 106 const EC_SCALAR *b) { 107 const BIGNUM *order = &group->order.N; 108 BN_ULONG tmp[EC_MAX_WORDS]; 109 bn_mod_sub_words(r->words, a->words, b->words, order->d, tmp, order->width); 110 OPENSSL_cleanse(tmp, sizeof(tmp)); 111} 112 113void ec_scalar_neg(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a) { 114 EC_SCALAR zero; 115 OPENSSL_memset(&zero, 0, sizeof(EC_SCALAR)); 116 ec_scalar_sub(group, r, &zero, a); 117} 118 119void ec_scalar_select(const EC_GROUP *group, EC_SCALAR *out, BN_ULONG mask, 120 const EC_SCALAR *a, const EC_SCALAR *b) { 121 const BIGNUM *order = &group->order.N; 122 bn_select_words(out->words, mask, a->words, b->words, order->width); 123} 124 125void ec_scalar_to_montgomery(const EC_GROUP *group, EC_SCALAR *r, 126 const EC_SCALAR *a) { 127 const BIGNUM *order = &group->order.N; 128 bn_to_montgomery_small(r->words, a->words, order->width, &group->order); 129} 130 131void ec_scalar_from_montgomery(const EC_GROUP *group, EC_SCALAR *r, 132 const EC_SCALAR *a) { 133 const BIGNUM *order = &group->order.N; 134 bn_from_montgomery_small(r->words, order->width, a->words, order->width, 135 &group->order); 136} 137 138void ec_scalar_mul_montgomery(const EC_GROUP *group, EC_SCALAR *r, 139 const EC_SCALAR *a, const EC_SCALAR *b) { 140 const BIGNUM *order = &group->order.N; 141 bn_mod_mul_montgomery_small(r->words, a->words, b->words, order->width, 142 &group->order); 143} 144 145void ec_simple_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r, 146 const EC_SCALAR *a) { 147 const BIGNUM *order = &group->order.N; 148 bn_mod_inverse0_prime_mont_small(r->words, a->words, order->width, 149 &group->order); 150} 151 152int ec_simple_scalar_to_montgomery_inv_vartime(const EC_GROUP *group, 153 EC_SCALAR *r, 154 const EC_SCALAR *a) { 155 if (ec_scalar_is_zero(group, a)) { 156 return 0; 157 } 158 159 // This implementation (in fact) runs in constant time, 160 // even though for this interface it is not mandatory. 161 162 // r = a^-1 in the Montgomery domain. This is 163 // |ec_scalar_to_montgomery| followed by |ec_scalar_inv0_montgomery|, but 164 // |ec_scalar_inv0_montgomery| followed by |ec_scalar_from_montgomery| is 165 // equivalent and slightly more efficient. 166 ec_scalar_inv0_montgomery(group, r, a); 167 ec_scalar_from_montgomery(group, r, r); 168 return 1; 169} 170 171void ec_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r, 172 const EC_SCALAR *a) { 173 group->meth->scalar_inv0_montgomery(group, r, a); 174} 175 176int ec_scalar_to_montgomery_inv_vartime(const EC_GROUP *group, EC_SCALAR *r, 177 const EC_SCALAR *a) { 178 return group->meth->scalar_to_montgomery_inv_vartime(group, r, a); 179} 180