Coverage Report

Created: 2024-11-21 07:03

/src/boringssl/crypto/fipsmodule/ec/simple_mul.c.inc
Line
Count
Source (jump to first uncovered line)
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
24
void ec_GFp_mont_mul(const EC_GROUP *group, EC_JACOBIAN *r,
25
40
                     const EC_JACOBIAN *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
40
  EC_JACOBIAN precomp[32];
32
40
  ec_GFp_simple_point_set_to_infinity(group, &precomp[0]);
33
40
  ec_GFp_simple_point_copy(&precomp[1], p);
34
1.24k
  for (size_t j = 2; j < OPENSSL_ARRAY_SIZE(precomp); j++) {
35
1.20k
    if (j & 1) {
36
600
      ec_GFp_mont_add(group, &precomp[j], &precomp[1], &precomp[j - 1]);
37
600
    } else {
38
600
      ec_GFp_mont_dbl(group, &precomp[j], &precomp[j / 2]);
39
600
    }
40
1.20k
  }
41
42
  // Divide bits in |scalar| into windows.
43
40
  unsigned bits =  EC_GROUP_order_bits(group);
44
40
  int r_is_at_infinity = 1;
45
18.1k
  for (unsigned i = bits - 1; i < bits; i--) {
46
18.1k
    if (!r_is_at_infinity) {
47
18.0k
      ec_GFp_mont_dbl(group, r, r);
48
18.0k
    }
49
18.1k
    if (i % 5 == 0) {
50
      // Compute the next window value.
51
3.64k
      const size_t width = group->order.N.width;
52
3.64k
      uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 4;
53
3.64k
      window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 3;
54
3.64k
      window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 2;
55
3.64k
      window |= bn_is_bit_set_words(scalar->words, width, i + 1) << 1;
56
3.64k
      window |= bn_is_bit_set_words(scalar->words, width, i);
57
58
      // Select the entry in constant-time.
59
3.64k
      EC_JACOBIAN tmp;
60
3.64k
      OPENSSL_memset(&tmp, 0, sizeof(EC_JACOBIAN));
61
120k
      for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(precomp); j++) {
62
116k
        BN_ULONG mask = constant_time_eq_w(j, window);
63
116k
        ec_point_select(group, &tmp, mask, &precomp[j], &tmp);
64
116k
      }
65
66
3.64k
      if (r_is_at_infinity) {
67
40
        ec_GFp_simple_point_copy(r, &tmp);
68
40
        r_is_at_infinity = 0;
69
3.60k
      } else {
70
3.60k
        ec_GFp_mont_add(group, r, r, &tmp);
71
3.60k
      }
72
3.64k
    }
73
18.1k
  }
74
40
  if (r_is_at_infinity) {
75
0
    ec_GFp_simple_point_set_to_infinity(group, r);
76
0
  }
77
40
}
78
79
void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
80
16
                          const EC_SCALAR *scalar) {
81
16
  ec_GFp_mont_mul(group, r, &group->generator.raw, scalar);
82
16
}
83
84
static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_JACOBIAN *out,
85
0
                                      size_t num, const EC_JACOBIAN *p) {
86
0
  assert(num > 1);
87
0
  ec_GFp_simple_point_set_to_infinity(group, &out[0]);
88
0
  ec_GFp_simple_point_copy(&out[1], p);
89
0
  for (size_t j = 2; j < num; j++) {
90
0
    if (j & 1) {
91
0
      ec_GFp_mont_add(group, &out[j], &out[1], &out[j - 1]);
92
0
    } else {
93
0
      ec_GFp_mont_dbl(group, &out[j], &out[j / 2]);
94
0
    }
95
0
  }
96
0
}
97
98
static void ec_GFp_mont_batch_get_window(const EC_GROUP *group,
99
                                         EC_JACOBIAN *out,
100
                                         const EC_JACOBIAN precomp[17],
101
0
                                         const EC_SCALAR *scalar, unsigned i) {
102
0
  const size_t width = group->order.N.width;
103
0
  uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 5;
104
0
  window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 4;
105
0
  window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 3;
106
0
  window |= bn_is_bit_set_words(scalar->words, width, i + 1) << 2;
107
0
  window |= bn_is_bit_set_words(scalar->words, width, i) << 1;
108
0
  if (i > 0) {
109
0
    window |= bn_is_bit_set_words(scalar->words, width, i - 1);
110
0
  }
111
0
  crypto_word_t sign, digit;
112
0
  ec_GFp_nistp_recode_scalar_bits(&sign, &digit, window);
113
114
  // Select the entry in constant-time.
115
0
  OPENSSL_memset(out, 0, sizeof(EC_JACOBIAN));
116
0
  for (size_t j = 0; j < 17; j++) {
117
0
    BN_ULONG mask = constant_time_eq_w(j, digit);
118
0
    ec_point_select(group, out, mask, &precomp[j], out);
119
0
  }
120
121
  // Negate if necessary.
122
0
  EC_FELEM neg_Y;
123
0
  ec_felem_neg(group, &neg_Y, &out->Y);
124
0
  crypto_word_t sign_mask = sign;
125
0
  sign_mask = 0u - sign_mask;
126
0
  ec_felem_select(group, &out->Y, sign_mask, &neg_Y, &out->Y);
127
0
}
128
129
void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_JACOBIAN *r,
130
                           const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
131
                           const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
132
0
                           const EC_JACOBIAN *p2, const EC_SCALAR *scalar2) {
133
0
  EC_JACOBIAN precomp[3][17];
134
0
  ec_GFp_mont_batch_precomp(group, precomp[0], 17, p0);
135
0
  ec_GFp_mont_batch_precomp(group, precomp[1], 17, p1);
136
0
  if (p2 != NULL) {
137
0
    ec_GFp_mont_batch_precomp(group, precomp[2], 17, p2);
138
0
  }
139
140
  // Divide bits in |scalar| into windows.
141
0
  unsigned bits = EC_GROUP_order_bits(group);
142
0
  int r_is_at_infinity = 1;
143
0
  for (unsigned i = bits; i <= bits; i--) {
144
0
    if (!r_is_at_infinity) {
145
0
      ec_GFp_mont_dbl(group, r, r);
146
0
    }
147
0
    if (i % 5 == 0) {
148
0
      EC_JACOBIAN tmp;
149
0
      ec_GFp_mont_batch_get_window(group, &tmp, precomp[0], scalar0, i);
150
0
      if (r_is_at_infinity) {
151
0
        ec_GFp_simple_point_copy(r, &tmp);
152
0
        r_is_at_infinity = 0;
153
0
      } else {
154
0
        ec_GFp_mont_add(group, r, r, &tmp);
155
0
      }
156
157
0
      ec_GFp_mont_batch_get_window(group, &tmp, precomp[1], scalar1, i);
158
0
      ec_GFp_mont_add(group, r, r, &tmp);
159
160
0
      if (p2 != NULL) {
161
0
        ec_GFp_mont_batch_get_window(group, &tmp, precomp[2], scalar2, i);
162
0
        ec_GFp_mont_add(group, r, r, &tmp);
163
0
      }
164
0
    }
165
0
  }
166
0
  if (r_is_at_infinity) {
167
0
    ec_GFp_simple_point_set_to_infinity(group, r);
168
0
  }
169
0
}
170
171
0
static unsigned ec_GFp_mont_comb_stride(const EC_GROUP *group) {
172
0
  return (EC_GROUP_get_degree(group) + EC_MONT_PRECOMP_COMB_SIZE - 1) /
173
0
         EC_MONT_PRECOMP_COMB_SIZE;
174
0
}
175
176
int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
177
0
                             const EC_JACOBIAN *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
0
  EC_JACOBIAN comb[(1 << EC_MONT_PRECOMP_COMB_SIZE) - 1];
184
0
  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
0
  comb[(1 << 0) - 1] = *p;
189
0
  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
0
    unsigned bit = 1 << i;
192
0
    ec_GFp_mont_dbl(group, &comb[bit - 1], &comb[bit / 2 - 1]);
193
0
    for (unsigned j = 1; j < stride; j++) {
194
0
      ec_GFp_mont_dbl(group, &comb[bit - 1], &comb[bit - 1]);
195
0
    }
196
    // Compute entries from 2^i + 1 to 2^i + (2^i - 1) by adding entry 2^i to
197
    // a previous entry.
198
0
    for (unsigned j = 1; j < bit; j++) {
199
0
      ec_GFp_mont_add(group, &comb[bit + j - 1], &comb[bit - 1], &comb[j - 1]);
200
0
    }
201
0
  }
202
203
  // Store the comb in affine coordinates to shrink the table. (This reduces
204
  // cache pressure and makes the constant-time selects faster.)
205
0
  static_assert(OPENSSL_ARRAY_SIZE(comb) == OPENSSL_ARRAY_SIZE(out->comb),
206
0
                "comb sizes did not match");
207
0
  return ec_jacobian_to_affine_batch(group, out->comb, comb,
208
0
                                     OPENSSL_ARRAY_SIZE(comb));
209
0
}
210
211
static void ec_GFp_mont_get_comb_window(const EC_GROUP *group,
212
                                        EC_JACOBIAN *out,
213
                                        const EC_PRECOMP *precomp,
214
0
                                        const EC_SCALAR *scalar, unsigned i) {
215
0
  const size_t width = group->order.N.width;
216
0
  unsigned stride = ec_GFp_mont_comb_stride(group);
217
  // Select the bits corresponding to the comb shifted up by |i|.
218
0
  unsigned window = 0;
219
0
  for (unsigned j = 0; j < EC_MONT_PRECOMP_COMB_SIZE; j++) {
220
0
    window |= bn_is_bit_set_words(scalar->words, width, j * stride + i)
221
0
              << j;
222
0
  }
223
224
  // Select precomp->comb[window - 1]. If |window| is zero, |match| will always
225
  // be zero, which will leave |out| at infinity.
226
0
  OPENSSL_memset(out, 0, sizeof(EC_JACOBIAN));
227
0
  for (unsigned j = 0; j < OPENSSL_ARRAY_SIZE(precomp->comb); j++) {
228
0
    BN_ULONG match = constant_time_eq_w(window, j + 1);
229
0
    ec_felem_select(group, &out->X, match, &precomp->comb[j].X, &out->X);
230
0
    ec_felem_select(group, &out->Y, match, &precomp->comb[j].Y, &out->Y);
231
0
  }
232
0
  BN_ULONG is_infinity = constant_time_is_zero_w(window);
233
0
  ec_felem_select(group, &out->Z, is_infinity, &out->Z, ec_felem_one(group));
234
0
}
235
236
void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
237
                             const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
238
                             const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
239
0
                             const EC_PRECOMP *p2, const EC_SCALAR *scalar2) {
240
0
  unsigned stride = ec_GFp_mont_comb_stride(group);
241
0
  int r_is_at_infinity = 1;
242
0
  for (unsigned i = stride - 1; i < stride; i--) {
243
0
    if (!r_is_at_infinity) {
244
0
      ec_GFp_mont_dbl(group, r, r);
245
0
    }
246
247
0
    EC_JACOBIAN tmp;
248
0
    ec_GFp_mont_get_comb_window(group, &tmp, p0, scalar0, i);
249
0
    if (r_is_at_infinity) {
250
0
      ec_GFp_simple_point_copy(r, &tmp);
251
0
      r_is_at_infinity = 0;
252
0
    } else {
253
0
      ec_GFp_mont_add(group, r, r, &tmp);
254
0
    }
255
256
0
    if (p1 != NULL) {
257
0
      ec_GFp_mont_get_comb_window(group, &tmp, p1, scalar1, i);
258
0
      ec_GFp_mont_add(group, r, r, &tmp);
259
0
    }
260
261
0
    if (p2 != NULL) {
262
0
      ec_GFp_mont_get_comb_window(group, &tmp, p2, scalar2, i);
263
0
      ec_GFp_mont_add(group, r, r, &tmp);
264
0
    }
265
0
  }
266
0
  if (r_is_at_infinity) {
267
0
    ec_GFp_simple_point_set_to_infinity(group, r);
268
0
  }
269
0
}