• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ec_GFp_mont_mul(const EC_GROUP * group,EC_RAW_POINT * r,const EC_RAW_POINT * p,const EC_SCALAR * scalar)24 void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r,
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];
32   ec_GFp_simple_point_set_to_infinity(group, &precomp[0]);
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) {
47       ec_GFp_mont_dbl(group, r, r);
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.
59       EC_RAW_POINT tmp;
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) {
67         ec_GFp_simple_point_copy(r, &tmp);
68         r_is_at_infinity = 0;
69       } else {
70         ec_GFp_mont_add(group, r, r, &tmp);
71       }
72     }
73   }
74   if (r_is_at_infinity) {
75     ec_GFp_simple_point_set_to_infinity(group, r);
76   }
77 }
78 
ec_GFp_mont_mul_base(const EC_GROUP * group,EC_RAW_POINT * r,const EC_SCALAR * scalar)79 void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_RAW_POINT *r,
80                           const EC_SCALAR *scalar) {
81   ec_GFp_mont_mul(group, r, &group->generator->raw, scalar);
82 }
83 
ec_GFp_mont_batch_precomp(const EC_GROUP * group,EC_RAW_POINT * out,size_t num,const EC_RAW_POINT * p)84 static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
85                                       size_t num, const EC_RAW_POINT *p) {
86   assert(num > 1);
87   ec_GFp_simple_point_set_to_infinity(group, &out[0]);
88   ec_GFp_simple_point_copy(&out[1], p);
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 
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)98 static void ec_GFp_mont_batch_get_window(const EC_GROUP *group,
99                                          EC_RAW_POINT *out,
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 
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)129 void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_RAW_POINT *r,
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) {
145       ec_GFp_mont_dbl(group, r, r);
146     }
147     if (i % 5 == 0) {
148       EC_RAW_POINT tmp;
149       ec_GFp_mont_batch_get_window(group, &tmp, precomp[0], scalar0, i);
150       if (r_is_at_infinity) {
151         ec_GFp_simple_point_copy(r, &tmp);
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) {
167     ec_GFp_simple_point_set_to_infinity(group, r);
168   }
169 }
170 
ec_GFp_mont_comb_stride(const EC_GROUP * group)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) /
173          EC_MONT_PRECOMP_COMB_SIZE;
174 }
175 
ec_GFp_mont_init_precomp(const EC_GROUP * group,EC_PRECOMP * out,const EC_RAW_POINT * p)176 int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
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.)
205   static_assert(OPENSSL_ARRAY_SIZE(comb) == OPENSSL_ARRAY_SIZE(out->comb),
206                 "comb sizes did not match");
207   return ec_jacobian_to_affine_batch(group, out->comb, comb,
208                                      OPENSSL_ARRAY_SIZE(comb));
209 }
210 
ec_GFp_mont_get_comb_window(const EC_GROUP * group,EC_RAW_POINT * out,const EC_PRECOMP * precomp,const EC_SCALAR * scalar,unsigned i)211 static void ec_GFp_mont_get_comb_window(const EC_GROUP *group,
212                                         EC_RAW_POINT *out,
213                                         const EC_PRECOMP *precomp,
214                                         const EC_SCALAR *scalar, unsigned i) {
215   const size_t width = group->order.width;
216   unsigned stride = ec_GFp_mont_comb_stride(group);
217   // Select the bits corresponding to the comb shifted up by |i|.
218   unsigned window = 0;
219   for (unsigned j = 0; j < EC_MONT_PRECOMP_COMB_SIZE; j++) {
220     window |= bn_is_bit_set_words(scalar->words, width, j * stride + i)
221               << j;
222   }
223 
224   // Select precomp->comb[window - 1]. If |window| is zero, |match| will always
225   // be zero, which will leave |out| at infinity.
226   OPENSSL_memset(out, 0, sizeof(EC_RAW_POINT));
227   for (unsigned j = 0; j < OPENSSL_ARRAY_SIZE(precomp->comb); j++) {
228     BN_ULONG match = constant_time_eq_w(window, j + 1);
229     ec_felem_select(group, &out->X, match, &precomp->comb[j].X, &out->X);
230     ec_felem_select(group, &out->Y, match, &precomp->comb[j].Y, &out->Y);
231   }
232   BN_ULONG is_infinity = constant_time_is_zero_w(window);
233   ec_felem_select(group, &out->Z, is_infinity, &out->Z, &group->one);
234 }
235 
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)236 void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
237                              const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
238                              const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
239                              const EC_PRECOMP *p2, const EC_SCALAR *scalar2) {
240   unsigned stride = ec_GFp_mont_comb_stride(group);
241   int r_is_at_infinity = 1;
242   for (unsigned i = stride - 1; i < stride; i--) {
243     if (!r_is_at_infinity) {
244       ec_GFp_mont_dbl(group, r, r);
245     }
246 
247     EC_RAW_POINT tmp;
248     ec_GFp_mont_get_comb_window(group, &tmp, p0, scalar0, i);
249     if (r_is_at_infinity) {
250       ec_GFp_simple_point_copy(r, &tmp);
251       r_is_at_infinity = 0;
252     } else {
253       ec_GFp_mont_add(group, r, r, &tmp);
254     }
255 
256     if (p1 != NULL) {
257       ec_GFp_mont_get_comb_window(group, &tmp, p1, scalar1, i);
258       ec_GFp_mont_add(group, r, r, &tmp);
259     }
260 
261     if (p2 != NULL) {
262       ec_GFp_mont_get_comb_window(group, &tmp, p2, scalar2, i);
263       ec_GFp_mont_add(group, r, r, &tmp);
264     }
265   }
266   if (r_is_at_infinity) {
267     ec_GFp_simple_point_set_to_infinity(group, r);
268   }
269 }
270