1 /*
2 * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 *
9 */
10
11 /*
12 * SM2 low level APIs are deprecated for public use, but still ok for
13 * internal use.
14 */
15 #include "internal/deprecated.h"
16
17 #include <string.h>
18 #include <openssl/err.h>
19 #include "crypto/bn.h"
20 #include "ec_local.h"
21 #include "internal/common.h"
22 #include "internal/constant_time.h"
23
24 #define P256_LIMBS (256 / BN_BITS2)
25
26 #if !defined(OPENSSL_NO_SM2_PRECOMP)
27 extern const BN_ULONG ecp_sm2p256_precomputed[8 * 32 * 256];
28 #endif
29
30 typedef struct {
31 BN_ULONG X[P256_LIMBS];
32 BN_ULONG Y[P256_LIMBS];
33 BN_ULONG Z[P256_LIMBS];
34 } P256_POINT;
35
36 typedef struct {
37 BN_ULONG X[P256_LIMBS];
38 BN_ULONG Y[P256_LIMBS];
39 } P256_POINT_AFFINE;
40
41 #if !defined(OPENSSL_NO_SM2_PRECOMP)
42 /* Coordinates of G, for which we have precomputed tables */
43 ALIGN32 static const BN_ULONG def_xG[P256_LIMBS] = {
44 0x715a4589334c74c7, 0x8fe30bbff2660be1,
45 0x5f9904466a39c994, 0x32c4ae2c1f198119
46 };
47
48 ALIGN32 static const BN_ULONG def_yG[P256_LIMBS] = {
49 0x02df32e52139f0a0, 0xd0a9877cc62a4740, 0x59bdcee36b692153, 0xbc3736a2f4f6779c
50 };
51 #endif
52
53 /* p and order for SM2 according to GB/T 32918.5-2017 */
54 ALIGN32 static const BN_ULONG def_p[P256_LIMBS] = {
55 0xffffffffffffffff, 0xffffffff00000000,
56 0xffffffffffffffff, 0xfffffffeffffffff
57 };
58
59 ALIGN32 static const BN_ULONG ONE[P256_LIMBS] = { 1, 0, 0, 0 };
60
61 /* Functions implemented in assembly */
62 /*
63 * Most of below mentioned functions *preserve* the property of inputs
64 * being fully reduced, i.e. being in [0, modulus) range. Simply put if
65 * inputs are fully reduced, then output is too.
66 */
67 /* Right shift: a >> 1 */
68 void bn_rshift1(BN_ULONG *a);
69 /* Sub: r = a - b */
70 void bn_sub(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
71 /* Modular div by 2: r = a / 2 mod p */
72 void ecp_sm2p256_div_by_2(BN_ULONG *r, const BN_ULONG *a);
73 /* Modular div by 2: r = a / 2 mod n, where n = ord(p) */
74 void ecp_sm2p256_div_by_2_mod_ord(BN_ULONG *r, const BN_ULONG *a);
75 /* Modular add: r = a + b mod p */
76 void ecp_sm2p256_add(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
77 /* Modular sub: r = a - b mod p */
78 void ecp_sm2p256_sub(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
79 /* Modular sub: r = a - b mod n, where n = ord(p) */
80 void ecp_sm2p256_sub_mod_ord(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
81 /* Modular mul by 3: out = 3 * a mod p */
82 void ecp_sm2p256_mul_by_3(BN_ULONG *r, const BN_ULONG *a);
83 /* Modular mul: r = a * b mod p */
84 void ecp_sm2p256_mul(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
85 /* Modular sqr: r = a ^ 2 mod p */
86 void ecp_sm2p256_sqr(BN_ULONG *r, const BN_ULONG *a);
87
is_zeros(const BN_ULONG * a)88 static ossl_inline BN_ULONG is_zeros(const BN_ULONG *a)
89 {
90 BN_ULONG res;
91
92 res = a[0] | a[1] | a[2] | a[3];
93
94 return constant_time_is_zero_64(res);
95 }
96
is_equal(const BN_ULONG * a,const BN_ULONG * b)97 static ossl_inline int is_equal(const BN_ULONG *a, const BN_ULONG *b)
98 {
99 BN_ULONG res;
100
101 res = a[0] ^ b[0];
102 res |= a[1] ^ b[1];
103 res |= a[2] ^ b[2];
104 res |= a[3] ^ b[3];
105
106 return constant_time_is_zero_64(res);
107 }
108
is_greater(const BN_ULONG * a,const BN_ULONG * b)109 static ossl_inline int is_greater(const BN_ULONG *a, const BN_ULONG *b)
110 {
111 int i;
112
113 for (i = P256_LIMBS - 1; i >= 0; --i) {
114 if (a[i] > b[i])
115 return 1;
116 if (a[i] < b[i])
117 return -1;
118 }
119
120 return 0;
121 }
122
123 #define is_one(a) is_equal(a, ONE)
124 #define is_even(a) !(a[0] & 1)
125 #define is_point_equal(a, b) \
126 is_equal(a->X, b->X) && is_equal(a->Y, b->Y) && is_equal(a->Z, b->Z)
127
128 /* Bignum and field elements conversion */
129 #define ecp_sm2p256_bignum_field_elem(out, in) \
130 bn_copy_words(out, in, P256_LIMBS)
131
132 /* Binary algorithm for inversion in Fp */
133 #define BN_MOD_INV(out, in, mod_div, mod_sub, mod) \
134 do { \
135 ALIGN32 BN_ULONG u[4]; \
136 ALIGN32 BN_ULONG v[4]; \
137 ALIGN32 BN_ULONG x1[4] = { 1, 0, 0, 0 }; \
138 ALIGN32 BN_ULONG x2[4] = { 0 }; \
139 \
140 if (is_zeros(in)) \
141 return; \
142 memcpy(u, in, 32); \
143 memcpy(v, mod, 32); \
144 while (!is_one(u) && !is_one(v)) { \
145 while (is_even(u)) { \
146 bn_rshift1(u); \
147 mod_div(x1, x1); \
148 } \
149 while (is_even(v)) { \
150 bn_rshift1(v); \
151 mod_div(x2, x2); \
152 } \
153 if (is_greater(u, v) == 1) { \
154 bn_sub(u, u, v); \
155 mod_sub(x1, x1, x2); \
156 } else { \
157 bn_sub(v, v, u); \
158 mod_sub(x2, x2, x1); \
159 } \
160 } \
161 if (is_one(u)) \
162 memcpy(out, x1, 32); \
163 else \
164 memcpy(out, x2, 32); \
165 } while (0)
166
167 /* Modular inverse |out| = |in|^(-1) mod |p|. */
ecp_sm2p256_mod_inverse(BN_ULONG * out,const BN_ULONG * in)168 static ossl_inline void ecp_sm2p256_mod_inverse(BN_ULONG *out,
169 const BN_ULONG *in)
170 {
171 BN_MOD_INV(out, in, ecp_sm2p256_div_by_2, ecp_sm2p256_sub, def_p);
172 }
173
174 /*
175 * Constant-time conditional copy: r = mask ? a : r, where mask is either 0 or
176 * all-ones. Used to select point-addition results without branching.
177 */
ecp_sm2p256_cond_copy(P256_POINT * r,const P256_POINT * a,BN_ULONG mask)178 static ossl_inline void ecp_sm2p256_cond_copy(P256_POINT *r,
179 const P256_POINT *a, BN_ULONG mask)
180 {
181 unsigned int i;
182
183 for (i = 0; i < P256_LIMBS; ++i) {
184 r->X[i] = constant_time_select_64(mask, a->X[i], r->X[i]);
185 r->Y[i] = constant_time_select_64(mask, a->Y[i], r->Y[i]);
186 r->Z[i] = constant_time_select_64(mask, a->Z[i], r->Z[i]);
187 }
188 }
189
190 /*
191 * Point double: R <- P + P
192 *
193 * Branch-free: the doubling formula already produces Z = 0 (the point at
194 * infinity) when the input Z is 0 (R->Z = 2*Y*Z), and the resulting X, Y are
195 * irrelevant for a Z = 0 point, so no is_zeros(P->Z) special case is needed.
196 */
ecp_sm2p256_point_double(P256_POINT * R,const P256_POINT * P)197 static void ecp_sm2p256_point_double(P256_POINT *R, const P256_POINT *P)
198 {
199 ALIGN32 BN_ULONG tmp0[P256_LIMBS];
200 ALIGN32 BN_ULONG tmp1[P256_LIMBS];
201 ALIGN32 BN_ULONG tmp2[P256_LIMBS];
202
203 ecp_sm2p256_sqr(tmp0, P->Z);
204 ecp_sm2p256_sub(tmp1, P->X, tmp0);
205 ecp_sm2p256_add(tmp0, P->X, tmp0);
206 ecp_sm2p256_mul(tmp1, tmp1, tmp0);
207 ecp_sm2p256_mul_by_3(tmp1, tmp1);
208 ecp_sm2p256_add(R->Y, P->Y, P->Y);
209 ecp_sm2p256_mul(R->Z, R->Y, P->Z);
210 ecp_sm2p256_sqr(R->Y, R->Y);
211 ecp_sm2p256_mul(tmp2, R->Y, P->X);
212 ecp_sm2p256_sqr(R->Y, R->Y);
213 ecp_sm2p256_div_by_2(R->Y, R->Y);
214 ecp_sm2p256_sqr(R->X, tmp1);
215 ecp_sm2p256_add(tmp0, tmp2, tmp2);
216 ecp_sm2p256_sub(R->X, R->X, tmp0);
217 ecp_sm2p256_sub(tmp0, tmp2, R->X);
218 ecp_sm2p256_mul(tmp0, tmp0, tmp1);
219 ecp_sm2p256_sub(tmp1, tmp0, R->Y);
220 memcpy(R->Y, tmp1, 32);
221 }
222
223 /* Point add affine: R <- P + Q */
224 /*
225 * NB: this function is deliberately NOT constant time. It is used only to
226 * precompute the table of small multiples of the *public* input point (see
227 * ecp_sm2p256_point_P_mul_by_scalar); the secret scalar never flows through
228 * it, so its identity-dependent branches cannot leak it. Keeping the fast
229 * branchy formula here avoids the constant-time overhead on the table build.
230 */
ecp_sm2p256_point_add_affine(P256_POINT * R,const P256_POINT * P,const P256_POINT_AFFINE * Q)231 static void ecp_sm2p256_point_add_affine(P256_POINT *R, const P256_POINT *P,
232 const P256_POINT_AFFINE *Q)
233 {
234 unsigned int i;
235 ALIGN32 BN_ULONG tmp0[P256_LIMBS] = { 0 };
236 ALIGN32 BN_ULONG tmp1[P256_LIMBS] = { 0 };
237 ALIGN32 BN_ULONG tmp2[P256_LIMBS] = { 0 };
238 ALIGN32 BN_ULONG tmp3[P256_LIMBS] = { 0 };
239
240 /* zero-check P->Z */
241 if (is_zeros(P->Z)) {
242 for (i = 0; i < P256_LIMBS; ++i) {
243 R->X[i] = Q->X[i];
244 R->Y[i] = Q->Y[i];
245 R->Z[i] = 0;
246 }
247 R->Z[0] = 1;
248
249 return;
250 }
251
252 ecp_sm2p256_sqr(tmp0, P->Z);
253 ecp_sm2p256_mul(tmp1, tmp0, P->Z);
254 ecp_sm2p256_mul(tmp0, tmp0, Q->X);
255 ecp_sm2p256_mul(tmp1, tmp1, Q->Y);
256 ecp_sm2p256_sub(tmp0, tmp0, P->X);
257 ecp_sm2p256_sub(tmp1, tmp1, P->Y);
258
259 /* zero-check tmp0, tmp1 */
260 if (is_zeros(tmp0)) {
261 if (is_zeros(tmp1)) {
262 P256_POINT K;
263
264 for (i = 0; i < P256_LIMBS; ++i) {
265 K.X[i] = Q->X[i];
266 K.Y[i] = Q->Y[i];
267 K.Z[i] = 0;
268 }
269 K.Z[0] = 1;
270 ecp_sm2p256_point_double(R, &K);
271 } else {
272 for (i = 0; i < P256_LIMBS; ++i)
273 R->Z[i] = 0;
274 }
275
276 return;
277 }
278
279 ecp_sm2p256_mul(R->Z, P->Z, tmp0);
280 ecp_sm2p256_sqr(tmp2, tmp0);
281 ecp_sm2p256_mul(tmp3, tmp2, tmp0);
282 ecp_sm2p256_mul(tmp2, tmp2, P->X);
283 ecp_sm2p256_add(tmp0, tmp2, tmp2);
284 ecp_sm2p256_sqr(R->X, tmp1);
285 ecp_sm2p256_sub(R->X, R->X, tmp0);
286 ecp_sm2p256_sub(R->X, R->X, tmp3);
287 ecp_sm2p256_sub(tmp2, tmp2, R->X);
288 ecp_sm2p256_mul(tmp2, tmp2, tmp1);
289 ecp_sm2p256_mul(tmp3, tmp3, P->Y);
290 ecp_sm2p256_sub(R->Y, tmp2, tmp3);
291 }
292
293 /* Point add: R <- P + Q */
ecp_sm2p256_point_add(P256_POINT * R,const P256_POINT * P,const P256_POINT * Q)294 static void ecp_sm2p256_point_add(P256_POINT *R, const P256_POINT *P,
295 const P256_POINT *Q)
296 {
297 ALIGN32 BN_ULONG tmp0[P256_LIMBS] = { 0 };
298 ALIGN32 BN_ULONG tmp1[P256_LIMBS] = { 0 };
299 ALIGN32 BN_ULONG tmp2[P256_LIMBS] = { 0 };
300 P256_POINT sum, dbl, res;
301 BN_ULONG p_inf, q_inf, is_dbl;
302
303 p_inf = is_zeros(P->Z);
304 q_inf = is_zeros(Q->Z);
305
306 /*
307 * General P + Q addition into |sum|, valid unless P or Q is infinity or
308 * P == +-Q. tmp0 = H and tmp1 = R are the coordinate differences: P and Q
309 * are the same point iff both are zero; P == -Q iff only H is zero (the
310 * formula then yields Z = 0, i.e. infinity, on its own).
311 */
312 ecp_sm2p256_sqr(tmp0, P->Z);
313 ecp_sm2p256_mul(tmp1, tmp0, P->Z);
314 ecp_sm2p256_mul(tmp0, tmp0, Q->X);
315 ecp_sm2p256_mul(tmp1, tmp1, Q->Y);
316 ecp_sm2p256_mul(sum.Y, P->Y, Q->Z);
317 ecp_sm2p256_mul(sum.Z, Q->Z, P->Z);
318 ecp_sm2p256_sqr(tmp2, Q->Z);
319 ecp_sm2p256_mul(sum.Y, tmp2, sum.Y);
320 ecp_sm2p256_mul(sum.X, tmp2, P->X);
321 ecp_sm2p256_sub(tmp0, tmp0, sum.X);
322 ecp_sm2p256_mul(sum.Z, tmp0, sum.Z);
323 ecp_sm2p256_sub(tmp1, tmp1, sum.Y);
324 is_dbl = is_zeros(tmp0) & is_zeros(tmp1);
325 ecp_sm2p256_sqr(tmp2, tmp0);
326 ecp_sm2p256_mul(tmp0, tmp0, tmp2);
327 ecp_sm2p256_mul(tmp2, tmp2, sum.X);
328 ecp_sm2p256_sqr(sum.X, tmp1);
329 ecp_sm2p256_sub(sum.X, sum.X, tmp2);
330 ecp_sm2p256_sub(sum.X, sum.X, tmp2);
331 ecp_sm2p256_sub(sum.X, sum.X, tmp0);
332 ecp_sm2p256_sub(tmp2, tmp2, sum.X);
333 ecp_sm2p256_mul(tmp2, tmp1, tmp2);
334 ecp_sm2p256_mul(tmp0, tmp0, sum.Y);
335 ecp_sm2p256_sub(sum.Y, tmp2, tmp0);
336
337 /* 2*P, for the P == Q case. */
338 ecp_sm2p256_point_double(&dbl, P);
339
340 /*
341 * Select the result without branching, in increasing priority:
342 * default -> sum (distinct points; also P == -Q which gives infinity)
343 * is_dbl -> dbl (P == Q)
344 * q_inf -> P (Q is infinity)
345 * p_inf -> Q (P is infinity; highest priority)
346 * All reads of P and Q happen before R is written, so R may alias P or Q.
347 */
348 memcpy(&res, &sum, sizeof(res));
349 ecp_sm2p256_cond_copy(&res, &dbl, is_dbl);
350 ecp_sm2p256_cond_copy(&res, P, q_inf);
351 ecp_sm2p256_cond_copy(&res, Q, p_inf);
352 memcpy(R, &res, sizeof(res));
353 }
354
355 #if !defined(OPENSSL_NO_SM2_PRECOMP)
356 /* Base point mul by scalar: k - scalar, G - base point */
357 /*
358 * Constant-time gather of the affine entry |index| from a 256-entry sub-table.
359 * |sub| points to the sub-table for one 8-bit comb window; entry v is stored
360 * as X[P256_LIMBS] followed by Y[P256_LIMBS] at sub + v * (2 * P256_LIMBS).
361 * Entry 0 is not stored, so index 0 yields the all-zero (X, Y) placeholder,
362 * which the caller turns into the point at infinity.
363 */
ecp_sm2p256_select_G(P256_POINT_AFFINE * R,const BN_ULONG * sub,unsigned int index)364 static void ecp_sm2p256_select_G(P256_POINT_AFFINE *R, const BN_ULONG *sub,
365 unsigned int index)
366 {
367 unsigned int v, j;
368
369 memset(R, 0, sizeof(*R));
370 for (v = 1; v < 256; ++v) {
371 BN_ULONG mask = constant_time_is_zero_64((BN_ULONG)(index ^ v));
372 const BN_ULONG *e = sub + (size_t)v * (2 * P256_LIMBS);
373
374 for (j = 0; j < P256_LIMBS; ++j) {
375 R->X[j] |= constant_time_select_64(mask, e[j], 0);
376 R->Y[j] |= constant_time_select_64(mask, e[P256_LIMBS + j], 0);
377 }
378 }
379 }
380
381 /*
382 * R = k*G using the precomputed comb. Constant-time: every 8-bit window is
383 * gathered from its full 256-entry sub-table with a mask and lifted to a
384 * Jacobian point whose Z is 1 for a non-zero window and 0 (infinity) for a
385 * zero window, so the unconditional, branch-free addition contributes nothing
386 * for a zero window and no secret-dependent branch or table index remains.
387 */
ecp_sm2p256_point_G_mul_by_scalar(P256_POINT * R,const BN_ULONG * k)388 static void ecp_sm2p256_point_G_mul_by_scalar(P256_POINT *R, const BN_ULONG *k)
389 {
390 unsigned int i, j, index;
391 P256_POINT_AFFINE Qaff;
392 P256_POINT QJ;
393
394 memset(R, 0, sizeof(P256_POINT));
395
396 for (i = 0; i < 32; ++i) {
397 index = (k[i / 8] >> (8 * (i % 8))) & 0xff;
398 ecp_sm2p256_select_G(&Qaff,
399 ecp_sm2p256_precomputed + (size_t)i * 256 * (2 * P256_LIMBS),
400 index);
401
402 {
403 /* Z = 1 iff the window is non-zero, else 0 (point at infinity). */
404 BN_ULONG nz = ~constant_time_is_zero_64((BN_ULONG)index);
405
406 for (j = 0; j < P256_LIMBS; ++j) {
407 QJ.X[j] = Qaff.X[j];
408 QJ.Y[j] = Qaff.Y[j];
409 QJ.Z[j] = 0;
410 }
411 QJ.Z[0] = nz & 1;
412 }
413 ecp_sm2p256_point_add(R, R, &QJ);
414 }
415 }
416 #endif
417
418 /*
419 * Constant-time gather of |index| from a 16-entry table of Jacobian points.
420 * Index 0 yields the all-zero point (Z = 0, i.e. the point at infinity).
421 */
ecp_sm2p256_select_P(P256_POINT * R,const P256_POINT tbl[16],unsigned int index)422 static void ecp_sm2p256_select_P(P256_POINT *R, const P256_POINT tbl[16],
423 unsigned int index)
424 {
425 unsigned int i, j;
426
427 memset(R, 0, sizeof(*R));
428 for (i = 1; i < 16; ++i) {
429 BN_ULONG mask = constant_time_is_zero_64((BN_ULONG)(index ^ i));
430
431 for (j = 0; j < P256_LIMBS; ++j) {
432 R->X[j] |= constant_time_select_64(mask, tbl[i].X[j], 0);
433 R->Y[j] |= constant_time_select_64(mask, tbl[i].Y[j], 0);
434 R->Z[j] |= constant_time_select_64(mask, tbl[i].Z[j], 0);
435 }
436 }
437 }
438
439 /*
440 * Affine point mul by scalar: k - scalar, P - affine point
441 *
442 * Constant-time windowed multiplication: every 4-bit window is processed
443 * uniformly with four doublings followed by a masked table gather and an
444 * unconditional, branch-free addition. There is no init/skip logic and no
445 * secret-dependent table index, so the running time and memory-access pattern
446 * do not depend on the value of the secret scalar.
447 */
ecp_sm2p256_point_P_mul_by_scalar(P256_POINT * R,const BN_ULONG * k,P256_POINT_AFFINE P)448 static void ecp_sm2p256_point_P_mul_by_scalar(P256_POINT *R, const BN_ULONG *k,
449 P256_POINT_AFFINE P)
450 {
451 int i;
452 unsigned int index, mask = 0x0f;
453 ALIGN64 P256_POINT precomputed[16];
454 P256_POINT T;
455
456 /* The first value of the precomputed table is P. */
457 memcpy(precomputed[1].X, P.X, 32);
458 memcpy(precomputed[1].Y, P.Y, 32);
459 precomputed[1].Z[0] = 1;
460 precomputed[1].Z[1] = 0;
461 precomputed[1].Z[2] = 0;
462 precomputed[1].Z[3] = 0;
463
464 /* The second value of the precomputed table is 2P. */
465 ecp_sm2p256_point_double(&precomputed[2], &precomputed[1]);
466
467 /* The subsequent elements are 3P, 4P, and so on. */
468 for (i = 3; i < 16; ++i)
469 ecp_sm2p256_point_add_affine(&precomputed[i], &precomputed[i - 1], &P);
470
471 memset(R, 0, sizeof(*R)); /* R = point at infinity */
472
473 for (i = 64 - 1; i >= 0; --i) {
474 index = (k[i / 16] >> (4 * (i % 16))) & mask;
475
476 ecp_sm2p256_point_double(R, R);
477 ecp_sm2p256_point_double(R, R);
478 ecp_sm2p256_point_double(R, R);
479 ecp_sm2p256_point_double(R, R);
480
481 ecp_sm2p256_select_P(&T, precomputed, index);
482 ecp_sm2p256_point_add(R, R, &T);
483 }
484 }
485
486 /* Get affine point */
ecp_sm2p256_point_get_affine(P256_POINT_AFFINE * R,const P256_POINT * P)487 static void ecp_sm2p256_point_get_affine(P256_POINT_AFFINE *R,
488 const P256_POINT *P)
489 {
490 ALIGN32 BN_ULONG z_inv3[P256_LIMBS] = { 0 };
491 ALIGN32 BN_ULONG z_inv2[P256_LIMBS] = { 0 };
492
493 if (is_one(P->Z)) {
494 memcpy(R->X, P->X, 32);
495 memcpy(R->Y, P->Y, 32);
496 return;
497 }
498
499 ecp_sm2p256_mod_inverse(z_inv3, P->Z);
500 ecp_sm2p256_sqr(z_inv2, z_inv3);
501 ecp_sm2p256_mul(R->X, P->X, z_inv2);
502 ecp_sm2p256_mul(z_inv3, z_inv3, z_inv2);
503 ecp_sm2p256_mul(R->Y, P->Y, z_inv3);
504 }
505
506 #if !defined(OPENSSL_NO_SM2_PRECOMP)
ecp_sm2p256_is_affine_G(const EC_POINT * generator)507 static int ecp_sm2p256_is_affine_G(const EC_POINT *generator)
508 {
509 return (bn_get_top(generator->X) == P256_LIMBS)
510 && (bn_get_top(generator->Y) == P256_LIMBS)
511 && is_equal(bn_get_words(generator->X), def_xG)
512 && is_equal(bn_get_words(generator->Y), def_yG)
513 && (generator->Z_is_one == 1);
514 }
515 #endif
516
517 /* r = sum(scalar[i]*point[i]) */
ecp_sm2p256_windowed_mul(const EC_GROUP * group,P256_POINT * r,const BIGNUM ** scalar,const EC_POINT ** point,size_t num,BN_CTX * ctx)518 static int ecp_sm2p256_windowed_mul(const EC_GROUP *group,
519 P256_POINT *r,
520 const BIGNUM **scalar,
521 const EC_POINT **point,
522 size_t num, BN_CTX *ctx)
523 {
524 unsigned int i;
525 int ret = 0;
526 const BIGNUM **scalars = NULL;
527 ALIGN32 BN_ULONG k[P256_LIMBS] = { 0 };
528 P256_POINT kP;
529 ALIGN32 union {
530 P256_POINT p;
531 P256_POINT_AFFINE a;
532 } t, p;
533
534 if (num > OPENSSL_MALLOC_MAX_NELEMS(P256_POINT)
535 || (scalars = OPENSSL_malloc(num * sizeof(BIGNUM *))) == NULL) {
536 ECerr(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
537 goto err;
538 }
539
540 memset(r, 0, sizeof(P256_POINT));
541
542 for (i = 0; i < num; i++) {
543 if (EC_POINT_is_at_infinity(group, point[i]))
544 continue;
545
546 if ((BN_num_bits(scalar[i]) > 256) || BN_is_negative(scalar[i])) {
547 BIGNUM *tmp;
548
549 if ((tmp = BN_CTX_get(ctx)) == NULL)
550 goto err;
551 if (!BN_nnmod(tmp, scalar[i], group->order, ctx)) {
552 ECerr(ERR_LIB_EC, ERR_R_BN_LIB);
553 goto err;
554 }
555 scalars[i] = tmp;
556 } else {
557 scalars[i] = scalar[i];
558 }
559
560 if (ecp_sm2p256_bignum_field_elem(k, scalars[i]) <= 0
561 || ecp_sm2p256_bignum_field_elem(p.p.X, point[i]->X) <= 0
562 || ecp_sm2p256_bignum_field_elem(p.p.Y, point[i]->Y) <= 0
563 || ecp_sm2p256_bignum_field_elem(p.p.Z, point[i]->Z) <= 0) {
564 ECerr(ERR_LIB_EC, EC_R_COORDINATES_OUT_OF_RANGE);
565 goto err;
566 }
567
568 ecp_sm2p256_point_get_affine(&t.a, &p.p);
569 ecp_sm2p256_point_P_mul_by_scalar(&kP, k, t.a);
570 ecp_sm2p256_point_add(r, r, &kP);
571 }
572
573 ret = 1;
574 err:
575 OPENSSL_free(scalars);
576 return ret;
577 }
578
579 /* r = scalar*G + sum(scalars[i]*points[i]) */
ecp_sm2p256_points_mul(const EC_GROUP * group,EC_POINT * r,const BIGNUM * scalar,size_t num,const EC_POINT * points[],const BIGNUM * scalars[],BN_CTX * ctx)580 static int ecp_sm2p256_points_mul(const EC_GROUP *group,
581 EC_POINT *r,
582 const BIGNUM *scalar,
583 size_t num,
584 const EC_POINT *points[],
585 const BIGNUM *scalars[], BN_CTX *ctx)
586 {
587 int ret = 0, p_is_infinity = 0;
588 const EC_POINT *generator = NULL;
589 ALIGN32 BN_ULONG k[P256_LIMBS] = { 0 };
590 ALIGN32 union {
591 P256_POINT p;
592 P256_POINT_AFFINE a;
593 } t, p;
594
595 if ((num + 1) == 0 || (num + 1) > OPENSSL_MALLOC_MAX_NELEMS(void *)) {
596 ECerr(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
597 goto err;
598 }
599
600 BN_CTX_start(ctx);
601
602 if (scalar) {
603 generator = EC_GROUP_get0_generator(group);
604 if (generator == NULL) {
605 ECerr(ERR_LIB_EC, EC_R_UNDEFINED_GENERATOR);
606 goto err;
607 }
608
609 if (!ecp_sm2p256_bignum_field_elem(k, scalar)) {
610 ECerr(ERR_LIB_EC, EC_R_COORDINATES_OUT_OF_RANGE);
611 goto err;
612 }
613 #if !defined(OPENSSL_NO_SM2_PRECOMP)
614 if (ecp_sm2p256_is_affine_G(generator)) {
615 ecp_sm2p256_point_G_mul_by_scalar(&p.p, k);
616 } else
617 #endif
618 {
619 /* if no precomputed table */
620 const EC_POINT *new_generator[1];
621 const BIGNUM *g_scalars[1];
622
623 new_generator[0] = generator;
624 g_scalars[0] = scalar;
625
626 if (!ecp_sm2p256_windowed_mul(group, &p.p, g_scalars, new_generator,
627 (new_generator[0] != NULL
628 && g_scalars[0] != NULL),
629 ctx))
630 goto err;
631 }
632 } else {
633 p_is_infinity = 1;
634 }
635 if (num) {
636 P256_POINT *out = &t.p;
637
638 if (p_is_infinity)
639 out = &p.p;
640
641 if (!ecp_sm2p256_windowed_mul(group, out, scalars, points, num, ctx))
642 goto err;
643
644 if (!p_is_infinity)
645 ecp_sm2p256_point_add(&p.p, &p.p, out);
646 }
647
648 /* Not constant-time, but we're only operating on the public output. */
649 if (!bn_set_words(r->X, p.p.X, P256_LIMBS)
650 || !bn_set_words(r->Y, p.p.Y, P256_LIMBS)
651 || !bn_set_words(r->Z, p.p.Z, P256_LIMBS))
652 goto err;
653 r->Z_is_one = is_equal(bn_get_words(r->Z), ONE) & 1;
654
655 ret = 1;
656 err:
657 BN_CTX_end(ctx);
658 return ret;
659 }
660
ecp_sm2p256_field_mul(const EC_GROUP * group,BIGNUM * r,const BIGNUM * a,const BIGNUM * b,BN_CTX * ctx)661 static int ecp_sm2p256_field_mul(const EC_GROUP *group, BIGNUM *r,
662 const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
663 {
664 ALIGN32 BN_ULONG a_fe[P256_LIMBS] = { 0 };
665 ALIGN32 BN_ULONG b_fe[P256_LIMBS] = { 0 };
666 ALIGN32 BN_ULONG r_fe[P256_LIMBS] = { 0 };
667
668 if (a == NULL || b == NULL || r == NULL)
669 return 0;
670
671 if (!ecp_sm2p256_bignum_field_elem(a_fe, a)
672 || !ecp_sm2p256_bignum_field_elem(b_fe, b)) {
673 ECerr(ERR_LIB_EC, EC_R_COORDINATES_OUT_OF_RANGE);
674 return 0;
675 }
676
677 ecp_sm2p256_mul(r_fe, a_fe, b_fe);
678
679 if (!bn_set_words(r, r_fe, P256_LIMBS))
680 return 0;
681
682 return 1;
683 }
684
ecp_sm2p256_field_sqr(const EC_GROUP * group,BIGNUM * r,const BIGNUM * a,BN_CTX * ctx)685 static int ecp_sm2p256_field_sqr(const EC_GROUP *group, BIGNUM *r,
686 const BIGNUM *a, BN_CTX *ctx)
687 {
688 ALIGN32 BN_ULONG a_fe[P256_LIMBS] = { 0 };
689 ALIGN32 BN_ULONG r_fe[P256_LIMBS] = { 0 };
690
691 if (a == NULL || r == NULL)
692 return 0;
693
694 if (!ecp_sm2p256_bignum_field_elem(a_fe, a)) {
695 ECerr(ERR_LIB_EC, EC_R_COORDINATES_OUT_OF_RANGE);
696 return 0;
697 }
698
699 ecp_sm2p256_sqr(r_fe, a_fe);
700
701 if (!bn_set_words(r, r_fe, P256_LIMBS))
702 return 0;
703
704 return 1;
705 }
706
EC_GFp_sm2p256_method(void)707 const EC_METHOD *EC_GFp_sm2p256_method(void)
708 {
709 static const EC_METHOD ret = {
710 EC_FLAGS_DEFAULT_OCT,
711 NID_X9_62_prime_field,
712 ossl_ec_GFp_simple_group_init,
713 ossl_ec_GFp_simple_group_finish,
714 ossl_ec_GFp_simple_group_clear_finish,
715 ossl_ec_GFp_simple_group_copy,
716 ossl_ec_GFp_simple_group_set_curve,
717 ossl_ec_GFp_simple_group_get_curve,
718 ossl_ec_GFp_simple_group_get_degree,
719 ossl_ec_group_simple_order_bits,
720 ossl_ec_GFp_simple_group_check_discriminant,
721 ossl_ec_GFp_simple_point_init,
722 ossl_ec_GFp_simple_point_finish,
723 ossl_ec_GFp_simple_point_clear_finish,
724 ossl_ec_GFp_simple_point_copy,
725 ossl_ec_GFp_simple_point_set_to_infinity,
726 ossl_ec_GFp_simple_point_set_affine_coordinates,
727 ossl_ec_GFp_simple_point_get_affine_coordinates,
728 0, 0, 0,
729 ossl_ec_GFp_simple_add,
730 ossl_ec_GFp_simple_dbl,
731 ossl_ec_GFp_simple_invert,
732 ossl_ec_GFp_simple_is_at_infinity,
733 ossl_ec_GFp_simple_is_on_curve,
734 ossl_ec_GFp_simple_cmp,
735 ossl_ec_GFp_simple_make_affine,
736 ossl_ec_GFp_simple_points_make_affine,
737 ecp_sm2p256_points_mul, /* mul */
738 0 /* precompute_mult */,
739 0 /* have_precompute_mult */,
740 ecp_sm2p256_field_mul,
741 ecp_sm2p256_field_sqr,
742 0 /* field_div */,
743 ossl_ec_GFp_simple_field_inv,
744 0 /* field_encode */,
745 0 /* field_decode */,
746 0 /* field_set_to_one */,
747 ossl_ec_key_simple_priv2oct,
748 ossl_ec_key_simple_oct2priv,
749 0, /* set private */
750 ossl_ec_key_simple_generate_key,
751 ossl_ec_key_simple_check_key,
752 ossl_ec_key_simple_generate_public_key,
753 0, /* keycopy */
754 0, /* keyfinish */
755 ossl_ecdh_simple_compute_key,
756 ossl_ecdsa_simple_sign_setup,
757 ossl_ecdsa_simple_sign_sig,
758 ossl_ecdsa_simple_verify_sig,
759 0, /* use constant‑time fallback for inverse mod order */
760 0, /* blind_coordinates */
761 0, /* ladder_pre */
762 0, /* ladder_step */
763 0 /* ladder_post */
764 };
765
766 return &ret;
767 }
768