summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortb <>2024-12-06 15:39:59 +0000
committertb <>2024-12-06 15:39:59 +0000
commiteb3e08f70ebb64ce7a9848592ac4705ef64a899b (patch)
tree44c20f6fb0ea8e363cf71669252bebc957b68254 /src
parent9026f3119d0fb71e88abcced3e32e113044416c2 (diff)
downloadopenbsd-eb3e08f70ebb64ce7a9848592ac4705ef64a899b.tar.gz
openbsd-eb3e08f70ebb64ce7a9848592ac4705ef64a899b.tar.bz2
openbsd-eb3e08f70ebb64ce7a9848592ac4705ef64a899b.zip
ec_mult: manage wNAF data in a struct
This refactors the wNAF multiplication further and introduces a small API that manages the wNAF digits for bn and the multiples of digit * point in a single struct that is initialized and freed in two API calls in the main function, ec_wNAF_mul(). This way the main algorithm is no longer cluttered with logic to keep various arrays in sync, helper functions calculating the wNAF splitting of bn and multiples of the point do not need to deal with memory management, and a pair of accessors obviates previously missing bounds checking. At this point we have reached a relatively clean and straightforward wNAF implementation that fits precisely the purpose needed in libcrypto, i.e., ECDSA verification instead of being generalized and optimized to the max for no good reason apart from endowing the author with an academic degree. Popper's famous maxim "if you can't say it clearly, keep quiet, and keep working until you can" very much applies to code as well. In other words, shut up and hack (and don't pour too much energy into commit messages, tb). ok jsing
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/ec/ec_mult.c217
1 files changed, 131 insertions, 86 deletions
diff --git a/src/lib/libcrypto/ec/ec_mult.c b/src/lib/libcrypto/ec/ec_mult.c
index 4944c34a1e..0454a436a2 100644
--- a/src/lib/libcrypto/ec/ec_mult.c
+++ b/src/lib/libcrypto/ec/ec_mult.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ec_mult.c,v 1.51 2024/11/23 12:56:31 tb Exp $ */ 1/* $OpenBSD: ec_mult.c,v 1.52 2024/12/06 15:39:59 tb Exp $ */
2/* 2/*
3 * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. 3 * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project.
4 */ 4 */
@@ -71,6 +71,14 @@
71 71
72#include "ec_local.h" 72#include "ec_local.h"
73 73
74/* Holds the wNAF digits of bn and the corresponding odd multiples of point. */
75struct ec_wnaf {
76 signed char *digits;
77 size_t num_digits;
78 EC_POINT **multiples;
79 size_t num_multiples;
80};
81
74static int 82static int
75ec_window_bits(const BIGNUM *bn) 83ec_window_bits(const BIGNUM *bn)
76{ 84{
@@ -96,22 +104,18 @@ ec_window_bits(const BIGNUM *bn)
96 */ 104 */
97 105
98static int 106static int
99ec_compute_wNAF(const BIGNUM *bn, signed char **out_wNAF, size_t *out_wNAF_len, 107ec_compute_wnaf(const BIGNUM *bn, signed char *digits, size_t num_digits)
100 size_t *out_len)
101{ 108{
102 signed char *wNAF = NULL;
103 size_t i, wNAF_len, len;
104 int digit, bit, next, sign, wbits, window; 109 int digit, bit, next, sign, wbits, window;
110 size_t i;
105 int ret = 0; 111 int ret = 0;
106 112
107 wNAF_len = BN_num_bits(bn) + 1; 113 if (num_digits != BN_num_bits(bn) + 1) {
108 if ((wNAF = calloc(1, wNAF_len)) == NULL) { 114 ECerror(ERR_R_INTERNAL_ERROR);
109 ECerror(ERR_R_MALLOC_FAILURE);
110 goto err; 115 goto err;
111 } 116 }
112 117
113 wbits = ec_window_bits(bn); 118 wbits = ec_window_bits(bn);
114 len = 1 << (wbits - 1);
115 119
116 sign = BN_is_negative(bn) ? -1 : 1; 120 sign = BN_is_negative(bn) ? -1 : 1;
117 121
@@ -126,7 +130,7 @@ ec_compute_wNAF(const BIGNUM *bn, signed char **out_wNAF, size_t *out_wNAF_len,
126 } 130 }
127 131
128 /* Instead of bn >>= 1 in each iteration, slide window to the left. */ 132 /* Instead of bn >>= 1 in each iteration, slide window to the left. */
129 for (i = 0; i < wNAF_len; i++) { 133 for (i = 0; i < num_digits; i++) {
130 digit = 0; 134 digit = 0;
131 135
132 /* 136 /*
@@ -142,100 +146,64 @@ ec_compute_wNAF(const BIGNUM *bn, signed char **out_wNAF, size_t *out_wNAF_len,
142 window -= digit; 146 window -= digit;
143 } 147 }
144 148
145 wNAF[i] = sign * digit; 149 digits[i] = sign * digit;
146 150
147 /* Slide the window to the left. */ 151 /* Slide the window to the left. */
148 window >>= 1; 152 window >>= 1;
149 window += bit * BN_is_bit_set(bn, i + wbits + 1); 153 window += bit * BN_is_bit_set(bn, i + wbits + 1);
150 } 154 }
151 155
152 *out_wNAF = wNAF;
153 wNAF = NULL;
154 *out_wNAF_len = wNAF_len;
155 *out_len = len;
156
157 ret = 1; 156 ret = 1;
158 157
159 err: 158 err:
160 free(wNAF);
161
162 return ret; 159 return ret;
163} 160}
164 161
165static void
166free_row(EC_POINT **row, size_t row_len)
167{
168 size_t i;
169
170 if (row == NULL)
171 return;
172
173 for (i = 0; i < row_len; i++)
174 EC_POINT_free(row[i]);
175 free(row);
176}
177
178static int 162static int
179ec_compute_odd_multiples(const EC_GROUP *group, const EC_POINT *point, 163ec_compute_odd_multiples(const EC_GROUP *group, const EC_POINT *point,
180 EC_POINT ***out_row, size_t row_len, BN_CTX *ctx) 164 EC_POINT **multiples, size_t num_multiples, BN_CTX *ctx)
181{ 165{
182 EC_POINT **row = NULL;
183 EC_POINT *doubled = NULL; 166 EC_POINT *doubled = NULL;
184 size_t i; 167 size_t i;
185 int ret = 0; 168 int ret = 0;
186 169
187 if (row_len < 1) 170 if (num_multiples < 1)
188 goto err;
189
190 if ((row = calloc(row_len, sizeof(*row))) == NULL)
191 goto err; 171 goto err;
192 172
193 if ((row[0] = EC_POINT_dup(point, group)) == NULL) 173 if ((multiples[0] = EC_POINT_dup(point, group)) == NULL)
194 goto err; 174 goto err;
195 175
196 if ((doubled = EC_POINT_new(group)) == NULL) 176 if ((doubled = EC_POINT_new(group)) == NULL)
197 goto err; 177 goto err;
198 if (!EC_POINT_dbl(group, doubled, point, ctx)) 178 if (!EC_POINT_dbl(group, doubled, point, ctx))
199 goto err; 179 goto err;
200 for (i = 1; i < row_len; i++) { 180 for (i = 1; i < num_multiples; i++) {
201 if ((row[i] = EC_POINT_new(group)) == NULL) 181 if ((multiples[i] = EC_POINT_new(group)) == NULL)
202 goto err; 182 goto err;
203 if (!EC_POINT_add(group, row[i], row[i - 1], doubled, ctx)) 183 if (!EC_POINT_add(group, multiples[i], multiples[i - 1], doubled,
184 ctx))
204 goto err; 185 goto err;
205 } 186 }
206 187
207 *out_row = row;
208 row = NULL;
209
210 ret = 1; 188 ret = 1;
211 189
212 err: 190 err:
213 EC_POINT_free(doubled); 191 EC_POINT_free(doubled);
214 free_row(row, row_len);
215 192
216 return ret; 193 return ret;
217} 194}
218 195
219/* 196/*
220 * Compute the wNAF representation of m and a list of odd multiples of point. 197 * Bring multiples held in wnaf0 and wnaf1 simultaneously into affine form
198 * so that the operations in the loop in ec_wNAF_mul() can take fast paths.
221 */ 199 */
222 200
223static int 201static int
224ec_compute_row(const EC_GROUP *group, const BIGNUM *m, const EC_POINT *point, 202ec_normalize_points(const EC_GROUP *group, struct ec_wnaf *wnaf0,
225 signed char **wNAF, size_t *wNAF_len, EC_POINT ***out_row, size_t *out_row_len, 203 struct ec_wnaf *wnaf1, BN_CTX *ctx)
226 BN_CTX *ctx)
227{
228 if (!ec_compute_wNAF(m, wNAF, wNAF_len, out_row_len))
229 return 0;
230 if (!ec_compute_odd_multiples(group, point, out_row, *out_row_len, ctx))
231 return 0;
232 return 1;
233}
234
235static int
236ec_normalize_rows(const EC_GROUP *group, EC_POINT **row0, size_t len0,
237 EC_POINT **row1, size_t len1, BN_CTX *ctx)
238{ 204{
205 EC_POINT **points0 = wnaf0->multiples, **points1 = wnaf1->multiples;
206 size_t len0 = wnaf0->num_multiples, len1 = wnaf1->num_multiples;
239 EC_POINT **val = NULL; 207 EC_POINT **val = NULL;
240 size_t len = 0; 208 size_t len = 0;
241 int ret = 0; 209 int ret = 0;
@@ -248,8 +216,8 @@ ec_normalize_rows(const EC_GROUP *group, EC_POINT **row0, size_t len0,
248 ECerror(ERR_R_MALLOC_FAILURE); 216 ECerror(ERR_R_MALLOC_FAILURE);
249 goto err; 217 goto err;
250 } 218 }
251 memcpy(&val[0], row0, sizeof(*val) * len0); 219 memcpy(&val[0], points0, sizeof(*val) * len0);
252 memcpy(&val[len0], row1, sizeof(*val) * len1); 220 memcpy(&val[len0], points1, sizeof(*val) * len1);
253 221
254 if (!EC_POINTs_make_affine(group, len, val, ctx)) 222 if (!EC_POINTs_make_affine(group, len, val, ctx))
255 goto err; 223 goto err;
@@ -262,6 +230,88 @@ ec_normalize_rows(const EC_GROUP *group, EC_POINT **row0, size_t len0,
262 return ret; 230 return ret;
263} 231}
264 232
233static void
234ec_points_free(EC_POINT **points, size_t num_points)
235{
236 size_t i;
237
238 if (points == NULL)
239 return;
240
241 for (i = 0; i < num_points; i++)
242 EC_POINT_free(points[i]);
243 free(points);
244}
245
246static void
247ec_wnaf_free(struct ec_wnaf *wnaf)
248{
249 if (wnaf == NULL)
250 return;
251
252 free(wnaf->digits);
253 ec_points_free(wnaf->multiples, wnaf->num_multiples);
254 free(wnaf);
255}
256
257/*
258 * Calculate wNAF splitting of bn and the corresponding odd multiples of point.
259 */
260
261static struct ec_wnaf *
262ec_wnaf_new(const EC_GROUP *group, const EC_POINT *point, const BIGNUM *bn,
263 BN_CTX *ctx)
264{
265 struct ec_wnaf *wnaf;
266
267 if ((wnaf = calloc(1, sizeof(*wnaf))) == NULL)
268 goto err;
269
270 wnaf->num_digits = BN_num_bits(bn) + 1;
271 if ((wnaf->digits = calloc(wnaf->num_digits,
272 sizeof(*wnaf->digits))) == NULL)
273 goto err;
274
275 if (!ec_compute_wnaf(bn, wnaf->digits, wnaf->num_digits))
276 goto err;
277
278 wnaf->num_multiples = 1 << (ec_window_bits(bn) - 1);
279 if ((wnaf->multiples = calloc(wnaf->num_multiples,
280 sizeof(*wnaf->multiples))) == NULL)
281 goto err;
282
283 if (!ec_compute_odd_multiples(group, point, wnaf->multiples,
284 wnaf->num_multiples, ctx))
285 goto err;
286
287 return wnaf;
288
289 err:
290 ec_wnaf_free(wnaf);
291
292 return NULL;
293}
294
295static signed char
296ec_wnaf_digit(struct ec_wnaf *wnaf, size_t idx)
297{
298 if (idx >= wnaf->num_digits)
299 return 0;
300
301 return wnaf->digits[idx];
302}
303
304const EC_POINT *
305ec_wnaf_multiple(struct ec_wnaf *wnaf, signed char digit)
306{
307 if (digit < 0)
308 return NULL;
309 if (digit >= 2 * wnaf->num_multiples)
310 return NULL;
311
312 return wnaf->multiples[digit >> 1];
313}
314
265/* 315/*
266 * Compute r = generator * m + point * n in non-constant time. 316 * Compute r = generator * m + point * n in non-constant time.
267 */ 317 */
@@ -270,15 +320,12 @@ int
270ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m, 320ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m,
271 const EC_POINT *point, const BIGNUM *n, BN_CTX *ctx) 321 const EC_POINT *point, const BIGNUM *n, BN_CTX *ctx)
272{ 322{
323 struct ec_wnaf *wnaf[2] = { NULL, NULL };
273 const EC_POINT *generator; 324 const EC_POINT *generator;
274 signed char *wNAF[2] = { 0 };
275 size_t wNAF_len[2] = { 0 };
276 EC_POINT **row[2] = { 0 };
277 size_t row_len[2] = { 0 };
278 size_t i; 325 size_t i;
279 int k; 326 int k;
280 int r_is_inverted = 0; 327 int r_is_inverted = 0;
281 size_t max_len = 0; 328 size_t num_digits;
282 int ret = 0; 329 int ret = 0;
283 330
284 if (m == NULL || n == NULL) { 331 if (m == NULL || n == NULL) {
@@ -295,18 +342,17 @@ ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m,
295 goto err; 342 goto err;
296 } 343 }
297 344
298 if (!ec_compute_row(group, m, generator, &wNAF[0], &wNAF_len[0], 345 if ((wnaf[0] = ec_wnaf_new(group, generator, m, ctx)) == NULL)
299 &row[0], &row_len[0], ctx))
300 goto err; 346 goto err;
301 if (!ec_compute_row(group, n, point, &wNAF[1], &wNAF_len[1], 347 if ((wnaf[1] = ec_wnaf_new(group, point, n, ctx)) == NULL)
302 &row[1], &row_len[1], ctx))
303 goto err; 348 goto err;
304 if (!ec_normalize_rows(group, row[0], row_len[0], row[1], row_len[1], ctx)) 349
350 if (!ec_normalize_points(group, wnaf[0], wnaf[1], ctx))
305 goto err; 351 goto err;
306 352
307 max_len = wNAF_len[0]; 353 num_digits = wnaf[0]->num_digits;
308 if (wNAF_len[1] > max_len) 354 if (wnaf[1]->num_digits > num_digits)
309 max_len = wNAF_len[1]; 355 num_digits = wnaf[1]->num_digits;
310 356
311 /* 357 /*
312 * Set r to the neutral element. Scan through the wNAF representations 358 * Set r to the neutral element. Scan through the wNAF representations
@@ -319,18 +365,16 @@ ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m,
319 if (!EC_POINT_set_to_infinity(group, r)) 365 if (!EC_POINT_set_to_infinity(group, r))
320 goto err; 366 goto err;
321 367
322 for (k = max_len - 1; k >= 0; k--) { 368 for (k = num_digits - 1; k >= 0; k--) {
323 if (!EC_POINT_dbl(group, r, r, ctx)) 369 if (!EC_POINT_dbl(group, r, r, ctx))
324 goto err; 370 goto err;
325 371
326 for (i = 0; i < 2; i++) { 372 for (i = 0; i < 2; i++) {
327 int digit; 373 const EC_POINT *multiple;
374 signed char digit;
328 int is_neg = 0; 375 int is_neg = 0;
329 376
330 if (k >= wNAF_len[i]) 377 if ((digit = ec_wnaf_digit(wnaf[i], k)) == 0)
331 continue;
332
333 if ((digit = wNAF[i][k]) == 0)
334 continue; 378 continue;
335 379
336 if (digit < 0) { 380 if (digit < 0) {
@@ -344,7 +388,10 @@ ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m,
344 r_is_inverted = !r_is_inverted; 388 r_is_inverted = !r_is_inverted;
345 } 389 }
346 390
347 if (!EC_POINT_add(group, r, r, row[i][digit >> 1], ctx)) 391 if ((multiple = ec_wnaf_multiple(wnaf[i], digit)) == NULL)
392 goto err;
393
394 if (!EC_POINT_add(group, r, r, multiple, ctx))
348 goto err; 395 goto err;
349 } 396 }
350 } 397 }
@@ -357,10 +404,8 @@ ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m,
357 ret = 1; 404 ret = 1;
358 405
359 err: 406 err:
360 free(wNAF[0]); 407 ec_wnaf_free(wnaf[0]);
361 free(wNAF[1]); 408 ec_wnaf_free(wnaf[1]);
362 free_row(row[0], row_len[0]);
363 free_row(row[1], row_len[1]);
364 409
365 return ret; 410 return ret;
366} 411}