diff options
author | tb <> | 2024-12-06 15:39:59 +0000 |
---|---|---|
committer | tb <> | 2024-12-06 15:39:59 +0000 |
commit | eb3e08f70ebb64ce7a9848592ac4705ef64a899b (patch) | |
tree | 44c20f6fb0ea8e363cf71669252bebc957b68254 /src | |
parent | 9026f3119d0fb71e88abcced3e32e113044416c2 (diff) | |
download | openbsd-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.c | 217 |
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. */ | ||
75 | struct ec_wnaf { | ||
76 | signed char *digits; | ||
77 | size_t num_digits; | ||
78 | EC_POINT **multiples; | ||
79 | size_t num_multiples; | ||
80 | }; | ||
81 | |||
74 | static int | 82 | static int |
75 | ec_window_bits(const BIGNUM *bn) | 83 | ec_window_bits(const BIGNUM *bn) |
76 | { | 84 | { |
@@ -96,22 +104,18 @@ ec_window_bits(const BIGNUM *bn) | |||
96 | */ | 104 | */ |
97 | 105 | ||
98 | static int | 106 | static int |
99 | ec_compute_wNAF(const BIGNUM *bn, signed char **out_wNAF, size_t *out_wNAF_len, | 107 | ec_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 | ||
165 | static void | ||
166 | free_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 | |||
178 | static int | 162 | static int |
179 | ec_compute_odd_multiples(const EC_GROUP *group, const EC_POINT *point, | 163 | ec_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 | ||
223 | static int | 201 | static int |
224 | ec_compute_row(const EC_GROUP *group, const BIGNUM *m, const EC_POINT *point, | 202 | ec_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 | |||
235 | static int | ||
236 | ec_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 | ||
233 | static void | ||
234 | ec_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 | |||
246 | static void | ||
247 | ec_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 | |||
261 | static struct ec_wnaf * | ||
262 | ec_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 | |||
295 | static signed char | ||
296 | ec_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 | |||
304 | const EC_POINT * | ||
305 | ec_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 | |||
270 | ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *m, | 320 | ec_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 | } |