jcs's openbsd hax
openbsd
at jcs 363 lines 8.0 kB view raw
1/* $OpenBSD: ec_mult.c,v 1.61 2025/12/26 18:44:19 tb Exp $ */ 2 3/* 4 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <stdint.h> 20#include <stdlib.h> 21#include <string.h> 22 23#include <openssl/bn.h> 24#include <openssl/ec.h> 25 26#include "ec_local.h" 27#include "err_local.h" 28 29/* Holds the wNAF digits of bn and the corresponding odd multiples of point. */ 30struct ec_wnaf { 31 signed char *digits; 32 size_t num_digits; 33 EC_POINT **multiples; 34 size_t num_multiples; 35}; 36 37static int 38ec_window_bits(const BIGNUM *bn) 39{ 40 int bits = BN_num_bits(bn); 41 42 if (bits >= 2000) 43 return 6; 44 if (bits >= 800) 45 return 5; 46 if (bits >= 300) 47 return 4; 48 if (bits >= 70) 49 return 3; 50 if (bits >= 20) 51 return 2; 52 53 return 1; 54} 55 56/* 57 * Width-(w+1) non-adjacent form of bn = \sum_j n_j 2^j, with odd n_j, 58 * where at most one of any (w+1) consecutive digits is non-zero. 59 */ 60 61static int 62ec_compute_wnaf(const BIGNUM *bn, signed char *digits, size_t num_digits) 63{ 64 int digit, bit, next, sign, wbits, window; 65 size_t i; 66 int ret = 0; 67 68 if (num_digits != BN_num_bits(bn) + 1) { 69 ECerror(ERR_R_INTERNAL_ERROR); 70 goto err; 71 } 72 73 sign = BN_is_negative(bn) ? -1 : 1; 74 75 wbits = ec_window_bits(bn); 76 77 bit = 1 << wbits; 78 next = bit << 1; 79 80 /* Extract the wbits + 1 lowest bits from bn into window. */ 81 window = 0; 82 for (i = 0; i < wbits + 1; i++) { 83 if (BN_is_bit_set(bn, i)) 84 window |= (1 << i); 85 } 86 87 /* Instead of bn >>= 1 in each iteration, slide window to the left. */ 88 for (i = 0; i < num_digits; i++) { 89 digit = 0; 90 91 /* 92 * If window is odd, the i-th wNAF digit is window (mods 2^w), 93 * where mods is the signed modulo in (-2^w-1, 2^w-1]. Subtract 94 * the digit from window, so window is 0 or next, and add the 95 * digit to the wNAF digits. 96 */ 97 if ((window & 1) != 0) { 98 digit = window; 99 if ((window & bit) != 0) 100 digit = window - next; 101 window -= digit; 102 } 103 104 digits[i] = sign * digit; 105 106 /* Slide the window to the left. */ 107 window >>= 1; 108 window += bit * BN_is_bit_set(bn, i + wbits + 1); 109 } 110 111 ret = 1; 112 113 err: 114 return ret; 115} 116 117static int 118ec_compute_odd_multiples(const EC_GROUP *group, const EC_POINT *point, 119 EC_POINT **multiples, size_t num_multiples, BN_CTX *ctx) 120{ 121 EC_POINT *doubled = NULL; 122 size_t i; 123 int ret = 0; 124 125 if (num_multiples < 1) 126 goto err; 127 128 if ((multiples[0] = EC_POINT_dup(point, group)) == NULL) 129 goto err; 130 131 if ((doubled = EC_POINT_new(group)) == NULL) 132 goto err; 133 if (!EC_POINT_dbl(group, doubled, point, ctx)) 134 goto err; 135 for (i = 1; i < num_multiples; i++) { 136 if ((multiples[i] = EC_POINT_new(group)) == NULL) 137 goto err; 138 if (!EC_POINT_add(group, multiples[i], multiples[i - 1], doubled, 139 ctx)) 140 goto err; 141 } 142 143 ret = 1; 144 145 err: 146 EC_POINT_free(doubled); 147 148 return ret; 149} 150 151/* 152 * Bring multiples held in wnaf0 and wnaf1 simultaneously into affine form 153 * so that the operations in the loop in ec_wnaf_mul() can take fast paths. 154 */ 155 156static int 157ec_normalize_points(const EC_GROUP *group, struct ec_wnaf *wnaf0, 158 struct ec_wnaf *wnaf1, BN_CTX *ctx) 159{ 160 EC_POINT **points0 = wnaf0->multiples, **points1 = wnaf1->multiples; 161 size_t len0 = wnaf0->num_multiples, len1 = wnaf1->num_multiples; 162 EC_POINT **val = NULL; 163 size_t len = 0; 164 int ret = 0; 165 166 if (len1 > SIZE_MAX - len0) 167 goto err; 168 len = len0 + len1; 169 170 if ((val = calloc(len, sizeof(*val))) == NULL) { 171 ECerror(ERR_R_MALLOC_FAILURE); 172 goto err; 173 } 174 memcpy(&val[0], points0, sizeof(*val) * len0); 175 memcpy(&val[len0], points1, sizeof(*val) * len1); 176 177 if (!group->meth->points_make_affine(group, len, val, ctx)) 178 goto err; 179 180 ret = 1; 181 182 err: 183 free(val); 184 185 return ret; 186} 187 188static void 189ec_points_free(EC_POINT **points, size_t num_points) 190{ 191 size_t i; 192 193 if (points == NULL) 194 return; 195 196 for (i = 0; i < num_points; i++) 197 EC_POINT_free(points[i]); 198 free(points); 199} 200 201static void 202ec_wnaf_free(struct ec_wnaf *wnaf) 203{ 204 if (wnaf == NULL) 205 return; 206 207 free(wnaf->digits); 208 ec_points_free(wnaf->multiples, wnaf->num_multiples); 209 free(wnaf); 210} 211 212/* 213 * Calculate wNAF splitting of bn and the corresponding odd multiples of point. 214 */ 215 216static struct ec_wnaf * 217ec_wnaf_new(const EC_GROUP *group, const BIGNUM *scalar, const EC_POINT *point, 218 BN_CTX *ctx) 219{ 220 struct ec_wnaf *wnaf; 221 222 if ((wnaf = calloc(1, sizeof(*wnaf))) == NULL) 223 goto err; 224 225 wnaf->num_digits = BN_num_bits(scalar) + 1; 226 if ((wnaf->digits = calloc(wnaf->num_digits, 227 sizeof(*wnaf->digits))) == NULL) 228 goto err; 229 230 if (!ec_compute_wnaf(scalar, wnaf->digits, wnaf->num_digits)) 231 goto err; 232 233 wnaf->num_multiples = 1ULL << (ec_window_bits(scalar) - 1); 234 if ((wnaf->multiples = calloc(wnaf->num_multiples, 235 sizeof(*wnaf->multiples))) == NULL) 236 goto err; 237 238 if (!ec_compute_odd_multiples(group, point, wnaf->multiples, 239 wnaf->num_multiples, ctx)) 240 goto err; 241 242 return wnaf; 243 244 err: 245 ec_wnaf_free(wnaf); 246 247 return NULL; 248} 249 250static signed char 251ec_wnaf_digit(struct ec_wnaf *wnaf, size_t idx) 252{ 253 if (idx >= wnaf->num_digits) 254 return 0; 255 256 return wnaf->digits[idx]; 257} 258 259static const EC_POINT * 260ec_wnaf_multiple(struct ec_wnaf *wnaf, signed char digit) 261{ 262 if (digit < 0) 263 return NULL; 264 if (digit >= 2 * wnaf->num_multiples) 265 return NULL; 266 267 return wnaf->multiples[digit >> 1]; 268} 269 270/* 271 * Compute r = scalar1 * point1 + scalar2 * point2 in non-constant time. 272 */ 273 274int 275ec_wnaf_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar1, 276 const EC_POINT *point1, const BIGNUM *scalar2, const EC_POINT *point2, 277 BN_CTX *ctx) 278{ 279 struct ec_wnaf *wnaf[2] = { NULL, NULL }; 280 size_t i; 281 int k; 282 int r_is_inverted = 0; 283 size_t num_digits; 284 int ret = 0; 285 286 if (scalar1 == NULL || scalar2 == NULL) { 287 ECerror(ERR_R_PASSED_NULL_PARAMETER); 288 goto err; 289 } 290 if (!ec_group_and_point_compatible(group, r) || 291 !ec_group_and_point_compatible(group, point1) || 292 !ec_group_and_point_compatible(group, point2)) { 293 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 294 goto err; 295 } 296 297 if ((wnaf[0] = ec_wnaf_new(group, scalar1, point1, ctx)) == NULL) 298 goto err; 299 if ((wnaf[1] = ec_wnaf_new(group, scalar2, point2, ctx)) == NULL) 300 goto err; 301 302 if (!ec_normalize_points(group, wnaf[0], wnaf[1], ctx)) 303 goto err; 304 305 num_digits = wnaf[0]->num_digits; 306 if (wnaf[1]->num_digits > num_digits) 307 num_digits = wnaf[1]->num_digits; 308 309 /* 310 * Set r to the neutral element. Scan through the wNAF representations 311 * of m and n, starting at the most significant digit. Double r and for 312 * each wNAF digit of scalar1 add the digit times point1, and for each 313 * wNAF digit of scalar2 add the digit times point2, adjusting the signs 314 * as appropriate. 315 */ 316 317 if (!EC_POINT_set_to_infinity(group, r)) 318 goto err; 319 320 for (k = num_digits - 1; k >= 0; k--) { 321 if (!EC_POINT_dbl(group, r, r, ctx)) 322 goto err; 323 324 for (i = 0; i < 2; i++) { 325 const EC_POINT *multiple; 326 signed char digit; 327 int is_neg = 0; 328 329 if ((digit = ec_wnaf_digit(wnaf[i], k)) == 0) 330 continue; 331 332 if (digit < 0) { 333 is_neg = 1; 334 digit = -digit; 335 } 336 337 if (is_neg != r_is_inverted) { 338 if (!EC_POINT_invert(group, r, ctx)) 339 goto err; 340 r_is_inverted = !r_is_inverted; 341 } 342 343 if ((multiple = ec_wnaf_multiple(wnaf[i], digit)) == NULL) 344 goto err; 345 346 if (!EC_POINT_add(group, r, r, multiple, ctx)) 347 goto err; 348 } 349 } 350 351 if (r_is_inverted) { 352 if (!EC_POINT_invert(group, r, ctx)) 353 goto err; 354 } 355 356 ret = 1; 357 358 err: 359 ec_wnaf_free(wnaf[0]); 360 ec_wnaf_free(wnaf[1]); 361 362 return ret; 363}