simple_mul.c
Go to the documentation of this file.
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 
17 #include <assert.h>
18 
19 #include "internal.h"
20 #include "../bn/internal.h"
21 #include "../../internal.h"
22 
23 
25  const EC_RAW_POINT *p, const EC_SCALAR *scalar) {
26  // This is a generic implementation for uncommon curves that not do not
27  // warrant a tuned one. It uses unsigned digits so that the doubling case in
28  // |ec_GFp_mont_add| is always unreachable, erring on safety and simplicity.
29 
30  // Compute a table of the first 32 multiples of |p| (including infinity).
31  EC_RAW_POINT precomp[32];
33  ec_GFp_simple_point_copy(&precomp[1], p);
34  for (size_t j = 2; j < OPENSSL_ARRAY_SIZE(precomp); j++) {
35  if (j & 1) {
36  ec_GFp_mont_add(group, &precomp[j], &precomp[1], &precomp[j - 1]);
37  } else {
38  ec_GFp_mont_dbl(group, &precomp[j], &precomp[j / 2]);
39  }
40  }
41 
42  // Divide bits in |scalar| into windows.
43  unsigned bits = BN_num_bits(&group->order);
44  int r_is_at_infinity = 1;
45  for (unsigned i = bits - 1; i < bits; i--) {
46  if (!r_is_at_infinity) {
48  }
49  if (i % 5 == 0) {
50  // Compute the next window value.
51  const size_t width = group->order.width;
52  uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 4;
53  window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 3;
54  window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 2;
55  window |= bn_is_bit_set_words(scalar->words, width, i + 1) << 1;
56  window |= bn_is_bit_set_words(scalar->words, width, i);
57 
58  // Select the entry in constant-time.
60  OPENSSL_memset(&tmp, 0, sizeof(EC_RAW_POINT));
61  for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(precomp); j++) {
62  BN_ULONG mask = constant_time_eq_w(j, window);
63  ec_point_select(group, &tmp, mask, &precomp[j], &tmp);
64  }
65 
66  if (r_is_at_infinity) {
68  r_is_at_infinity = 0;
69  } else {
71  }
72  }
73  }
74  if (r_is_at_infinity) {
76  }
77 }
78 
80  const EC_SCALAR *scalar) {
81  ec_GFp_mont_mul(group, r, &group->generator->raw, scalar);
82 }
83 
85  size_t num, const EC_RAW_POINT *p) {
86  assert(num > 1);
89  for (size_t j = 2; j < num; j++) {
90  if (j & 1) {
91  ec_GFp_mont_add(group, &out[j], &out[1], &out[j - 1]);
92  } else {
93  ec_GFp_mont_dbl(group, &out[j], &out[j / 2]);
94  }
95  }
96 }
97 
100  const EC_RAW_POINT precomp[17],
101  const EC_SCALAR *scalar, unsigned i) {
102  const size_t width = group->order.width;
103  uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 5;
104  window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 4;
105  window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 3;
106  window |= bn_is_bit_set_words(scalar->words, width, i + 1) << 2;
107  window |= bn_is_bit_set_words(scalar->words, width, i) << 1;
108  if (i > 0) {
109  window |= bn_is_bit_set_words(scalar->words, width, i - 1);
110  }
111  crypto_word_t sign, digit;
112  ec_GFp_nistp_recode_scalar_bits(&sign, &digit, window);
113 
114  // Select the entry in constant-time.
115  OPENSSL_memset(out, 0, sizeof(EC_RAW_POINT));
116  for (size_t j = 0; j < 17; j++) {
117  BN_ULONG mask = constant_time_eq_w(j, digit);
118  ec_point_select(group, out, mask, &precomp[j], out);
119  }
120 
121  // Negate if necessary.
122  EC_FELEM neg_Y;
123  ec_felem_neg(group, &neg_Y, &out->Y);
124  crypto_word_t sign_mask = sign;
125  sign_mask = 0u - sign_mask;
126  ec_felem_select(group, &out->Y, sign_mask, &neg_Y, &out->Y);
127 }
128 
130  const EC_RAW_POINT *p0, const EC_SCALAR *scalar0,
131  const EC_RAW_POINT *p1, const EC_SCALAR *scalar1,
132  const EC_RAW_POINT *p2, const EC_SCALAR *scalar2) {
133  EC_RAW_POINT precomp[3][17];
134  ec_GFp_mont_batch_precomp(group, precomp[0], 17, p0);
135  ec_GFp_mont_batch_precomp(group, precomp[1], 17, p1);
136  if (p2 != NULL) {
137  ec_GFp_mont_batch_precomp(group, precomp[2], 17, p2);
138  }
139 
140  // Divide bits in |scalar| into windows.
141  unsigned bits = BN_num_bits(&group->order);
142  int r_is_at_infinity = 1;
143  for (unsigned i = bits; i <= bits; i--) {
144  if (!r_is_at_infinity) {
146  }
147  if (i % 5 == 0) {
149  ec_GFp_mont_batch_get_window(group, &tmp, precomp[0], scalar0, i);
150  if (r_is_at_infinity) {
152  r_is_at_infinity = 0;
153  } else {
154  ec_GFp_mont_add(group, r, r, &tmp);
155  }
156 
157  ec_GFp_mont_batch_get_window(group, &tmp, precomp[1], scalar1, i);
158  ec_GFp_mont_add(group, r, r, &tmp);
159 
160  if (p2 != NULL) {
161  ec_GFp_mont_batch_get_window(group, &tmp, precomp[2], scalar2, i);
162  ec_GFp_mont_add(group, r, r, &tmp);
163  }
164  }
165  }
166  if (r_is_at_infinity) {
168  }
169 }
170 
171 static unsigned ec_GFp_mont_comb_stride(const EC_GROUP *group) {
172  return (BN_num_bits(&group->field) + EC_MONT_PRECOMP_COMB_SIZE - 1) /
174 }
175 
177  const EC_RAW_POINT *p) {
178  // comb[i - 1] stores the ith element of the comb. That is, if i is
179  // b4 * 2^4 + b3 * 2^3 + ... + b0 * 2^0, it stores k * |p|, where k is
180  // b4 * 2^(4*stride) + b3 * 2^(3*stride) + ... + b0 * 2^(0*stride). stride
181  // here is |ec_GFp_mont_comb_stride|. We store at index i - 1 because the 0th
182  // comb entry is always infinity.
183  EC_RAW_POINT comb[(1 << EC_MONT_PRECOMP_COMB_SIZE) - 1];
184  unsigned stride = ec_GFp_mont_comb_stride(group);
185 
186  // We compute the comb sequentially by the highest set bit. Initially, all
187  // entries up to 2^0 are filled.
188  comb[(1 << 0) - 1] = *p;
189  for (unsigned i = 1; i < EC_MONT_PRECOMP_COMB_SIZE; i++) {
190  // Compute entry 2^i by doubling the entry for 2^(i-1) |stride| times.
191  unsigned bit = 1 << i;
192  ec_GFp_mont_dbl(group, &comb[bit - 1], &comb[bit / 2 - 1]);
193  for (unsigned j = 1; j < stride; j++) {
194  ec_GFp_mont_dbl(group, &comb[bit - 1], &comb[bit - 1]);
195  }
196  // Compute entries from 2^i + 1 to 2^i + (2^i - 1) by adding entry 2^i to
197  // a previous entry.
198  for (unsigned j = 1; j < bit; j++) {
199  ec_GFp_mont_add(group, &comb[bit + j - 1], &comb[bit - 1], &comb[j - 1]);
200  }
201  }
202 
203  // Store the comb in affine coordinates to shrink the table. (This reduces
204  // cache pressure and makes the constant-time selects faster.)
206  OPENSSL_ARRAY_SIZE(comb) == OPENSSL_ARRAY_SIZE(out->comb),
207  "comb sizes did not match");
208  return ec_jacobian_to_affine_batch(group, out->comb, comb,
209  OPENSSL_ARRAY_SIZE(comb));
210 }
211 
213  EC_RAW_POINT *out,
214  const EC_PRECOMP *precomp,
215  const EC_SCALAR *scalar, unsigned i) {
216  const size_t width = group->order.width;
217  unsigned stride = ec_GFp_mont_comb_stride(group);
218  // Select the bits corresponding to the comb shifted up by |i|.
219  unsigned window = 0;
220  for (unsigned j = 0; j < EC_MONT_PRECOMP_COMB_SIZE; j++) {
221  window |= bn_is_bit_set_words(scalar->words, width, j * stride + i)
222  << j;
223  }
224 
225  // Select precomp->comb[window - 1]. If |window| is zero, |match| will always
226  // be zero, which will leave |out| at infinity.
227  OPENSSL_memset(out, 0, sizeof(EC_RAW_POINT));
228  for (unsigned j = 0; j < OPENSSL_ARRAY_SIZE(precomp->comb); j++) {
229  BN_ULONG match = constant_time_eq_w(window, j + 1);
230  ec_felem_select(group, &out->X, match, &precomp->comb[j].X, &out->X);
231  ec_felem_select(group, &out->Y, match, &precomp->comb[j].Y, &out->Y);
232  }
233  BN_ULONG is_infinity = constant_time_is_zero_w(window);
234  ec_felem_select(group, &out->Z, is_infinity, &out->Z, &group->one);
235 }
236 
238  const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
239  const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
240  const EC_PRECOMP *p2, const EC_SCALAR *scalar2) {
241  unsigned stride = ec_GFp_mont_comb_stride(group);
242  int r_is_at_infinity = 1;
243  for (unsigned i = stride - 1; i < stride; i--) {
244  if (!r_is_at_infinity) {
246  }
247 
249  ec_GFp_mont_get_comb_window(group, &tmp, p0, scalar0, i);
250  if (r_is_at_infinity) {
252  r_is_at_infinity = 0;
253  } else {
254  ec_GFp_mont_add(group, r, r, &tmp);
255  }
256 
257  if (p1 != NULL) {
258  ec_GFp_mont_get_comb_window(group, &tmp, p1, scalar1, i);
259  ec_GFp_mont_add(group, r, r, &tmp);
260  }
261 
262  if (p2 != NULL) {
263  ec_GFp_mont_get_comb_window(group, &tmp, p2, scalar2, i);
264  ec_GFp_mont_add(group, r, r, &tmp);
265  }
266  }
267  if (r_is_at_infinity) {
269  }
270 }
width
int width
Definition: libuv/docs/code/tty-gravity/main.c:10
ec_GFp_nistp_recode_scalar_bits
#define ec_GFp_nistp_recode_scalar_bits
Definition: boringssl_prefix_symbols.h:3073
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
scalar::words
uint32_t words[8]
Definition: spake25519.c:319
ec_felem_neg
#define ec_felem_neg
Definition: boringssl_prefix_symbols.h:3099
ec_point_select
#define ec_point_select
Definition: boringssl_prefix_symbols.h:3121
ec_GFp_simple_point_set_to_infinity
#define ec_GFp_simple_point_set_to_infinity
Definition: boringssl_prefix_symbols.h:3086
scalar
Definition: spake25519.c:317
match
unsigned char match[65280+2]
Definition: bloaty/third_party/zlib/examples/gun.c:165
OPENSSL_ARRAY_SIZE
#define OPENSSL_ARRAY_SIZE(array)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:179
u
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:351
ec_jacobian_to_affine_batch
#define ec_jacobian_to_affine_batch
Definition: boringssl_prefix_symbols.h:3112
xds_manager.p
p
Definition: xds_manager.py:60
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
OPENSSL_memset
static void * OPENSSL_memset(void *dst, int c, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:835
EC_RAW_POINT
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:260
constant_time_is_zero_w
static crypto_word_t constant_time_is_zero_w(crypto_word_t a)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:372
ec_GFp_mont_batch_get_window
static void ec_GFp_mont_batch_get_window(const EC_GROUP *group, EC_RAW_POINT *out, const EC_RAW_POINT precomp[17], const EC_SCALAR *scalar, unsigned i)
Definition: simple_mul.c:98
EC_AFFINE::X
EC_FELEM X
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:270
bn_is_bit_set_words
#define bn_is_bit_set_words
Definition: boringssl_prefix_symbols.h:2860
bits
OPENSSL_EXPORT ASN1_BIT_STRING * bits
Definition: x509v3.h:482
ec_GFp_mont_mul_batch
void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_RAW_POINT *r, const EC_RAW_POINT *p0, const EC_SCALAR *scalar0, const EC_RAW_POINT *p1, const EC_SCALAR *scalar1, const EC_RAW_POINT *p2, const EC_SCALAR *scalar2)
Definition: simple_mul.c:129
ec_GFp_mont_mul_base
void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_RAW_POINT *r, const EC_SCALAR *scalar)
Definition: simple_mul.c:79
EC_AFFINE::Y
EC_FELEM Y
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:270
ec_GFp_mont_get_comb_window
static void ec_GFp_mont_get_comb_window(const EC_GROUP *group, EC_RAW_POINT *out, const EC_PRECOMP *precomp, const EC_SCALAR *scalar, unsigned i)
Definition: simple_mul.c:212
ec_GFp_mont_mul
void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r, const EC_RAW_POINT *p, const EC_SCALAR *scalar)
Definition: simple_mul.c:24
ec_GFp_simple_point_copy
#define ec_GFp_simple_point_copy
Definition: boringssl_prefix_symbols.h:3084
EC_FELEM
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:195
ec_felem_select
#define ec_felem_select
Definition: boringssl_prefix_symbols.h:3101
BN_num_bits
#define BN_num_bits
Definition: boringssl_prefix_symbols.h:974
upload.group
group
Definition: bloaty/third_party/googletest/googlemock/scripts/upload.py:397
ec_GFp_mont_comb_stride
static unsigned ec_GFp_mont_comb_stride(const EC_GROUP *group)
Definition: simple_mul.c:171
internal.h
ec_group_st
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:573
ec_GFp_mont_batch_precomp
static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_RAW_POINT *out, size_t num, const EC_RAW_POINT *p)
Definition: simple_mul.c:84
EC_PRECOMP
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:342
fix_build_deps.r
r
Definition: fix_build_deps.py:491
xds_manager.num
num
Definition: xds_manager.py:56
EC_MONT_PRECOMP_COMB_SIZE
#define EC_MONT_PRECOMP_COMB_SIZE
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:337
ec_GFp_mont_mul_precomp
void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_RAW_POINT *r, const EC_PRECOMP *p0, const EC_SCALAR *scalar0, const EC_PRECOMP *p1, const EC_SCALAR *scalar1, const EC_PRECOMP *p2, const EC_SCALAR *scalar2)
Definition: simple_mul.c:237
ec_GFp_mont_dbl
#define ec_GFp_mont_dbl
Definition: boringssl_prefix_symbols.h:3059
EC_SCALAR
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:103
autogen_x86imm.tmp
tmp
Definition: autogen_x86imm.py:12
constant_time_eq_w
static crypto_word_t constant_time_eq_w(crypto_word_t a, crypto_word_t b)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:394
ec_GFp_mont_init_precomp
int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out, const EC_RAW_POINT *p)
Definition: simple_mul.c:176
ec.h
EC_PRECOMP::comb
EC_AFFINE comb[(1<< EC_MONT_PRECOMP_COMB_SIZE) - 1]
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/internal.h:343
ec_GFp_mont_add
#define ec_GFp_mont_add
Definition: boringssl_prefix_symbols.h:3058
OPENSSL_STATIC_ASSERT
#define OPENSSL_STATIC_ASSERT(cond, msg)
Definition: type_check.h:75
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:12