xref: /freebsd/crypto/openssl/crypto/ec/ecp_sm2p256.c (revision f9bc005b8ef3b507a5ecbc2d7fe4411ef70eff38)
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