Sorry for so long to reply, I tried to fork a branch in gitlab(https://git.lysator.liu.se/nettle/nettle) but failed, seemed that I don’t have enough permissions, or should I push my code in github(https://github.com/gnutls/nettle) ? Here are the replies:
>"zhongxuan (A)" <[email protected]> writes: > >> Anyway, I made a realization of SM2, Here is the first part of it, >> including the curve and sm2_add and sm2_mul in affine coordinate. > >Thanks, I'm having a first read, see comments below. It would be good to have >a link to the best english-language (and freely available) reference. I think >you have told me earlier, and I've found >https://datatracker.ietf.org/doc/html/draft-shen-sm2-ecdsa. It would be >helpful with a reference in a comment, e.g., at the top of ecc-sm2.c. Insert a opensource link of this elliptic curve at the top of ecc-sm2.c > >> And if it's convenient to you, I can push the other parts including >> keygen, crypt and sign. > >I think it's a good first step to get basic scalar multiplication working, >i.e., ecc_point_mul and ecc_point_mul_g working and tested. Thus this sm2 is also a 'a + 3 mod p = 0' elliptic curve, the mul_a and mul_g function of secp256r1 can also work. We have tested the result with the geometric method like what in eccdata.c. > >For signatures, are they similar to ECDSA, or something different? For >encryption, how does that work? Yes its similar to ECDSA, you can refer to this page: https://datatracker.ietf.org/doc/html/draft-shen-sm2-ecdsa Or there is an official public manual about this curve: http://www.gmbz.org.cn/main/postDetail.html?id=20180724110812 I'm not sure whether could you access these pdfs. > >My initial comments on your patch inline below. > >Regards, >/Niels > >> --- /dev/null >> +++ b/ecc-sm2.c >> @@ -0,0 +1,261 @@ >> +/* ecc-sm2.c >> + >> + Compile time constant (but machine dependent) tables. > >Anything that is machine dependent should be in ecc-sm2.h, generated by >eccdata. Removed. > >> + Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights >> reserved. >> + >> + This file is part of GNU Nettle. >> + >> + GNU Nettle is free software: you can redistribute it and/or >> + modify it under the terms of either: >> + >> + * the GNU Lesser General Public License as published by the Free >> + Software Foundation; either version 3 of the License, or (at your >> + option) any later version. >> + >> + or >> + >> + * the GNU General Public License as published by the Free >> + Software Foundation; either version 2 of the License, or (at your >> + option) any later version. >> + >> + or both in parallel, as here. >> + >> + GNU Nettle is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + General Public License for more details. >> + >> + You should have received copies of the GNU General Public License and >> + the GNU Lesser General Public License along with this program. If >> + not, see http://www.gnu.org/licenses/. >> +*/ >> + >> +/* Development of Nettle's ECC support was funded by the .SE >> +Internet Fund. */ >> + >> +#if HAVE_CONFIG_H >> +# include "config.h" >> +#endif >> + >> +#include <string.h> >> +#include <assert.h> >> + >> +#include "sm2.h" >> +#include "sm2-internal.h" >> +#include "ecc-internal.h" >> +#include "ecc-sm2.h" >> +#include "ecc-curve.h" >> + >> +const char *nettle_sm2_a = >> +"fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc"; >> +const char *nettle_sm2_xG = >> +"32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7"; >> +const char *nettle_sm2_yG = >> +"bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0"; > >These strings appear unused. Yep, this base point is unused, removed. The nettle_sm2_a used to check whether a point is in sm2 curve, by checking y^2 = x^3 + ax + b. > >> +static void >> +ecc_sm2_inv (const struct ecc_modulo *p, >> + mp_limb_t *rp, const mp_limb_t *ap, >> + mp_limb_t *scratch) { #define a5m1 scratch >> +#define >> +t0 (scratch + ECC_LIMB_SIZE) #define a15m1 t0 #define a32m1 a5m1 >> +#define a62m1 (scratch + 2*ECC_LIMB_SIZE) #define a96m1 t0 #define >> +a3 (scratch + 3*ECC_LIMB_SIZE) #define tp (scratch + >> +4*ECC_LIMB_SIZE) >> +/* >> + Addition chain for p - 2 = 2^{256} - 2^{224} + 2^{192} + 2^{96} - >> +3 >> + >> + 2^5 - 1 = 1 + 2 (2^4 - 1) = 1 + 2 (2^2+1)(2 + 1) 4 S + 3 M >> + 2^{15} - 1 = (2^5 - 1) (1 + 2^5 (1 + 2^5) 10 S + 2 M >> + 2^{16} - 1 = 1 + 2 (2^{15} - 1) S + M >> + 2^{32} - 1 = (2^{16} + 1) (2^{16} - 1) 16 S + M >> + >> + 2^{31} - 1 = (2^{16} - 1) * 2^{15} + 2^{15} - 1 >> + 2^{62} - 1 = (2^{31} - 1) * 2^{31} + 2^{31} - 1 >> + 2^{94} - 1 = (2^{62} - 1) * 2^{32} + 2^{32} - 1 >> + 2^{96} - 1 = (2^{94} - 1) * 2^{2} + 3 >> + >> + 2^{64} - 2^{32} - 1 = (2^{32} - 2) * 2^{32} + 2^{32} - 1 >> + 2^{160} - 2^{128} - 1 = (2^{64} - 2^{32} - 1) * 2^{96} + 2^{96} - 1 >> + 2^{254} - 2^{222} - 2^{94} + 2^{62} - 1 = (2^{160} - 2^{128} - 1) * >> 2^{94} + 2^{62} - 1 >> + 2^{256} - 2^{224} - 2^{96} + 2^{64} - 3 = (2^{254} - 2^{222} - >> + 2^{94} + 2^{62} - 1) * 2^{2} + 1 >> + >> + */ >> + ecc_mod_sqr (p, rp, ap, tp); /* a^2 */ >> + ecc_mod_mul (p, a3, rp, ap, tp); /* a^3 */ >> + ecc_mod_pow_2kp1 (p, t0, a3, 2, tp); /* a^{2^4 - 1} */ >> + ecc_mod_sqr (p, rp, t0, tp); /* a^{2^5 - 2} */ >> + ecc_mod_mul (p, a5m1, rp, ap, tp); /* a^{2^5 - 1}, a5m1 */ >> + >> + ecc_mod_pow_2kp1 (p, rp, a5m1, 5, tp); /* a^{2^{10} - 1, a5m1*/ >> + ecc_mod_pow_2k_mul (p, a15m1, rp, 5, a5m1, tp); /* a^{2^{15} - 1}, a5m1 >> a15m1 */ >> + ecc_mod_sqr (p, rp, a15m1, tp); /* a^{2^{16} - 2}, a15m1 */ >> + ecc_mod_mul (p, rp, rp, ap, tp); /* a^{2^{16} - 1}, a15m1 */ >> + ecc_mod_pow_2kp1 (p, a32m1, rp, 16, tp); /* a^{2^{32} - 1}, a15m1, >> a32m1 */ >> + ecc_mod_pow_2k_mul (p, rp, rp, 15, a15m1, tp); /* a^{2^{31} - 1}, >> + a15m1 */ >> + >> + ecc_mod_pow_2kp1 (p, a62m1, rp, 31, tp); /* a^{2^{62} - 1}, a62m1 >> + */ ecc_mod_pow_2k_mul (p, a96m1, a62m1, 32, a32m1, tp); /* >> + a^{2^{94} - 1}, a62m1, a32m1 */ ecc_mod_pow_2k_mul (p, a96m1, >> + a96m1, 2, a3, tp); /* a^{2^{96} - 1}, a96m1, a3 */ >> + >> + ecc_mod_sqr (p, rp, rp, tp); /* a^{2^{32} - 2} */ >> + ecc_mod_pow_2k_mul (p, rp, rp, 32, a32m1, tp); /* a^{2^{64} - >> +2^{32} - 1 */ >> + ecc_mod_pow_2k_mul (p, rp, rp, 96, a96m1, tp); /* a^{2^{160} - >> +2^{128} - 1 */ >> + ecc_mod_pow_2k_mul (p, rp, rp, 94, a62m1, tp); /* a^{2^{254} - >> +2^{222} - 2^{94} + 2^{62} - 1}, a62m1 */ >> + ecc_mod_pow_2k_mul (p, rp, rp, 2, ap, tp); /* a^{2^{256} - 2^{224} >> +- 2^{96} + 2^{64} - 3} */ } >> + >> +void >> +sm2_get_order (mpz_t order) >> +{ >> + if (!order->_mp_d) >> + return; >> + const struct ecc_curve *ecc = nettle_get_sm2(); >> + mpz_set_n(order, ecc->q.m, ecc->q.size); } > >Why is the sm2_get_order needed? It appears unused in the current patch. Yes, this is a test interface, removed. > >> +static mp_limb_t SM2_P[8] = { >> + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, >> + 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, }; > >Is this for 32-bit limb size? On which platform have you tested the code? >Should probably use _nettle_sm2.p.m instead. No, its still a 64-bit limb size, we use it in fast reduction, we will try to use a nettle interface instead. > >I'm a bit confused, because this looks like 32-bit limbs, but elsewhere you >shift by 32 bits which isn't valid for this limb size. > >> +static int sm2_bn_cmp(const mp_limb_t *a, const mp_limb_t *b) { >> + int i; >> + for (i = 7; i >= 0; i--) { >> + if (a[i] > b[i]) >> + return 1; >> + if (a[i] < b[i]) >> + return -1; >> + } >> + return 0; >> +} > >This will not be side-channel silent. Seems that we can use mpn_cmp instead, though I don’t get the difference between mpn_cmp and this sm2_bn_cmp, is mpn_cmp also not side-channel silent? > >> +static void sm2_bn_sub(mp_limb_t *ret, const mp_limb_t *a, const >> +mp_limb_t *b) { >> + int i; >> + mp_limb_t r[8]; >> + r[0] = ((uint64_t)1 << 32) + a[0] - b[0]; >> + for (i = 1; i < 7; i++) { >> + r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32); >> + r[i - 1] &= 0xffffffff; >> + } >> + r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1; >> + r[i - 1] &= 0xffffffff; >> + memcpy(ret, r, 64); >> +} > >Is there some reason the general ecc_mod_sub can't work work? Seems that it can't work. We use a fast reduction matrix, splitting a 64 bits limb into two 32 bits limbs. I also tried mpn_sub_n but seems it doesn’t work too. I am trying to optimize the calculation or use ecc_mod here instead. > >> +static void >> +ecc_sm2_modp (const struct ecc_modulo *p, mp_limb_t *rp, mp_limb_t >> +*xp) { >> + uint64_t s[16] = {0}; >> + uint64_t d[8] = {0}; >> + uint64_t r[8] = {0}; >> + >> + for (int i = 0; i < 8; i++) { >> + s[2*i] = xp[i] & 0xffffffff; >> + s[2*i+1] = xp[i] >> 32; >> + } >> + >> + r[0] = s[0] + s[8] + s[9] + s[10] + s[11] + s[12] + ((s[13] + >> + s[14] >> + + s[15]) << 1); r[1] = s[1] + s[9] + s[10] + s[11] + s[12] + s[13] >> + + ((s[14] + s[15]) << 1); r[2] = s[2]; r[3] = s[3] + s[8] + s[11] >> + + s[12] + s[14] + s[15] + (s[13] << 1); r[4] = s[4] + s[9] + s[12] >> + + s[13] + s[15] + (s[14] << 1); r[5] = s[5] + s[10] + s[13] + >> + + s[14] (s[15] << 1); r[6] = s[6] + s[11] + s[14] + s[15]; r[7] = >> + + s[7] + >> + s[8] + s[9] + s[10] + s[11] + s[15] + ((s[12] + s[13] + s[14] + >> + s[15]) << 1); >> + >> + for (int i = 1; i < 8; i++) { >> + r[i] += r[i - 1] >> 32; >> + r[i - 1] &= 0xffffffff; >> + } >> + >> + d[2] = s[8] + s[9] + s[13] + s[14]; d[3] = d[2] >> 32; d[2] &= >> + 0xffffffff; sm2_bn_sub(r, r, d); >> + >> + while (sm2_bn_cmp(r, SM2_P) >= 0) { >> + sm2_bn_sub(r, r, SM2_P); >> + } >> + >> + rp[0] = (r[0] & 0xffffffff) + ((r[1] & 0xffffffff) << 32); rp[1] >> + = (r[2] & 0xffffffff) + ((r[3] & 0xffffffff) << 32); rp[2] = (r[4] >> + & 0xffffffff) + ((r[5] & 0xffffffff) << 32); rp[3] = (r[6] & >> + 0xffffffff) + ((r[7] & 0xffffffff) << 32); } > >I would suggest starting with the general ecc_mod function (I think it should >work for the modulo used with sm2). When that is in place, one can add >optimized variants for 32-bit and/or 64-bit limbs to speed that up. Here is a problem, ecc_mod stop in ' assert (bn < mn); ' in ecc-mod.c line 56, is sm2 different from other weierstrass curves or I made some mistakes? To avoid this I still use ecc_sm2_modp but change the cmp functions with mpn functions. > >> +const struct ecc_curve _nettle_sm2 = { >> + { >> + 256, >> + ECC_LIMB_SIZE, >> + ECC_BMODP_SIZE, >> + ECC_REDC_SIZE, >> + 4 * ECC_LIMB_SIZE, >> + 4 * ECC_LIMB_SIZE, >> + 0, >> + >> + ecc_p, >> + ecc_Bmodp, >> + ecc_Bmodp_shifted, >> + ecc_redc_ppm1, >> + ecc_pp1h, >> + >> + NULL, >> + ecc_sm2_modp, >> + ecc_sm2_inv, >> + NULL, >> + NULL, >> + }, >> + { >> + 256, >> + ECC_LIMB_SIZE, >> + ECC_BMODQ_SIZE, >> + 0, >> + ECC_MOD_INV_ITCH (ECC_LIMB_SIZE), >> + 0, >> + 0, >> + >> + ecc_q, >> + ecc_Bmodq, >> + ecc_Bmodq_shifted, >> + NULL, >> + ecc_qp1h, >> + >> + NULL, >> + NULL, >> + ecc_mod_inv, >> + NULL, >> + NULL, >> + }, >> + >> + ECC_REDC_SIZE == 0, >> + ECC_PIPPENGER_K, >> + ECC_PIPPENGER_C, >> + >> + ECC_ADD_JJA_ITCH (ECC_LIMB_SIZE), >> + ECC_ADD_JJJ_ITCH (ECC_LIMB_SIZE), >> + ECC_DUP_JJ_ITCH (ECC_LIMB_SIZE), >> + ECC_MUL_A_ITCH (ECC_LIMB_SIZE), >> + ECC_MUL_G_ITCH (ECC_LIMB_SIZE), >> + ECC_J_TO_A_ITCH(ECC_LIMB_SIZE, 4 * ECC_LIMB_SIZE), >> + >> + ecc_add_jja, >> + ecc_add_jjj, >> + ecc_dup_jj, > >I had expected pointers to new add and dup functions here, since existing >functions assume a = -3. Thus this sm2's p = 2^256 - x^224 - 2^96 + 2^64 - 1, which is also a 'a + 3 mod p = 0' elliptic curve, the add_jja, add_jjj, dup_jj can also work. We proved it by comparing with geometric method. > >> + ecc_mul_a, >> + ecc_mul_g, >> + ecc_j_to_a, >> + >> + ecc_b, >> + ecc_unit, >> + ecc_table >> +}; >> + >> +const struct ecc_curve *nettle_get_sm2(void) { >> + return &_nettle_sm2; >> +} >> diff --git a/eccdata.c b/eccdata.c >> index 4d8827f..71a524d 100644 >> --- a/eccdata.c >> +++ b/eccdata.c >> @@ -44,6 +44,9 @@ >> >> /* Affine coordinates, for simplicity. Infinity point, i.e., te >> neutral group element, is represented using the is_zero flag. */ >> + >> +const char *nettle_sm2_a = >> +"fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc"; > >Do I get it right that sm2 uses a weierstrass curve, but with a different a >value than the a = -3 used for the other weierstrass curves? >For the eccdata program, I would suggest adding the a constant to the struct >ecc_curve, and use the same formulas for all the weierstrass curves. E.g, add >an argument to ecc_curve_init_str to set a, and let NULL mean the default of >-3. Now we add param a in eccdata first. Besides, I let NULL in EDWARDS curve, which means also -3 although EDWARDS don’t have a param a, would it be fine? Did some changes to ecc_dup to use same formulas in all weierstrass curves. > >> struct ecc_point >> { >> int is_zero; >> @@ -59,6 +62,8 @@ enum ecc_type >> ECC_TYPE_EDWARDS, >> /* -x^2 + y^2 = 1 - d x^2 y^2 */ >> ECC_TYPE_TWISTED_EDWARDS, >> + /* y^2 = x^3 + ax + b (mod p) */ >> + ECC_TYPE_SM2, >> }; >> >> struct ecc_curve >> @@ -145,64 +150,111 @@ static void >> ecc_dup (const struct ecc_curve *ecc, >> struct ecc_point *r, const struct ecc_point *p) { >> - if (ecc->type != ECC_TYPE_WEIERSTRASS) >> - { >> - ecc_add (ecc, r, p, p); >> - return; >> - } >> + if (ecc->type != ECC_TYPE_WEIERSTRASS && ecc->type != >> + ECC_TYPE_SM2) { >> + ecc_add (ecc, r, p, p); >> + return; >> + } >> if (ecc_zero_p (p)) >> ecc_set_zero (ecc, r); >> >> + else if (ecc->type == ECC_TYPE_SM2) { >> + mpz_t m, t, x, y, a; >> + >> + mpz_init (m); >> + mpz_init (t); >> + mpz_init (x); >> + mpz_init (y); >> + mpz_init_set_str(a, nettle_sm2_a, 16); >> + >> + /* m = (2 y)^-1 */ >> + mpz_mul_ui (m, p->y, 2); >> + mpz_invert (m, m, ecc->p); >> + >> + /* t = 3x^2 + a */ >> + mpz_mul (t, p->x, p->x); >> + mpz_mod (t, t, ecc->p); >> + mpz_mul_ui (t, t, 3); >> + mpz_mod (t, t, ecc->p); >> + mpz_add(t, t, a); >> + mpz_mod (t, t, ecc->p); >> + >> + /* t = t * m */ >> + mpz_mul (t, t, m); >> + mpz_mod (t, t, ecc->p); >> + >> + /* x' = t^2 - 2 x */ >> + mpz_mul (x, t, t); >> + mpz_submul_ui (x, p->x, 2); >> + >> + mpz_mod (x, x, ecc->p); >> + >> + /* y' = (x - x') * t - y */ >> + mpz_sub (y, p->x, x); >> + mpz_mul (y, y, t); >> + mpz_sub (y, y, p->y); >> + mpz_mod (y, y, ecc->p); >> + >> + r->is_zero = 0; >> + mpz_swap (x, r->x); >> + mpz_swap (y, r->y); >> + >> + mpz_clear (m); >> + mpz_clear (t); >> + mpz_clear (x); >> + mpz_clear (y); >> + } >> else >> - { >> - mpz_t m, t, x, y; >> - >> - mpz_init (m); >> - mpz_init (t); >> - mpz_init (x); >> - mpz_init (y); >> - >> - /* m = (2 y)^-1 */ >> - mpz_mul_ui (m, p->y, 2); >> - mpz_invert (m, m, ecc->p); >> - >> - /* t = 3 (x^2 - 1) * m */ >> - mpz_mul (t, p->x, p->x); >> - mpz_mod (t, t, ecc->p); >> - mpz_sub_ui (t, t, 1); >> - mpz_mul_ui (t, t, 3); >> - >> - mpz_mul (t, t, m); >> - mpz_mod (t, t, ecc->p); >> - >> - /* x' = t^2 - 2 x */ >> - mpz_mul (x, t, t); >> - mpz_submul_ui (x, p->x, 2); >> - >> - mpz_mod (x, x, ecc->p); >> - >> - /* y' = (x - x') * t - y */ >> - mpz_sub (y, p->x, x); >> - mpz_mul (y, y, t); >> - mpz_sub (y, y, p->y); >> - mpz_mod (y, y, ecc->p); >> - >> - r->is_zero = 0; >> - mpz_swap (x, r->x); >> - mpz_swap (y, r->y); >> - >> - mpz_clear (m); >> - mpz_clear (t); >> - mpz_clear (x); >> - mpz_clear (y); >> - } >> + { >> + mpz_t m, t, x, y; >> + >> + mpz_init (m); >> + mpz_init (t); >> + mpz_init (x); >> + mpz_init (y); >> + >> + /* m = (2 y)^-1 */ >> + mpz_mul_ui (m, p->y, 2); >> + mpz_invert (m, m, ecc->p); >> + >> + /* t = 3 (x^2 - 1) * m */ >> + mpz_mul (t, p->x, p->x); >> + mpz_mod (t, t, ecc->p); >> + mpz_sub_ui (t, t, 1); >> + mpz_mul_ui (t, t, 3); >> + >> + mpz_mul (t, t, m); >> + mpz_mod (t, t, ecc->p); >> + >> + /* x' = t^2 - 2 x */ >> + mpz_mul (x, t, t); >> + mpz_submul_ui (x, p->x, 2); >> + >> + mpz_mod (x, x, ecc->p); >> + >> + /* y' = (x - x') * t - y */ >> + mpz_sub (y, p->x, x); >> + mpz_mul (y, y, t); >> + mpz_sub (y, y, p->y); >> + mpz_mod (y, y, ecc->p); >> + >> + r->is_zero = 0; >> + mpz_swap (x, r->x); >> + mpz_swap (y, r->y); >> + >> + mpz_clear (m); >> + mpz_clear (t); >> + mpz_clear (x); >> + mpz_clear (y); >> + } >> } >> >> static void >> ecc_add (const struct ecc_curve *ecc, struct ecc_point *r, >> const struct ecc_point *p, const struct ecc_point *q) { >> - if (ecc->type == ECC_TYPE_WEIERSTRASS) >> + if (ecc->type == ECC_TYPE_WEIERSTRASS || ecc->type == >> + ECC_TYPE_SM2) >> { >> if (ecc_zero_p (p)) >> ecc_set (r, q); >> @@ -760,6 +812,25 @@ ecc_curve_init (struct ecc_curve *ecc, const char >> *curve) >> "c0d8f97ea1ca9472b5d444285d0d4f5b" >> "32e236f86de51839"); >> } >> + else if (!strcmp (curve, "sm2")) >> + { >> + ecc_curve_init_str (ecc, ECC_TYPE_SM2, >> + /* p */ >> + "fffffffeffffffffffffffffffffffff" >> + "ffffffff00000000ffffffffffffffff", >> + /* b */ >> + "28e9fa9e9d9f5e344d5a9e4bcf6509a7" >> + "f39789f515ab8f92ddbcbd414d940e93", >> + /* q (order) */ >> + "fffffffeffffffffffffffffffffffff" >> + "7203df6b21c6052b53bbf40939d54123", >> + /* g_x */ >> + "32c4ae2c1f1981195f9904466a39c994" >> + "8fe30bbff2660be1715a4589334c74c7", >> + /* g_y */ >> + "bc3736a2f4f6779c59bdcee36b692153" >> + "d0a9877cc62a474002df32e52139f0a0"); >> + } >> else >> { >> fprintf (stderr, "No known curve with name %s\n", curve); diff >> --git a/sm2-add.c b/sm2-add.c new file mode 100644 index >> 0000000..f32676c >> --- /dev/null >> +++ b/sm2-add.c >> @@ -0,0 +1,67 @@ >> +/* sm2-mul.c >> + >> + Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights >> reserved. >> + >> + This file is part of GNU Nettle. >> + >> + GNU Nettle is free software: you can redistribute it and/or >> + modify it under the terms of either: >> + >> + * the GNU Lesser General Public License as published by the Free >> + Software Foundation; either version 3 of the License, or (at your >> + option) any later version. >> + >> + or >> + >> + * the GNU General Public License as published by the Free >> + Software Foundation; either version 2 of the License, or (at your >> + option) any later version. >> + >> + or both in parallel, as here. >> + >> + GNU Nettle is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + General Public License for more details. >> + >> + You should have received copies of the GNU General Public License and >> + the GNU Lesser General Public License along with this program. If >> + not, see http://www.gnu.org/licenses/. >> +*/ >> + >> +#if HAVE_CONFIG_H >> +# include "config.h" >> +#endif >> + >> +#include <string.h> >> + >> +#include "ecc.h" >> +#include "ecc-internal.h" >> + >> +#include "sm2.h" >> +#include "sm2-internal.h" >> + >> +int >> +sm2_add (struct ecc_point *r, const struct ecc_point *p, >> + const struct ecc_point *q) > >What's the usecase for this function? If it is needed, it might be better with >a general ecc_point_add. Its just an encapsulation, we will remove it. > >> +{ >> + const struct ecc_curve *ecc = p->ecc; >> + if (!sm2_check_point(p) || !sm2_check_point(q)) { >> + return 0; >> + } >> + >> + mp_size_t itch = 3*SM2_LIMB_SIZE + ecc->mul_itch; mp_limb_t >> + *scratch = gmp_alloc_limbs (itch); mp_limb_t *pj = xalloc_limbs >> + (3*ecc->p.size); mp_limb_t *qj = xalloc_limbs (3*ecc->p.size); >> + ecc_a_to_j (ecc, pj, p->p); ecc_a_to_j (ecc, qj, q->p); >> + >> + ecc->add_hhh(p->ecc, scratch, pj, qj, scratch + 3*SM2_LIMB_SIZE); >> + ecc->h_to_a (ecc, 0, r->p, scratch, scratch + 3*SM2_LIMB_SIZE); >> + >> + gmp_free_limbs (scratch, itch); >> + free(pj); >> + free(qj); >> + return 1; >> +} >> diff --git a/sm2-internal.h b/sm2-internal.h new file mode 100644 >> index 0000000..adcc379 >> --- /dev/null >> +++ b/sm2-internal.h >> @@ -0,0 +1,69 @@ >> +/* sm2-internal.h >> + >> + Things that are used only by the testsuite and benchmark, and >> + not included in the library. > >Is that right? The file is included by library files, e.g., ecc-sm2.c. That’s not accurate, removed this. > >> + Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights >> reserved. >> + >> + This file is part of GNU Nettle. >> + >> + GNU Nettle is free software: you can redistribute it and/or >> + modify it under the terms of either: >> + >> + * the GNU Lesser General Public License as published by the Free >> + Software Foundation; either version 3 of the License, or (at your >> + option) any later version. >> + >> + or >> + >> + * the GNU General Public License as published by the Free >> + Software Foundation; either version 2 of the License, or (at your >> + option) any later version. >> + >> + or both in parallel, as here. >> + >> + GNU Nettle is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + General Public License for more details. >> + >> + You should have received copies of the GNU General Public License and >> + the GNU Lesser General Public License along with this program. If >> + not, see http://www.gnu.org/licenses/. >> +*/ >> + >> +#ifndef SM2_INTERNAL_H_INCLUDED >> +#define SM2_INTERNAL_H_INCLUDED >> + >> +#include <assert.h> >> + >> +#include "nettle-meta.h" >> + >> +#include "sm2.h" >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +#define xalloc nettle_xalloc >> +#define xalloc_limbs nettle_xalloc_limbs >> + >> +#define SM2_LIMB_SIZE 4 >> +#define SM2_LIMB_BYTES 8 >> + >> +#define IS_ILLEG_KEY(key) \ >> + (!(key)) || (((key)->ecc) != &_nettle_sm2) || !((key)->p) >> + >> +extern const char *nettle_sm2_a; >> +extern const char *nettle_sm2_xG; >> +extern const char *nettle_sm2_yG; >> + >> +void *xalloc(size_t size); >> + >> +mp_limb_t *xalloc_limbs(mp_size_t n); > >Much of this looks questionable to me. SM2_LIMB_BYTES and SM2_LIMB_SIZE are >machine dependent. Using corresponding elements of struct ecc_curve would be >better than the nettle_sm2_a, nettle_sm2_xG and nettle_sm2_yG strings. (If >there's no good place in the current struct ecc_curve to store the a constant, >that should be added). Yep, this should be changed. ALL macros machine dependent moved, I tried add para a in ecc_curve. Here is a problem, in the point check of ecc_point_set and test_ecc_point_valid_p > >And xalloc functions are already defined for the testsuite and benchmark. Removed. > >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif /* NETTLE_INTERNAL_H_INCLUDED */ >> diff --git a/sm2-lib.c b/sm2-lib.c >> new file mode 100644 >> index 0000000..0fefb20 >> --- /dev/null >> +++ b/sm2-lib.c >> @@ -0,0 +1,63 @@ >> +/* sm2-lib.c >> + >> + Things that are used only by the testsuite and benchmark, and >> + not included in the library. > >I'd prefer to not have this file. In particular, it's confusing with "lib" in >the name when it's not part of the library. The description is not accurate, file removed. > >> + Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights >> reserved. >> + >> + This file is part of GNU Nettle. >> + >> + GNU Nettle is free software: you can redistribute it and/or >> + modify it under the terms of either: >> + >> + * the GNU Lesser General Public License as published by the Free >> + Software Foundation; either version 3 of the License, or (at your >> + option) any later version. >> + >> + or >> + >> + * the GNU General Public License as published by the Free >> + Software Foundation; either version 2 of the License, or (at your >> + option) any later version. >> + >> + or both in parallel, as here. >> + >> + GNU Nettle is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + General Public License for more details. >> + >> + You should have received copies of the GNU General Public License and >> + the GNU Lesser General Public License along with this program. If >> + not, see http://www.gnu.org/licenses/. >> +*/ >> + >> +#if HAVE_CONFIG_H >> +# include "config.h" >> +#endif >> + >> +#include <assert.h> >> +#include <stdlib.h> >> +#include <stdio.h> >> +#include <string.h> >> + >> +#include "sm2-internal.h" >> +#include "ecc-internal.h" >> + >> +void * >> +xalloc(size_t size) >> +{ >> + void *p = malloc(size); >> + if (size && !p) { >> + fprintf(stderr, "Virtual memory exhausted.\n"); >> + abort(); >> + } >> + >> + return p; >> +} >> + >> +mp_limb_t * >> +xalloc_limbs (mp_size_t n) >> +{ >> + return xalloc (n * sizeof (mp_limb_t)); } >> diff --git a/sm2-mul.c b/sm2-mul.c >> new file mode 100644 >> index 0000000..f65d196 >> --- /dev/null >> +++ b/sm2-mul.c >> @@ -0,0 +1,64 @@ >> +/* sm2-mul.c >> + >> + Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights >> reserved. >> + >> + This file is part of GNU Nettle. >> + >> + GNU Nettle is free software: you can redistribute it and/or >> + modify it under the terms of either: >> + >> + * the GNU Lesser General Public License as published by the Free >> + Software Foundation; either version 3 of the License, or (at your >> + option) any later version. >> + >> + or >> + >> + * the GNU General Public License as published by the Free >> + Software Foundation; either version 2 of the License, or (at your >> + option) any later version. >> + >> + or both in parallel, as here. >> + >> + GNU Nettle is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + General Public License for more details. >> + >> + You should have received copies of the GNU General Public License and >> + the GNU Lesser General Public License along with this program. If >> + not, see http://www.gnu.org/licenses/. >> +*/ >> + >> +#if HAVE_CONFIG_H >> +# include "config.h" >> +#endif >> + >> +#include <string.h> >> + >> +#include "ecc.h" >> +#include "ecc-internal.h" >> + >> +#include "sm2.h" >> +#include "sm2-internal.h" >> + >> +int >> +sm2_mul (struct ecc_point *q, const struct ecc_scalar *n, >> + const struct ecc_point *p) >> +{ >> + const struct ecc_curve *ecc = p->ecc; >> + if (!sm2_check_point(p)) { >> + return 0; >> + } >> + mp_size_t itch = 3*SM2_LIMB_SIZE + p->ecc->mul_itch; >> + mp_limb_t *scratch = gmp_alloc_limbs (itch); >> + >> + mp_limb_t *pj = xalloc_limbs (3*SM2_LIMB_SIZE); ecc_a_to_j >> + (p->ecc, pj, p->p); >> + >> + p->ecc->mul(p->ecc, scratch, n->p, pj, scratch + 3*SM2_LIMB_SIZE); >> + p->ecc->h_to_a (p->ecc, 0, q->p, scratch, scratch + >> + 3*SM2_LIMB_SIZE); >> + >> + gmp_free_limbs (scratch, itch); >> + free(pj); >> + return 1; >> +} > >I think the general ecc_point_mul (and other ecc_point_* functions) should be >used also for sm2. The validation done by sm2_check_point should go in >ecc_point_set (currently, handling various curves in that function is a bit >messy handling, it would make sense to add a function pointer in ecc_curve for >doing the point validation. These encapsulations are removed. Add an ecc_point_check function from ecc_point_set, I wonder is there necessary to add a function pointer in ecc_curve? > >> diff --git a/sm2-point.c b/sm2-point.c new file mode 100644 index >> 0000000..0146692 >> --- /dev/null >> +++ b/sm2-point.c >> @@ -0,0 +1,105 @@ >> +/* sm2-point.c >> + >> + Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights >> reserved. >> + >> + This file is part of GNU Nettle. >> + >> + GNU Nettle is free software: you can redistribute it and/or >> + modify it under the terms of either: >> + >> + * the GNU Lesser General Public License as published by the Free >> + Software Foundation; either version 3 of the License, or (at your >> + option) any later version. >> + >> + or >> + >> + * the GNU General Public License as published by the Free >> + Software Foundation; either version 2 of the License, or (at your >> + option) any later version. >> + >> + or both in parallel, as here. >> + >> + GNU Nettle is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + General Public License for more details. >> + >> + You should have received copies of the GNU General Public License and >> + the GNU Lesser General Public License along with this program. If >> + not, see http://www.gnu.org/licenses/. >> +*/ >> + >> +#if HAVE_CONFIG_H >> +# include "config.h" >> +#endif >> + >> +#include <stdio.h> >> +#include <string.h> >> +#include <stdlib.h> >> + >> +#include "ecc.h" >> +#include "ecc-internal.h" >> + >> +#include "sm2.h" >> +#include "sm2-internal.h" >> + >> +int >> +sm2_check_point(const struct ecc_point *point) { >> + mpz_t t, x, y, a; >> + mpz_t lhs, rhs; >> + int res; >> + mp_size_t size; >> + >> + if (IS_ILLEG_KEY(point) != 0) >> + return 0; >> + >> + size = point->ecc->p.size; >> + >> + /* First check range */ >> + if (mpn_cmp (point->p, point->ecc->p.m, size) >= 0 >> + || mpn_cmp (point->p + size, point->ecc->p.m, size) >= 0) >> + return 0; >> + >> + mpz_init (lhs); >> + mpz_init (rhs); >> + >> + mpz_init_set_str(a, nettle_sm2_a, 16); mpz_roinit_n (x, point->p, >> + size); mpz_roinit_n (y, point->p + size, size); >> + >> + mpz_mul (lhs, y, y); >> + >> + /* Check y^2 = x^3 + ax + b */ >> + mpz_mul (rhs, x, x); >> + mpz_add (rhs, rhs, a); >> + mpz_mul (rhs, rhs, x); >> + mpz_add (rhs, rhs, mpz_roinit_n (t, point->ecc->b, size)); >> + >> + res = mpz_congruent_p (lhs, rhs, mpz_roinit_n (t, point->ecc->p.m, >> + size)); >> + >> + mpz_clear (lhs); >> + mpz_clear (rhs); >> + mpz_clear (a); >> + >> + return res; >> +} >> + >> +int >> +sm2_point_set (struct ecc_point *p, const mpz_t x, const mpz_t y) { >> + if (p == NULL || p->p == NULL || x == NULL || y == NULL) >> + return 0; >> + >> + p->ecc = &_nettle_sm2; >> + mp_size_t size = p->ecc->p.size; >> + >> + mpz_limbs_copy (p->p, x, size); >> + mpz_limbs_copy (p->p + size, y, size); >> + >> + if (!sm2_check_point(p)) { >> + return 0; >> + } >> + >> + return 1; >> +} >> diff --git a/sm2.h b/sm2.h >> new file mode 100644 >> index 0000000..1443b68 >> --- /dev/null >> +++ b/sm2.h >> @@ -0,0 +1,65 @@ >> +/* sm2.h >> + Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights >> reserved. >> + This file is part of GNU Nettle. >> + GNU Nettle is free software: you can redistribute it and/or >> + modify it under the terms of either: >> + * the GNU Lesser General Public License as published by the Free >> + Software Foundation; either version 3 of the License, or (at your >> + option) any later version. >> + or >> + * the GNU General Public License as published by the Free >> + Software Foundation; either version 2 of the License, or (at your >> + option) any later version. >> + or both in parallel, as here. >> + GNU Nettle is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + General Public License for more details. >> + You should have received copies of the GNU General Public License and >> + the GNU Lesser General Public License along with this program. If >> + not, see http://www.gnu.org/licenses/. >> +*/ >> + >> +#ifndef NETTLE_SM2_H_INCLUDED >> +#define NETTLE_SM2_H_INCLUDED >> + >> +#include "nettle-types.h" >> +#include "nettle-meta.h" >> + >> +#include "ecc.h" >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +#define sm2_get_order nettle_sm2_get_order #define sm2_check_point >> +nettle_sm2_check_point #define sm2_point_set nettle_sm2_point_set >> +#define sm2_add nettle_sm2_add #define sm2_mul nettle_sm2_mul >> + >> +void >> +sm2_get_order(mpz_t order); >> + >> +int >> +sm2_check_point(const struct ecc_point *point); >> + >> +int >> +sm2_point_set (struct ecc_point *p, const mpz_t x, const mpz_t y); >> + >> +int >> +sm2_add (struct ecc_point *r, const struct ecc_point *p, >> + const struct ecc_point *q); >> + >> +int >> +sm2_mul (struct ecc_point *q, const struct ecc_scalar *n, >> + const struct ecc_point *p); > >There are no curve-specific public functions like this for any of the other >curves, so it would be nice if we could eliminate them and just use the >ecc_point_* functions. Sure. > >> +const struct ecc_curve * _NETTLE_ATTRIBUTE_PURE >> +nettle_get_sm2(void); > >I think this declaration belongs in ecc_curve.h. Moved. > >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif /* NETTLE_SM2_H_INCLUDED */ >> + >> diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index >> c266282..6bda2b7 100644 >> --- a/testsuite/Makefile.in >> +++ b/testsuite/Makefile.in >> @@ -56,7 +56,8 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \ >> eddsa-compress-test.c eddsa-sign-test.c \ >> eddsa-verify-test.c ed25519-test.c ed448-test.c \ >> gostdsa-sign-test.c gostdsa-verify-test.c \ >> - gostdsa-keygen-test.c gostdsa-vko-test.c >> + gostdsa-keygen-test.c gostdsa-vko-test.c \ >> + sm2-base-test.c \ >> >> TS_SOURCES = $(TS_NETTLE_SOURCES) $(TS_HOGWEED_SOURCES) CXX_SOURCES >> = cxx-test.cxx diff --git a/testsuite/sm2-base-test.c >> b/testsuite/sm2-base-test.c new file mode 100644 index >> 0000000..be03970 >> --- /dev/null >> +++ b/testsuite/sm2-base-test.c >> @@ -0,0 +1,161 @@ >> +#include "testutils.h" >> + >> +char *order = >> +"fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123"; > >If you add sm2 to the list ecc_curves in testutils.c, existing ecc tests will >test sm2 as well. You will need to also update the test_ecc_point_valid_p >function and the ecc_ref list in the same file. Already added, seemed the ecc_mod is not compatible with sm2, I'm trying to figured out. > >> +char *pkey = >> +"81a2088f008d0e28dd4add66041cf1050cbaf053ab48f4284eb701152be5c310"; >> +char *xG = >> +"8ffdbc04ac27f21a41c878e171294962150fa9b3dece424d41abfa869260bbf0"; >> +char *yG = >> +"a6648a20e162a7ac07597f199d722ff965cfdfab1744aed669565b11bcf15cfe"; >> +char *xR = >> +"3e5641b3e68eb47e6fae1271057e1ea0faedbb49df0d690722eaca6e45f5a76c"; >> +char *yR = >> +"d0b0bf0d16a1e4dbc814a6e7b53c07a84997660b7ed0fa0cdeb93bf12000cdf6"; >> + >> +char *Px = >> +"8070905f2cf1118ec1d41a0d07dd8dd4ac663bdbe4ad85df101d0baa875d4699"; >> +char *Py = >> +"5a947c2c3b2a4bf6113e4e609190209b64f672ddca99b6a7dbf55e2fbf7019a3"; >> +char *Qx = >> +"3dd60d9474b46d903f3daf7f532eb9e81a5ea97e2676dfca39493a218a223feb"; >> +char *Qy = >> +"dd8fe0b3cf91c793d1df27a30f707d5d46b170478e210de110f6954749b40994"; >> +char *Rx = >> +"df86af4b5b7830ac4d6730e93bc3a4dd67e303c3e2824eb76dc61b26e2884f7f"; >> +char *Ry = >> +"23d8e385c6f7aea20d38df11de924427b3cea394e648e4b19b4ba086addc490a"; >> + >> +char *gx = >> +"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"; >> +char *gy = >> +"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"; >> + >> +void sm2_point_print (struct ecc_point *p); void test_get_order >> +(void); void test_add (void); void test_mul (void); >> + >> +void >> +sm2_point_print (struct ecc_point *p) { >> + char str[1024]; >> + mpz_t x, y; >> + mpz_init (x); >> + mpz_init (y); >> + ecc_point_get(p, x, y); >> + mpz_get_str(str, 16, x); >> + printf("Px : %s\n", str); >> + mpz_get_str(str, 16, y); >> + printf("Py : %s\n", str); >> + mpz_clear(x); >> + mpz_clear(y); >> +} >> + >> +void >> +test_get_order (void) >> +{ >> + int ret = 0; >> + mpz_t r, R; >> + >> + mpz_init(r); >> + mpz_init_set_str(R, order, 16); >> + >> + sm2_get_order(r); >> + >> + ret = mpz_cmp(r, R); >> + ASSERT(ret == 0); >> + >> + mpz_clear(r); >> + mpz_clear(R); >> +} >> + >> +void >> +test_get_order_NULL (void) >> +{ >> + mpz_t r; >> + >> + mpz_init(r); >> + >> + r->_mp_d = NULL; >> + sm2_get_order(r); >> + >> + mpz_clear(r); >> +} >> + >> +void >> +test_add (void) >> +{ >> + int ret = 0; >> + const struct ecc_curve *ecc = nettle_get_sm2(); >> + struct ecc_point pointp, pointq, Res; >> + mpz_t x, y; >> + >> + ecc_point_init (&pointp, ecc); >> + ecc_point_init (&pointq, ecc); >> + ecc_point_init (&Res, ecc); >> + mpz_init (x); >> + mpz_init (y); >> + mpz_set_str(x, Px, 16); >> + mpz_set_str(y, Py, 16); >> + sm2_point_set(&pointp, x, y); >> + mpz_set_str(x, Qx, 16); >> + mpz_set_str(y, Qy, 16); >> + sm2_point_set(&pointq, x, y); >> + >> + sm2_add(&Res, &pointp, &pointq); >> + >> + if (verbose) >> + sm2_point_print (&Res); >> + >> + mpz_set_str(x, Rx, 16); >> + mpz_set_str(y, Ry, 16); >> + sm2_point_set(&pointq, x, y); >> + >> + ret = mpn_cmp(Res.p, pointq.p, SM2_LIMB_BYTES); ASSERT(ret == 0); >> + >> + ecc_point_clear(&pointp); >> + ecc_point_clear(&pointq); >> + ecc_point_clear(&Res); >> + mpz_clear (x); >> + mpz_clear (y); >> +} >> + >> +void >> +test_mul (void) >> +{ >> + int ret = 0; >> + const struct ecc_curve *ecc = nettle_get_sm2(); >> + struct ecc_point pub, pr, Res; >> + struct ecc_scalar key; >> + mpz_t x, y; >> + >> + ecc_point_init (&pub, ecc); >> + ecc_point_init (&pr, ecc); >> + ecc_point_init (&Res, ecc); >> + ecc_scalar_init (&key, ecc); >> + mpz_init (x); >> + mpz_init (y); >> + >> + mpz_set_str(x, pkey, 16); >> + ecc_scalar_set(&key, x); >> + mpz_set_str(x, xG, 16); >> + mpz_set_str(y, yG, 16); >> + sm2_point_set(&pub, x, y); >> + >> + sm2_mul(&pr, &key, &pub); >> + >> + if (verbose) >> + sm2_point_print (&pr); >> + >> + mpz_set_str(x, xR, 16); >> + mpz_set_str(y, yR, 16); >> + sm2_point_set(&Res, x, y); >> + >> + ret = mpn_cmp(Res.p, pr.p, SM2_LIMB_BYTES); ASSERT(ret == 0); >> + >> + ecc_point_clear(&pub); >> + ecc_point_clear(&pr); >> + ecc_point_clear(&Res); >> + ecc_scalar_clear(&key); >> + mpz_clear (x); >> + mpz_clear (y); >> +} >> + >> +void >> +test_main (void) >> +{ >> + test_get_order(); >> + test_get_order_NULL(); >> + test_add(); >> + test_mul(); >> +} >> diff --git a/testsuite/testutils.h b/testsuite/testutils.h index >> 3e23978..c2cf5e1 100644 >> --- a/testsuite/testutils.h >> +++ b/testsuite/testutils.h >> @@ -22,6 +22,8 @@ >> # include "ecc.h" >> # include "ecc-internal.h" >> # include "ecdsa.h" >> +# include "sm2.h" >> +# include "sm2-internal.h" >> # include "gmp-glue.h" >> # if NETTLE_USE_MINI_GMP >> # include "knuth-lfib.h" > >-- >Niels Möller. PGP key CB4962D070D77D7FCB8BA36271D8F1FF368C6677. >Internet email is subject to wholesale government surveillance. > > _______________________________________________ nettle-bugs mailing list -- [email protected] To unsubscribe send an email to [email protected]
